tx · 4KpgZEacQWBKTx5XuKYMV8ozCx4eyjS4VDDQvRkuGtfZ

3MumkGGztCKAXpWDqxkddofqXSUbqQkvSJy:  -0.04900000 Waves

2023.04.28 18:32 [2554601] smart account 3MumkGGztCKAXpWDqxkddofqXSUbqQkvSJy > SELF 0.00000000 Waves

{ "type": 13, "id": "4KpgZEacQWBKTx5XuKYMV8ozCx4eyjS4VDDQvRkuGtfZ", "fee": 4900000, "feeAssetId": null, "timestamp": 1682695943273, "version": 2, "chainId": 84, "sender": "3MumkGGztCKAXpWDqxkddofqXSUbqQkvSJy", "senderPublicKey": "C3PaRKeL8AUKbwUqdniMQtThgcTh5DYHV1777Hkxy7rp", "proofs": [ "4ab7KvAB9SDbziMD3okmZLv7tBbNTP2Yo3NMckvsoiSELByvux38kyMYuTJxd4xox7Xm38bQiVwUtvXxQYrvs5uh" ], "script": "base64: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aWwACkFSVFBSRVNBTEUCB1BSRVNBTEUAD1BSRVNBTEVOVU1MQU5EUwD0AwEPZ2V0U3RyaW5nT3JGYWlsAgdhZGRyZXNzA2tleQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCdCAIFB2FkZHJlc3MFA2tleQkAuQkCCQDMCAICCm1hbmRhdG9yeSAJAMwIAgkApQgBBQdhZGRyZXNzCQDMCAICAS4JAMwIAgUDa2V5CQDMCAICDyBpcyBub3QgZGVmaW5lZAUDbmlsAgABDGdldEludE9yRWxzZQIDa2V5CmRlZmF1bHRWYWwJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwUDa2V5BQpkZWZhdWx0VmFsABFJZHhDZmdTdGFraW5nRGFwcAABABFJZHhDZmdFY29ub215RGFwcAACABRJZHhDZmdHb3Zlcm5hbmNlRGFwcAADAQprZXlSZXN0Q2ZnAAIOJXNfX3Jlc3RDb25maWcBDmtleVJlc3RBZGRyZXNzAAIMJXNfX3Jlc3RBZGRyARFyZWFkUmVzdENmZ09yRmFpbAEEcmVzdAkAvAkCCQEPZ2V0U3RyaW5nT3JGYWlsAgUEcmVzdAkBCmtleVJlc3RDZmcABQNTRVABGGdldENvbnRyYWN0QWRkcmVzc09yRmFpbAIHcmVzdENmZwNpZHgJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQCRAwIFB3Jlc3RDZmcFA2lkeAkArAICAipSZXN0IGNmZyBkb2Vzbid0IGNvbnRhaW4gYWRkcmVzcyBhdCBpbmRleCAJAKQDAQUDaWR4AAxyZXN0Q29udHJhY3QJARFAZXh0ck5hdGl2ZSgxMDYyKQEJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUEdGhpcwkBDmtleVJlc3RBZGRyZXNzAAUVZGVmYXVsdFJlc3RBZGRyZXNzU3RyAAdyZXN0Q2ZnCQERcmVhZFJlc3RDZmdPckZhaWwBBQxyZXN0Q29udHJhY3QAD2Vjb25vbXlDb250cmFjdAkBGGdldENvbnRyYWN0QWRkcmVzc09yRmFpbAIFB3Jlc3RDZmcFEUlkeENmZ0Vjb25vbXlEYXBwAAtnb3ZDb250cmFjdAkBGGdldENvbnRyYWN0QWRkcmVzc09yRmFpbAIFB3Jlc3RDZmcFFElkeENmZ0dvdmVybmFuY2VEYXBwARFrZXlMYXN0VHhJZEJ5VXNlcgEEYWRkcgkArAICAg9sYXN0VHhJZEJ5VXNlcl8FBGFkZHIBEmtleU5leHRGcmVlTGFuZE51bQACC25leHRMYW5kTnVtARBrZXlMYW5kVG9Bc3NldElkAQdsYW5kTnVtCQCsAgICDGxhbmRUb0Fzc2V0XwUHbGFuZE51bQEKa2V5TmZ0TmFtZQIHbGFuZE51bQhsYW5kU2l6ZQkArAICCQCsAgIFCkxBTkRQUkVGSVgFB2xhbmROdW0FCGxhbmRTaXplARVrZXlMYW5kQXNzZXRJZFRvT3duZXIBB2Fzc2V0SWQJAKwCAgIJbmZ0T3duZXJfBQdhc3NldElkARBrZXlEdWNrSWRUb093bmVyAQdhc3NldElkCQCsAgICCmR1Y2tPd25lcl8FB2Fzc2V0SWQBFmtleVN0YWtlZFRpbWVCeUFzc2V0SWQBB2Fzc2V0SWQJAKwCAgILc3Rha2VkVGltZV8FB2Fzc2V0SWQBFmtleUluZnJhTGV2ZWxCeUFzc2V0SWQBB2Fzc2V0SWQJAKwCAgILaW5mcmFMZXZlbF8FB2Fzc2V0SWQBHmtleUluZnJhTGV2ZWxCeUFzc2V0SWRBbmRPd25lcgIHYXNzZXRJZAlvd25lckFkZHIJAKwCAgkArAICCQCsAgICHGluZnJhTGV2ZWxCeUFzc2V0SWRBbmRPd25lcl8FB2Fzc2V0SWQCAV8FCW93bmVyQWRkcgEfa2V5UHJlc2FsZUFydEFjdGl2YXRlZEJ5QXNzZXRJZAEHYXNzZXRJZAkArAICAhRwcmVzYWxlQXJ0QWN0aXZhdGVkXwUHYXNzZXRJZAEna2V5UHJlc2FsZUFydEFjdGl2YXRlZEJ5QXNzZXRJZEFuZE93bmVyAgdhc3NldElkCW93bmVyQWRkcgkArAICCQCsAgIJAKwCAgIlcHJlc2FsZUFydEFjdGl2YXRlZEJ5QXNzZXRJZEFuZE93bmVyXwUHYXNzZXRJZAIBXwUJb3duZXJBZGRyASBrZXlMYW5kQXJ0U3RhdHVzQnlUeXBlQW5kQXNzZXRJZAIEdHlwZQdhc3NldElkCQC5CQIJAMwIAgINbGFuZEFydFN0YXR1cwkAzAgCBQR0eXBlCQDMCAIFB2Fzc2V0SWQFA25pbAIBXwEla2V5TGFuZEFydFN0YXR1c0J5VHlwZUFzc2V0SWRBbmRPd25lcgMEdHlwZQdhc3NldElkCW93bmVyQWRkcgkAuQkCCQDMCAICImxhbmRBcnRTdGF0dXNCeVR5cGVBc3NldElkQW5kT3duZXIJAMwIAgUEdHlwZQkAzAgCBQdhc3NldElkCQDMCAIFCW93bmVyQWRkcgUDbmlsAgFfARRrZXlTdGFrZWREdWNrQnlPd25lcgEJb3duZXJBZGRyCQCsAgICEnN0YWtlZER1Y2tCeU93bmVyXwUJb3duZXJBZGRyASJrZXlTdGFrZWRUaW1lQnlUeXBlQXNzZXRJZEFuZE93bmVyAwduZnRUeXBlB2Fzc2V0SWQJb3duZXJBZGRyCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgIgc3Rha2VkVGltZUJ5VHlwZUFzc2V0SWRBbmRPd25lcl8FB25mdFR5cGUCAV8FB2Fzc2V0SWQCAV8FCW93bmVyQWRkcgERa2V5TGFuZE51bVRvT3duZXIBB2xhbmROdW0JAKwCAgIKbGFuZE93bmVyXwUHbGFuZE51bQERa2V5QmFja3BhY2tCeUR1Y2sBC2R1Y2tBc3NldElkCQCsAgICCWJhY2tQYWNrXwULZHVja0Fzc2V0SWQBEmtleVdhcmVob3VzZUJ5TGFuZAELbGFuZEFzc2V0SWQJAKwCAgIKd2FyZUhvdXNlXwULbGFuZEFzc2V0SWQBD2tleUR1Y2tMb2NhdGlvbgELZHVja0Fzc2V0SWQJAKwCAgINZHVja0xvY2F0aW9uXwULZHVja0Fzc2V0SWQBDWtleUR1Y2tIZWFsdGgBC2R1Y2tBc3NldElkCQCsAgICC2R1Y2tIZWFsdGhfBQtkdWNrQXNzZXRJZAERa2V5UmVzUHJvcG9ydGlvbnMAAhNyZXNUeXBlc1Byb3BvcnRpb25zARVrZXlTdGFrZWRMYW5kc0J5T3duZXIBCW93bmVyQWRkcgkArAICAhNzdGFrZWRMYW5kc0J5T3duZXJfBQlvd25lckFkZHIBCmtleUJsb2NrZWQAAhBjb250cmFjdHNCbG9ja2VkARVrZXlVc2VyR3dsUmVsZWFzZVRpbWUBCHVzZXJBZGRyCQCsAgICGiVzJXNfX3VzZXJHd2xSZWxlYXNlVGltZV9fBQh1c2VyQWRkcgAKcmVjTGFuZE51bQAAAAtyZWNMYW5kU2l6ZQABAAtyZWNUZXJyYWlucwACAAxyZWNDb250aW5lbnQAAwAPbG9jSWR4Q29udGluZW50AAAACmxvY0lkeFR5cGUAAQAIbG9jSWR4SWQAAgAKYnBJZHhMZXZlbAAAAAhicElkeFJlcwABAAhicElkeE1hdAACAAlicElkeFByb2QAAwAId2hJZHhWb2wAAAAId2hJZHhSZXMAAQAId2hJZHhNYXQAAgAJd2hJZHhQcm9kAAMADndoSWR4TG9ja2VkVm9sAAQAC2NsYWltTW9kZVdoAAAADWNsYWltTW9kZUR1Y2sAAQATY2xhaW1Nb2RlV2hUaGVuRHVjawACAQhhc1N0cmluZwEBdgQHJG1hdGNoMAUBdgMJAAECBQckbWF0Y2gwAgZTdHJpbmcEAXMFByRtYXRjaDAFAXMJAAIBAhhmYWlsIHRvIGNhc3QgaW50byBTdHJpbmcBE2Rpc3RyaWJ1dGVCeVdlaWdodHMCBXRvdGFsB3dlaWdodHMEA3N1bQkAZAIJAGQCCQBkAgkAZAIJAGQCCQCRAwIFB3dlaWdodHMAAAkAkQMCBQd3ZWlnaHRzAAEJAJEDAgUHd2VpZ2h0cwACCQCRAwIFB3dlaWdodHMAAwkAkQMCBQd3ZWlnaHRzAAQJAJEDAgUHd2VpZ2h0cwAFAwkAZwIAAAUDc3VtCQACAQIQWmVybyB3ZWlnaHRzIHN1bQQFbm9ybTYJAGsDBQV0b3RhbAUFTVVMVDYFA3N1bQoBCm5vcm1hbGl6ZXICA2FjYwRlbGVtCQDNCAIFA2FjYwkAawMFBGVsZW0FBW5vcm02BQVNVUxUNgoAAiRsBQd3ZWlnaHRzCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQpub3JtYWxpemVyAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhNMaXN0IHNpemUgZXhjZWVkcyA2CQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGARJnZXROZWVkZWRNYXRlcmlhbHMBBXRvdGFsBAVwcm9wcwkAtQkCCQEFdmFsdWUBCQCiCAEJARFrZXlSZXNQcm9wb3J0aW9ucwACAV8DCQECIT0CCQCQAwEFBXByb3BzBQZOVU1SRVMJAAIBAhZXcm9uZyBwcm9wb3J0aW9ucyBkYXRhBAFyCQDMCAIJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQVwcm9wcwAACQDMCAIJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQVwcm9wcwABCQDMCAIJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQVwcm9wcwACCQDMCAIJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQVwcm9wcwADCQDMCAIJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQVwcm9wcwAECQDMCAIJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQVwcm9wcwAFBQNuaWwJARNkaXN0cmlidXRlQnlXZWlnaHRzAgUFdG90YWwFAXIBEXN1YnRyYWN0TWF0ZXJpYWxzAwxzaG91bGRVc2VNYXQDaGFzCXRvdGFsTmVlZAQEbmVlZAkBEmdldE5lZWRlZE1hdGVyaWFscwEFCXRvdGFsTmVlZAoBCnN1YnRyYWN0b3ICA2FjYwNpZHgEBnJlc3VsdAkAZQIJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQNoYXMFA2lkeAkAkQMCBQRuZWVkBQNpZHgDCQBmAgAABQZyZXN1bHQJAAIBCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgIYTm90IGVub3VnaCBtYXRlcmlhbCBpZHg9CQCkAwEFA2lkeAILLCB5b3UgaGF2ZSAJAJEDAgUDaGFzBQNpZHgCCywgYnV0IG5lZWQgCQCkAwEJAJEDAgUEbmVlZAUDaWR4CQDNCAIFA2FjYwkApAMBBQZyZXN1bHQDBQxzaG91bGRVc2VNYXQKAAIkbAkAzAgCAAAJAMwIAgABCQDMCAIAAgkAzAgCAAMJAMwIAgAECQDMCAIABQUDbmlsCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQpzdWJ0cmFjdG9yAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhNMaXN0IHNpemUgZXhjZWVkcyA2CQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGBQNoYXMBGXVwZGF0ZVByb3BvcnRpb25zSW50ZXJuYWwECHByb3BMaXN0DXRlcnJhaW5Db3VudHMNbGFuZFNpemVJbmRleARzaWduAwkBAiE9AgkAkAMBBQhwcm9wTGlzdAUGTlVNUkVTCQACAQIWV3JvbmcgcHJvcG9ydGlvbnMgZGF0YQoBB3VwZGF0ZXICA2FjYwFpBAZyZXN1bHQJAGQCCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUIcHJvcExpc3QFAWkJAGgCCQBoAgUEc2lnbgkAkQMCBQ10ZXJyYWluQ291bnRzBQFpBQ1sYW5kU2l6ZUluZGV4AwkAZgIAAAUGcmVzdWx0CQACAQkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICAhZQYW5pYyEgUGllY2VzIG9mIHR5cGU9CQCkAwEFAWkCBywgc2lnbj0JAKQDAQUEc2lnbgIULCAgdGVycmFpbkNvdW50c1tpXT0JAKQDAQkAkQMCBQ10ZXJyYWluQ291bnRzBQFpAhAsIGxhbmRTaXplSW5kZXg9CQCkAwEFDWxhbmRTaXplSW5kZXgJAM0IAgUDYWNjCQCkAwEFBnJlc3VsdAQBcgoAAiRsCQDMCAIAAAkAzAgCAAEJAMwIAgACCQDMCAIAAwkAzAgCAAQJAMwIAgAFBQNuaWwKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjBfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBB3VwZGF0ZXICBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECE0xpc3Qgc2l6ZSBleGNlZWRzIDYJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYJALkJAgUBcgIBXwERdXBkYXRlUHJvcG9ydGlvbnMDDXRlcnJhaW5Db3VudHMNbGFuZFNpemVJbmRleARzaWduBAhwcm9wTGlzdAkAtQkCCQELdmFsdWVPckVsc2UCCQCiCAEJARFrZXlSZXNQcm9wb3J0aW9ucwACCzBfMF8wXzBfMF8wAgFfCQEZdXBkYXRlUHJvcG9ydGlvbnNJbnRlcm5hbAQFCHByb3BMaXN0BQ10ZXJyYWluQ291bnRzBQ1sYW5kU2l6ZUluZGV4BQRzaWduAQ1jb3VudFRlcnJhaW5zAQh0ZXJyYWlucwkAzAgCCQBlAgkAkAMBCQC1CQIFCHRlcnJhaW5zAgFBAAEJAMwIAgkAZQIJAJADAQkAtQkCBQh0ZXJyYWlucwIBQgABCQDMCAIJAGUCCQCQAwEJALUJAgUIdGVycmFpbnMCAUMAAQkAzAgCCQBlAgkAkAMBCQC1CQIFCHRlcnJhaW5zAgFEAAEJAMwIAgkAZQIJAJADAQkAtQkCBQh0ZXJyYWlucwIBRQABCQDMCAIJAGUCCQCQAwEJALUJAgUIdGVycmFpbnMCAUYAAQUDbmlsAQ9udW1QaWVjZXNCeVNpemUBCGxhbmRTaXplBAckbWF0Y2gwBQhsYW5kU2l6ZQMJAAACAgFTBQckbWF0Y2gwBQVTU0laRQMJAAACAgFNBQckbWF0Y2gwBQVNU0laRQMJAAACAgFMBQckbWF0Y2gwBQVMU0laRQMJAAACAgJYTAUHJG1hdGNoMAUGWExTSVpFAwkAAAICA1hYTAUHJG1hdGNoMAUHWFhMU0laRQkAAgECEVVua25vd24gbGFuZCBzaXplAQxzdWJPbmVJbkxpc3QDBWFMaXN0A2lkeAZhbW91bnQKAQZzdWJiZXICA2FjYwFpCQDNCAIFA2FjYwMJAAACBQFpBQNpZHgJAKQDAQkAZQIJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQVhTGlzdAUBaQUGYW1vdW50CQCRAwIFBWFMaXN0BQFpBAFyCgACJGwJAMwIAgAACQDMCAIAAQkAzAgCAAIJAMwIAgADCQDMCAIABAkAzAgCAAUFA25pbAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEGc3ViYmVyAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRp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tQkCCQELdmFsdWVPckVsc2UCCQCiCAEFBWJwS2V5AhowOjBfMF8wXzBfMF8wOjBfMF8wXzBfMF8wOgIBOgkAzAgCCQCkAwEJAQt2YWx1ZU9yRWxzZQIJALYJAQkAkQMCBQFwBQpicElkeExldmVsAAAJAMwIAgMJAAACCQCQAwEJALUJAgkAkQMCBQFwBQhicElkeFJlcwIBXwUGTlVNUkVTCQCRAwIFAXAFCGJwSWR4UmVzAgswXzBfMF8wXzBfMAkAzAgCAwkAAAIJAJADAQkAtQkCCQCRAwIFAXAFCGJwSWR4TWF0AgFfBQZOVU1SRVMJAJEDAgUBcAUIYnBJZHhNYXQCCzBfMF8wXzBfMF8wCQDMCAIJAJEDAgUBcAUJYnBJZHhQcm9kBQNuaWwBEmdldFdhcmVob3VzZVZvbHVtZQEJdm9sUHJlZml4BAVwYXJ0cwkAtQkCBQl2b2xQcmVmaXgCAV8JAGgCCQBoAgUMV0hNVUxUSVBMSUVSCQBkAgkBDXBhcnNlSW50VmFsdWUBCQCRAwIFBXBhcnRzAAEAAQkBDXBhcnNlSW50VmFsdWUBCQCRAwIFBXBhcnRzAAABDGdldFdhcmVob3VzZQMFd2hLZXkJbGFuZEluZGV4CmluZnJhTGV2ZWwECXZvbFByZWZpeAkArAICCQCsAgIJAKQDAQUJbGFuZEluZGV4AgFfCQCkAwEFCmluZnJhTGV2ZWwEAXAJALUJAgkBC3ZhbHVlT3JFbHNlAgkAoggBBQV3aEtleQkArAICBQl2b2xQcmVmaXgCGzowXzBfMF8wXzBfMDowXzBfMF8wXzBfMDo6MAIBOgkAzAgCCQCRAwIFAXAFCHdoSWR4Vm9sCQDMCAIDCQAAAgkAkAMBCQC1CQIJAJEDAgUBcAUId2hJZHhSZXMCAV8FBk5VTVJFUwkAkQMCBQFwBQh3aElkeFJlcwILMF8wXzBfMF8wXzAJAMwIAgMJAAACCQCQAwEJALUJAgkAkQMCBQFwBQh3aElkeE1hdAIBXwUGTlVNUkVTCQCRAwIFAXAFCHdoSWR4TWF0AgswXzBfMF8wXzBfMAkAzAgCCQCRAwIFAXAFCXdoSWR4UHJvZAkAzAgCAwkAZgIABQkAkAMBBQFwAgEwCQCRAwIFAXAFDndoSWR4TG9ja2VkVm9sBQNuaWwBGWdldFdhcmVob3VzZUN1cnJSZXNWb2x1bWUBCWN1cnJlbnRXaAoBA3N1bQIDYWNjBGl0ZW0JAGQCBQNhY2MJAQ1wYXJzZUludFZhbHVlAQUEaXRlbQoAAiRsCQC1CQIJAJEDAgUJY3VycmVudFdoBQh3aElkeFJlcwIBXwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAAAAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEDc3VtAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhNMaXN0IHNpemUgZXhjZWVkcyA2CQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGARlnZXRXYXJlaG91c2VDdXJyTWF0Vm9sdW1lAQljdXJyZW50V2gKAQNzdW0CA2FjYwRpdGVtCQBkAgUDYWNjCQENcGFyc2VJbnRWYWx1ZQEFBGl0ZW0KAAIkbAkAtQkCCQCRAwIFCWN1cnJlbnRXaAUId2hJZHhNYXQCAV8KAAIkcwkAkAMBBQIkbAoABSRhY2MwAAAKAQUkZjBfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBA3N1bQIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQITTGlzdCBzaXplIGV4Y2VlZHMgNgkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgEbZ2V0V2FyZWhvdXNlQ3Vyckdvb2RzVm9sdW1lAQljdXJyZW50V2gEBWdvb2RzCQCRAwIFCWN1cnJlbnRXaAUJd2hJZHhQcm9kAwkAAAIFBWdvb2RzAgAAAAoBA3N1bQIDYWNjBGl0ZW0JAGQCBQNhY2MJAQ1wYXJzZUludFZhbHVlAQUEaXRlbQoAAiRsCQC8CQIFBWdvb2RzAgFfCgACJHMJAJADAQUCJGwKAAUkYWNjMAAACgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQNzdW0CBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDUwCQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoACwAMAA0ADgAPABAAEQASABMAFAAVABYAFwAYABkAGgAbABwAHQAeAB8AIAAhACIAIwAkACUAJgAnACgAKQAqACsALAAtAC4ALwAwADEAMgEJbW92ZVN0dWZmAwpjYXJnb1BhcnRzCWN1cnJlbnRXaAtjdXJyZW50UGFjawMJAQIhPQIJAJADAQUKY2FyZ29QYXJ0cwADCQACAQI0Y2FyZ29MaXN0U3RyIHNob3VsZCBjb250YWluIGV4YWN0bHkgMiAnOicgc2VwYXJhdG9ycwQIcmVzUGFydHMJALUJAgkAkQMCBQpjYXJnb1BhcnRzAAACAV8ECG1hdFBhcnRzCQC1CQIJAJEDAgUKY2FyZ29QYXJ0cwABAgFfBAlwcm9kUGFydHMDCQAAAgkAkQMCBQpjYXJnb1BhcnRzAAICAAUDbmlsCQC1CQIJAJEDAgUKY2FyZ29QYXJ0cwACAgFfAwkBAiE9AgkAkAMBBQhyZXNQYXJ0cwUGTlVNUkVTCQACAQIgQWxsIDYgcmVzb3VyY2VzIHNob3VsZCBiZSBwYXNzZWQDCQECIT0CCQCQAwEFCG1hdFBhcnRzBQZOVU1SRVMJAAIBAiBBbGwgNiBtYXRlcmlhbHMgc2hvdWxkIGJlIHBhc3NlZAQMY3VycldoUmVzVm9sCQEZZ2V0V2FyZWhvdXNlQ3VyclJlc1ZvbHVtZQEFCWN1cnJlbnRXaAQMY3VycldoTWF0Vm9sCQEZZ2V0V2FyZWhvdXNlQ3Vyck1hdFZvbHVtZQEFCWN1cnJlbnRXaAQOY3VycldoR29vZHNWb2wJARtnZXRXYXJlaG91c2VDdXJyR29vZHNWb2x1bWUBBQljdXJyZW50V2gED2N1cnJXaExvY2tlZFZvbAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCWN1cnJlbnRXaAUOd2hJZHhMb2NrZWRWb2wEC3doU3BhY2VMZWZ0CQBlAgkAZQIJAGUCCQBlAgkBEmdldFdhcmVob3VzZVZvbHVtZQEJAJEDAgUJY3VycmVudFdoBQh3aElkeFZvbAUMY3VycldoUmVzVm9sBQxjdXJyV2hNYXRWb2wFDmN1cnJXaEdvb2RzVm9sBQ9jdXJyV2hMb2NrZWRWb2wECWN1cnJXaFJlcwkAtQkCCQCRAwIFCWN1cnJlbnRXaAUId2hJZHhSZXMCAV8ECWN1cnJXaE1hdAkAtQkCCQCRAwIFCWN1cnJlbnRXaAUId2hJZHhNYXQCAV8ECmN1cnJXaFByb2QDCQAAAgkAkQMCBQljdXJyZW50V2gFCXdoSWR4UHJvZAIABQNuaWwJALUJAgkAkQMCBQljdXJyZW50V2gFCXdoSWR4UHJvZAIBXwQOY3VycmVudFBhY2tSZXMJALUJAgkAkQMCBQtjdXJyZW50UGFjawUIYnBJZHhSZXMCAV8EDmN1cnJlbnRQYWNrTWF0CQC1CQIJAJEDAgULY3VycmVudFBhY2sFCGJwSWR4TWF0AgFfBA9jdXJyZW50UGFja1Byb2QDCQAAAgkAkQMCBQtjdXJyZW50UGFjawUJYnBJZHhQcm9kAgAFA25pbAkAtQkCCQCRAwIFC2N1cnJlbnRQYWNrBQlicElkeFByb2QCAV8KAQNtdlICA2FjYwRpdGVtBAFpCAUDYWNjAl8xBAJhbQkBDXBhcnNlSW50VmFsdWUBBQRpdGVtBAN3aHIJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQljdXJyV2hSZXMFAWkEA2JwcgkBDXBhcnNlSW50VmFsdWUBCQCRAwIFDmN1cnJlbnRQYWNrUmVzBQFpAwkAAAIFAmFtAAAJAJYKBAkAZAIFAWkAAQkAzQgCCAUDYWNjAl8yCQCRAwIFCWN1cnJXaFJlcwUBaQkAzQgCCAUDYWNjAl8zCQCRAwIFDmN1cnJlbnRQYWNrUmVzBQFpCAUDYWNjAl80AwkAZgIFAmFtAAADCQBmAgUCYW0FA2JwcgkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgIQQXR0ZW1wdCB0byB0YWtlIAUEaXRlbQIZIGZyb20gYmFja3BhY2ssIGJ1dCBvbmx5IAkApAMBBQNicHICCiBhdmFpbGFibGUJAJYKBAkAZAIFAWkAAQkAzQgCCAUDYWNjAl8yCQCkAwEJAGQCBQN3aHIFAmFtCQDNCAIIBQNhY2MCXzMJAKQDAQkAZQIFA2JwcgUCYW0JAGQCCAUDYWNjAl80BQJhbQMJAGYCCQEBLQEFAmFtBQN3aHIJAAIBCQCsAgIJAKwCAgkArAICCQCsAgICEEF0dGVtcHQgdG8gdGFrZSAJAKQDAQkBAS0BBQJhbQIaIGZyb20gd2FyZWhvdXNlLCBidXQgb25seSAJAKQDAQUDd2hyAgogYXZhaWxhYmxlCQCWCgQJAGQCBQFpAAEJAM0IAggFA2FjYwJfMgkApAMBCQBkAgUDd2hyBQJhbQkAzQgCCAUDYWNjAl8zCQCkAwEJAGUCBQNicHIFAmFtCQBkAggFA2FjYwJfNAUCYW0EAXIKAAIkbAUIcmVzUGFydHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwCQCWCgQAAAUDbmlsBQNuaWwAAAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEDbXZSAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhNMaXN0IHNpemUgZXhjZWVkcyA2CQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGCgEDbXZNAgNhY2MEaXRlbQQBaQgFA2FjYwJfMQQCYW0JAQ1wYXJzZUludFZhbHVlAQUEaXRlbQQDd2htCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUJY3VycldoTWF0BQFpBANicG0JAQ1wYXJzZUludFZhbHVlAQkAkQMCBQ5jdXJyZW50UGFja01hdAUBaQMJAAACBQJhbQAACQCWCgQJAGQCBQFpAAEJAM0IAggFA2FjYwJfMgkAkQMCBQljdXJyV2hNYXQFAWkJAM0IAggFA2FjYwJfMwkAkQMCBQ5jdXJyZW50UGFja01hdAUBaQgFA2FjYwJfNAMJAGYCBQJhbQAAAwkAZgIFAmFtBQNicG0JAAIBCQCsAgIJAKwCAgkArAICCQCsAgICEEF0dGVtcHQgdG8gdGFrZSAFBGl0ZW0CGSBmcm9tIGJhY2twYWNrLCBidXQgb25seSAJAKQDAQUDYnBtAgogYXZhaWxhYmxlCQCWCgQJAGQCBQFpAAEJAM0IAggFA2FjYwJfMgkApAMBCQBkAgUDd2htBQJhbQkAzQgCCAUDYWNjAl8zCQCkAwEJAGUCBQNicG0FAmFtCQBkAggFA2FjYwJfNAUCYW0DCQBmAgkBAS0BBQJhbQUDd2htCQACAQkArAICCQCsAgIJAKwCAgkArAICAhBBdHRlbXB0IHRvIHRha2UgCQCkAwEJAQEtAQUCYW0CGiBmcm9tIHdhcmVob3VzZSwgYnV0IG9ubHkgCQCkAwEFA3dobQIKIGF2YWlsYWJsZQkAlgoECQBkAgUBaQABCQDNCAIIBQNhY2MCXzIJAKQDAQkAZAIFA3dobQUCYW0JAM0IAggFA2FjYwJfMwkApAMBCQBlAgUDYnBtBQJhbQkAZAIIBQNhY2MCXzQFAmFtBAFtCgACJGwFCG1hdFBhcnRzCgACJHMJAJADAQUCJGwKAAUkYWNjMAkAlgoEAAAFA25pbAUDbmlsCAUBcgJfNAoBBSRmMV8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEDbXZNAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYxXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhNMaXN0IHNpemUgZXhjZWVkcyA2CQEFJGYxXzICCQEFJGYxXzECCQEFJGYxXzECCQEFJGYxXzECCQEFJGYxXzECCQEFJGYxXzECCQEFJGYxXzECBQUkYWNjMAAAAAEAAgADAAQABQAGCgEDbXZQAgNhY2MEaXRlbQQBaQgFA2FjYwJfMQQCYW0JAQ1wYXJzZUludFZhbHVlAQUEaXRlbQQDd2hwCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUKY3VycldoUHJvZAUBaQQDYnBwCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUPY3VycmVudFBhY2tQcm9kBQFpAwkAAAIFAmFtAAAJAJYKBAkAZAIFAWkAAQkAzQgCCAUDYWNjAl8yCQCRAwIFCmN1cnJXaFByb2QFAWkJAM0IAggFA2FjYwJfMwkAkQMCBQ9jdXJyZW50UGFja1Byb2QFAWkIBQNhY2MCXzQDCQBmAgUCYW0AAAMJAGYCBQJhbQUDYnBwCQACAQkArAICCQCsAgIJAKwCAgkArAICAhBBdHRlbXB0IHRvIHRha2UgBQRpdGVtAhkgZnJvbSBiYWNrcGFjaywgYnV0IG9ubHkgCQCkAwEFA2JwcAIKIGF2YWlsYWJsZQkAlgoECQBkAgUBaQABCQDNCAIIBQNhY2MCXzIJAKQDAQkAZAIFA3docAUCYW0JAM0IAggFA2FjYwJfMwkApAMBCQBlAgUDYnBwBQJhbQkAZAIIBQNhY2MCXzQFAmFtAwkAZgIJAQEtAQUCYW0FA3docAkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgIQQXR0ZW1wdCB0byB0YWtlIAkApAMBCQEBLQEFAmFtAhogZnJvbSB3YXJlaG91c2UsIGJ1dCBvbmx5IAkApAMBBQN3aHACCiBhdmFpbGFibGUJAJYKBAkAZAIFAWkAAQkAzQgCCAUDYWNjAl8yCQCkAwEJAGQCBQN3aHAFAmFtCQDNCAIIBQNhY2MCXzMJAKQDAQkAZQIFA2JwcAUCYW0JAGQCCAUDYWNjAl80BQJhbQQBcAoAAiRsBQlwcm9kUGFydHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwCQCWCgQAAAUDbmlsBQNuaWwIBQFtAl80CgEFJGYyXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQNtdlACBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjJfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDUwCQEFJGYyXzICCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoACwAMAA0ADgAPABAAEQASABMAFAAVABYAFwAYABkAGgAbABwAHQAeAB8AIAAhACIAIwAkACUAJgAnACgAKQAqACsALAAtAC4ALwAwADEAMgQIdm9sU2FsZG8IBQFwAl80AwkAZgIFCHZvbFNhbGRvBQt3aFNwYWNlTGVmdAkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgIVQXR0ZW1wdCB0byBwdXQgdG90YWwgCQCkAwEFCHZvbFNhbGRvAhEgc3R1ZmYsIGJ1dCBvbmx5IAkApAMBBQt3aFNwYWNlTGVmdAIVIHdhcmVob3VzZSBzcGFjZSBsZWZ0CQCYCgYJALkJAggFAXICXzICAV8JALkJAggFAW0CXzICAV8JALkJAggFAXACXzICAV8JALkJAggFAXICXzMCAV8JALkJAggFAW0CXzMCAV8JALkJAggFAXACXzMCAV8BEmV4cGVkaXRpb25JbnRlcm5hbAIGY2FsbGVyBHR4SWQECHVzZXJBZGRyCQClCAEFBmNhbGxlcgQGYmlnTnVtCQEDYWJzAQkAngMBBQR0eElkBAdmcmVlTnVtCQELdmFsdWVPckVsc2UCCQCfCAEJARJrZXlOZXh0RnJlZUxhbmROdW0ACQBkAgUPUFJFU0FMRU5VTUxBTkRTAAEEB2xhbmROdW0JAKQDAQUHZnJlZU51bQQMY29udGluZW50SWR4CQCgAwEJALsCAgUGYmlnTnVtBQVGSVZFWAQIdGVycmFpbnMJAQtnZW5UZXJyYWlucwIFBmJpZ051bQUMY29udGluZW50SWR4BAljb250aW5lbnQJAJEDAgUKY29udGluZW50cwUMY29udGluZW50SWR4BAVpc3N1ZQkAwggFCQEKa2V5TmZ0TmFtZQIFB2xhbmROdW0CAVMJALkJAgkAzAgCBQdsYW5kTnVtCQDMCAICAVMJAMwIAgUIdGVycmFpbnMJAMwIAgUJY29udGluZW50BQNuaWwCAV8AAQAABwQHYXNzZXRJZAkAuAgBBQVpc3N1ZQQCaWQJANgEAQUHYXNzZXRJZAkAlAoCCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQESa2V5TmV4dEZyZWVMYW5kTnVtAAkAZAIFB2ZyZWVOdW0AAQkAzAgCBQVpc3N1ZQkAzAgCCQELU3RyaW5nRW50cnkCCQEQa2V5TGFuZFRvQXNzZXRJZAEFB2xhbmROdW0FAmlkCQDMCAIJAQtTdHJpbmdFbnRyeQIJARVrZXlMYW5kQXNzZXRJZFRvT3duZXIBBQJpZAUIdXNlckFkZHIJAMwIAgkBC1N0cmluZ0VudHJ5AgkBEWtleUxhbmROdW1Ub093bmVyAQUHbGFuZE51bQUIdXNlckFkZHIJAMwIAgkBDEludGVnZXJFbnRyeQIJARZrZXlJbmZyYUxldmVsQnlBc3NldElkAQUCaWQAAAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBHmtleUluZnJhTGV2ZWxCeUFzc2V0SWRBbmRPd25lcgIFAmlkBQh1c2VyQWRkcgAACQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMFBmNhbGxlcgABBQdhc3NldElkBQNuaWwJAJQKAgUCaWQFCWNvbnRpbmVudAEQZXhwZWRpdGlvbkNvbW1vbgUMc2hvdWxkVXNlTWF0BmNhbGxlcgR0eElkB21lc3NhZ2UDc2lnAwkBASEBCQDEEwMFB21lc3NhZ2UFA3NpZwUDcHViCQACAQIYc2lnbmF0dXJlIGRvZXMgbm90IG1hdGNoBAVwYXJ0cwkAtQkCCQCwCQEFB21lc3NhZ2UCATsEAmhwCQC1CQIJAJEDAgkAtQkCCQCRAwIFBXBhcnRzAAACAXwAAAIBXwQFY3VySFAJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQJocAAABAVuZXdIUAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFAmhwAAEECmxvY0FuZFRpbWUJALUJAgkAkQMCBQVwYXJ0cwABAgE6BA50YXJnZXRMb2NhdGlvbgkAtQkCCQCRAwIFCmxvY0FuZFRpbWUAAAIBXwMJAQIhPQIJAJEDAgUOdGFyZ2V0TG9jYXRpb24AAQIBRQkAAgECK2V4cGVkaXRpb24gdGFyZ2V0IGxvY2F0aW9uIHR5cGUgc2hvdWxkIGJlIEUEBHRpbWUJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQpsb2NBbmRUaW1lAAEDAwkAZgIFBHRpbWUJAGQCCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAURRklWRU1JTlVURVNNSUxMSVMGCQBmAgkAZQIIBQlsYXN0QmxvY2sJdGltZXN0YW1wBRFGSVZFTUlOVVRFU01JTExJUwUEdGltZQkAAgECEnNpZ25hdHVyZSBvdXRkYXRlZAQIdXNlckFkZHIJAKUIAQUGY2FsbGVyBAtkdWNrQXNzZXRJZAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCiCAEJARRrZXlTdGFrZWREdWNrQnlPd25lcgEFCHVzZXJBZGRyAhxZb3UgZG9uJ3QgaGF2ZSBhIGR1Y2sgc3Rha2VkBAlrZXlIZWFsdGgJAQ1rZXlEdWNrSGVhbHRoAQULZHVja0Fzc2V0SWQEDG9sZEZyb21TdGF0ZQkBC3ZhbHVlT3JFbHNlAgkAnwgBBQlrZXlIZWFsdGgAZAMJAQIhPQIFDG9sZEZyb21TdGF0ZQUFY3VySFAJAAIBCQCsAgIJAKwCAgkArAICAgpvbGRIZWFsdGg9CQCkAwEJAQt2YWx1ZU9yRWxzZQIJAJ8IAQUJa2V5SGVhbHRoAGQCLyBmcm9tIHN0YXRlIGRvZXMgbm90IG1hdGNoIG9uZSBmcm9tIGZsaWdodCBsb2c9CQCkAwEFBWN1ckhQAwkAZwIAAAUFY3VySFAJAAIBAh5Zb3UgY2FuJ3QgZmx5IHdpdGggemVybyBoZWFsdGgDCQBnAgAABQVuZXdIUAkAlAoCCQDNCAIDCQEBIQEFDHNob3VsZFVzZU1hdAkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDBQZjYWxsZXIFB0VYUFVTRE4FC3VzZG5Bc3NldElkBQNuaWwFA25pbAkBDEludGVnZXJFbnRyeQIFCWtleUhlYWx0aAAAAgAEBWJwS2V5CQERa2V5QmFja3BhY2tCeUR1Y2sBBQtkdWNrQXNzZXRJZAQLY3VycmVudFBhY2sJAQtnZXRCYWNrcGFjawEFBWJwS2V5BAVtTGlzdAkAtQkCCQCRAwIFC2N1cnJlbnRQYWNrBQhicElkeE1hdAIBXwQGbmV3TWF0CQC5CQIJARFzdWJ0cmFjdE1hdGVyaWFscwMFDHNob3VsZFVzZU1hdAUFbUxpc3QFDEVYUE1BVEVSSUFMUwIBXwQBZQkBEmV4cGVkaXRpb25JbnRlcm5hbAIFBmNhbGxlcgUEdHhJZAQCaWQICAUBZQJfMgJfMQkAlAoCCQDNCAIJAM0IAgkAzQgCCAUBZQJfMQkBC1N0cmluZ0VudHJ5AgkBD2tleUR1Y2tMb2NhdGlvbgEFC2R1Y2tBc3NldElkCQC5CQIJAMwIAggIBQFlAl8yAl8yCQDMCAICAUwJAMwIAgUCaWQFA25pbAIBXwkBDEludGVnZXJFbnRyeQIFCWtleUhlYWx0aAUFbmV3SFAJAQtTdHJpbmdFbnRyeQIFBWJwS2V5CQC5CQIJAMwIAgkAkQMCBQtjdXJyZW50UGFjawUKYnBJZHhMZXZlbAkAzAgCCQCRAwIFC2N1cnJlbnRQYWNrBQhicElkeFJlcwkAzAgCBQZuZXdNYXQJAMwIAgkAkQMCBQtjdXJyZW50UGFjawUJYnBJZHhQcm9kBQNuaWwCAToFAmlkAQxhcHBseUJvbnVzZXMCC2xhbmRBc3NldElkBnBpZWNlcwQKaW5mcmFMZXZlbAkBC3ZhbHVlT3JFbHNlAgkAnwgBCQEWa2V5SW5mcmFMZXZlbEJ5QXNzZXRJZAEFC2xhbmRBc3NldElkAAAECWFydFBpZWNlcwkBC3ZhbHVlT3JFbHNlAgkAnwgBCQEga2V5TGFuZEFydFN0YXR1c0J5VHlwZUFuZEFzc2V0SWQCBQpBUlRQUkVTQUxFBQtsYW5kQXNzZXRJZAMJAQt2YWx1ZU9yRWxzZQIJAKAIAQkBH2tleVByZXNhbGVBcnRBY3RpdmF0ZWRCeUFzc2V0SWQBBQtsYW5kQXNzZXRJZAcFBnBpZWNlcwAACQBkAgkAZAIFD0RBSUxZUkVTQllQSUVDRQkAawMFD0RBSUxZUkVTQllQSUVDRQUKaW5mcmFMZXZlbAAECQBrAwUPREFJTFlSRVNCWVBJRUNFCQBoAgUJYXJ0UGllY2VzAAMJAGgCBQZwaWVjZXMAFAEUY2hlY2tDbGFpbUNvbmRpdGlvbnMDBGFkZHIJY2xhaW1Nb2RlDWxhbmRBc3NldElkSW4EDSR0MDIzNjMwMjQxNjkDCQAAAgUJY2xhaW1Nb2RlBQtjbGFpbU1vZGVXaAkAlAoCBQ1sYW5kQXNzZXRJZEluCQELdmFsdWVPckVsc2UCCQCiCAEJARRrZXlTdGFrZWREdWNrQnlPd25lcgEFBGFkZHICAAQLZHVja0Fzc2V0SWQJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAoggBCQEUa2V5U3Rha2VkRHVja0J5T3duZXIBBQRhZGRyAhxZb3UgZG9uJ3QgaGF2ZSBhIGR1Y2sgc3Rha2VkBAtjdXJMb2NhdGlvbgkBC3ZhbHVlT3JFbHNlAgkAoggBCQEPa2V5RHVja0xvY2F0aW9uAQULZHVja0Fzc2V0SWQFD0RFRkFVTFRMT0NBVElPTgQDbG9jCQC1CQIJAQV2YWx1ZQEFC2N1ckxvY2F0aW9uAgFfAwkBAiE9AgkAkQMCBQNsb2MFCmxvY0lkeFR5cGUCAUwJAAIBCQCsAgIJAKwCAgIWRHVjayBsb2NhdGlvbiB0eXBlIGlzIAkAkQMCBQNsb2MFCmxvY0lkeFR5cGUCESwgYnV0IHNob3VsZCBiZSBMCQCUCgIJAJEDAgUDbG9jBQhsb2NJZHhJZAULZHVja0Fzc2V0SWQEC2xhbmRBc3NldElkCAUNJHQwMjM2MzAyNDE2OQJfMQQGZHVja0lkCAUNJHQwMjM2MzAyNDE2OQJfMgQFYXNzZXQJAQV2YWx1ZQEJAOwHAQkA2QQBBQtsYW5kQXNzZXRJZAQHdGltZUtleQkBFmtleVN0YWtlZFRpbWVCeUFzc2V0SWQBBQtsYW5kQXNzZXRJZAQJc2F2ZWRUaW1lCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ8IAQUHdGltZUtleQkArAICCQCsAgICBUxhbmQgCAUFYXNzZXQEbmFtZQIOIGlzIG5vdCBzdGFrZWQEBW93bmVyCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKIIAQkBFWtleUxhbmRBc3NldElkVG9Pd25lcgEFC2xhbmRBc3NldElkCQCsAgIJAKwCAgIETkZUIAgFBWFzc2V0BG5hbWUCDCBpcyBvcnBoYW5lZAMJAQIhPQIFBW93bmVyBQRhZGRyCQACAQkArAICBQpMQU5EUFJFRklYAg0gaXMgbm90IHlvdXJzBAFkCQC1CQIIBQVhc3NldAtkZXNjcmlwdGlvbgIBXwkAlgoEBQZkdWNrSWQFC2xhbmRBc3NldElkBQFkBQlzYXZlZFRpbWUBEGNsYWltUmVzSW50ZXJuYWwEBGFkZHIGYW1vdW50CWNsYWltTW9kZQ1sYW5kQXNzZXRJZEluAwkAZgIAAAUGYW1vdW50CQACAQIPTmVnYXRpdmUgYW1vdW50BAFjCQEUY2hlY2tDbGFpbUNvbmRpdGlvbnMDBQRhZGRyBQljbGFpbU1vZGUFDWxhbmRBc3NldElkSW4ECGxhbmRTaXplCQCRAwIIBQFjAl8zBQtyZWNMYW5kU2l6ZQQNdGVycmFpbkNvdW50cwkBDWNvdW50VGVycmFpbnMBCQCRAwIIBQFjAl8zBQtyZWNUZXJyYWlucwQJZGVsdGFUaW1lCQBlAggFCWxhc3RCbG9jawl0aW1lc3RhbXAIBQFjAl80AwkAZgIAAAUJZGVsdGFUaW1lCQACAQkArAICCQCsAgIJAKwCAgImU2F2ZWQgdGltZXN0YW1wIGlzIGluIGZ1dHVyZSwgc2F2ZWQgPSAJAKQDAQgFAWMCXzQCDCwgY3VycmVudCA9IAkApAMBCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAQGcGllY2VzCQEPbnVtUGllY2VzQnlTaXplAQUIbGFuZFNpemUEFmRhaWx5UHJvZHVjdGlvbkJ5UGllY2UJAQxhcHBseUJvbnVzZXMCCAUBYwJfMgUGcGllY2VzBAhhdmFpbFJlcwkAawMFCWRlbHRhVGltZQkAaAIFFmRhaWx5UHJvZHVjdGlvbkJ5UGllY2UFBnBpZWNlcwUJREFZTUlMTElTAwkAZgIFBmFtb3VudAUIYXZhaWxSZXMJAAIBCQCsAgIJAKwCAgkArAICAiJOb3QgZW5vdWdoIHJlc291cmNlcywgYXZhaWxhYmxlID0gCQCkAwEFCGF2YWlsUmVzAg4sIHJlcXVlc3RlZCA9IAkApAMBBQZhbW91bnQEDG5ld0RlbHRhVGltZQkAawMJAGUCBQhhdmFpbFJlcwUGYW1vdW50BQlEQVlNSUxMSVMJAGgCBRZkYWlseVByb2R1Y3Rpb25CeVBpZWNlBQZwaWVjZXMEDG5ld1RpbWVzdGFtcAkAZQIIBQlsYXN0QmxvY2sJdGltZXN0YW1wBQxuZXdEZWx0YVRpbWUECWxhbmRJbmRleAkAaQIFBnBpZWNlcwUFU1NJWkUECnJlc1RvQ2xhaW0JAQl2aXJ0Q2xhaW0EBQ10ZXJyYWluQ291bnRzCQBlAgUJZGVsdGFUaW1lBQxuZXdEZWx0YVRpbWUFCWxhbmRJbmRleAUWZGFpbHlQcm9kdWN0aW9uQnlQaWVjZQQFd2hLZXkJARJrZXlXYXJlaG91c2VCeUxhbmQBCAUBYwJfMgQKaW5mcmFMZXZlbAkBC3ZhbHVlT3JFbHNlAgkAnwgBCQEWa2V5SW5mcmFMZXZlbEJ5QXNzZXRJZAEIBQFjAl8yAAAECWN1cnJlbnRXaAkBDGdldFdhcmVob3VzZQMFBXdoS2V5BQlsYW5kSW5kZXgFCmluZnJhTGV2ZWwEDGN1cnJXaFJlc1ZvbAkBGWdldFdhcmVob3VzZUN1cnJSZXNWb2x1bWUBBQljdXJyZW50V2gEDGN1cnJXaE1hdFZvbAkBGWdldFdhcmVob3VzZUN1cnJNYXRWb2x1bWUBBQljdXJyZW50V2gEDmN1cnJXaEdvb2RzVm9sCQEbZ2V0V2FyZWhvdXNlQ3Vyckdvb2RzVm9sdW1lAQUJY3VycmVudFdoBA9jdXJyV2hMb2NrZWRWb2wJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQljdXJyZW50V2gFDndoSWR4TG9ja2VkVm9sBAt3aFNwYWNlTGVmdAkAZQIJAGUCCQBlAgkAZQIJARJnZXRXYXJlaG91c2VWb2x1bWUBCQCRAwIFCWN1cnJlbnRXaAUId2hJZHhWb2wFDGN1cnJXaFJlc1ZvbAUMY3VycldoTWF0Vm9sBQ5jdXJyV2hHb29kc1ZvbAUPY3VycldoTG9ja2VkVm9sAwMJAAACBQljbGFpbU1vZGUFC2NsYWltTW9kZVdoCQBmAgUGYW1vdW50BQt3aFNwYWNlTGVmdAcJAAIBCQCsAgIJAKwCAgIFT25seSAJAKQDAQULd2hTcGFjZUxlZnQCGCBzcGFjZSBsZWZ0IGluIHdhcmVob3VzZQQFYnBLZXkJARFrZXlCYWNrcGFja0J5RHVjawEIBQFjAl8xBAtjdXJyZW50UGFjawkBC2dldEJhY2twYWNrAQUFYnBLZXkEDmN1cnJlbnRQYWNrUmVzCQC1CQIJAJEDAgULY3VycmVudFBhY2sFCGJwSWR4UmVzAgFfBAxjdXJyZW50V2hSZXMJALUJAgkAkQMCBQljdXJyZW50V2gFCHdoSWR4UmVzAgFfBA0kdDAyNjgxNzI3MzIwAwkAAAIFCWNsYWltTW9kZQULY2xhaW1Nb2RlV2gJAJQKAgkBBmFkZFJlcwUFDGN1cnJlbnRXaFJlcwUNdGVycmFpbkNvdW50cwkAZQIFCWRlbHRhVGltZQUMbmV3RGVsdGFUaW1lBQlsYW5kSW5kZXgFFmRhaWx5UHJvZHVjdGlvbkJ5UGllY2UJAJEDAgULY3VycmVudFBhY2sFCGJwSWR4UmVzAwkAAAIFCWNsYWltTW9kZQUNY2xhaW1Nb2RlRHVjawkAlAoCCQCRAwIFCWN1cnJlbnRXaAUId2hJZHhSZXMJAQZhZGRSZXMFBQ5jdXJyZW50UGFja1JlcwUNdGVycmFpbkNvdW50cwkAZQIFCWRlbHRhVGltZQUMbmV3RGVsdGFUaW1lBQlsYW5kSW5kZXgFFmRhaWx5UHJvZHVjdGlvbkJ5UGllY2UJAQ1kaXN0cmlidXRlUmVzBAUMY3VycmVudFdoUmVzBQ5jdXJyZW50UGFja1JlcwUKcmVzVG9DbGFpbQULd2hTcGFjZUxlZnQEBXdoUmVzCAUNJHQwMjY4MTcyNzMyMAJfMQQFYnBSZXMIBQ0kdDAyNjgxNzI3MzIwAl8yCQCXCgUJAMwIAgkBDEludGVnZXJFbnRyeQIJARZrZXlTdGFrZWRUaW1lQnlBc3NldElkAQgFAWMCXzIFDG5ld1RpbWVzdGFtcAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBImtleVN0YWtlZFRpbWVCeVR5cGVBc3NldElkQW5kT3duZXIDBQpMQU5EUFJFRklYCAUBYwJfMgUEYWRkcgUMbmV3VGltZXN0YW1wBQNuaWwFBWJwS2V5CQDMCAIJAJEDAgULY3VycmVudFBhY2sFCmJwSWR4TGV2ZWwJAMwIAgUFYnBSZXMJAMwIAgkAkQMCBQtjdXJyZW50UGFjawUIYnBJZHhNYXQJAMwIAgkAkQMCBQtjdXJyZW50UGFjawUJYnBJZHhQcm9kBQNuaWwFBXdoS2V5CQDMCAIJAJEDAgUJY3VycmVudFdoBQh3aElkeFZvbAkAzAgCBQV3aFJlcwkAzAgCCQCRAwIFCWN1cnJlbnRXaAUId2hJZHhNYXQJAMwIAgkAkQMCBQljdXJyZW50V2gFCXdoSWR4UHJvZAkAzAgCCQCRAwIFCWN1cnJlbnRXaAUOd2hJZHhMb2NrZWRWb2wFA25pbAEIY2xhaW1BbGwEBGFkZHILbGFuZEFzc2V0SWQGcGllY2VzCWNsYWltTW9kZQQHdGltZUtleQkBFmtleVN0YWtlZFRpbWVCeUFzc2V0SWQBBQtsYW5kQXNzZXRJZAQJc2F2ZWRUaW1lCQEFdmFsdWUBCQCfCAEFB3RpbWVLZXkECGF2YWlsUmVzCQBoAgkAawMJAGUCCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAUJc2F2ZWRUaW1lCQEMYXBwbHlCb251c2VzAgULbGFuZEFzc2V0SWQFBnBpZWNlcwUJREFZTUlMTElTBQZwaWVjZXMJARBjbGFpbVJlc0ludGVybmFsBAUEYWRkcgUIYXZhaWxSZXMFCWNsYWltTW9kZQULbGFuZEFzc2V0SWQBDXVwSW5mcmFDb21tb24EDHNob3VsZFVzZU1hdAZjYWxsZXINcGF5bWVudEFtb3VudAtsYW5kQXNzZXRJZAQEYWRkcgkApQgBBQZjYWxsZXIEAWMJARRjaGVja0NsYWltQ29uZGl0aW9ucwMFBGFkZHIFE2NsYWltTW9kZVdoVGhlbkR1Y2sFC2xhbmRBc3NldElkBAZwaWVjZXMJAQ9udW1QaWVjZXNCeVNpemUBCQCRAwIIBQFjAl8zBQtyZWNMYW5kU2l6ZQQIaW5mcmFLZXkJARZrZXlJbmZyYUxldmVsQnlBc3NldElkAQgFAWMCXzIECGN1ckxldmVsCQELdmFsdWVPckVsc2UCCQCfCAEFCGluZnJhS2V5AAADCQBnAgUIY3VyTGV2ZWwAAwkAAgECJkN1cnJlbnRseSBtYXggaW5mcmFzdHJ1Y3R1cmUgbGV2ZWwgPSAzBAhuZXdMZXZlbAkAZAIFCGN1ckxldmVsAAEEBGNvc3QJAGsDBRVJbmZyYVVwZ3JhZGVDb3N0U1VzZG4JAGgCBQZwaWVjZXMFCG5ld0xldmVsBQVTU0laRQMDCQEBIQEFDHNob3VsZFVzZU1hdAkBAiE9AgUNcGF5bWVudEFtb3VudAUEY29zdAcJAAIBCQCsAgICG1BheW1lbnQgYXR0YWNoZWQgc2hvdWxkIGJlIAkApAMBBQRjb3N0BAVicEtleQkBEWtleUJhY2twYWNrQnlEdWNrAQgFAWMCXzEEC2N1cnJlbnRQYWNrCQELZ2V0QmFja3BhY2sBBQVicEtleQQFbUxpc3QJALUJAgkAkQMCBQtjdXJyZW50UGFjawUIYnBJZHhNYXQCAV8EBm5ld01hdAkAuQkCCQERc3VidHJhY3RNYXRlcmlhbHMDBQxzaG91bGRVc2VNYXQFBW1MaXN0CQBrAwURSW5mcmFVcGdyYWRlQ29zdFMJAGgCBQZwaWVjZXMFCG5ld0xldmVsBQVTU0laRQIBXwQLY2xhaW1SZXN1bHQJAQhjbGFpbUFsbAQFBGFkZHIIBQFjAl8yBQZwaWVjZXMFE2NsYWltTW9kZVdoVGhlbkR1Y2sEBndoRGF0YQgFC2NsYWltUmVzdWx0Al81BApuZXdWb2xEYXRhCQC5CQIJAMwIAgkAkQMCCQC1CQIJAJEDAgUGd2hEYXRhBQh3aElkeFZvbAIBXwAACQDMCAIJAKQDAQUIbmV3TGV2ZWwFA25pbAIBXwkAlAoCCQDOCAIJAMwIAgkBDEludGVnZXJFbnRyeQIFCGluZnJhS2V5BQhuZXdMZXZlbAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBHmtleUluZnJhTGV2ZWxCeUFzc2V0SWRBbmRPd25lcgIIBQFjAl8yBQRhZGRyBQhuZXdMZXZlbAkAzAgCCQELU3RyaW5nRW50cnkCBQVicEtleQkAuQkCCQDMCAIJAJEDAgULY3VycmVudFBhY2sFCmJwSWR4TGV2ZWwJAMwIAgkAkQMCCAULY2xhaW1SZXN1bHQCXzMFCGJwSWR4UmVzCQDMCAIFBm5ld01hdAkAzAgCCQCRAwIFC2N1cnJlbnRQYWNrBQlicElkeFByb2QFA25pbAIBOgkAzAgCCQELU3RyaW5nRW50cnkCCAULY2xhaW1SZXN1bHQCXzQJALkJAgkAzAgCBQpuZXdWb2xEYXRhCQDMCAIJAJEDAgUGd2hEYXRhBQh3aElkeFJlcwkAzAgCCQCRAwIFBndoRGF0YQUId2hJZHhNYXQJAMwIAgkAkQMCBQZ3aERhdGEFCXdoSWR4UHJvZAkAzAgCCQCRAwIFBndoRGF0YQUOd2hJZHhMb2NrZWRWb2wFA25pbAIBOgUDbmlsCAULY2xhaW1SZXN1bHQCXzEFCG5ld0xldmVsARJhY3RpdmF0ZVByZXNhbGVBcnQCBGFkZHINbGFuZEFzc2V0SWRJbgQBYwkBFGNoZWNrQ2xhaW1Db25kaXRpb25zAwUEYWRkcgUTY2xhaW1Nb2RlV2hUaGVuRHVjawUNbGFuZEFzc2V0SWRJbgQLbGFuZEFzc2V0SWQIBQFjAl8yBA1hY3RpdmF0aW9uS2V5CQEfa2V5UHJlc2FsZUFydEFjdGl2YXRlZEJ5QXNzZXRJZAEFC2xhbmRBc3NldElkAwkBC3ZhbHVlT3JFbHNlAgkAoAgBBQ1hY3RpdmF0aW9uS2V5BwkAAgECJVByZXNhbGUgYXJ0aWZhY3QgaXMgYWxyZWFkeSBhY3RpdmF0ZWQDCQBmAgkBDXBhcnNlSW50VmFsdWUBCQCRAwIIBQFjAl8zBQpyZWNMYW5kTnVtBQ9QUkVTQUxFTlVNTEFORFMJAAIBCQCsAgIJAKwCAgkArAICBQpMQU5EUFJFRklYAgEgBQtsYW5kQXNzZXRJZAIlIGlzIG5vdCBlbGlnaWJsZSBmb3IgcHJlc2FsZSBhcnRpZmFjdAQGcGllY2VzCQEPbnVtUGllY2VzQnlTaXplAQkAkQMCCAUBYwJfMwULcmVjTGFuZFNpemUEC2NsYWltUmVzdWx0CQEIY2xhaW1BbGwEBQRhZGRyBQtsYW5kQXNzZXRJZAUGcGllY2VzBRNjbGFpbU1vZGVXaFRoZW5EdWNrCQDNCAIJAM0IAgkAzQgCCQDNCAIJAM0IAgkAzQgCCAULY2xhaW1SZXN1bHQCXzEJAQxCb29sZWFuRW50cnkCBQ1hY3RpdmF0aW9uS2V5BgkBDEJvb2xlYW5FbnRyeQIJASdrZXlQcmVzYWxlQXJ0QWN0aXZhdGVkQnlBc3NldElkQW5kT3duZXICBQtsYW5kQXNzZXRJZAUEYWRkcgYJAQxJbnRlZ2VyRW50cnkCCQEga2V5TGFuZEFydFN0YXR1c0J5VHlwZUFuZEFzc2V0SWQCBQpBUlRQUkVTQUxFBQtsYW5kQXNzZXRJZAUGcGllY2VzCQEMSW50ZWdlckVudHJ5AgkBJWtleUxhbmRBcnRTdGF0dXNCeVR5cGVBc3NldElkQW5kT3duZXIDBQpBUlRQUkVTQUxFBQtsYW5kQXNzZXRJZAUEYWRkcgUGcGllY2VzCQELU3RyaW5nRW50cnkCCAULY2xhaW1SZXN1bHQCXzIJALkJAggFC2NsYWltUmVzdWx0Al8zAgE6CQELU3RyaW5nRW50cnkCCAULY2xhaW1SZXN1bHQCXzQJALkJAggFC2NsYWltUmVzdWx0Al81AgE6AQ1tZXJnZUludGVybmFsBwtuZXdMYW5kU2l6ZQhuZXdMZXZlbAdmb3JtdWxhBGFkZHIMbGFuZEFzc2V0SWRzBHR4SWQHbmVlZE1hdAQLZHVja0Fzc2V0SWQJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAoggBCQEUa2V5U3Rha2VkRHVja0J5T3duZXIBBQRhZGRyAhxZb3UgZG9uJ3QgaGF2ZSBhIGR1Y2sgc3Rha2VkCgEKY2hlY2tNZXJnZQIDYWNjC2xhbmRBc3NldElkBAVhc3NldAkBBXZhbHVlAQkA7AcBCQDZBAEFC2xhbmRBc3NldElkBAd0aW1lS2V5CQEWa2V5U3Rha2VkVGltZUJ5QXNzZXRJZAEFC2xhbmRBc3NldElkBAlzYXZlZFRpbWUJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnwgBBQd0aW1lS2V5CQCsAgIJAKwCAgIETkZUIAgFBWFzc2V0BG5hbWUCDiBpcyBub3Qgc3Rha2VkBAVvd25lcgkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCiCAEJARVrZXlMYW5kQXNzZXRJZFRvT3duZXIBBQtsYW5kQXNzZXRJZAkArAICCQCsAgICBE5GVCAIBQVhc3NldARuYW1lAgwgaXMgb3JwaGFuZWQDCQECIT0CBQVvd25lcgUEYWRkcgkAAgEJAKwCAgUKTEFORFBSRUZJWAINIGlzIG5vdCB5b3VycwQBZAkAtQkCCAUFYXNzZXQLZGVzY3JpcHRpb24CAV8ECWNvbnRpbmVudAkAkQMCBQFkBQxyZWNDb250aW5lbnQDAwkBAiE9AggFA2FjYwJfMwIACQECIT0CCAUDYWNjAl8zBQljb250aW5lbnQHCQACAQIuTGFuZHMgc2hvdWxkIGJlIG9uIHRoZSBzYW1lIGNvbnRpbmVudCB0byBtZXJnZQQIbGFuZFNpemUJAJEDAgUBZAULcmVjTGFuZFNpemUEB3NpemVzSW4IBQNhY2MCXzEEAWkJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAswkCBQdzaXplc0luBQhsYW5kU2l6ZQInWW91IGhhdmVuJ3QgcGFzc2VkIGFsbCB0aGUgbGFuZHMgbmVlZGVkBAhzaXplc091dAkArAICCQCvAgIFB3NpemVzSW4FAWkJALACAgUHc2l6ZXNJbgkAZAIFAWkAAQQGcGllY2VzCQEPbnVtUGllY2VzQnlTaXplAQUIbGFuZFNpemUEBGFydHMJAGQCCAUDYWNjAl8yCQELdmFsdWVPckVsc2UCCQCfCAEJASBrZXlMYW5kQXJ0U3RhdHVzQnlUeXBlQW5kQXNzZXRJZAIFCkFSVFBSRVNBTEUFC2xhbmRBc3NldElkAwkBC3ZhbHVlT3JFbHNlAgkAoAgBCQEfa2V5UHJlc2FsZUFydEFjdGl2YXRlZEJ5QXNzZXRJZAEFC2xhbmRBc3NldElkBwUGcGllY2VzAAAECmluZnJhTGV2ZWwJAQt2YWx1ZU9yRWxzZQIJAJ8IAQkBFmtleUluZnJhTGV2ZWxCeUFzc2V0SWQBBQtsYW5kQXNzZXRJZAAABAhyZXFMZXZlbAQHJG1hdGNoMAUIbGFuZFNpemUDCQAAAgIBUwUHJG1hdGNoMAADAwkAAAICAU0FByRtYXRjaDAABAMJAAACAgFMBQckbWF0Y2gwAAUDCQAAAgICWEwFByRtYXRjaDAABgkAAgECGk9ubHkgUywgTSwgTCwgWEwgY2FuIG1lcmdlAwkBAiE9AgUKaW5mcmFMZXZlbAUIcmVxTGV2ZWwJAAIBAiJBbGwgbGFuZHMgc2hvdWxkIGJlIG1heGVkIHRvIG1lcmdlBAdsYW5kTnVtCQCRAwIFAWQFCnJlY0xhbmROdW0EDXRlcnJhaW5Db3VudHMJAQ1jb3VudFRlcnJhaW5zAQkAkQMCBQFkBQtyZWNUZXJyYWlucwQJZGVsdGFUaW1lCQBlAggFCWxhc3RCbG9jawl0aW1lc3RhbXAFCXNhdmVkVGltZQMJAGYCAAAFCWRlbHRhVGltZQkAAgEJAKwCAgkArAICCQCsAgICJlNhdmVkIHRpbWVzdGFtcCBpcyBpbiBmdXR1cmUsIHNhdmVkID0gCQCkAwEFCXNhdmVkVGltZQIMLCBjdXJyZW50ID0gCQCkAwEIBQlsYXN0QmxvY2sJdGltZXN0YW1wBBZkYWlseVByb2R1Y3Rpb25CeVBpZWNlCQEMYXBwbHlCb251c2VzAgULbGFuZEFzc2V0SWQFBnBpZWNlcwQJbGFuZEluZGV4CQBpAgUGcGllY2VzBQVTU0laRQQFYnBSZXMJAQZhZGRSZXMFCQC1CQIIBQNhY2MCXzQCAV8FDXRlcnJhaW5Db3VudHMFCWRlbHRhVGltZQUJbGFuZEluZGV4BRZkYWlseVByb2R1Y3Rpb25CeVBpZWNlBAVwcm9wcwkBGXVwZGF0ZVByb3BvcnRpb25zSW50ZXJuYWwECQC1CQIIBQNhY2MCXzYCAV8FDXRlcnJhaW5Db3VudHMFCWxhbmRJbmRleAD///////////8BBAVsYW5kcwgFA2FjYwJfNwQDaWR4CQDPCAIFBWxhbmRzBQtsYW5kQXNzZXRJZAMJAQEhAQkBCWlzRGVmaW5lZAEFA2lkeAkAAgEJAKwCAgIgWW91ciBzdGFrZWQgbGFuZHMgZG9uJ3QgY29udGFpbiAFC2xhbmRBc3NldElkCQCZCgcFCHNpemVzT3V0BQRhcnRzBQljb250aW5lbnQFBWJwUmVzCQDNCAIJAM0IAgkAzQgCCQDNCAIJAM0IAgkAzQgCCQDNCAIJAM0IAgkAzQgCCQDNCAIJAM0IAgkAzQgCCQDNCAIJAM0IAggFA2FjYwJfNQkBC0RlbGV0ZUVudHJ5AQkBFmtleVN0YWtlZFRpbWVCeUFzc2V0SWQBBQtsYW5kQXNzZXRJZAkBC0RlbGV0ZUVudHJ5AQkBImtleVN0YWtlZFRpbWVCeVR5cGVBc3NldElkQW5kT3duZXIDBQpMQU5EUFJFRklYBQtsYW5kQXNzZXRJZAUEYWRkcgkBC0RlbGV0ZUVudHJ5AQkBEGtleUxhbmRUb0Fzc2V0SWQBBQdsYW5kTnVtCQELRGVsZXRlRW50cnkBCQEKa2V5TmZ0TmFtZQIFB2xhbmROdW0FCGxhbmRTaXplCQELRGVsZXRlRW50cnkBCQEVa2V5TGFuZEFzc2V0SWRUb093bmVyAQULbGFuZEFzc2V0SWQJAQtEZWxldGVFbnRyeQEJARZrZXlJbmZyYUxldmVsQnlBc3NldElkAQULbGFuZEFzc2V0SWQJAQtEZWxldGVFbnRyeQEJAR5rZXlJbmZyYUxldmVsQnlBc3NldElkQW5kT3duZXICBQtsYW5kQXNzZXRJZAUEYWRkcgkBC0RlbGV0ZUVudHJ5AQkBH2tleVByZXNhbGVBcnRBY3RpdmF0ZWRCeUFzc2V0SWQBBQtsYW5kQXNzZXRJZAkBC0RlbGV0ZUVudHJ5AQkBJ2tleVByZXNhbGVBcnRBY3RpdmF0ZWRCeUFzc2V0SWRBbmRPd25lcgIFC2xhbmRBc3NldElkBQRhZGRyCQELRGVsZXRlRW50cnkBCQEga2V5TGFuZEFydFN0YXR1c0J5VHlwZUFuZEFzc2V0SWQCBQpBUlRQUkVTQUxFBQtsYW5kQXNzZXRJZAkBC0RlbGV0ZUVudHJ5AQkBJWtleUxhbmRBcnRTdGF0dXNCeVR5cGVBc3NldElkQW5kT3duZXIDBQpBUlRQUkVTQUxFBQtsYW5kQXNzZXRJZAUEYWRkcgkBC0RlbGV0ZUVudHJ5AQkBEWtleUxhbmROdW1Ub093bmVyAQUHbGFuZE51bQkBC0RlbGV0ZUVudHJ5AQkBEmtleVdhcmVob3VzZUJ5TGFuZAEFC2xhbmRBc3NldElkCQEEQnVybgIJANkEAQULbGFuZEFzc2V0SWQAAQUFcHJvcHMJANEIAgUFbGFuZHMJAQV2YWx1ZQEFA2lkeAQFYnBLZXkJARFrZXlCYWNrcGFja0J5RHVjawEFC2R1Y2tBc3NldElkBAtjdXJyZW50UGFjawkBC2dldEJhY2twYWNrAQUFYnBLZXkEB3Byb3BTdHIJAQt2YWx1ZU9yRWxzZQIJAKIIAQkBEWtleVJlc1Byb3BvcnRpb25zAAILMF8wXzBfMF8wXzAECGxhbmRzS2V5CQEVa2V5U3Rha2VkTGFuZHNCeU93bmVyAQUEYWRkcgQIbGFuZHNTdHIJAKIIAQUIbGFuZHNLZXkEB2xhbmRzSW4DCQEJaXNEZWZpbmVkAQUIbGFuZHNTdHIJAL0JAgkBBXZhbHVlAQUIbGFuZHNTdHICAV8FA25pbAQBcgoAAiRsBQxsYW5kQXNzZXRJZHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwCQCZCgcFB2Zvcm11bGEAAAIACQCRAwIFC2N1cnJlbnRQYWNrBQhicElkeFJlcwUDbmlsBQdwcm9wU3RyBQdsYW5kc0luCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQpjaGVja01lcmdlAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhNMaXN0IHNpemUgZXhjZWVkcyA1CQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQQJY29udGluZW50CAUBcgJfMwQMY29udGluZW50SWR4CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAM8IAgUKY29udGluZW50cwUJY29udGluZW50CQCsAgICE1Vua25vd24gY29udGluZW50OiAFCWNvbnRpbmVudAQIdGVycmFpbnMJAQtnZW5UZXJyYWlucwIJAQNhYnMBCQCeAwEFBHR4SWQFDGNvbnRpbmVudElkeAQHZnJlZU51bQkBC3ZhbHVlT3JFbHNlAgkAnwgBCQESa2V5TmV4dEZyZWVMYW5kTnVtAAkAZAIFD1BSRVNBTEVOVU1MQU5EUwABBApuZXdMYW5kTnVtCQCkAwEFB2ZyZWVOdW0EBWlzc3VlCQDCCAUJAQprZXlOZnROYW1lAgUKbmV3TGFuZE51bQULbmV3TGFuZFNpemUJALkJAgkAzAgCBQpuZXdMYW5kTnVtCQDMCAIFC25ld0xhbmRTaXplCQDMCAIFCHRlcnJhaW5zCQDMCAIFCWNvbnRpbmVudAUDbmlsAgFfAAEAAAcEB2Fzc2V0SWQJALgIAQUFaXNzdWUEDm5ld0xhbmRBc3NldElkCQDYBAEFB2Fzc2V0SWQEBm5ld01hdAkAuQkCCQERc3VidHJhY3RNYXRlcmlhbHMDCQBmAgUHbmVlZE1hdAAACQC1CQIJAJEDAgULY3VycmVudFBhY2sFCGJwSWR4TWF0AgFfBQduZWVkTWF0AgFfCQCUCgIJAM0IAgkAzQgCCQDNCAIJAM0IAgkAzQgCCQDNCAIJAM0IAgkAzQgCCQDNCAIJAM0IAgkAzQgCCQDNCAIJAM0IAgkAzQgCCAUBcgJfNQMJAGYCCQCQAwEIBQFyAl83AAAJAQtTdHJpbmdFbnRyeQIFCGxhbmRzS2V5CQC7CQIIBQFyAl83AgFfCQELRGVsZXRlRW50cnkBBQhsYW5kc0tleQkBDEludGVnZXJFbnRyeQIJARJrZXlOZXh0RnJlZUxhbmROdW0ACQBkAgUHZnJlZU51bQABBQVpc3N1ZQkBC1N0cmluZ0VudHJ5AgkBEGtleUxhbmRUb0Fzc2V0SWQBBQpuZXdMYW5kTnVtBQ5uZXdMYW5kQXNzZXRJZAkBC1N0cmluZ0VudHJ5AgkBFWtleUxhbmRBc3NldElkVG9Pd25lcgEFDm5ld0xhbmRBc3NldElkBQRhZGRyCQELU3RyaW5nRW50cnkCCQERa2V5TGFuZE51bVRvT3duZXIBBQpuZXdMYW5kTnVtBQRhZGRyCQEMSW50ZWdlckVudHJ5AgkBIGtleUxhbmRBcnRTdGF0dXNCeVR5cGVBbmRBc3NldElkAgUKQVJUUFJFU0FMRQUObmV3TGFuZEFzc2V0SWQIBQFyAl8yCQEMSW50ZWdlckVudHJ5AgkBJWtleUxhbmRBcnRTdGF0dXNCeVR5cGVBc3NldElkQW5kT3duZXIDBQpBUlRQUkVTQUxFBQ5uZXdMYW5kQXNzZXRJZAUEYWRkcggFAXICXzIJAQxJbnRlZ2VyRW50cnkCCQEWa2V5SW5mcmFMZXZlbEJ5QXNzZXRJZAEFDm5ld0xhbmRBc3NldElkBQhuZXdMZXZlbAkBDEludGVnZXJFbnRyeQIJAR5rZXlJbmZyYUxldmVsQnlBc3NldElkQW5kT3duZXICBQ5uZXdMYW5kQXNzZXRJZAUEYWRkcgUIbmV3TGV2ZWwJAQtTdHJpbmdFbnRyeQIFBWJwS2V5CQC5CQIJAMwIAgkAkQMCBQtjdXJyZW50UGFjawUKYnBJZHhMZXZlbAkAzAgCCAUBcgJfNAkAzAgCBQZuZXdNYXQJAMwIAgkAkQMCBQtjdXJyZW50UGFjawUJYnBJZHhQcm9kBQNuaWwCAToJAQtTdHJpbmdFbnRyeQIJARFrZXlSZXNQcm9wb3J0aW9ucwAIBQFyAl82CQELU3RyaW5nRW50cnkCCQEPa2V5RHVja0xvY2F0aW9uAQULZHVja0Fzc2V0SWQJALkJAgkAzAgCBQljb250aW5lbnQJAMwIAgIBTAkAzAgCBQ5uZXdMYW5kQXNzZXRJZAUDbmlsAgFfCQEOU2NyaXB0VHJhbnNmZXIDCQERQGV4dHJOYXRpdmUoMTA2MikBBQRhZGRyAAEFB2Fzc2V0SWQFDm5ld0xhbmRBc3NldElkAQNzMm0DBGFkZHIMbGFuZEFzc2V0SWRzBHR4SWQJAQ1tZXJnZUludGVybmFsBwIBTQADAgRTU1NTBQRhZGRyBQxsYW5kQXNzZXRJZHMFBHR4SWQAAAEDbTJsBQRhZGRyDGxhbmRBc3NldElkcwR0eElkDHNob3VsZFVzZU1hdA1wYXltZW50QW1vdW50BARjb3N0CQBoAgUVSW5mcmFVcGdyYWRlQ29zdFNVc2RuAAQDAwkBASEBBQxzaG91bGRVc2VNYXQJAQIhPQIFDXBheW1lbnRBbW91bnQFBGNvc3QHCQACAQkArAICAhtQYXltZW50IGF0dGFjaGVkIHNob3VsZCBiZSAJAKQDAQUEY29zdAkBDW1lcmdlSW50ZXJuYWwHAgFMAAQCA1NNTQUEYWRkcgUMbGFuZEFzc2V0SWRzBQR0eElkCQBoAgURSW5mcmFVcGdyYWRlQ29zdFMABAEEbDJ4bAUEYWRkcgxsYW5kQXNzZXRJZHMEdHhJZAxzaG91bGRVc2VNYXQNcGF5bWVudEFtb3VudAQEY29zdAkAaAIFFUluZnJhVXBncmFkZUNvc3RTVXNkbgAvAwMJAQEhAQUMc2hvdWxkVXNlTWF0CQECIT0CBQ1wYXltZW50QW1vdW50BQRjb3N0BwkAAgEJAKwCAgIbUGF5bWVudCBhdHRhY2hlZCBzaG91bGQgYmUgCQCkAwEFBGNvc3QJAQ1tZXJnZUludGVybmFsBwICWEwABQIFU1NTTUwFBGFkZHIFDGxhbmRBc3NldElkcwUEdHhJZAkAaAIFEUluZnJhVXBncmFkZUNvc3RTAC8BBnhsMnh4bAUEYWRkcgxsYW5kQXNzZXRJZHMEdHhJZAxzaG91bGRVc2VNYXQNcGF5bWVudEFtb3VudAQEY29zdAkAaAIFFUluZnJhVXBncmFkZUNvc3RTVXNkbgA2AwMJAQEhAQUMc2hvdWxkVXNlTWF0CQECIT0CBQ1wYXltZW50QW1vdW50BQRjb3N0BwkAAgEJAKwCAgIbUGF5bWVudCBhdHRhY2hlZCBzaG91bGQgYmUgCQCkAwEFBGNvc3QJAQ1tZXJnZUludGVybmFsBwIDWFhMAAYCA0xYTAUEYWRkcgUMbGFuZEFzc2V0SWRzBQR0eElkCQBoAgURSW5mcmFVcGdyYWRlQ29zdFMANgELbWVyZ2VDb21tb24FDHNob3VsZFVzZU1hdARhZGRyDXBheW1lbnRBbW91bnQMbGFuZEFzc2V0SWRzBHR4SWQEC21lcmdlUmVzdWx0BAckbWF0Y2gwCQCQAwEFDGxhbmRBc3NldElkcwMJAAACAAQFByRtYXRjaDAJAQNzMm0DBQRhZGRyBQxsYW5kQXNzZXRJZHMFBHR4SWQDCQAAAgADBQckbWF0Y2gwCQEDbTJsBQUEYWRkcgUMbGFuZEFzc2V0SWRzBQR0eElkBQxzaG91bGRVc2VNYXQFDXBheW1lbnRBbW91bnQDCQAAAgAFBQckbWF0Y2gwCQEEbDJ4bAUFBGFkZHIFDGxhbmRBc3NldElkcwUEdHhJZAUMc2hvdWxkVXNlTWF0BQ1wYXltZW50QW1vdW50AwkAAAIAAgUHJG1hdGNoMAkBBnhsMnh4bAUFBGFkZHIFDGxhbmRBc3NldElkcwUEdHhJZAUMc2hvdWxkVXNlTWF0BQ1wYXltZW50QW1vdW50CQACAQINVW5rbm93biBtZXJnZQULbWVyZ2VSZXN1bHQBBnByb2xvZwEBaQMDCQECIT0CCAUBaQxvcmlnaW5DYWxsZXIFDHJlc3RDb250cmFjdAkBC3ZhbHVlT3JFbHNlAgkAoAgBCQEKa2V5QmxvY2tlZAAHBwkAAgECH0NvbnRyYWN0cyBhcmUgdW5kZXIgbWFpbnRlbmFuY2UJAQtTdHJpbmdFbnRyeQIJARFrZXlMYXN0VHhJZEJ5VXNlcgEJAKUIAQgFAWkMb3JpZ2luQ2FsbGVyCQDYBAEIBQFpDXRyYW5zYWN0aW9uSWQZAWkBDWNvbnN0cnVjdG9yVjEBCHJlc3RBZGRyAwkBAiE9AggFAWkGY2FsbGVyBQR0aGlzCQACAQIRUGVybWlzc2lvbiBkZW5pZWQJAMwIAgkBC1N0cmluZ0VudHJ5AgkBDmtleVJlc3RBZGRyZXNzAAUIcmVzdEFkZHIFA25pbAFpAQpzZXRCbG9ja2VkAQlpc0Jsb2NrZWQDCQECIT0CCAUBaQZjYWxsZXIFBHRoaXMJAAIBAhFwZXJtaXNzaW9uIGRlbmllZAkAzAgCCQEMQm9vbGVhbkVudHJ5AgkBCmtleUJsb2NrZWQABQlpc0Jsb2NrZWQFA25pbAFpAQlzdGFrZUxhbmQABAxwcm9sb2dBY3Rpb24JAQZwcm9sb2cBBQFpAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwABCQACAQIcRXhhY3RseSBvbmUgcGF5bWVudCByZXF1aXJlZAQDcG10CQEFdmFsdWUBCQCRAwIIBQFpCHBheW1lbnRzAAAEB2Fzc2V0SWQJAQV2YWx1ZQEIBQNwbXQHYXNzZXRJZAQHYWRkcmVzcwkApQgBCAUBaQZjYWxsZXIDCQECIT0CCAUDcG10BmFtb3VudAABCQACAQkArAICCQCsAgICBE5GVCAFCkxBTkRQUkVGSVgCJCB0b2tlbiBzaG91bGQgYmUgYXR0YWNoZWQgYXMgcGF5bWVudAQFYXNzZXQJAQV2YWx1ZQEJAOwHAQUHYXNzZXRJZAMJAQIhPQIIBQVhc3NldAZpc3N1ZXIFBHRoaXMJAAIBAhdVbmtub3duIGlzc3VlciBvZiB0b2tlbgMJAQEhAQkBCGNvbnRhaW5zAggFBWFzc2V0BG5hbWUFCkxBTkRQUkVGSVgJAAIBCQCsAgIJAKwCAgIJT25seSBORlQgBQpMQU5EUFJFRklYAhQgdG9rZW5zIGFyZSBhY2NlcHRlZAQLbGFuZE51bVNpemUJALACAggFBWFzc2V0BG5hbWUABAQHbGFuZE51bQMJAQhjb250YWlucwIFC2xhbmROdW1TaXplAgNYWEwJALMCAgULbGFuZE51bVNpemUAAwMJAQhjb250YWlucwIFC2xhbmROdW1TaXplAgJYTAkAswICBQtsYW5kTnVtU2l6ZQACCQCzAgIFC2xhbmROdW1TaXplAAEDCQEBIQEJAQlpc0RlZmluZWQBCQC2CQEFB2xhbmROdW0JAAIBCQCsAgICHkNhbm5vdCBwYXJzZSBsYW5kIG51bWJlciBmcm9tIAgFBWFzc2V0BG5hbWUEC2xhbmRBc3NldElkCQDYBAEFB2Fzc2V0SWQEB3RpbWVLZXkJARZrZXlTdGFrZWRUaW1lQnlBc3NldElkAQULbGFuZEFzc2V0SWQDCQEJaXNEZWZpbmVkAQkAnwgBBQd0aW1lS2V5CQACAQkArAICCQCsAgICBE5GVCAIBQVhc3NldARuYW1lAhIgaXMgYWxyZWFkeSBzdGFrZWQEAWQJALUJAggFBWFzc2V0C2Rlc2NyaXB0aW9uAgFfBA10ZXJyYWluQ291bnRzCQENY291bnRUZXJyYWlucwEJAJEDAgUBZAULcmVjVGVycmFpbnMEBXByb3BzCQERdXBkYXRlUHJvcG9ydGlvbnMDBQ10ZXJyYWluQ291bnRzCQBpAgkBD251bVBpZWNlc0J5U2l6ZQEJAJEDAgUBZAULcmVjTGFuZFNpemUFBVNTSVpFAAEECGxhbmRzU3RyCQCiCAEJARVrZXlTdGFrZWRMYW5kc0J5T3duZXIBBQdhZGRyZXNzBAVsYW5kcwMJAQlpc0RlZmluZWQBBQhsYW5kc1N0cgkAvQkCCQEFdmFsdWUBBQhsYW5kc1N0cgIBXwUDbmlsAwkBD2NvbnRhaW5zRWxlbWVudAIFBWxhbmRzBQtsYW5kQXNzZXRJZAkAAgEJAKwCAgIiWW91ciBzdGFrZWQgbGFuZHMgYWxyZWFkeSBjb250YWluIAULbGFuZEFzc2V0SWQJAMwIAgkBDEludGVnZXJFbnRyeQIFB3RpbWVLZXkIBQlsYXN0QmxvY2sJdGltZXN0YW1wCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEia2V5U3Rha2VkVGltZUJ5VHlwZUFzc2V0SWRBbmRPd25lcgMFCkxBTkRQUkVGSVgFC2xhbmRBc3NldElkBQdhZGRyZXNzCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAkAzAgCCQELU3RyaW5nRW50cnkCCQEVa2V5U3Rha2VkTGFuZHNCeU93bmVyAQUHYWRkcmVzcwkAuwkCCQDNCAIFBWxhbmRzBQtsYW5kQXNzZXRJZAIBXwkAzAgCCQELU3RyaW5nRW50cnkCCQEVa2V5TGFuZEFzc2V0SWRUb093bmVyAQULbGFuZEFzc2V0SWQFB2FkZHJlc3MJAMwIAgkBC1N0cmluZ0VudHJ5AgkBEWtleUxhbmROdW1Ub093bmVyAQUHbGFuZE51bQUHYWRkcmVzcwkAzAgCCQELU3RyaW5nRW50cnkCCQERa2V5UmVzUHJvcG9ydGlvbnMABQVwcm9wcwkAzAgCBQxwcm9sb2dBY3Rpb24FA25pbAFpAQt1bnN0YWtlTGFuZAENbGFuZEFzc2V0SWRJbgQMcHJvbG9nQWN0aW9uCQEGcHJvbG9nAQUBaQMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAAkAAgECJHVuc3Rha2UgZG9lc24ndCByZXF1aXJlIGFueSBwYXltZW50cwQEYWRkcgkApQgBCAUBaQZjYWxsZXIEAWMJARRjaGVja0NsYWltQ29uZGl0aW9ucwMFBGFkZHIFDWNsYWltTW9kZUR1Y2sFDWxhbmRBc3NldElkSW4EC2xhbmRBc3NldElkCAUBYwJfMgQIbGFuZHNLZXkJARVrZXlTdGFrZWRMYW5kc0J5T3duZXIBBQRhZGRyBA10ZXJyYWluQ291bnRzCQENY291bnRUZXJyYWlucwEJAJEDAggFAWMCXzMFC3JlY1RlcnJhaW5zBAZwaWVjZXMJAQ9udW1QaWVjZXNCeVNpemUBCQCRAwIIBQFjAl8zBQtyZWNMYW5kU2l6ZQQFcHJvcHMJARF1cGRhdGVQcm9wb3J0aW9ucwMFDXRlcnJhaW5Db3VudHMJAGkCBQZwaWVjZXMFBVNTSVpFAP///////////wEEC2NsYWltUmVzdWx0CQEIY2xhaW1BbGwEBQRhZGRyBQtsYW5kQXNzZXRJZAUGcGllY2VzBQ1jbGFpbU1vZGVEdWNrBAVsYW5kcwkAvQkCCQELdmFsdWVPckVsc2UCCQCiCAEFCGxhbmRzS2V5AgACAV8EA2lkeAkAzwgCBQVsYW5kcwULbGFuZEFzc2V0SWQDCQEBIQEJAQlpc0RlZmluZWQBBQNpZHgJAAIBCQCsAgICIFlvdXIgc3Rha2VkIGxhbmRzIGRvbid0IGNvbnRhaW4gBQtsYW5kQXNzZXRJZAQBdAgJAQV2YWx1ZQEJAO0HAQUGaGVpZ2h0CXRpbWVzdGFtcAQLcmVsZWFzZVRpbWUJAQt2YWx1ZU9yRWxzZQIJAJoIAgULZ292Q29udHJhY3QJARVrZXlVc2VyR3dsUmVsZWFzZVRpbWUBBQRhZGRyAAADCQBnAgULcmVsZWFzZVRpbWUFAXQJAAIBCQCsAgICOVlvdXIgZ1dMIGFyZSB0YWtpbmcgcGFydCBpbiB2b3RpbmcsIGNhbm5vdCB1bnN0YWtlIHVudGlsIAkApAMBBQtyZWxlYXNlVGltZQkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCAUBaQZjYWxsZXIAAQkA2QQBBQtsYW5kQXNzZXRJZAkAzAgCCQELRGVsZXRlRW50cnkBCQEWa2V5U3Rha2VkVGltZUJ5QXNzZXRJZAEFC2xhbmRBc3NldElkCQDMCAIJAQtEZWxldGVFbnRyeQEJASJrZXlTdGFrZWRUaW1lQnlUeXBlQXNzZXRJZEFuZE93bmVyAwUKTEFORFBSRUZJWAULbGFuZEFzc2V0SWQFBGFkZHIJAMwIAgkBC1N0cmluZ0VudHJ5AgkBEWtleVJlc1Byb3BvcnRpb25zAAUFcHJvcHMJAMwIAgkBC1N0cmluZ0VudHJ5AggFC2NsYWltUmVzdWx0Al8yCQC5CQIIBQtjbGFpbVJlc3VsdAJfMwIBOgkAzAgCAwkAZgIJAJADAQUFbGFuZHMAAQkBC1N0cmluZ0VudHJ5AgUIbGFuZHNLZXkJALsJAgkA0QgCBQVsYW5kcwkBBXZhbHVlAQUDaWR4AgFfCQELRGVsZXRlRW50cnkBBQhsYW5kc0tleQkAzAgCBQxwcm9sb2dBY3Rpb24FA25pbAFpAQlzdGFrZUR1Y2sABAxwcm9sb2dBY3Rpb24JAQZwcm9sb2cBBQFpAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwABCQACAQIcRXhhY3RseSBvbmUgcGF5bWVudCByZXF1aXJlZAQDcG10CQEFdmFsdWUBCQCRAwIIBQFpCHBheW1lbnRzAAAEB2Fzc2V0SWQJAQV2YWx1ZQEIBQNwbXQHYXNzZXRJZAQHYWRkcmVzcwkApQgBCAUBaQZjYWxsZXIDCQECIT0CCAUDcG10BmFtb3VudAABCQACAQkArAICCQCsAgICBE5GVCAFCkRVQ0tQUkVGSVgCJCB0b2tlbiBzaG91bGQgYmUgYXR0YWNoZWQgYXMgcGF5bWVudAQFYXNzZXQJAQV2YWx1ZQEJAOwHAQUHYXNzZXRJZAMDCQECIT0CCAUFYXNzZXQGaXNzdWVyBQ1pbmN1YmF0b3JBZGRyCQECIT0CCAUFYXNzZXQGaXNzdWVyBQticmVlZGVyQWRkcgcJAAIBCQCsAgIJAKwCAgISVW5rbm93biBpc3N1ZXIgb2YgBQpEVUNLUFJFRklYAgYgdG9rZW4DCQEBIQEJAQhjb250YWlucwIIBQVhc3NldARuYW1lBQpEVUNLUFJFRklYCQACAQkArAICCQCsAgICCU9ubHkgTkZUIAUKRFVDS1BSRUZJWAIUIHRva2VucyBhcmUgYWNjZXB0ZWQECmFzc2V0SWRTdHIJANgEAQUHYXNzZXRJZAQHdGltZUtleQkBFmtleVN0YWtlZFRpbWVCeUFzc2V0SWQBBQphc3NldElkU3RyAwkBCWlzRGVmaW5lZAEJAJ8IAQUHdGltZUtleQkAAgEJAKwCAgkArAICAgRORlQgCAUFYXNzZXQEbmFtZQISIGlzIGFscmVhZHkgc3Rha2VkAwkBCWlzRGVmaW5lZAEJAKIIAQkBFGtleVN0YWtlZER1Y2tCeU93bmVyAQUHYWRkcmVzcwkAAgEJAKwCAgIdWW91IGFscmVhZHkgc3Rha2VkIG9uZSBkdWNrOiAIBQVhc3NldARuYW1lBAZsb2NLZXkJAQ9rZXlEdWNrTG9jYXRpb24BBQphc3NldElkU3RyBAhsb2NhdGlvbgkAoggBBQZsb2NLZXkEBWJwS2V5CQERa2V5QmFja3BhY2tCeUR1Y2sBBQphc3NldElkU3RyBAhiYWNrcGFjawkAoggBBQVicEtleQkAzggCCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQd0aW1lS2V5CAUJbGFzdEJsb2NrCXRpbWVzdGFtcAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBImtleVN0YWtlZFRpbWVCeVR5cGVBc3NldElkQW5kT3duZXIDBQpEVUNLUFJFRklYCQDYBAEFB2Fzc2V0SWQFB2FkZHJlc3MIBQlsYXN0QmxvY2sJdGltZXN0YW1wCQDMCAIJAQtTdHJpbmdFbnRyeQIJARBrZXlEdWNrSWRUb093bmVyAQUKYXNzZXRJZFN0cgUHYWRkcmVzcwkAzAgCCQELU3RyaW5nRW50cnkCCQEUa2V5U3Rha2VkRHVja0J5T3duZXIBBQdhZGRyZXNzBQphc3NldElkU3RyBQNuaWwDCQEJaXNEZWZpbmVkAQUIbG9jYXRpb24FA25pbAkAzggCCQDMCAIJAQtTdHJpbmdFbnRyeQIFBmxvY0tleQUPREVGQVVMVExPQ0FUSU9OBQNuaWwDCQEJaXNEZWZpbmVkAQUIYmFja3BhY2sFA25pbAkAzQgCCQDNCAIJAMwIAgkBC1N0cmluZ0VudHJ5AgUFYnBLZXkCGjA6MF8wXzBfMF8wXzA6MF8wXzBfMF8wXzA6BQNuaWwJAQxJbnRlZ2VyRW50cnkCCQENa2V5RHVja0hlYWx0aAEFCmFzc2V0SWRTdHIAZAUMcHJvbG9nQWN0aW9uAWkBC3Vuc3Rha2VEdWNrAQphc3NldElkU3RyBAxwcm9sb2dBY3Rpb24JAQZwcm9sb2cBBQFpAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwAACQACAQIkdW5zdGFrZSBkb2Vzbid0IHJlcXVpcmUgYW55IHBheW1lbnRzBAdhc3NldElkCQDZBAEFCmFzc2V0SWRTdHIEB2FkZHJlc3MJAKUIAQgFAWkGY2FsbGVyBAVhc3NldAkBBXZhbHVlAQkA7AcBBQdhc3NldElkBAd0aW1lS2V5CQEWa2V5U3Rha2VkVGltZUJ5QXNzZXRJZAEJANgEAQUHYXNzZXRJZAMJAQEhAQkBCWlzRGVmaW5lZAEJAJ8IAQUHdGltZUtleQkAAgEJAKwCAgkArAICAgRORlQgCAUFYXNzZXQEbmFtZQIOIGlzIG5vdCBzdGFrZWQDCQEBIQEJAQlpc0RlZmluZWQBCQCiCAEJARRrZXlTdGFrZWREdWNrQnlPd25lcgEFB2FkZHJlc3MJAAIBCQCsAgIJAKwCAgIJVGhlIGR1Y2sgCAUFYXNzZXQEbmFtZQIOIGlzIG5vdCBzdGFrZWQEBW93bmVyCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKIIAQkBEGtleUR1Y2tJZFRvT3duZXIBCQDYBAEFB2Fzc2V0SWQJAKwCAgkArAICAgRORlQgCAUFYXNzZXQEbmFtZQIMIGlzIG9ycGhhbmVkAwkBAiE9AgUFb3duZXIFB2FkZHJlc3MJAAIBAhdTdGFrZWQgTkZUIGlzIG5vdCB5b3VycwQJa2V5SGVhbHRoCQENa2V5RHVja0hlYWx0aAEFCmFzc2V0SWRTdHIEBmhlYWx0aAkBC3ZhbHVlT3JFbHNlAgkAnwgBBQlrZXlIZWFsdGgAZAMJAQIhPQIFBmhlYWx0aABkCQACAQImUGxlYXNlIGhlYWwgeW91ciBkdWNrIGJlZm9yZSB1bnN0YWtpbmcJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwgFAWkGY2FsbGVyAAEFB2Fzc2V0SWQJAMwIAgkBC0RlbGV0ZUVudHJ5AQUHdGltZUtleQkAzAgCCQELRGVsZXRlRW50cnkBBQlrZXlIZWFsdGgJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBD2tleUR1Y2tMb2NhdGlvbgEFCmFzc2V0SWRTdHIJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBEGtleUR1Y2tJZFRvT3duZXIBBQphc3NldElkU3RyCQDMCAIJAQtEZWxldGVFbnRyeQEJASJrZXlTdGFrZWRUaW1lQnlUeXBlQXNzZXRJZEFuZE93bmVyAwUKRFVDS1BSRUZJWAUKYXNzZXRJZFN0cgUHYWRkcmVzcwkAzAgCCQELRGVsZXRlRW50cnkBCQEUa2V5U3Rha2VkRHVja0J5T3duZXIBBQdhZGRyZXNzCQDMCAIFDHByb2xvZ0FjdGlvbgUDbmlsAWkBCGNsYWltUmVzAgZhbW91bnQObGFuZEFzc2V0SWRTdHIEDHByb2xvZ0FjdGlvbgkBBnByb2xvZwEFAWkDCQECIT0CCQCQAwEIBQFpCHBheW1lbnRzAAAJAAIBAiVjbGFpbVJlcyBkb2Vzbid0IHJlcXVpcmUgYW55IHBheW1lbnRzBARhZGRyCQClCAEIBQFpDG9yaWdpbkNhbGxlcgQGcmVzdWx0CQEQY2xhaW1SZXNJbnRlcm5hbAQFBGFkZHIFBmFtb3VudAUNY2xhaW1Nb2RlRHVjawUObGFuZEFzc2V0SWRTdHIJAJQKAgkAzQgCCQDNCAIJAM0IAggFBnJlc3VsdAJfMQkBC1N0cmluZ0VudHJ5AggFBnJlc3VsdAJfMgkAuQkCCAUGcmVzdWx0Al8zAgE6CQELU3RyaW5nRW50cnkCCAUGcmVzdWx0Al80CQC5CQIIBQZyZXN1bHQCXzUCAToFDHByb2xvZ0FjdGlvbgkAkQMCCAUGcmVzdWx0Al8zBQhicElkeFJlcwFpAQxjbGFpbVJlc1RvV0gCBmFtb3VudA5sYW5kQXNzZXRJZFN0cgQMcHJvbG9nQWN0aW9uCQEGcHJvbG9nAQUBaQMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAAkAAgECJWNsYWltUmVzIGRvZXNuJ3QgcmVxdWlyZSBhbnkgcGF5bWVudHMEBGFkZHIJAKUIAQgFAWkMb3JpZ2luQ2FsbGVyBAZyZXN1bHQJARBjbGFpbVJlc0ludGVybmFsBAUEYWRkcgUGYW1vdW50BQtjbGFpbU1vZGVXaAUObGFuZEFzc2V0SWRTdHIJAJQKAgkAzQgCCQDNCAIJAM0IAggFBnJlc3VsdAJfMQkBC1N0cmluZ0VudHJ5AggFBnJlc3VsdAJfMgkAuQkCCAUGcmVzdWx0Al8zAgE6CQELU3RyaW5nRW50cnkCCAUGcmVzdWx0Al80CQC5CQIIBQZyZXN1bHQCXzUCAToFDHByb2xvZ0FjdGlvbgkAkQMCCAUGcmVzdWx0Al81BQh3aElkeFJlcwFpAQZmbGlnaHQCB21lc3NhZ2UDc2lnBAxwcm9sb2dBY3Rpb24JAQZwcm9sb2cBBQFpAwkBASEBCQDEEwMFB21lc3NhZ2UFA3NpZwUDcHViCQACAQIYc2lnbmF0dXJlIGRvZXMgbm90IG1hdGNoAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwAACQACAQIjZmxpZ2h0IGRvZXNuJ3QgcmVxdWlyZSBhbnkgcGF5bWVudHMEBXBhcnRzCQC1CQIJALAJAQUHbWVzc2FnZQIBOwQCaHAJALUJAgkAkQMCCQC1CQIJAJEDAgUFcGFydHMAAAIBfAAAAgFfBAVjdXJIUAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFAmhwAAAEBW5ld0hQCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUCaHAAAQQNbmV3TG9jQW5kVGltZQkAtQkCCQCRAwIFBXBhcnRzAAECAToEC25ld0xvY2F0aW9uCQCRAwIFDW5ld0xvY0FuZFRpbWUAAAQEdGltZQkBDXBhcnNlSW50VmFsdWUBCQCRAwIFDW5ld0xvY0FuZFRpbWUAAQMDCQBmAgUEdGltZQkAZAIIBQlsYXN0QmxvY2sJdGltZXN0YW1wBRFGSVZFTUlOVVRFU01JTExJUwYJAGYCCQBlAggFCWxhc3RCbG9jawl0aW1lc3RhbXAFEUZJVkVNSU5VVEVTTUlMTElTBQR0aW1lCQACAQISc2lnbmF0dXJlIG91dGRhdGVkBAtkdWNrQXNzZXRJZAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCiCAEJARRrZXlTdGFrZWREdWNrQnlPd25lcgEJAKUIAQgFAWkGY2FsbGVyAhxZb3UgZG9uJ3QgaGF2ZSBhIGR1Y2sgc3Rha2VkBAlrZXlIZWFsdGgJAQ1rZXlEdWNrSGVhbHRoAQULZHVja0Fzc2V0SWQEDG9sZEZyb21TdGF0ZQkBC3ZhbHVlT3JFbHNlAgkAnwgBBQlrZXlIZWFsdGgAZAMJAQIhPQIFDG9sZEZyb21TdGF0ZQUFY3VySFAJAAIBCQCsAgIJAKwCAgkArAICAgpvbGRIZWFsdGg9CQCkAwEJAQt2YWx1ZU9yRWxzZQIJAJ8IAQUJa2V5SGVhbHRoAGQCLyBmcm9tIHN0YXRlIGRvZXMgbm90IG1hdGNoIG9uZSBmcm9tIGZsaWdodCBsb2c9CQCkAwEFBWN1ckhQAwkAZwIAAAUFY3VySFAJAAIBAh5Zb3UgY2FuJ3QgZmx5IHdpdGggemVybyBoZWFsdGgEBmxvY0tleQkBD2tleUR1Y2tMb2NhdGlvbgEFC2R1Y2tBc3NldElkBAtjdXJMb2NhdGlvbgkBC3ZhbHVlT3JFbHNlAgkAoggBBQZsb2NLZXkFD0RFRkFVTFRMT0NBVElPTgMJAAACBQtuZXdMb2NhdGlvbgULY3VyTG9jYXRpb24JAAIBAiJZb3UgY2FuJ3QgZmx5IHRvIHRoZSBzYW1lIGxvY2F0aW9uCQCUCgIJAMwIAgkBC1N0cmluZ0VudHJ5AgUGbG9jS2V5AwkAZgIFBW5ld0hQAAAFC25ld0xvY2F0aW9uBQtjdXJMb2NhdGlvbgkAzAgCCQEMSW50ZWdlckVudHJ5AgUJa2V5SGVhbHRoBQVuZXdIUAkAzAgCBQxwcm9sb2dBY3Rpb24FA25pbAUEdW5pdAFpAQlzZXRIZWFsdGgCBmhlYWx0aAtkdWNrQXNzZXRJZAQMcHJvbG9nQWN0aW9uCQEGcHJvbG9nAQUBaQMDCQBmAgAABQZoZWFsdGgGCQBmAgUGaGVhbHRoAGQJAAIBAhpIUCBzaG91bGQgYmUgd2l0aGluIDAuLjEwMAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDWtleUR1Y2tIZWFsdGgBBQtkdWNrQXNzZXRJZAUGaGVhbHRoCQDMCAIFDHByb2xvZ0FjdGlvbgUDbmlsAWkBBGhlYWwCB21hdFR5cGUGYW1vdW50BAxwcm9sb2dBY3Rpb24JAQZwcm9sb2cBBQFpAwMJAGYCAAAFB21hdFR5cGUGCQBnAgUHbWF0VHlwZQUGTlVNUkVTCQACAQkArAICAhJVbmtub3duIG1hdGVyaWFsOiAJAKQDAQUHbWF0VHlwZQMJAGcCAAAFBmFtb3VudAkAAgEJAKwCAgIbQW1vdW50IHNob3VsZCBiZSBwb3NpdGl2ZSEgCQCkAwEFBmFtb3VudAQLZHVja0Fzc2V0SWQJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAoggBCQEUa2V5U3Rha2VkRHVja0J5T3duZXIBCQClCAEIBQFpBmNhbGxlcgIcWW91IGRvbid0IGhhdmUgYSBkdWNrIHN0YWtlZAQJa2V5SGVhbHRoCQENa2V5RHVja0hlYWx0aAEFC2R1Y2tBc3NldElkBAlvbGRIZWFsdGgJAQt2YWx1ZU9yRWxzZQIJAJ8IAQUJa2V5SGVhbHRoAGQDCQBnAgUJb2xkSGVhbHRoAGQJAAIBAhpIUCBzaG91bGQgYmUgPCAxMDAgdG8gaGVhbAQFYnBLZXkJARFrZXlCYWNrcGFja0J5RHVjawEFC2R1Y2tBc3NldElkBAtjdXJyZW50UGFjawkBC2dldEJhY2twYWNrAQUFYnBLZXkEBW1MaXN0CQC1CQIJAJEDAgULY3VycmVudFBhY2sFCGJwSWR4TWF0AgFfBA1jdXJyZW50QW1vdW50CQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUFbUxpc3QFB21hdFR5cGUEC2RlbHRhSGVhbHRoCQCXAwEJAMwIAgkAaQIFBmFtb3VudAUISEVBTENPU1QJAMwIAgkAZQIAZAUJb2xkSGVhbHRoBQNuaWwEC3NwZW5kQW1vdW50CQBoAgULZGVsdGFIZWFsdGgFCEhFQUxDT1NUAwkAZgIFC3NwZW5kQW1vdW50BQ1jdXJyZW50QW1vdW50CQACAQkArAICCQCsAgIJAKwCAgkArAICCQCsAgICCVlvdSBuZWVkIAkApAMBBQtzcGVuZEFtb3VudAIEIG9mIAkAkQMCBQhtYXRUeXBlcwUHbWF0VHlwZQIkIHRvIGhlYWwsIGJ1dCB5b3UgYmFja3BhY2sgY29udGFpbnMgCQCkAwEFDWN1cnJlbnRBbW91bnQEBm5ld01hdAkBDHN1Yk9uZUluTGlzdAMFBW1MaXN0BQdtYXRUeXBlBQtzcGVuZEFtb3VudAkAzAgCCQEMSW50ZWdlckVudHJ5AgUJa2V5SGVhbHRoCQBkAgUJb2xkSGVhbHRoBQtkZWx0YUhlYWx0aAkAzAgCCQELU3RyaW5nRW50cnkCBQVicEtleQkAuQkCCQDMCAIJAJEDAgULY3VycmVudFBhY2sFCmJwSWR4TGV2ZWwJAMwIAgkAkQMCBQtjdXJyZW50UGFjawUIYnBJZHhSZXMJAMwIAgUGbmV3TWF0CQDMCAIJAJEDAgULY3VycmVudFBhY2sFCWJwSWR4UHJvZAUDbmlsAgE6CQDMCAIFDHByb2xvZ0FjdGlvbgUDbmlsAWkBDnVwZGF0ZUJhY2twYWNrAgtkdWNrQXNzZXRJZAduZXdQYWNrBAxwcm9sb2dBY3Rpb24JAQZwcm9sb2cBBQFpAwkBAiE9AggFAWkGY2FsbGVyBQ9lY29ub215Q29udHJhY3QJAAIBAhFwZXJtaXNzaW9uIGRlbmllZAkAlAoCCQDMCAIJAQtTdHJpbmdFbnRyeQIJARFrZXlCYWNrcGFja0J5RHVjawEFC2R1Y2tBc3NldElkBQduZXdQYWNrCQDMCAIFDHByb2xvZ0FjdGlvbgUDbmlsBQduZXdQYWNrAWkBCGJ1eVNMYW5kAAMJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwkAAgECEVBlcm1pc3Npb24gZGVuaWVkBAxwcm9sb2dBY3Rpb24JAQZwcm9sb2cBBQFpAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwABCQACAQIcRXhhY3RseSBvbmUgcGF5bWVudCByZXF1aXJlZAQDcG10CQEFdmFsdWUBCQCRAwIIBQFpCHBheW1lbnRzAAADCQECIT0CCAUDcG10B2Fzc2V0SWQFC3VzZG5Bc3NldElkCQACAQIaQWxsb3dlZCBVU0ROIHBheW1lbnQgb25seSEDCQECIT0CCAUDcG10BmFtb3VudAUHRVhQVVNETgkAAgEJAKwCAgIbUGF5bWVudCBhdHRhY2hlZCBzaG91bGQgYmUgCQCkAwEFB0VYUFVTRE4EBnJlc3VsdAkBEmV4cGVkaXRpb25JbnRlcm5hbAIIBQFpBmNhbGxlcggFAWkNdHJhbnNhY3Rpb25JZAkAlAoCCQDNCAIJAM0IAggFBnJlc3VsdAJfMQkBDlNjcmlwdFRyYW5zZmVyAwUPZWNvbm9teUNvbnRyYWN0CAUDcG10BmFtb3VudAULdXNkbkFzc2V0SWQFDHByb2xvZ0FjdGlvbggIBQZyZXN1bHQCXzICXzEBaQEKZXhwZWRpdGlvbgIHbWVzc2FnZQNzaWcEDHByb2xvZ0FjdGlvbgkBBnByb2xvZwEFAWkDCQECIT0CCQCQAwEIBQFpCHBheW1lbnRzAAAJAAIBAidleHBlZGl0aW9uIGRvZXNuJ3QgcmVxdWlyZSBhbnkgcGF5bWVudHMEBnJlc3VsdAkBEGV4cGVkaXRpb25Db21tb24FBggFAWkGY2FsbGVyCAUBaQ10cmFuc2FjdGlvbklkBQdtZXNzYWdlBQNzaWcJAJQKAgkAzQgCCAUGcmVzdWx0Al8xBQxwcm9sb2dBY3Rpb24IBQZyZXN1bHQCXzIBaQEMdXBncmFkZUluZnJhAQtsYW5kQXNzZXRJZAQMcHJvbG9nQWN0aW9uCQEGcHJvbG9nAQUBaQMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAAkAAgECM0luZnJhc3RydWN0dXJlIHVwZ3JhZGUgZG9lc24ndCByZXF1aXJlIGFueSBwYXltZW50cwQGcmVzdWx0CQENdXBJbmZyYUNvbW1vbgQGCAUBaQZjYWxsZXIAAAULbGFuZEFzc2V0SWQJAJQKAgkAzQgCCAUGcmVzdWx0Al8xBQxwcm9sb2dBY3Rpb24IBQZyZXN1bHQCXzIBaQEQdXBncmFkZUluZnJhVXNkbgELbGFuZEFzc2V0SWQDCQECIT0CCAUBaQZjYWxsZXIFBHRoaXMJAAIBAhFQZXJtaXNzaW9uIGRlbmllZAQMcHJvbG9nQWN0aW9uCQEGcHJvbG9nAQUBaQMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAQkAAgECHEV4YWN0bHkgb25lIHBheW1lbnQgcmVxdWlyZWQEA3BtdAkBBXZhbHVlAQkAkQMCCAUBaQhwYXltZW50cwAAAwkBAiE9AggFA3BtdAdhc3NldElkBQt1c2RuQXNzZXRJZAkAAgECGkFsbG93ZWQgVVNETiBwYXltZW50IG9ubHkhBAZyZXN1bHQJAQ11cEluZnJhQ29tbW9uBAcIBQFpBmNhbGxlcggFA3BtdAZhbW91bnQFC2xhbmRBc3NldElkCQCUCgIJAM0IAgkAzQgCCAUGcmVzdWx0Al8xCQEOU2NyaXB0VHJhbnNmZXIDBQ9lY29ub215Q29udHJhY3QIBQNwbXQGYW1vdW50BQt1c2RuQXNzZXRJZAUMcHJvbG9nQWN0aW9uCAUGcmVzdWx0Al8yAWkBEGFjdGl2YXRlQXJ0aWZhY3QCB2FydE5hbWULbGFuZEFzc2V0SWQEDHByb2xvZ0FjdGlvbgkBBnByb2xvZwEFAWkDCQECIT0CCQCQAwEIBQFpCHBheW1lbnRzAAAJAAIBAjBBcnRpZmFjdCBhY3RpdmF0aW9uIGRvZXNuJ3QgcmVxdWlyZSBhbnkgcGF5bWVudHMEBnJlc3VsdAQHJG1hdGNoMAUHYXJ0TmFtZQMJAAACAgdQUkVTQUxFBQckbWF0Y2gwCQESYWN0aXZhdGVQcmVzYWxlQXJ0AgkApQgBCAUBaQZjYWxsZXIFC2xhbmRBc3NldElkCQACAQIQVW5rbm93biBhcnRpZmFjdAkAzQgCBQZyZXN1bHQFDHByb2xvZ0FjdGlvbgFpAQptZXJnZUxhbmRzAQxsYW5kQXNzZXRJZHMEDHByb2xvZ0FjdGlvbgkBBnByb2xvZwEFAWkDCQECIT0CCQCQAwEIBQFpCHBheW1lbnRzAAAJAAIBAipMYW5kcyBtZXJnaW5nIGRvZXNuJ3QgcmVxdWlyZSBhbnkgcGF5bWVudHMEBnJlc3VsdAkBC21lcmdlQ29tbW9uBQYJAKUIAQgFAWkGY2FsbGVyAAAFDGxhbmRBc3NldElkcwgFAWkNdHJhbnNhY3Rpb25JZAkAlAoCCQDNCAIIBQZyZXN1bHQCXzEFDHByb2xvZ0FjdGlvbggFBnJlc3VsdAJfMgFpAQ5tZXJnZUxhbmRzVXNkbgEMbGFuZEFzc2V0SWRzBAxwcm9sb2dBY3Rpb24JAQZwcm9sb2cBBQFpAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwABCQACAQIcRXhhY3RseSBvbmUgcGF5bWVudCByZXF1aXJlZAQDcG10CQEFdmFsdWUBCQCRAwIIBQFpCHBheW1lbnRzAAADCQECIT0CCAUDcG10B2Fzc2V0SWQFC3VzZG5Bc3NldElkCQACAQIaQWxsb3dlZCBVU0ROIHBheW1lbnQgb25seSEEBnJlc3VsdAkBC21lcmdlQ29tbW9uBQcJAKUIAQgFAWkGY2FsbGVyCAUDcG10BmFtb3VudAUMbGFuZEFzc2V0SWRzCAUBaQ10cmFuc2FjdGlvbklkCQCUCgIJAM0IAgkAzQgCCAUGcmVzdWx0Al8xCQEOU2NyaXB0VHJhbnNmZXIDBQ9lY29ub215Q29udHJhY3QIBQNwbXQGYW1vdW50BQt1c2RuQXNzZXRJZAUMcHJvbG9nQWN0aW9uCAUGcmVzdWx0Al8yAWkBDWNhcmdvRXhjaGFuZ2UCDGNhcmdvTGlzdFN0cgtsYW5kQXNzZXRJZAQMcHJvbG9nQWN0aW9uCQEGcHJvbG9nAQUBaQQKY2FyZ29QYXJ0cwkAvAkCBQxjYXJnb0xpc3RTdHICAToEBGFkZHIJAKUIAQgFAWkMb3JpZ2luQ2FsbGVyBAVhc3NldAkBBXZhbHVlAQkA7AcBCQDZBAEFC2xhbmRBc3NldElkBAd0aW1lS2V5CQEWa2V5U3Rha2VkVGltZUJ5QXNzZXRJZAEFC2xhbmRBc3NldElkAwkBASEBCQEJaXNEZWZpbmVkAQkAnwgBBQd0aW1lS2V5CQACAQkArAICCAUFYXNzZXQEbmFtZQIOIGlzIG5vdCBzdGFrZWQEBW93bmVyCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKIIAQkBFWtleUxhbmRBc3NldElkVG9Pd25lcgEFC2xhbmRBc3NldElkCQCsAgIJAKwCAgIETkZUIAgFBWFzc2V0BG5hbWUCDCBpcyBvcnBoYW5lZAMJAQIhPQIFBW93bmVyBQRhZGRyCQACAQkArAICBQpMQU5EUFJFRklYAg0gaXMgbm90IHlvdXJzBAlsYW5kSW5kZXgJAGkCCQEPbnVtUGllY2VzQnlTaXplAQkAkQMCCQC1CQIIBQVhc3NldAtkZXNjcmlwdGlvbgIBXwULcmVjTGFuZFNpemUFBVNTSVpFBAppbmZyYUxldmVsCQELdmFsdWVPckVsc2UCCQCfCAEJARZrZXlJbmZyYUxldmVsQnlBc3NldElkAQULbGFuZEFzc2V0SWQAAAQLZHVja0Fzc2V0SWQJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAoggBCQEUa2V5U3Rha2VkRHVja0J5T3duZXIBBQRhZGRyAhxZb3UgZG9uJ3QgaGF2ZSBhIGR1Y2sgc3Rha2VkBAtjdXJMb2NhdGlvbgkBC3ZhbHVlT3JFbHNlAgkAoggBCQEPa2V5RHVja0xvY2F0aW9uAQULZHVja0Fzc2V0SWQFD0RFRkFVTFRMT0NBVElPTgQDbG9jCQC1CQIJAQV2YWx1ZQEFC2N1ckxvY2F0aW9uAgFfAwkBAiE9AgkAkQMCBQNsb2MFCmxvY0lkeFR5cGUCAUwJAAIBCQCsAgIJAKwCAgIWRHVjayBsb2NhdGlvbiB0eXBlIGlzIAkAkQMCBQNsb2MFCmxvY0lkeFR5cGUCESwgYnV0IHNob3VsZCBiZSBMAwkBAiE9AgkAkQMCBQNsb2MFCGxvY0lkeElkBQtsYW5kQXNzZXRJZAkAAgEJAKwCAgIbRHVjayBzaG91bGQgYmUgb24gdGhlIGxhbmQgBQtsYW5kQXNzZXRJZAQFd2hLZXkJARJrZXlXYXJlaG91c2VCeUxhbmQBBQtsYW5kQXNzZXRJZAQJY3VycmVudFdoCQEMZ2V0V2FyZWhvdXNlAwUFd2hLZXkFCWxhbmRJbmRleAUKaW5mcmFMZXZlbAQFYnBLZXkJARFrZXlCYWNrcGFja0J5RHVjawEFC2R1Y2tBc3NldElkBAtjdXJyZW50UGFjawkBC2dldEJhY2twYWNrAQUFYnBLZXkEBnJlc3VsdAkBCW1vdmVTdHVmZgMFCmNhcmdvUGFydHMFCWN1cnJlbnRXaAULY3VycmVudFBhY2sJAMwIAgkBC1N0cmluZ0VudHJ5AgUFYnBLZXkJALkJAgkAzAgCCQCRAwIFC2N1cnJlbnRQYWNrBQpicElkeExldmVsCQDMCAIIBQZyZXN1bHQCXzQJAMwIAggFBnJlc3VsdAJfNQkAzAgCCAUGcmVzdWx0Al82BQNuaWwCAToJAMwIAgkBC1N0cmluZ0VudHJ5AgUFd2hLZXkJALkJAgkAzAgCCQCRAwIFCWN1cnJlbnRXaAUId2hJZHhWb2wJAMwIAggFBnJlc3VsdAJfMQkAzAgCCAUGcmVzdWx0Al8yCQDMCAIIBQZyZXN1bHQCXzMJAMwIAgkAkQMCBQljdXJyZW50V2gFDndoSWR4TG9ja2VkVm9sBQNuaWwCAToJAMwIAgUMcHJvbG9nQWN0aW9uBQNuaWwBaQENc2F2ZVdhcmVob3VzZQIFd2hTdHILbGFuZEFzc2V0SWQEDHByb2xvZ0FjdGlvbgkBBnByb2xvZwEFAWkDCQECIT0CCAUBaQZjYWxsZXIFD2Vjb25vbXlDb250cmFjdAkAAgECDUFjY2VzcyBkZW5pZWQEBXdoS2V5CQESa2V5V2FyZWhvdXNlQnlMYW5kAQULbGFuZEFzc2V0SWQDCQECIT0CCQCQAwEJALwJAgUFd2hTdHICAToABQkAAgECMHdhcmVob3VzZSBzdHJpbmcgc2hvdWxkIGNvbnRhaW4gNCAnOicgc2VwYXJhdG9ycwkAlAoCCQDMCAIJAQtTdHJpbmdFbnRyeQIFBXdoS2V5BQV3aFN0cgkAzAgCBQxwcm9sb2dBY3Rpb24FA25pbAUFd2hTdHIBaQEcc3BsaXRCeUdsb2JhbFdlaWdodHNSRUFET05MWQEGYW1vdW50CQCUCgIFA25pbAkBEmdldE5lZWRlZE1hdGVyaWFscwEFBmFtb3VudAFpASRzcGxpdEJ5R2xvYmFsQW5kTG9jYWxXZWlnaHRzUkVBRE9OTFkDCW1hdEFtb3VudAlyZXNBbW91bnQIdGVycmFpbnMEDXRlcnJhaW5Db3VudHMJAQ1jb3VudFRlcnJhaW5zAQUIdGVycmFpbnMJAJQKAgUDbmlsCQCUCgIJARJnZXROZWVkZWRNYXRlcmlhbHMBBQltYXRBbW91bnQJARNkaXN0cmlidXRlQnlXZWlnaHRzAgUJcmVzQW1vdW50BQ10ZXJyYWluQ291bnRzAWkBE2dldEJhY2twYWNrUkVBRE9OTFkBC2R1Y2tBc3NldElkCQCUCgIFA25pbAkAuQkCCQELZ2V0QmFja3BhY2sBCQERa2V5QmFja3BhY2tCeUR1Y2sBBQtkdWNrQXNzZXRJZAIBOgFpARRnZXRXYXJlaG91c2VSRUFET05MWQELbGFuZEFzc2V0SWQEBWFzc2V0CQEFdmFsdWUBCQDsBwEJANkEAQULbGFuZEFzc2V0SWQECWxhbmRJbmRleAkAaQIJAQ9udW1QaWVjZXNCeVNpemUBCQCRAwIJALUJAggFBWFzc2V0C2Rlc2NyaXB0aW9uAgFfBQtyZWNMYW5kU2l6ZQUFU1NJWkUECmluZnJhTGV2ZWwJAQt2YWx1ZU9yRWxzZQIJAJ8IAQkBFmtleUluZnJhTGV2ZWxCeUFzc2V0SWQBBQtsYW5kQXNzZXRJZAAACQCUCgIFA25pbAkAugkCCQEMZ2V0V2FyZWhvdXNlAwkBEmtleVdhcmVob3VzZUJ5TGFuZAEFC2xhbmRBc3NldElkBQlsYW5kSW5kZXgFCmluZnJhTGV2ZWwCAToAphZRzA==", "height": 2554601, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: GMztVU1UGs47gWWrzZPHbNWT37VriqxfGne8oFTushLe Next: 7Lm3otfM7HtFLCKF4piqiXURHigf2vkmSqVAXG9787bV Diff:
OldNewDifferences
1212 else throw("Unknown chain")
1313 }
1414
15-let InfraUpgradeCostS = match chain {
15+let incubatorAddr = match chain {
1616 case _ =>
1717 if ((base58'2W' == $match0))
18- then 6307198406
18+ then addressFromStringValue("3PEktVux2RhchSN63DsDo4b4mz4QqzKSeDv")
1919 else if ((base58'2T' == $match0))
20- then 63071984
20+ then this
2121 else throw("Unknown chain")
2222 }
23+
24+let breederAddr = match chain {
25+ case _ =>
26+ if ((base58'2W' == $match0))
27+ then addressFromStringValue("3PDVuU45H7Eh5dmtNbnRNRStGwULA7NY6Hb")
28+ else if ((base58'2T' == $match0))
29+ then this
30+ else throw("Unknown chain")
31+}
32+
33+let defaultRestAddressStr = match chain {
34+ case _ =>
35+ if ((base58'2W' == $match0))
36+ then "3PQCuvFbvh4LkPUnrnU1z3jnbA1p9m3WNhv"
37+ else if ((base58'2T' == $match0))
38+ then "3MumkGGztCKAXpWDqxkddofqXSUbqQkvSJy"
39+ else throw("Unknown chain")
40+}
41+
42+let pub = base58'6LfPuKJjLgekmncBhMg2LZyMTNVzZBccXR28ySXm9uXD'
43+
44+let HEALCOST = 10000
2345
2446 let LANDPREFIX = "LAND"
2547
2648 let DUCKPREFIX = "DUCK"
2749
28-let SEP = "__"
29-
30-let ARTPRESALE = "PRESALE"
31-
32-let DAILYRESBYPIECE = 3456000
33-
34-let DAYMILLIS = 86400000
50+let DEFAULTLOCATION = "Africa_F_Africa"
3551
3652 let NUMRES = 6
3753
4561
4662 let XXLSIZE = 625
4763
48-let recLandNum = 0
64+let DAILYRESBYPIECE = 3456000
4965
50-let recLandSize = 1
66+let DAYMILLIS = 86400000
5167
52-let recTerrains = 2
68+let FIVEMINUTESMILLIS = 300000
5369
54-let recContinent = 3
70+let RESOURCEPRICEMIN = 158549
5571
56-let whIdxVol = 0
72+let WHMULTIPLIER = 10000000000
5773
58-let whIdxRes = 1
74+let InfraUpgradeCostS = match chain {
75+ case _ =>
76+ if ((base58'2W' == $match0))
77+ then 6307198406
78+ else if ((base58'2T' == $match0))
79+ then 63071984
80+ else throw("Unknown chain")
81+}
5982
60-let whIdxMat = 2
83+let InfraUpgradeCostSUsdn = match chain {
84+ case _ =>
85+ if ((base58'2W' == $match0))
86+ then 40000000
87+ else if ((base58'2T' == $match0))
88+ then 400000
89+ else throw("Unknown chain")
90+}
6191
62-let whIdxProd = 3
92+let EXPMATERIALS = match chain {
93+ case _ =>
94+ if ((base58'2W' == $match0))
95+ then 157679960139
96+ else if ((base58'2T' == $match0))
97+ then 1576799601
98+ else throw("Unknown chain")
99+}
63100
64-let whIdxLockedVol = 4
101+let EXPUSDN = match chain {
102+ case _ =>
103+ if ((base58'2W' == $match0))
104+ then 1000000000
105+ else if ((base58'2T' == $match0))
106+ then 10000000
107+ else throw("Unknown chain")
108+}
65109
66-func keyRestCfg () = "%s__restConfig"
110+let SEP = "__"
111+
112+let MULT6 = 1000000
113+
114+let FIVEX = toBigInt(5)
115+
116+let TWENTYX = toBigInt(20)
117+
118+let TWENTY2X = toBigInt((20 * 20))
119+
120+let TWENTY3X = toBigInt(((20 * 20) * 20))
121+
122+let TWENTY4X = toBigInt((((20 * 20) * 20) * 20))
123+
124+let TWENTY5X = toBigInt(((((20 * 20) * 20) * 20) * 20))
125+
126+let matTypes = ["Fuel", "Metal", "Plank", "Glass", "Plastic", "Protein"]
127+
128+let continents = ["Asia", "Europe", "Americas", "Oceania", "Africa"]
129+
130+let ARTPRESALE = "PRESALE"
131+
132+let PRESALENUMLANDS = 500
133+
134+func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), makeString(["mandatory ", toString(address), ".", key, " is not defined"], ""))
135+
136+
137+func getIntOrElse (key,defaultVal) = valueOrElse(getInteger(this, key), defaultVal)
67138
68139
69140 let IdxCfgStakingDapp = 1
72143
73144 let IdxCfgGovernanceDapp = 3
74145
75-func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), makeString(["mandatory ", toString(address), ".", key, " is not defined"], ""))
146+func keyRestCfg () = "%s__restConfig"
76147
77148
78-func readRestCfgOrFail () = split_4C(getStringOrFail(this, keyRestCfg()), SEP)
149+func keyRestAddress () = "%s__restAddr"
150+
151+
152+func readRestCfgOrFail (rest) = split_4C(getStringOrFail(rest, keyRestCfg()), SEP)
79153
80154
81155 func getContractAddressOrFail (restCfg,idx) = valueOrErrorMessage(addressFromString(restCfg[idx]), ("Rest cfg doesn't contain address at index " + toString(idx)))
82156
83157
84-let restCfg = readRestCfgOrFail()
158+let restContract = addressFromStringValue(valueOrElse(getString(this, keyRestAddress()), defaultRestAddressStr))
85159
86-let stakingContract = getContractAddressOrFail(restCfg, IdxCfgStakingDapp)
160+let restCfg = readRestCfgOrFail(restContract)
87161
88162 let economyContract = getContractAddressOrFail(restCfg, IdxCfgEconomyDapp)
89163
90-let governanceContract = getContractAddressOrFail(restCfg, IdxCfgEconomyDapp)
164+let govContract = getContractAddressOrFail(restCfg, IdxCfgGovernanceDapp)
91165
92-func keyBlocked () = "contractsBlocked"
166+func keyLastTxIdByUser (addr) = ("lastTxIdByUser_" + addr)
167+
168+
169+func keyNextFreeLandNum () = "nextLandNum"
170+
171+
172+func keyLandToAssetId (landNum) = ("landToAsset_" + landNum)
173+
174+
175+func keyNftName (landNum,landSize) = ((LANDPREFIX + landNum) + landSize)
176+
177+
178+func keyLandAssetIdToOwner (assetId) = ("nftOwner_" + assetId)
93179
94180
95181 func keyDuckIdToOwner (assetId) = ("duckOwner_" + assetId)
98184 func keyStakedTimeByAssetId (assetId) = ("stakedTime_" + assetId)
99185
100186
187+func keyInfraLevelByAssetId (assetId) = ("infraLevel_" + assetId)
188+
189+
190+func keyInfraLevelByAssetIdAndOwner (assetId,ownerAddr) = ((("infraLevelByAssetIdAndOwner_" + assetId) + "_") + ownerAddr)
191+
192+
193+func keyPresaleArtActivatedByAssetId (assetId) = ("presaleArtActivated_" + assetId)
194+
195+
196+func keyPresaleArtActivatedByAssetIdAndOwner (assetId,ownerAddr) = ((("presaleArtActivatedByAssetIdAndOwner_" + assetId) + "_") + ownerAddr)
197+
198+
199+func keyLandArtStatusByTypeAndAssetId (type,assetId) = makeString(["landArtStatus", type, assetId], "_")
200+
201+
202+func keyLandArtStatusByTypeAssetIdAndOwner (type,assetId,ownerAddr) = makeString(["landArtStatusByTypeAssetIdAndOwner", type, assetId, ownerAddr], "_")
203+
204+
101205 func keyStakedDuckByOwner (ownerAddr) = ("stakedDuckByOwner_" + ownerAddr)
102206
103207
104208 func keyStakedTimeByTypeAssetIdAndOwner (nftType,assetId,ownerAddr) = ((((("stakedTimeByTypeAssetIdAndOwner_" + nftType) + "_") + assetId) + "_") + ownerAddr)
209+
210+
211+func keyLandNumToOwner (landNum) = ("landOwner_" + landNum)
105212
106213
107214 func keyBackpackByDuck (duckAssetId) = ("backPack_" + duckAssetId)
116223 func keyDuckHealth (duckAssetId) = ("duckHealth_" + duckAssetId)
117224
118225
119-func keyLandAssetIdToOwner (assetId) = ("nftOwner_" + assetId)
120-
121-
122-func keyInfraLevelByAssetId (assetId) = ("infraLevel_" + assetId)
123-
124-
125-func keyLandArtStatusByTypeAndAssetId (type,assetId) = makeString(["landArtStatus", type, assetId], "_")
126-
127-
128-func keyPresaleArtActivatedByAssetId (assetId) = ("presaleArtActivated_" + assetId)
226+func keyResProportions () = "resTypesProportions"
129227
130228
131229 func keyStakedLandsByOwner (ownerAddr) = ("stakedLandsByOwner_" + ownerAddr)
132230
133231
134-func keyOrderByLand (landAssetId) = ("landOrder_" + landAssetId)
232+func keyBlocked () = "contractsBlocked"
135233
234+
235+func keyUserGwlReleaseTime (userAddr) = ("%s%s__userGwlReleaseTime__" + userAddr)
236+
237+
238+let recLandNum = 0
239+
240+let recLandSize = 1
241+
242+let recTerrains = 2
243+
244+let recContinent = 3
245+
246+let locIdxContinent = 0
247+
248+let locIdxType = 1
249+
250+let locIdxId = 2
251+
252+let bpIdxLevel = 0
253+
254+let bpIdxRes = 1
255+
256+let bpIdxMat = 2
257+
258+let bpIdxProd = 3
259+
260+let whIdxVol = 0
261+
262+let whIdxRes = 1
263+
264+let whIdxMat = 2
265+
266+let whIdxProd = 3
267+
268+let whIdxLockedVol = 4
269+
270+let claimModeWh = 0
271+
272+let claimModeDuck = 1
273+
274+let claimModeWhThenDuck = 2
136275
137276 func asString (v) = match v {
138277 case s: String =>
142281 }
143282
144283
145-func asBoolean (v) = match v {
146- case s: Boolean =>
147- s
148- case _ =>
149- throw("fail to cast into Boolean")
150-}
284+func distributeByWeights (total,weights) = {
285+ let sum = (((((weights[0] + weights[1]) + weights[2]) + weights[3]) + weights[4]) + weights[5])
286+ if ((0 >= sum))
287+ then throw("Zero weights sum")
288+ else {
289+ let norm6 = fraction(total, MULT6, sum)
290+ func normalizer (acc,elem) = (acc :+ fraction(elem, norm6, MULT6))
151291
292+ let $l = weights
293+ let $s = size($l)
294+ let $acc0 = nil
295+ func $f0_1 ($a,$i) = if (($i >= $s))
296+ then $a
297+ else normalizer($a, $l[$i])
152298
153-func asListIntCompacted (val) = match val {
154- case valAnyList: List[Any] =>
155- if ((size(valAnyList) != NUMRES))
156- then throw(("Array size is " + toString(size(valAnyList))))
157- else {
158- func conv (acc,item) = match item {
159- case it: Int =>
160- (acc :+ toString(it))
161- case _ =>
162- throw("List type is not Int")
163- }
299+ func $f0_2 ($a,$i) = if (($i >= $s))
300+ then $a
301+ else throw("List size exceeds 6")
164302
165- let r = {
166- let $l = valAnyList
167- let $s = size($l)
168- let $acc0 = nil
169- func $f0_1 ($a,$i) = if (($i >= $s))
170- then $a
171- else conv($a, $l[$i])
172-
173- func $f0_2 ($a,$i) = if (($i >= $s))
174- then $a
175- else throw("List size exceeds 6")
176-
177- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
178- }
179- makeString(r, "_")
180- }
181- case _ =>
182- throw("fail to cast into List")
183-}
184-
185-
186-func asSplitResult (val) = match val {
187- case t2: (List[Any], List[Any]) =>
188- $Tuple2(asListIntCompacted(t2._1), asListIntCompacted(t2._2))
189- case _ =>
190- throw("fail to cast into (List, List)")
191-}
192-
193-
194-func walletInternal (userAddressOpt) = {
195- let addr = addressFromString(userAddressOpt)
196- let balance = if (isDefined(addr))
197- then wavesBalance(value(addr))
198- else BalanceDetails(0, 0, 0, 0)
199- let usdnBalance = if (isDefined(addr))
200- then assetBalance(value(addr), usdnAssetId)
201- else 0
202- makeString(["%s%d%d", "wallet", toString(balance.available), toString(usdnBalance)], SEP)
303+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
304+ }
203305 }
204306
205307
206-func applyBonuses (landAssetId,pieces) = {
207- let infraLevel = valueOrElse(getInteger(stakingContract, keyInfraLevelByAssetId(landAssetId)), 0)
208- let artPieces = valueOrElse(getInteger(stakingContract, keyLandArtStatusByTypeAndAssetId(ARTPRESALE, landAssetId)), if (valueOrElse(getBoolean(stakingContract, keyPresaleArtActivatedByAssetId(landAssetId)), false))
209- then pieces
210- else 0)
211- $Tuple3(infraLevel, artPieces, ((DAILYRESBYPIECE + fraction(DAILYRESBYPIECE, infraLevel, 4)) + fraction(DAILYRESBYPIECE, (artPieces * 3), (pieces * 20))))
308+func getNeededMaterials (total) = {
309+ let props = split(value(getString(keyResProportions())), "_")
310+ if ((size(props) != NUMRES))
311+ then throw("Wrong proportions data")
312+ else {
313+ let r = [parseIntValue(props[0]), parseIntValue(props[1]), parseIntValue(props[2]), parseIntValue(props[3]), parseIntValue(props[4]), parseIntValue(props[5])]
314+ distributeByWeights(total, r)
315+ }
212316 }
317+
318+
319+func subtractMaterials (shouldUseMat,has,totalNeed) = {
320+ let need = getNeededMaterials(totalNeed)
321+ func subtractor (acc,idx) = {
322+ let result = (parseIntValue(has[idx]) - need[idx])
323+ if ((0 > result))
324+ then throw(((((("Not enough material idx=" + toString(idx)) + ", you have ") + has[idx]) + ", but need ") + toString(need[idx])))
325+ else (acc :+ toString(result))
326+ }
327+
328+ if (shouldUseMat)
329+ then {
330+ let $l = [0, 1, 2, 3, 4, 5]
331+ let $s = size($l)
332+ let $acc0 = nil
333+ func $f0_1 ($a,$i) = if (($i >= $s))
334+ then $a
335+ else subtractor($a, $l[$i])
336+
337+ func $f0_2 ($a,$i) = if (($i >= $s))
338+ then $a
339+ else throw("List size exceeds 6")
340+
341+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
342+ }
343+ else has
344+ }
345+
346+
347+func updateProportionsInternal (propList,terrainCounts,landSizeIndex,sign) = if ((size(propList) != NUMRES))
348+ then throw("Wrong proportions data")
349+ else {
350+ func updater (acc,i) = {
351+ let result = (parseIntValue(propList[i]) + ((sign * terrainCounts[i]) * landSizeIndex))
352+ if ((0 > result))
353+ then throw(((((((("Panic! Pieces of type=" + toString(i)) + ", sign=") + toString(sign)) + ", terrainCounts[i]=") + toString(terrainCounts[i])) + ", landSizeIndex=") + toString(landSizeIndex)))
354+ else (acc :+ toString(result))
355+ }
356+
357+ let r = {
358+ let $l = [0, 1, 2, 3, 4, 5]
359+ let $s = size($l)
360+ let $acc0 = nil
361+ func $f0_1 ($a,$i) = if (($i >= $s))
362+ then $a
363+ else updater($a, $l[$i])
364+
365+ func $f0_2 ($a,$i) = if (($i >= $s))
366+ then $a
367+ else throw("List size exceeds 6")
368+
369+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
370+ }
371+ makeString(r, "_")
372+ }
373+
374+
375+func updateProportions (terrainCounts,landSizeIndex,sign) = {
376+ let propList = split(valueOrElse(getString(keyResProportions()), "0_0_0_0_0_0"), "_")
377+ updateProportionsInternal(propList, terrainCounts, landSizeIndex, sign)
378+ }
379+
380+
381+func countTerrains (terrains) = [(size(split(terrains, "A")) - 1), (size(split(terrains, "B")) - 1), (size(split(terrains, "C")) - 1), (size(split(terrains, "D")) - 1), (size(split(terrains, "E")) - 1), (size(split(terrains, "F")) - 1)]
213382
214383
215384 func numPiecesBySize (landSize) = match landSize {
228397 }
229398
230399
400+func subOneInList (aList,idx,amount) = {
401+ func subber (acc,i) = (acc :+ (if ((i == idx))
402+ then toString((parseIntValue(aList[i]) - amount))
403+ else aList[i]))
404+
405+ let r = {
406+ let $l = [0, 1, 2, 3, 4, 5]
407+ let $s = size($l)
408+ let $acc0 = nil
409+ func $f0_1 ($a,$i) = if (($i >= $s))
410+ then $a
411+ else subber($a, $l[$i])
412+
413+ func $f0_2 ($a,$i) = if (($i >= $s))
414+ then $a
415+ else throw("List size exceeds 6")
416+
417+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
418+ }
419+ makeString(r, "_")
420+ }
421+
422+
423+func addRes (currentRes,terrainCounts,deltaTime,landSizeIndex,dailyByPieceWithBonuses) = {
424+ func adder (acc,i) = {
425+ let resOfType = ((fraction(deltaTime, dailyByPieceWithBonuses, DAYMILLIS) * terrainCounts[i]) * landSizeIndex)
426+ (acc :+ toString((parseIntValue(currentRes[i]) + resOfType)))
427+ }
428+
429+ let r = {
430+ let $l = [0, 1, 2, 3, 4, 5]
431+ let $s = size($l)
432+ let $acc0 = nil
433+ func $f0_1 ($a,$i) = if (($i >= $s))
434+ then $a
435+ else adder($a, $l[$i])
436+
437+ func $f0_2 ($a,$i) = if (($i >= $s))
438+ then $a
439+ else throw("List size exceeds 6")
440+
441+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
442+ }
443+ makeString(r, "_")
444+ }
445+
446+
447+func virtClaim (terrainCounts,deltaTime,landSizeIndex,dailyByPieceWithBonuses) = {
448+ func adder (acc,i) = {
449+ let resOfType = ((fraction(deltaTime, dailyByPieceWithBonuses, DAYMILLIS) * terrainCounts[i]) * landSizeIndex)
450+ $Tuple2((acc._1 :+ resOfType), (acc._2 + resOfType))
451+ }
452+
453+ let $l = [0, 1, 2, 3, 4, 5]
454+ let $s = size($l)
455+ let $acc0 = $Tuple2(nil, 0)
456+ func $f0_1 ($a,$i) = if (($i >= $s))
457+ then $a
458+ else adder($a, $l[$i])
459+
460+ func $f0_2 ($a,$i) = if (($i >= $s))
461+ then $a
462+ else throw("List size exceeds 6")
463+
464+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
465+ }
466+
467+
468+func distributeRes (currentWhRes,currentPackRes,resToClaim,whSpaceLeft) = {
469+ let resListToClaim = resToClaim._1
470+ let resAmToClaim = resToClaim._2
471+ if ((resAmToClaim == 0))
472+ then $Tuple2(makeString(currentWhRes, "_"), makeString(currentPackRes, "_"))
473+ else if ((whSpaceLeft >= resAmToClaim))
474+ then {
475+ func addLists (acc,i) = (acc :+ toString((parseIntValue(currentWhRes[i]) + resListToClaim[i])))
476+
477+ let r = {
478+ let $l = [0, 1, 2, 3, 4, 5]
479+ let $s = size($l)
480+ let $acc0 = nil
481+ func $f0_1 ($a,$i) = if (($i >= $s))
482+ then $a
483+ else addLists($a, $l[$i])
484+
485+ func $f0_2 ($a,$i) = if (($i >= $s))
486+ then $a
487+ else throw("List size exceeds 6")
488+
489+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
490+ }
491+ $Tuple2(makeString(r, "_"), makeString(currentPackRes, "_"))
492+ }
493+ else {
494+ func addPartLists (acc,i) = {
495+ let whPart = fraction(resListToClaim[i], whSpaceLeft, resAmToClaim)
496+ $Tuple2((acc._1 :+ toString((parseIntValue(currentWhRes[i]) + whPart))), (acc._2 :+ toString(((parseIntValue(currentPackRes[i]) + resListToClaim[i]) - whPart))))
497+ }
498+
499+ let r = {
500+ let $l = [0, 1, 2, 3, 4, 5]
501+ let $s = size($l)
502+ let $acc0 = $Tuple2(nil, nil)
503+ func $f0_1 ($a,$i) = if (($i >= $s))
504+ then $a
505+ else addPartLists($a, $l[$i])
506+
507+ func $f0_2 ($a,$i) = if (($i >= $s))
508+ then $a
509+ else throw("List size exceeds 6")
510+
511+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
512+ }
513+ $Tuple2(makeString(r._1, "_"), makeString(r._2, "_"))
514+ }
515+ }
516+
517+
518+func abs (x) = if ((x >= toBigInt(0)))
519+ then x
520+ else -(x)
521+
522+
523+let freq = [[1, 4, 9, 10, 15], [5, 8, 13, 14, 15], [6, 9, 14, 15, 16], [4, 7, 8, 13, 18], [1, 6, 7, 15, 19]]
524+
525+func genChar (n,freqs) = {
526+ let rem = toInt((n % TWENTYX))
527+ let letter = if ((freqs[0] > rem))
528+ then "A"
529+ else if ((freqs[1] > rem))
530+ then "B"
531+ else if ((freqs[2] > rem))
532+ then "C"
533+ else if ((freqs[3] > rem))
534+ then "D"
535+ else if ((freqs[4] > rem))
536+ then "E"
537+ else "F"
538+ letter
539+ }
540+
541+
542+func genTerrains (seed,continentIdx) = {
543+ let f = freq[continentIdx]
544+ func terrainGenerator (acc,elem) = $Tuple2((((((acc._1 + genChar(acc._2, f)) + genChar((acc._2 / TWENTYX), f)) + genChar((acc._2 / TWENTY2X), f)) + genChar((acc._2 / TWENTY3X), f)) + genChar((acc._2 / TWENTY4X), f)), (acc._2 / TWENTY5X))
545+
546+ let t = {
547+ let $l = [1, 2, 3, 4, 5]
548+ let $s = size($l)
549+ let $acc0 = $Tuple2("", (seed / FIVEX))
550+ func $f0_1 ($a,$i) = if (($i >= $s))
551+ then $a
552+ else terrainGenerator($a, $l[$i])
553+
554+ func $f0_2 ($a,$i) = if (($i >= $s))
555+ then $a
556+ else throw("List size exceeds 5")
557+
558+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5)
559+ }
560+ t._1
561+ }
562+
563+
564+func getBackpack (bpKey) = {
565+ let p = split(valueOrElse(getString(bpKey), "0:0_0_0_0_0_0:0_0_0_0_0_0:"), ":")
566+[toString(valueOrElse(parseInt(p[bpIdxLevel]), 0)), if ((size(split(p[bpIdxRes], "_")) == NUMRES))
567+ then p[bpIdxRes]
568+ else "0_0_0_0_0_0", if ((size(split(p[bpIdxMat], "_")) == NUMRES))
569+ then p[bpIdxMat]
570+ else "0_0_0_0_0_0", p[bpIdxProd]]
571+ }
572+
573+
574+func getWarehouseVolume (volPrefix) = {
575+ let parts = split(volPrefix, "_")
576+ ((WHMULTIPLIER * (parseIntValue(parts[1]) + 1)) * parseIntValue(parts[0]))
577+ }
578+
579+
231580 func getWarehouse (whKey,landIndex,infraLevel) = {
232581 let volPrefix = ((toString(landIndex) + "_") + toString(infraLevel))
233- let p = split(valueOrElse(getString(stakingContract, whKey), (volPrefix + ":0_0_0_0_0_0:0_0_0_0_0_0::0")), ":")
582+ let p = split(valueOrElse(getString(whKey), (volPrefix + ":0_0_0_0_0_0:0_0_0_0_0_0::0")), ":")
234583 [p[whIdxVol], if ((size(split(p[whIdxRes], "_")) == NUMRES))
235584 then p[whIdxRes]
236585 else "0_0_0_0_0_0", if ((size(split(p[whIdxMat], "_")) == NUMRES))
241590 }
242591
243592
244-func duckInfoTuple (duckAssetId) = $Tuple5(valueOrElse(getInteger(stakingContract, keyStakedTimeByAssetId(duckAssetId)), -1), value(assetInfo(fromBase58String(duckAssetId))).name, valueOrElse(getString(stakingContract, keyDuckLocation(duckAssetId)), ""), valueOrElse(getInteger(stakingContract, keyDuckHealth(duckAssetId)), -1), asString(invoke(stakingContract, "getBackpackREADONLY", [duckAssetId], nil)))
593+func getWarehouseCurrResVolume (currentWh) = {
594+ func sum (acc,item) = (acc + parseIntValue(item))
595+
596+ let $l = split(currentWh[whIdxRes], "_")
597+ let $s = size($l)
598+ let $acc0 = 0
599+ func $f0_1 ($a,$i) = if (($i >= $s))
600+ then $a
601+ else sum($a, $l[$i])
602+
603+ func $f0_2 ($a,$i) = if (($i >= $s))
604+ then $a
605+ else throw("List size exceeds 6")
606+
607+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
608+ }
245609
246610
247-func duckInfoArray (duckAssetId,owner,duckInf) = [("%s%s__assetId__" + duckAssetId), ("%s%s__owner__" + owner), ("%s%d__stakedTime__" + toString(duckInf._1)), ("%s%s__name__" + duckInf._2), ("%s%s__location__" + duckInf._3), ("%s%d__health__" + toString(duckInf._4)), ("%s%s__backPack__" + duckInf._5)]
611+func getWarehouseCurrMatVolume (currentWh) = {
612+ func sum (acc,item) = (acc + parseIntValue(item))
613+
614+ let $l = split(currentWh[whIdxMat], "_")
615+ let $s = size($l)
616+ let $acc0 = 0
617+ func $f0_1 ($a,$i) = if (($i >= $s))
618+ then $a
619+ else sum($a, $l[$i])
620+
621+ func $f0_2 ($a,$i) = if (($i >= $s))
622+ then $a
623+ else throw("List size exceeds 6")
624+
625+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
626+ }
248627
249628
250-func landInfoArray (landAssetId,owner,stakedTime) = if ((landAssetId == ""))
251- then throw("landAssetId is required")
629+func getWarehouseCurrGoodsVolume (currentWh) = {
630+ let goods = currentWh[whIdxProd]
631+ if ((goods == ""))
632+ then 0
633+ else {
634+ func sum (acc,item) = (acc + parseIntValue(item))
635+
636+ let $l = split_4C(goods, "_")
637+ let $s = size($l)
638+ let $acc0 = 0
639+ func $f0_1 ($a,$i) = if (($i >= $s))
640+ then $a
641+ else sum($a, $l[$i])
642+
643+ func $f0_2 ($a,$i) = if (($i >= $s))
644+ then $a
645+ else throw("List size exceeds 50")
646+
647+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40), 41), 42), 43), 44), 45), 46), 47), 48), 49), 50)
648+ }
649+ }
650+
651+
652+func moveStuff (cargoParts,currentWh,currentPack) = if ((size(cargoParts) != 3))
653+ then throw("cargoListStr should contain exactly 2 ':' separators")
252654 else {
253- let a = value(assetInfo(fromBase58String(landAssetId)))
254- let d = split(a.description, "_")
255- let landNum = if ((a.quantity > 0))
256- then d[recLandNum]
257- else ("-" + d[recLandNum])
258- let pieces = numPiecesBySize(d[recLandSize])
259- let productivity = applyBonuses(landAssetId, pieces)
260- let deltaTime = (lastBlock.timestamp - stakedTime)
261- let availRes = if ((stakedTime > 0))
262- then fraction(deltaTime, (productivity._3 * pieces), DAYMILLIS)
263- else 0
264- let needMat = fraction(InfraUpgradeCostS, (pieces * (productivity._1 + 1)), SSIZE)
265- let globalAndLocal = if ((stakedTime > 0))
266- then asSplitResult(invoke(stakingContract, "splitByGlobalAndLocalWeightsREADONLY", [needMat, availRes, d[recTerrains]], nil))
267- else $Tuple2(asListIntCompacted(invoke(stakingContract, "splitByGlobalWeightsREADONLY", [needMat], nil)), "")
268-[("%s%s__assetId__" + landAssetId), ("%s%s__owner__" + owner), ("%s%d__stakedTime__" + toString(stakedTime)), ("%s%s__description__" + makeString([landNum, d[recLandSize], d[recTerrains], d[recContinent]], "_")), ("%s%d__infraLevel__" + toString(productivity._1)), ("%s%s__availResByType__" + globalAndLocal._2), ("%s%d__availResTotal__" + toString(availRes)), ("%s%s__needMaterial__" + globalAndLocal._1), makeString(["%s%s", "landArtefacts", ("PRESALE:" + toString(productivity._2))], SEP), ("%s%s__warehouse__" + makeString(getWarehouse(keyWarehouseByLand(landAssetId), (pieces / SSIZE), productivity._1), ":")), ("%s%s__landOrder__" + valueOrElse(getString(economyContract, keyOrderByLand(landAssetId)), "0@0_0@0_0@0_0@0_0@0_0@0:0@0_0@0_0@0_0@0_0@0_0@0:"))]
655+ let resParts = split(cargoParts[0], "_")
656+ let matParts = split(cargoParts[1], "_")
657+ let prodParts = if ((cargoParts[2] == ""))
658+ then nil
659+ else split(cargoParts[2], "_")
660+ if ((size(resParts) != NUMRES))
661+ then throw("All 6 resources should be passed")
662+ else if ((size(matParts) != NUMRES))
663+ then throw("All 6 materials should be passed")
664+ else {
665+ let currWhResVol = getWarehouseCurrResVolume(currentWh)
666+ let currWhMatVol = getWarehouseCurrMatVolume(currentWh)
667+ let currWhGoodsVol = getWarehouseCurrGoodsVolume(currentWh)
668+ let currWhLockedVol = parseIntValue(currentWh[whIdxLockedVol])
669+ let whSpaceLeft = ((((getWarehouseVolume(currentWh[whIdxVol]) - currWhResVol) - currWhMatVol) - currWhGoodsVol) - currWhLockedVol)
670+ let currWhRes = split(currentWh[whIdxRes], "_")
671+ let currWhMat = split(currentWh[whIdxMat], "_")
672+ let currWhProd = if ((currentWh[whIdxProd] == ""))
673+ then nil
674+ else split(currentWh[whIdxProd], "_")
675+ let currentPackRes = split(currentPack[bpIdxRes], "_")
676+ let currentPackMat = split(currentPack[bpIdxMat], "_")
677+ let currentPackProd = if ((currentPack[bpIdxProd] == ""))
678+ then nil
679+ else split(currentPack[bpIdxProd], "_")
680+ func mvR (acc,item) = {
681+ let i = acc._1
682+ let am = parseIntValue(item)
683+ let whr = parseIntValue(currWhRes[i])
684+ let bpr = parseIntValue(currentPackRes[i])
685+ if ((am == 0))
686+ then $Tuple4((i + 1), (acc._2 :+ currWhRes[i]), (acc._3 :+ currentPackRes[i]), acc._4)
687+ else if ((am > 0))
688+ then if ((am > bpr))
689+ then throw((((("Attempt to take " + item) + " from backpack, but only ") + toString(bpr)) + " available"))
690+ else $Tuple4((i + 1), (acc._2 :+ toString((whr + am))), (acc._3 :+ toString((bpr - am))), (acc._4 + am))
691+ else if ((-(am) > whr))
692+ then throw((((("Attempt to take " + toString(-(am))) + " from warehouse, but only ") + toString(whr)) + " available"))
693+ else $Tuple4((i + 1), (acc._2 :+ toString((whr + am))), (acc._3 :+ toString((bpr - am))), (acc._4 + am))
694+ }
695+
696+ let r = {
697+ let $l = resParts
698+ let $s = size($l)
699+ let $acc0 = $Tuple4(0, nil, nil, 0)
700+ func $f0_1 ($a,$i) = if (($i >= $s))
701+ then $a
702+ else mvR($a, $l[$i])
703+
704+ func $f0_2 ($a,$i) = if (($i >= $s))
705+ then $a
706+ else throw("List size exceeds 6")
707+
708+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
709+ }
710+ func mvM (acc,item) = {
711+ let i = acc._1
712+ let am = parseIntValue(item)
713+ let whm = parseIntValue(currWhMat[i])
714+ let bpm = parseIntValue(currentPackMat[i])
715+ if ((am == 0))
716+ then $Tuple4((i + 1), (acc._2 :+ currWhMat[i]), (acc._3 :+ currentPackMat[i]), acc._4)
717+ else if ((am > 0))
718+ then if ((am > bpm))
719+ then throw((((("Attempt to take " + item) + " from backpack, but only ") + toString(bpm)) + " available"))
720+ else $Tuple4((i + 1), (acc._2 :+ toString((whm + am))), (acc._3 :+ toString((bpm - am))), (acc._4 + am))
721+ else if ((-(am) > whm))
722+ then throw((((("Attempt to take " + toString(-(am))) + " from warehouse, but only ") + toString(whm)) + " available"))
723+ else $Tuple4((i + 1), (acc._2 :+ toString((whm + am))), (acc._3 :+ toString((bpm - am))), (acc._4 + am))
724+ }
725+
726+ let m = {
727+ let $l = matParts
728+ let $s = size($l)
729+ let $acc0 = $Tuple4(0, nil, nil, r._4)
730+ func $f1_1 ($a,$i) = if (($i >= $s))
731+ then $a
732+ else mvM($a, $l[$i])
733+
734+ func $f1_2 ($a,$i) = if (($i >= $s))
735+ then $a
736+ else throw("List size exceeds 6")
737+
738+ $f1_2($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($acc0, 0), 1), 2), 3), 4), 5), 6)
739+ }
740+ func mvP (acc,item) = {
741+ let i = acc._1
742+ let am = parseIntValue(item)
743+ let whp = parseIntValue(currWhProd[i])
744+ let bpp = parseIntValue(currentPackProd[i])
745+ if ((am == 0))
746+ then $Tuple4((i + 1), (acc._2 :+ currWhProd[i]), (acc._3 :+ currentPackProd[i]), acc._4)
747+ else if ((am > 0))
748+ then if ((am > bpp))
749+ then throw((((("Attempt to take " + item) + " from backpack, but only ") + toString(bpp)) + " available"))
750+ else $Tuple4((i + 1), (acc._2 :+ toString((whp + am))), (acc._3 :+ toString((bpp - am))), (acc._4 + am))
751+ else if ((-(am) > whp))
752+ then throw((((("Attempt to take " + toString(-(am))) + " from warehouse, but only ") + toString(whp)) + " available"))
753+ else $Tuple4((i + 1), (acc._2 :+ toString((whp + am))), (acc._3 :+ toString((bpp - am))), (acc._4 + am))
754+ }
755+
756+ let p = {
757+ let $l = prodParts
758+ let $s = size($l)
759+ let $acc0 = $Tuple4(0, nil, nil, m._4)
760+ func $f2_1 ($a,$i) = if (($i >= $s))
761+ then $a
762+ else mvP($a, $l[$i])
763+
764+ func $f2_2 ($a,$i) = if (($i >= $s))
765+ then $a
766+ else throw("List size exceeds 50")
767+
768+ $f2_2($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40), 41), 42), 43), 44), 45), 46), 47), 48), 49), 50)
769+ }
770+ let volSaldo = p._4
771+ if ((volSaldo > whSpaceLeft))
772+ then throw((((("Attempt to put total " + toString(volSaldo)) + " stuff, but only ") + toString(whSpaceLeft)) + " warehouse space left"))
773+ else $Tuple6(makeString(r._2, "_"), makeString(m._2, "_"), makeString(p._2, "_"), makeString(r._3, "_"), makeString(m._3, "_"), makeString(p._3, "_"))
774+ }
269775 }
270776
271777
272-func landOrderInfoArray (landAssetId,owner) = if ((landAssetId == ""))
273- then throw("landAssetId is required")
778+func expeditionInternal (caller,txId) = {
779+ let userAddr = toString(caller)
780+ let bigNum = abs(toBigInt(txId))
781+ let freeNum = valueOrElse(getInteger(keyNextFreeLandNum()), (PRESALENUMLANDS + 1))
782+ let landNum = toString(freeNum)
783+ let continentIdx = toInt((bigNum % FIVEX))
784+ let terrains = genTerrains(bigNum, continentIdx)
785+ let continent = continents[continentIdx]
786+ let issue = Issue(keyNftName(landNum, "S"), makeString([landNum, "S", terrains, continent], "_"), 1, 0, false)
787+ let assetId = calculateAssetId(issue)
788+ let id = toBase58String(assetId)
789+ $Tuple2([IntegerEntry(keyNextFreeLandNum(), (freeNum + 1)), issue, StringEntry(keyLandToAssetId(landNum), id), StringEntry(keyLandAssetIdToOwner(id), userAddr), StringEntry(keyLandNumToOwner(landNum), userAddr), IntegerEntry(keyInfraLevelByAssetId(id), 0), IntegerEntry(keyInfraLevelByAssetIdAndOwner(id, userAddr), 0), ScriptTransfer(caller, 1, assetId)], $Tuple2(id, continent))
790+ }
791+
792+
793+func expeditionCommon (shouldUseMat,caller,txId,message,sig) = if (!(sigVerify_8Kb(message, sig, pub)))
794+ then throw("signature does not match")
274795 else {
275- let a = value(assetInfo(fromBase58String(landAssetId)))
276- let d = split(a.description, "_")
277- let pieces = numPiecesBySize(d[recLandSize])
278- let productivity = applyBonuses(landAssetId, pieces)
279-[("%s%s__assetId__" + landAssetId), ("%s%s__owner__" + owner), ("%s%s__warehouse__" + makeString(getWarehouse(keyWarehouseByLand(landAssetId), (pieces / SSIZE), productivity._1), ":")), ("%s%s__landOrder__" + valueOrElse(getString(economyContract, keyOrderByLand(landAssetId)), "0@0_0@0_0@0_0@0_0@0_0@0:0@0_0@0_0@0_0@0_0@0_0@0:"))]
796+ let parts = split(toUtf8String(message), ";")
797+ let hp = split(split(parts[0], "|")[0], "_")
798+ let curHP = parseIntValue(hp[0])
799+ let newHP = parseIntValue(hp[1])
800+ let locAndTime = split(parts[1], ":")
801+ let targetLocation = split(locAndTime[0], "_")
802+ if ((targetLocation[1] != "E"))
803+ then throw("expedition target location type should be E")
804+ else {
805+ let time = parseIntValue(locAndTime[1])
806+ if (if ((time > (lastBlock.timestamp + FIVEMINUTESMILLIS)))
807+ then true
808+ else ((lastBlock.timestamp - FIVEMINUTESMILLIS) > time))
809+ then throw("signature outdated")
810+ else {
811+ let userAddr = toString(caller)
812+ let duckAssetId = valueOrErrorMessage(getString(keyStakedDuckByOwner(userAddr)), "You don't have a duck staked")
813+ let keyHealth = keyDuckHealth(duckAssetId)
814+ let oldFromState = valueOrElse(getInteger(keyHealth), 100)
815+ if ((oldFromState != curHP))
816+ then throw(((("oldHealth=" + toString(valueOrElse(getInteger(keyHealth), 100))) + " from state does not match one from flight log=") + toString(curHP)))
817+ else if ((0 >= curHP))
818+ then throw("You can't fly with zero health")
819+ else if ((0 >= newHP))
820+ then $Tuple2(((if (!(shouldUseMat))
821+ then [ScriptTransfer(caller, EXPUSDN, usdnAssetId)]
822+ else nil) :+ IntegerEntry(keyHealth, 0)), "")
823+ else {
824+ let bpKey = keyBackpackByDuck(duckAssetId)
825+ let currentPack = getBackpack(bpKey)
826+ let mList = split(currentPack[bpIdxMat], "_")
827+ let newMat = makeString(subtractMaterials(shouldUseMat, mList, EXPMATERIALS), "_")
828+ let e = expeditionInternal(caller, txId)
829+ let id = e._2._1
830+ $Tuple2((((e._1 :+ StringEntry(keyDuckLocation(duckAssetId), makeString([e._2._2, "L", id], "_"))) :+ IntegerEntry(keyHealth, newHP)) :+ StringEntry(bpKey, makeString([currentPack[bpIdxLevel], currentPack[bpIdxRes], newMat, currentPack[bpIdxProd]], ":"))), id)
831+ }
832+ }
833+ }
280834 }
281835
282836
837+func applyBonuses (landAssetId,pieces) = {
838+ let infraLevel = valueOrElse(getInteger(keyInfraLevelByAssetId(landAssetId)), 0)
839+ let artPieces = valueOrElse(getInteger(keyLandArtStatusByTypeAndAssetId(ARTPRESALE, landAssetId)), if (valueOrElse(getBoolean(keyPresaleArtActivatedByAssetId(landAssetId)), false))
840+ then pieces
841+ else 0)
842+ ((DAILYRESBYPIECE + fraction(DAILYRESBYPIECE, infraLevel, 4)) + fraction(DAILYRESBYPIECE, (artPieces * 3), (pieces * 20)))
843+ }
844+
845+
846+func checkClaimConditions (addr,claimMode,landAssetIdIn) = {
847+ let $t02363024169 = if ((claimMode == claimModeWh))
848+ then $Tuple2(landAssetIdIn, valueOrElse(getString(keyStakedDuckByOwner(addr)), ""))
849+ else {
850+ let duckAssetId = valueOrErrorMessage(getString(keyStakedDuckByOwner(addr)), "You don't have a duck staked")
851+ let curLocation = valueOrElse(getString(keyDuckLocation(duckAssetId)), DEFAULTLOCATION)
852+ let loc = split(value(curLocation), "_")
853+ if ((loc[locIdxType] != "L"))
854+ then throw((("Duck location type is " + loc[locIdxType]) + ", but should be L"))
855+ else $Tuple2(loc[locIdxId], duckAssetId)
856+ }
857+ let landAssetId = $t02363024169._1
858+ let duckId = $t02363024169._2
859+ let asset = value(assetInfo(fromBase58String(landAssetId)))
860+ let timeKey = keyStakedTimeByAssetId(landAssetId)
861+ let savedTime = valueOrErrorMessage(getInteger(timeKey), (("Land " + asset.name) + " is not staked"))
862+ let owner = valueOrErrorMessage(getString(keyLandAssetIdToOwner(landAssetId)), (("NFT " + asset.name) + " is orphaned"))
863+ if ((owner != addr))
864+ then throw((LANDPREFIX + " is not yours"))
865+ else {
866+ let d = split(asset.description, "_")
867+ $Tuple4(duckId, landAssetId, d, savedTime)
868+ }
869+ }
870+
871+
872+func claimResInternal (addr,amount,claimMode,landAssetIdIn) = if ((0 > amount))
873+ then throw("Negative amount")
874+ else {
875+ let c = checkClaimConditions(addr, claimMode, landAssetIdIn)
876+ let landSize = c._3[recLandSize]
877+ let terrainCounts = countTerrains(c._3[recTerrains])
878+ let deltaTime = (lastBlock.timestamp - c._4)
879+ if ((0 > deltaTime))
880+ then throw(((("Saved timestamp is in future, saved = " + toString(c._4)) + ", current = ") + toString(lastBlock.timestamp)))
881+ else {
882+ let pieces = numPiecesBySize(landSize)
883+ let dailyProductionByPiece = applyBonuses(c._2, pieces)
884+ let availRes = fraction(deltaTime, (dailyProductionByPiece * pieces), DAYMILLIS)
885+ if ((amount > availRes))
886+ then throw(((("Not enough resources, available = " + toString(availRes)) + ", requested = ") + toString(amount)))
887+ else {
888+ let newDeltaTime = fraction((availRes - amount), DAYMILLIS, (dailyProductionByPiece * pieces))
889+ let newTimestamp = (lastBlock.timestamp - newDeltaTime)
890+ let landIndex = (pieces / SSIZE)
891+ let resToClaim = virtClaim(terrainCounts, (deltaTime - newDeltaTime), landIndex, dailyProductionByPiece)
892+ let whKey = keyWarehouseByLand(c._2)
893+ let infraLevel = valueOrElse(getInteger(keyInfraLevelByAssetId(c._2)), 0)
894+ let currentWh = getWarehouse(whKey, landIndex, infraLevel)
895+ let currWhResVol = getWarehouseCurrResVolume(currentWh)
896+ let currWhMatVol = getWarehouseCurrMatVolume(currentWh)
897+ let currWhGoodsVol = getWarehouseCurrGoodsVolume(currentWh)
898+ let currWhLockedVol = parseIntValue(currentWh[whIdxLockedVol])
899+ let whSpaceLeft = ((((getWarehouseVolume(currentWh[whIdxVol]) - currWhResVol) - currWhMatVol) - currWhGoodsVol) - currWhLockedVol)
900+ if (if ((claimMode == claimModeWh))
901+ then (amount > whSpaceLeft)
902+ else false)
903+ then throw((("Only " + toString(whSpaceLeft)) + " space left in warehouse"))
904+ else {
905+ let bpKey = keyBackpackByDuck(c._1)
906+ let currentPack = getBackpack(bpKey)
907+ let currentPackRes = split(currentPack[bpIdxRes], "_")
908+ let currentWhRes = split(currentWh[whIdxRes], "_")
909+ let $t02681727320 = if ((claimMode == claimModeWh))
910+ then $Tuple2(addRes(currentWhRes, terrainCounts, (deltaTime - newDeltaTime), landIndex, dailyProductionByPiece), currentPack[bpIdxRes])
911+ else if ((claimMode == claimModeDuck))
912+ then $Tuple2(currentWh[whIdxRes], addRes(currentPackRes, terrainCounts, (deltaTime - newDeltaTime), landIndex, dailyProductionByPiece))
913+ else distributeRes(currentWhRes, currentPackRes, resToClaim, whSpaceLeft)
914+ let whRes = $t02681727320._1
915+ let bpRes = $t02681727320._2
916+ $Tuple5([IntegerEntry(keyStakedTimeByAssetId(c._2), newTimestamp), IntegerEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, c._2, addr), newTimestamp)], bpKey, [currentPack[bpIdxLevel], bpRes, currentPack[bpIdxMat], currentPack[bpIdxProd]], whKey, [currentWh[whIdxVol], whRes, currentWh[whIdxMat], currentWh[whIdxProd], currentWh[whIdxLockedVol]])
917+ }
918+ }
919+ }
920+ }
921+
922+
923+func claimAll (addr,landAssetId,pieces,claimMode) = {
924+ let timeKey = keyStakedTimeByAssetId(landAssetId)
925+ let savedTime = value(getInteger(timeKey))
926+ let availRes = (fraction((lastBlock.timestamp - savedTime), applyBonuses(landAssetId, pieces), DAYMILLIS) * pieces)
927+ claimResInternal(addr, availRes, claimMode, landAssetId)
928+ }
929+
930+
931+func upInfraCommon (shouldUseMat,caller,paymentAmount,landAssetId) = {
932+ let addr = toString(caller)
933+ let c = checkClaimConditions(addr, claimModeWhThenDuck, landAssetId)
934+ let pieces = numPiecesBySize(c._3[recLandSize])
935+ let infraKey = keyInfraLevelByAssetId(c._2)
936+ let curLevel = valueOrElse(getInteger(infraKey), 0)
937+ if ((curLevel >= 3))
938+ then throw("Currently max infrastructure level = 3")
939+ else {
940+ let newLevel = (curLevel + 1)
941+ let cost = fraction(InfraUpgradeCostSUsdn, (pieces * newLevel), SSIZE)
942+ if (if (!(shouldUseMat))
943+ then (paymentAmount != cost)
944+ else false)
945+ then throw(("Payment attached should be " + toString(cost)))
946+ else {
947+ let bpKey = keyBackpackByDuck(c._1)
948+ let currentPack = getBackpack(bpKey)
949+ let mList = split(currentPack[bpIdxMat], "_")
950+ let newMat = makeString(subtractMaterials(shouldUseMat, mList, fraction(InfraUpgradeCostS, (pieces * newLevel), SSIZE)), "_")
951+ let claimResult = claimAll(addr, c._2, pieces, claimModeWhThenDuck)
952+ let whData = claimResult._5
953+ let newVolData = makeString([split(whData[whIdxVol], "_")[0], toString(newLevel)], "_")
954+ $Tuple2(([IntegerEntry(infraKey, newLevel), IntegerEntry(keyInfraLevelByAssetIdAndOwner(c._2, addr), newLevel), StringEntry(bpKey, makeString([currentPack[bpIdxLevel], claimResult._3[bpIdxRes], newMat, currentPack[bpIdxProd]], ":")), StringEntry(claimResult._4, makeString([newVolData, whData[whIdxRes], whData[whIdxMat], whData[whIdxProd], whData[whIdxLockedVol]], ":"))] ++ claimResult._1), newLevel)
955+ }
956+ }
957+ }
958+
959+
960+func activatePresaleArt (addr,landAssetIdIn) = {
961+ let c = checkClaimConditions(addr, claimModeWhThenDuck, landAssetIdIn)
962+ let landAssetId = c._2
963+ let activationKey = keyPresaleArtActivatedByAssetId(landAssetId)
964+ if (valueOrElse(getBoolean(activationKey), false))
965+ then throw("Presale artifact is already activated")
966+ else if ((parseIntValue(c._3[recLandNum]) > PRESALENUMLANDS))
967+ then throw((((LANDPREFIX + " ") + landAssetId) + " is not eligible for presale artifact"))
968+ else {
969+ let pieces = numPiecesBySize(c._3[recLandSize])
970+ let claimResult = claimAll(addr, landAssetId, pieces, claimModeWhThenDuck)
971+ ((((((claimResult._1 :+ BooleanEntry(activationKey, true)) :+ BooleanEntry(keyPresaleArtActivatedByAssetIdAndOwner(landAssetId, addr), true)) :+ IntegerEntry(keyLandArtStatusByTypeAndAssetId(ARTPRESALE, landAssetId), pieces)) :+ IntegerEntry(keyLandArtStatusByTypeAssetIdAndOwner(ARTPRESALE, landAssetId, addr), pieces)) :+ StringEntry(claimResult._2, makeString(claimResult._3, ":"))) :+ StringEntry(claimResult._4, makeString(claimResult._5, ":")))
972+ }
973+ }
974+
975+
976+func mergeInternal (newLandSize,newLevel,formula,addr,landAssetIds,txId,needMat) = {
977+ let duckAssetId = valueOrErrorMessage(getString(keyStakedDuckByOwner(addr)), "You don't have a duck staked")
978+ func checkMerge (acc,landAssetId) = {
979+ let asset = value(assetInfo(fromBase58String(landAssetId)))
980+ let timeKey = keyStakedTimeByAssetId(landAssetId)
981+ let savedTime = valueOrErrorMessage(getInteger(timeKey), (("NFT " + asset.name) + " is not staked"))
982+ let owner = valueOrErrorMessage(getString(keyLandAssetIdToOwner(landAssetId)), (("NFT " + asset.name) + " is orphaned"))
983+ if ((owner != addr))
984+ then throw((LANDPREFIX + " is not yours"))
985+ else {
986+ let d = split(asset.description, "_")
987+ let continent = d[recContinent]
988+ if (if ((acc._3 != ""))
989+ then (acc._3 != continent)
990+ else false)
991+ then throw("Lands should be on the same continent to merge")
992+ else {
993+ let landSize = d[recLandSize]
994+ let sizesIn = acc._1
995+ let i = valueOrErrorMessage(indexOf(sizesIn, landSize), "You haven't passed all the lands needed")
996+ let sizesOut = (take(sizesIn, i) + drop(sizesIn, (i + 1)))
997+ let pieces = numPiecesBySize(landSize)
998+ let arts = (acc._2 + valueOrElse(getInteger(keyLandArtStatusByTypeAndAssetId(ARTPRESALE, landAssetId)), if (valueOrElse(getBoolean(keyPresaleArtActivatedByAssetId(landAssetId)), false))
999+ then pieces
1000+ else 0))
1001+ let infraLevel = valueOrElse(getInteger(keyInfraLevelByAssetId(landAssetId)), 0)
1002+ let reqLevel = match landSize {
1003+ case _ =>
1004+ if (("S" == $match0))
1005+ then 3
1006+ else if (("M" == $match0))
1007+ then 4
1008+ else if (("L" == $match0))
1009+ then 5
1010+ else if (("XL" == $match0))
1011+ then 6
1012+ else throw("Only S, M, L, XL can merge")
1013+ }
1014+ if ((infraLevel != reqLevel))
1015+ then throw("All lands should be maxed to merge")
1016+ else {
1017+ let landNum = d[recLandNum]
1018+ let terrainCounts = countTerrains(d[recTerrains])
1019+ let deltaTime = (lastBlock.timestamp - savedTime)
1020+ if ((0 > deltaTime))
1021+ then throw(((("Saved timestamp is in future, saved = " + toString(savedTime)) + ", current = ") + toString(lastBlock.timestamp)))
1022+ else {
1023+ let dailyProductionByPiece = applyBonuses(landAssetId, pieces)
1024+ let landIndex = (pieces / SSIZE)
1025+ let bpRes = addRes(split(acc._4, "_"), terrainCounts, deltaTime, landIndex, dailyProductionByPiece)
1026+ let props = updateProportionsInternal(split(acc._6, "_"), terrainCounts, landIndex, -1)
1027+ let lands = acc._7
1028+ let idx = indexOf(lands, landAssetId)
1029+ if (!(isDefined(idx)))
1030+ then throw(("Your staked lands don't contain " + landAssetId))
1031+ else $Tuple7(sizesOut, arts, continent, bpRes, ((((((((((((((acc._5 :+ DeleteEntry(keyStakedTimeByAssetId(landAssetId))) :+ DeleteEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, landAssetId, addr))) :+ DeleteEntry(keyLandToAssetId(landNum))) :+ DeleteEntry(keyNftName(landNum, landSize))) :+ DeleteEntry(keyLandAssetIdToOwner(landAssetId))) :+ DeleteEntry(keyInfraLevelByAssetId(landAssetId))) :+ DeleteEntry(keyInfraLevelByAssetIdAndOwner(landAssetId, addr))) :+ DeleteEntry(keyPresaleArtActivatedByAssetId(landAssetId))) :+ DeleteEntry(keyPresaleArtActivatedByAssetIdAndOwner(landAssetId, addr))) :+ DeleteEntry(keyLandArtStatusByTypeAndAssetId(ARTPRESALE, landAssetId))) :+ DeleteEntry(keyLandArtStatusByTypeAssetIdAndOwner(ARTPRESALE, landAssetId, addr))) :+ DeleteEntry(keyLandNumToOwner(landNum))) :+ DeleteEntry(keyWarehouseByLand(landAssetId))) :+ Burn(fromBase58String(landAssetId), 1)), props, removeByIndex(lands, value(idx)))
1032+ }
1033+ }
1034+ }
1035+ }
1036+ }
1037+
1038+ let bpKey = keyBackpackByDuck(duckAssetId)
1039+ let currentPack = getBackpack(bpKey)
1040+ let propStr = valueOrElse(getString(keyResProportions()), "0_0_0_0_0_0")
1041+ let landsKey = keyStakedLandsByOwner(addr)
1042+ let landsStr = getString(landsKey)
1043+ let landsIn = if (isDefined(landsStr))
1044+ then split_51C(value(landsStr), "_")
1045+ else nil
1046+ let r = {
1047+ let $l = landAssetIds
1048+ let $s = size($l)
1049+ let $acc0 = $Tuple7(formula, 0, "", currentPack[bpIdxRes], nil, propStr, landsIn)
1050+ func $f0_1 ($a,$i) = if (($i >= $s))
1051+ then $a
1052+ else checkMerge($a, $l[$i])
1053+
1054+ func $f0_2 ($a,$i) = if (($i >= $s))
1055+ then $a
1056+ else throw("List size exceeds 5")
1057+
1058+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5)
1059+ }
1060+ let continent = r._3
1061+ let continentIdx = valueOrErrorMessage(indexOf(continents, continent), ("Unknown continent: " + continent))
1062+ let terrains = genTerrains(abs(toBigInt(txId)), continentIdx)
1063+ let freeNum = valueOrElse(getInteger(keyNextFreeLandNum()), (PRESALENUMLANDS + 1))
1064+ let newLandNum = toString(freeNum)
1065+ let issue = Issue(keyNftName(newLandNum, newLandSize), makeString([newLandNum, newLandSize, terrains, continent], "_"), 1, 0, false)
1066+ let assetId = calculateAssetId(issue)
1067+ let newLandAssetId = toBase58String(assetId)
1068+ let newMat = makeString(subtractMaterials((needMat > 0), split(currentPack[bpIdxMat], "_"), needMat), "_")
1069+ $Tuple2(((((((((((((((r._5 :+ (if ((size(r._7) > 0))
1070+ then StringEntry(landsKey, makeString_11C(r._7, "_"))
1071+ else DeleteEntry(landsKey))) :+ IntegerEntry(keyNextFreeLandNum(), (freeNum + 1))) :+ issue) :+ StringEntry(keyLandToAssetId(newLandNum), newLandAssetId)) :+ StringEntry(keyLandAssetIdToOwner(newLandAssetId), addr)) :+ StringEntry(keyLandNumToOwner(newLandNum), addr)) :+ IntegerEntry(keyLandArtStatusByTypeAndAssetId(ARTPRESALE, newLandAssetId), r._2)) :+ IntegerEntry(keyLandArtStatusByTypeAssetIdAndOwner(ARTPRESALE, newLandAssetId, addr), r._2)) :+ IntegerEntry(keyInfraLevelByAssetId(newLandAssetId), newLevel)) :+ IntegerEntry(keyInfraLevelByAssetIdAndOwner(newLandAssetId, addr), newLevel)) :+ StringEntry(bpKey, makeString([currentPack[bpIdxLevel], r._4, newMat, currentPack[bpIdxProd]], ":"))) :+ StringEntry(keyResProportions(), r._6)) :+ StringEntry(keyDuckLocation(duckAssetId), makeString([continent, "L", newLandAssetId], "_"))) :+ ScriptTransfer(addressFromStringValue(addr), 1, assetId)), newLandAssetId)
1072+ }
1073+
1074+
1075+func s2m (addr,landAssetIds,txId) = mergeInternal("M", 3, "SSSS", addr, landAssetIds, txId, 0)
1076+
1077+
1078+func m2l (addr,landAssetIds,txId,shouldUseMat,paymentAmount) = {
1079+ let cost = (InfraUpgradeCostSUsdn * 4)
1080+ if (if (!(shouldUseMat))
1081+ then (paymentAmount != cost)
1082+ else false)
1083+ then throw(("Payment attached should be " + toString(cost)))
1084+ else mergeInternal("L", 4, "SMM", addr, landAssetIds, txId, (InfraUpgradeCostS * 4))
1085+ }
1086+
1087+
1088+func l2xl (addr,landAssetIds,txId,shouldUseMat,paymentAmount) = {
1089+ let cost = (InfraUpgradeCostSUsdn * 47)
1090+ if (if (!(shouldUseMat))
1091+ then (paymentAmount != cost)
1092+ else false)
1093+ then throw(("Payment attached should be " + toString(cost)))
1094+ else mergeInternal("XL", 5, "SSSML", addr, landAssetIds, txId, (InfraUpgradeCostS * 47))
1095+ }
1096+
1097+
1098+func xl2xxl (addr,landAssetIds,txId,shouldUseMat,paymentAmount) = {
1099+ let cost = (InfraUpgradeCostSUsdn * 54)
1100+ if (if (!(shouldUseMat))
1101+ then (paymentAmount != cost)
1102+ else false)
1103+ then throw(("Payment attached should be " + toString(cost)))
1104+ else mergeInternal("XXL", 6, "LXL", addr, landAssetIds, txId, (InfraUpgradeCostS * 54))
1105+ }
1106+
1107+
1108+func mergeCommon (shouldUseMat,addr,paymentAmount,landAssetIds,txId) = {
1109+ let mergeResult = match size(landAssetIds) {
1110+ case _ =>
1111+ if ((4 == $match0))
1112+ then s2m(addr, landAssetIds, txId)
1113+ else if ((3 == $match0))
1114+ then m2l(addr, landAssetIds, txId, shouldUseMat, paymentAmount)
1115+ else if ((5 == $match0))
1116+ then l2xl(addr, landAssetIds, txId, shouldUseMat, paymentAmount)
1117+ else if ((2 == $match0))
1118+ then xl2xxl(addr, landAssetIds, txId, shouldUseMat, paymentAmount)
1119+ else throw("Unknown merge")
1120+ }
1121+ mergeResult
1122+ }
1123+
1124+
1125+func prolog (i) = if (if ((i.originCaller != restContract))
1126+ then valueOrElse(getBoolean(keyBlocked()), false)
1127+ else false)
1128+ then throw("Contracts are under maintenance")
1129+ else StringEntry(keyLastTxIdByUser(toString(i.originCaller)), toBase58String(i.transactionId))
1130+
1131+
2831132 @Callable(i)
284-func constructorV1 (stakingContract,economyContract,governanceContract) = if ((i.caller != this))
285- then throw("permissions denied")
286- else [StringEntry(keyRestCfg(), makeString(["%s%s%s", stakingContract, economyContract, governanceContract], SEP))]
1133+func constructorV1 (restAddr) = if ((i.caller != this))
1134+ then throw("Permission denied")
1135+ else [StringEntry(keyRestAddress(), restAddr)]
2871136
2881137
2891138
2901139 @Callable(i)
291-func walletInfoREADONLY (userAddressOpt) = $Tuple2(nil, walletInternal(userAddressOpt))
1140+func setBlocked (isBlocked) = if ((i.caller != this))
1141+ then throw("permission denied")
1142+ else [BooleanEntry(keyBlocked(), isBlocked)]
2921143
2931144
2941145
2951146 @Callable(i)
296-func duckInfoREADONLY (duckAssetId,userAddressOpt) = {
297- let addr = addressFromString(userAddressOpt)
298- let duckAsset = fromBase58String(duckAssetId)
299- if ((duckAssetId == ""))
300- then throw("duckAssetId is required")
1147+func stakeLand () = {
1148+ let prologAction = prolog(i)
1149+ if ((size(i.payments) != 1))
1150+ then throw("Exactly one payment required")
3011151 else {
302- let duckOwner = getString(stakingContract, keyDuckIdToOwner(duckAssetId))
303- let owner = if (isDefined(duckOwner))
304- then value(duckOwner)
305- else if (if (isDefined(addr))
306- then (assetBalance(value(addr), duckAsset) == 1)
307- else false)
308- then userAddressOpt
309- else ""
310- $Tuple2(nil, $Tuple2(duckInfoArray(duckAssetId, owner, duckInfoTuple(duckAssetId)), walletInternal(userAddressOpt)))
1152+ let pmt = value(i.payments[0])
1153+ let assetId = value(pmt.assetId)
1154+ let address = toString(i.caller)
1155+ if ((pmt.amount != 1))
1156+ then throw((("NFT " + LANDPREFIX) + " token should be attached as payment"))
1157+ else {
1158+ let asset = value(assetInfo(assetId))
1159+ if ((asset.issuer != this))
1160+ then throw("Unknown issuer of token")
1161+ else if (!(contains(asset.name, LANDPREFIX)))
1162+ then throw((("Only NFT " + LANDPREFIX) + " tokens are accepted"))
1163+ else {
1164+ let landNumSize = drop(asset.name, 4)
1165+ let landNum = if (contains(landNumSize, "XXL"))
1166+ then dropRight(landNumSize, 3)
1167+ else if (contains(landNumSize, "XL"))
1168+ then dropRight(landNumSize, 2)
1169+ else dropRight(landNumSize, 1)
1170+ if (!(isDefined(parseInt(landNum))))
1171+ then throw(("Cannot parse land number from " + asset.name))
1172+ else {
1173+ let landAssetId = toBase58String(assetId)
1174+ let timeKey = keyStakedTimeByAssetId(landAssetId)
1175+ if (isDefined(getInteger(timeKey)))
1176+ then throw((("NFT " + asset.name) + " is already staked"))
1177+ else {
1178+ let d = split(asset.description, "_")
1179+ let terrainCounts = countTerrains(d[recTerrains])
1180+ let props = updateProportions(terrainCounts, (numPiecesBySize(d[recLandSize]) / SSIZE), 1)
1181+ let landsStr = getString(keyStakedLandsByOwner(address))
1182+ let lands = if (isDefined(landsStr))
1183+ then split_51C(value(landsStr), "_")
1184+ else nil
1185+ if (containsElement(lands, landAssetId))
1186+ then throw(("Your staked lands already contain " + landAssetId))
1187+ else [IntegerEntry(timeKey, lastBlock.timestamp), IntegerEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, landAssetId, address), lastBlock.timestamp), StringEntry(keyStakedLandsByOwner(address), makeString_11C((lands :+ landAssetId), "_")), StringEntry(keyLandAssetIdToOwner(landAssetId), address), StringEntry(keyLandNumToOwner(landNum), address), StringEntry(keyResProportions(), props), prologAction]
1188+ }
1189+ }
1190+ }
1191+ }
3111192 }
3121193 }
3131194
3141195
3151196
3161197 @Callable(i)
317-func landInfoREADONLY (landAssetId,userAddressOpt) = {
318- let addr = addressFromString(userAddressOpt)
319- let landAsset = fromBase58String(landAssetId)
320- if ((landAssetId == ""))
321- then throw("landAssetId is required")
1198+func unstakeLand (landAssetIdIn) = {
1199+ let prologAction = prolog(i)
1200+ if ((size(i.payments) != 0))
1201+ then throw("unstake doesn't require any payments")
3221202 else {
323- let stakedTime = valueOrElse(getInteger(stakingContract, keyStakedTimeByAssetId(landAssetId)), 0)
324- let owner = if ((stakedTime > 0))
325- then value(getString(stakingContract, keyLandAssetIdToOwner(landAssetId)))
326- else if (if (isDefined(addr))
327- then (assetBalance(value(addr), landAsset) == 1)
328- else false)
329- then userAddressOpt
330- else ""
331- let stakedDuck = getString(stakingContract, keyStakedDuckByOwner(userAddressOpt))
332- let duckInf = if (if (isDefined(addr))
333- then isDefined(stakedDuck)
334- else false)
335- then {
336- let duckAssetId = value(stakedDuck)
337- $Tuple2(duckAssetId, duckInfoTuple(duckAssetId))
1203+ let addr = toString(i.caller)
1204+ let c = checkClaimConditions(addr, claimModeDuck, landAssetIdIn)
1205+ let landAssetId = c._2
1206+ let landsKey = keyStakedLandsByOwner(addr)
1207+ let terrainCounts = countTerrains(c._3[recTerrains])
1208+ let pieces = numPiecesBySize(c._3[recLandSize])
1209+ let props = updateProportions(terrainCounts, (pieces / SSIZE), -1)
1210+ let claimResult = claimAll(addr, landAssetId, pieces, claimModeDuck)
1211+ let lands = split_51C(valueOrElse(getString(landsKey), ""), "_")
1212+ let idx = indexOf(lands, landAssetId)
1213+ if (!(isDefined(idx)))
1214+ then throw(("Your staked lands don't contain " + landAssetId))
1215+ else {
1216+ let t = value(blockInfoByHeight(height)).timestamp
1217+ let releaseTime = valueOrElse(getInteger(govContract, keyUserGwlReleaseTime(addr)), 0)
1218+ if ((releaseTime >= t))
1219+ then throw(("Your gWL are taking part in voting, cannot unstake until " + toString(releaseTime)))
1220+ else [ScriptTransfer(i.caller, 1, fromBase58String(landAssetId)), DeleteEntry(keyStakedTimeByAssetId(landAssetId)), DeleteEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, landAssetId, addr)), StringEntry(keyResProportions(), props), StringEntry(claimResult._2, makeString(claimResult._3, ":")), if ((size(lands) > 1))
1221+ then StringEntry(landsKey, makeString_11C(removeByIndex(lands, value(idx)), "_"))
1222+ else DeleteEntry(landsKey), prologAction]
3381223 }
339- else $Tuple2("", $Tuple5(-1, "", "", -1, ""))
340- $Tuple2(nil, $Tuple3(landInfoArray(landAssetId, owner, stakedTime), duckInfoArray(duckInf._1, userAddressOpt, duckInf._2), walletInternal(userAddressOpt)))
3411224 }
3421225 }
3431226
3441227
3451228
3461229 @Callable(i)
347-func stakedLandsInfoREADONLY (myAddress,landOwnerAddress) = if ((landOwnerAddress == ""))
348- then throw("landOwnerAddress is required")
349- else {
350- let myAddr = addressFromString(myAddress)
351- let landsStr = getString(stakingContract, keyStakedLandsByOwner(landOwnerAddress))
352- let lands = if (isDefined(landsStr))
353- then split_51C(value(landsStr), "_")
354- else nil
355- func oneLand (acc,landAssetId) = {
356- let landAsset = fromBase58String(landAssetId)
357- if ((landAssetId == ""))
358- then throw("landAssetId is required")
1230+func stakeDuck () = {
1231+ let prologAction = prolog(i)
1232+ if ((size(i.payments) != 1))
1233+ then throw("Exactly one payment required")
1234+ else {
1235+ let pmt = value(i.payments[0])
1236+ let assetId = value(pmt.assetId)
1237+ let address = toString(i.caller)
1238+ if ((pmt.amount != 1))
1239+ then throw((("NFT " + DUCKPREFIX) + " token should be attached as payment"))
3591240 else {
360- let stakedTime = valueOrElse(getInteger(stakingContract, keyStakedTimeByAssetId(landAssetId)), 0)
361- let descr = value(assetInfo(landAsset)).description
362- let d = split(descr, "_")
363- let pieces = numPiecesBySize(d[recLandSize])
364- let productivity = applyBonuses(landAssetId, pieces)
365- let deltaTime = (lastBlock.timestamp - stakedTime)
366- let availRes = fraction(deltaTime, (productivity._3 * pieces), DAYMILLIS)
367- (acc :+ [("%s%s__landAssetId__" + landAssetId), ("%s%d__stakedTime__" + toString(stakedTime)), ("%s%s__description__" + descr), ("%s%d__infraLevel__" + toString(productivity._1)), makeString(["%s%s", "landArtefacts", ("PRESALE:" + toString(productivity._2))], SEP), ("%s%s__availRes__" + toString(availRes))])
1241+ let asset = value(assetInfo(assetId))
1242+ if (if ((asset.issuer != incubatorAddr))
1243+ then (asset.issuer != breederAddr)
1244+ else false)
1245+ then throw((("Unknown issuer of " + DUCKPREFIX) + " token"))
1246+ else if (!(contains(asset.name, DUCKPREFIX)))
1247+ then throw((("Only NFT " + DUCKPREFIX) + " tokens are accepted"))
1248+ else {
1249+ let assetIdStr = toBase58String(assetId)
1250+ let timeKey = keyStakedTimeByAssetId(assetIdStr)
1251+ if (isDefined(getInteger(timeKey)))
1252+ then throw((("NFT " + asset.name) + " is already staked"))
1253+ else if (isDefined(getString(keyStakedDuckByOwner(address))))
1254+ then throw(("You already staked one duck: " + asset.name))
1255+ else {
1256+ let locKey = keyDuckLocation(assetIdStr)
1257+ let location = getString(locKey)
1258+ let bpKey = keyBackpackByDuck(assetIdStr)
1259+ let backpack = getString(bpKey)
1260+ ([IntegerEntry(timeKey, lastBlock.timestamp), IntegerEntry(keyStakedTimeByTypeAssetIdAndOwner(DUCKPREFIX, toBase58String(assetId), address), lastBlock.timestamp), StringEntry(keyDuckIdToOwner(assetIdStr), address), StringEntry(keyStakedDuckByOwner(address), assetIdStr)] ++ (if (isDefined(location))
1261+ then nil
1262+ else ([StringEntry(locKey, DEFAULTLOCATION)] ++ (if (isDefined(backpack))
1263+ then nil
1264+ else (([StringEntry(bpKey, "0:0_0_0_0_0_0:0_0_0_0_0_0:")] :+ IntegerEntry(keyDuckHealth(assetIdStr), 100)) :+ prologAction)))))
1265+ }
1266+ }
3681267 }
3691268 }
1269+ }
3701270
371- let r = {
372- let $l = lands
373- let $s = size($l)
374- let $acc0 = nil
375- func $f0_1 ($a,$i) = if (($i >= $s))
376- then $a
377- else oneLand($a, $l[$i])
3781271
379- func $f0_2 ($a,$i) = if (($i >= $s))
380- then $a
381- else throw("List size exceeds 100")
3821272
383- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40), 41), 42), 43), 44), 45), 46), 47), 48), 49), 50), 51), 52), 53), 54), 55), 56), 57), 58), 59), 60), 61), 62), 63), 64), 65), 66), 67), 68), 69), 70), 71), 72), 73), 74), 75), 76), 77), 78), 79), 80), 81), 82), 83), 84), 85), 86), 87), 88), 89), 90), 91), 92), 93), 94), 95), 96), 97), 98), 99), 100)
1273+@Callable(i)
1274+func unstakeDuck (assetIdStr) = {
1275+ let prologAction = prolog(i)
1276+ if ((size(i.payments) != 0))
1277+ then throw("unstake doesn't require any payments")
1278+ else {
1279+ let assetId = fromBase58String(assetIdStr)
1280+ let address = toString(i.caller)
1281+ let asset = value(assetInfo(assetId))
1282+ let timeKey = keyStakedTimeByAssetId(toBase58String(assetId))
1283+ if (!(isDefined(getInteger(timeKey))))
1284+ then throw((("NFT " + asset.name) + " is not staked"))
1285+ else if (!(isDefined(getString(keyStakedDuckByOwner(address)))))
1286+ then throw((("The duck " + asset.name) + " is not staked"))
1287+ else {
1288+ let owner = valueOrErrorMessage(getString(keyDuckIdToOwner(toBase58String(assetId))), (("NFT " + asset.name) + " is orphaned"))
1289+ if ((owner != address))
1290+ then throw("Staked NFT is not yours")
1291+ else {
1292+ let keyHealth = keyDuckHealth(assetIdStr)
1293+ let health = valueOrElse(getInteger(keyHealth), 100)
1294+ if ((health != 100))
1295+ then throw("Please heal your duck before unstaking")
1296+ else [ScriptTransfer(i.caller, 1, assetId), DeleteEntry(timeKey), DeleteEntry(keyHealth), DeleteEntry(keyDuckLocation(assetIdStr)), DeleteEntry(keyDuckIdToOwner(assetIdStr)), DeleteEntry(keyStakedTimeByTypeAssetIdAndOwner(DUCKPREFIX, assetIdStr, address)), DeleteEntry(keyStakedDuckByOwner(address)), prologAction]
1297+ }
1298+ }
3841299 }
385- let stakedDuck = getString(stakingContract, keyStakedDuckByOwner(myAddress))
386- let duckInf = if (if (isDefined(myAddr))
387- then isDefined(stakedDuck)
388- else false)
389- then {
390- let duckAssetId = value(stakedDuck)
391- $Tuple2(duckAssetId, duckInfoTuple(duckAssetId))
1300+ }
1301+
1302+
1303+
1304+@Callable(i)
1305+func claimRes (amount,landAssetIdStr) = {
1306+ let prologAction = prolog(i)
1307+ if ((size(i.payments) != 0))
1308+ then throw("claimRes doesn't require any payments")
1309+ else {
1310+ let addr = toString(i.originCaller)
1311+ let result = claimResInternal(addr, amount, claimModeDuck, landAssetIdStr)
1312+ $Tuple2((((result._1 :+ StringEntry(result._2, makeString(result._3, ":"))) :+ StringEntry(result._4, makeString(result._5, ":"))) :+ prologAction), result._3[bpIdxRes])
1313+ }
1314+ }
1315+
1316+
1317+
1318+@Callable(i)
1319+func claimResToWH (amount,landAssetIdStr) = {
1320+ let prologAction = prolog(i)
1321+ if ((size(i.payments) != 0))
1322+ then throw("claimRes doesn't require any payments")
1323+ else {
1324+ let addr = toString(i.originCaller)
1325+ let result = claimResInternal(addr, amount, claimModeWh, landAssetIdStr)
1326+ $Tuple2((((result._1 :+ StringEntry(result._2, makeString(result._3, ":"))) :+ StringEntry(result._4, makeString(result._5, ":"))) :+ prologAction), result._5[whIdxRes])
1327+ }
1328+ }
1329+
1330+
1331+
1332+@Callable(i)
1333+func flight (message,sig) = {
1334+ let prologAction = prolog(i)
1335+ if (!(sigVerify_8Kb(message, sig, pub)))
1336+ then throw("signature does not match")
1337+ else if ((size(i.payments) != 0))
1338+ then throw("flight doesn't require any payments")
1339+ else {
1340+ let parts = split(toUtf8String(message), ";")
1341+ let hp = split(split(parts[0], "|")[0], "_")
1342+ let curHP = parseIntValue(hp[0])
1343+ let newHP = parseIntValue(hp[1])
1344+ let newLocAndTime = split(parts[1], ":")
1345+ let newLocation = newLocAndTime[0]
1346+ let time = parseIntValue(newLocAndTime[1])
1347+ if (if ((time > (lastBlock.timestamp + FIVEMINUTESMILLIS)))
1348+ then true
1349+ else ((lastBlock.timestamp - FIVEMINUTESMILLIS) > time))
1350+ then throw("signature outdated")
1351+ else {
1352+ let duckAssetId = valueOrErrorMessage(getString(keyStakedDuckByOwner(toString(i.caller))), "You don't have a duck staked")
1353+ let keyHealth = keyDuckHealth(duckAssetId)
1354+ let oldFromState = valueOrElse(getInteger(keyHealth), 100)
1355+ if ((oldFromState != curHP))
1356+ then throw(((("oldHealth=" + toString(valueOrElse(getInteger(keyHealth), 100))) + " from state does not match one from flight log=") + toString(curHP)))
1357+ else if ((0 >= curHP))
1358+ then throw("You can't fly with zero health")
1359+ else {
1360+ let locKey = keyDuckLocation(duckAssetId)
1361+ let curLocation = valueOrElse(getString(locKey), DEFAULTLOCATION)
1362+ if ((newLocation == curLocation))
1363+ then throw("You can't fly to the same location")
1364+ else $Tuple2([StringEntry(locKey, if ((newHP > 0))
1365+ then newLocation
1366+ else curLocation), IntegerEntry(keyHealth, newHP), prologAction], unit)
1367+ }
1368+ }
3921369 }
393- else $Tuple2("", $Tuple5(-1, "", "", -1, ""))
394- $Tuple2(nil, $Tuple3(r, duckInfoArray(duckInf._1, myAddress, duckInf._2), walletInternal(myAddress)))
1370+ }
1371+
1372+
1373+
1374+@Callable(i)
1375+func setHealth (health,duckAssetId) = {
1376+ let prologAction = prolog(i)
1377+ if (if ((0 > health))
1378+ then true
1379+ else (health > 100))
1380+ then throw("HP should be within 0..100")
1381+ else [IntegerEntry(keyDuckHealth(duckAssetId), health), prologAction]
1382+ }
1383+
1384+
1385+
1386+@Callable(i)
1387+func heal (matType,amount) = {
1388+ let prologAction = prolog(i)
1389+ if (if ((0 > matType))
1390+ then true
1391+ else (matType >= NUMRES))
1392+ then throw(("Unknown material: " + toString(matType)))
1393+ else if ((0 >= amount))
1394+ then throw(("Amount should be positive! " + toString(amount)))
1395+ else {
1396+ let duckAssetId = valueOrErrorMessage(getString(keyStakedDuckByOwner(toString(i.caller))), "You don't have a duck staked")
1397+ let keyHealth = keyDuckHealth(duckAssetId)
1398+ let oldHealth = valueOrElse(getInteger(keyHealth), 100)
1399+ if ((oldHealth >= 100))
1400+ then throw("HP should be < 100 to heal")
1401+ else {
1402+ let bpKey = keyBackpackByDuck(duckAssetId)
1403+ let currentPack = getBackpack(bpKey)
1404+ let mList = split(currentPack[bpIdxMat], "_")
1405+ let currentAmount = parseIntValue(mList[matType])
1406+ let deltaHealth = min([(amount / HEALCOST), (100 - oldHealth)])
1407+ let spendAmount = (deltaHealth * HEALCOST)
1408+ if ((spendAmount > currentAmount))
1409+ then throw(((((("You need " + toString(spendAmount)) + " of ") + matTypes[matType]) + " to heal, but you backpack contains ") + toString(currentAmount)))
1410+ else {
1411+ let newMat = subOneInList(mList, matType, spendAmount)
1412+[IntegerEntry(keyHealth, (oldHealth + deltaHealth)), StringEntry(bpKey, makeString([currentPack[bpIdxLevel], currentPack[bpIdxRes], newMat, currentPack[bpIdxProd]], ":")), prologAction]
1413+ }
1414+ }
1415+ }
1416+ }
1417+
1418+
1419+
1420+@Callable(i)
1421+func updateBackpack (duckAssetId,newPack) = {
1422+ let prologAction = prolog(i)
1423+ if ((i.caller != economyContract))
1424+ then throw("permission denied")
1425+ else $Tuple2([StringEntry(keyBackpackByDuck(duckAssetId), newPack), prologAction], newPack)
1426+ }
1427+
1428+
1429+
1430+@Callable(i)
1431+func buySLand () = if ((i.caller != this))
1432+ then throw("Permission denied")
1433+ else {
1434+ let prologAction = prolog(i)
1435+ if ((size(i.payments) != 1))
1436+ then throw("Exactly one payment required")
1437+ else {
1438+ let pmt = value(i.payments[0])
1439+ if ((pmt.assetId != usdnAssetId))
1440+ then throw("Allowed USDN payment only!")
1441+ else if ((pmt.amount != EXPUSDN))
1442+ then throw(("Payment attached should be " + toString(EXPUSDN)))
1443+ else {
1444+ let result = expeditionInternal(i.caller, i.transactionId)
1445+ $Tuple2(((result._1 :+ ScriptTransfer(economyContract, pmt.amount, usdnAssetId)) :+ prologAction), result._2._1)
1446+ }
1447+ }
3951448 }
3961449
3971450
3981451
3991452 @Callable(i)
400-func duckByOwnerInfoREADONLY (userAddress) = {
401- let stakedDuck = getString(stakingContract, keyStakedDuckByOwner(userAddress))
402- $Tuple2(nil, if (if (isDefined(addressFromString(userAddress)))
403- then isDefined(stakedDuck)
404- else false)
405- then {
406- let duckAssetId = value(stakedDuck)
407- duckInfoArray(duckAssetId, userAddress, duckInfoTuple(duckAssetId))
1453+func expedition (message,sig) = {
1454+ let prologAction = prolog(i)
1455+ if ((size(i.payments) != 0))
1456+ then throw("expedition doesn't require any payments")
1457+ else {
1458+ let result = expeditionCommon(true, i.caller, i.transactionId, message, sig)
1459+ $Tuple2((result._1 :+ prologAction), result._2)
4081460 }
409- else duckInfoArray("", userAddress, $Tuple5(-1, "", "", -1, "")))
4101461 }
4111462
4121463
4131464
4141465 @Callable(i)
415-func duckByAssetIdInfoREADONLY (duckAssetId) = {
416- let owner = getString(stakingContract, keyDuckIdToOwner(duckAssetId))
417- let duckInf = duckInfoTuple(duckAssetId)
418- $Tuple2(nil, duckInfoArray(duckAssetId, if (isDefined(owner))
419- then value(owner)
420- else "", duckInfoTuple(duckAssetId)))
1466+func upgradeInfra (landAssetId) = {
1467+ let prologAction = prolog(i)
1468+ if ((size(i.payments) != 0))
1469+ then throw("Infrastructure upgrade doesn't require any payments")
1470+ else {
1471+ let result = upInfraCommon(true, i.caller, 0, landAssetId)
1472+ $Tuple2((result._1 :+ prologAction), result._2)
1473+ }
4211474 }
4221475
4231476
4241477
4251478 @Callable(i)
426-func landByAssetIdInfoREADONLY (landAssetId) = if ((landAssetId == ""))
427- then throw("landAssetId is required")
1479+func upgradeInfraUsdn (landAssetId) = if ((i.caller != this))
1480+ then throw("Permission denied")
4281481 else {
429- let stakedTime = valueOrElse(getInteger(stakingContract, keyStakedTimeByAssetId(landAssetId)), -1)
430- let owner = if ((stakedTime > 0))
431- then value(getString(stakingContract, keyLandAssetIdToOwner(landAssetId)))
432- else ""
433- $Tuple2(nil, landInfoArray(landAssetId, owner, stakedTime))
1482+ let prologAction = prolog(i)
1483+ if ((size(i.payments) != 1))
1484+ then throw("Exactly one payment required")
1485+ else {
1486+ let pmt = value(i.payments[0])
1487+ if ((pmt.assetId != usdnAssetId))
1488+ then throw("Allowed USDN payment only!")
1489+ else {
1490+ let result = upInfraCommon(false, i.caller, pmt.amount, landAssetId)
1491+ $Tuple2(((result._1 :+ ScriptTransfer(economyContract, pmt.amount, usdnAssetId)) :+ prologAction), result._2)
1492+ }
1493+ }
4341494 }
4351495
4361496
4371497
4381498 @Callable(i)
439-func stakedLandsByOwnerInfoREADONLY (landOwnerAddress) = if ((landOwnerAddress == ""))
440- then throw("landOwnerAddress is required")
441- else {
442- let landsStr = getString(stakingContract, keyStakedLandsByOwner(landOwnerAddress))
443- let lands = if (isDefined(landsStr))
444- then split_51C(value(landsStr), "_")
445- else nil
446- func oneLand (acc,landAssetId) = if ((landAssetId == ""))
447- then throw("landAssetId is required")
448- else {
449- let stakedTime = valueOrElse(getInteger(stakingContract, keyStakedTimeByAssetId(landAssetId)), -1)
450- (acc :+ landInfoArray(landAssetId, landOwnerAddress, stakedTime))
451- }
452-
453- let r = {
454- let $l = lands
455- let $s = size($l)
456- let $acc0 = nil
457- func $f0_1 ($a,$i) = if (($i >= $s))
458- then $a
459- else oneLand($a, $l[$i])
460-
461- func $f0_2 ($a,$i) = if (($i >= $s))
462- then $a
463- else throw("List size exceeds 100")
464-
465- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40), 41), 42), 43), 44), 45), 46), 47), 48), 49), 50), 51), 52), 53), 54), 55), 56), 57), 58), 59), 60), 61), 62), 63), 64), 65), 66), 67), 68), 69), 70), 71), 72), 73), 74), 75), 76), 77), 78), 79), 80), 81), 82), 83), 84), 85), 86), 87), 88), 89), 90), 91), 92), 93), 94), 95), 96), 97), 98), 99), 100)
1499+func activateArtifact (artName,landAssetId) = {
1500+ let prologAction = prolog(i)
1501+ if ((size(i.payments) != 0))
1502+ then throw("Artifact activation doesn't require any payments")
1503+ else {
1504+ let result = match artName {
1505+ case _ =>
1506+ if (("PRESALE" == $match0))
1507+ then activatePresaleArt(toString(i.caller), landAssetId)
1508+ else throw("Unknown artifact")
4661509 }
467- $Tuple2(nil, r)
468- }
469-
470-
471-
472-@Callable(i)
473-func landsByIdsInfoREADONLY (landAssetIds) = {
474- func oneLand (acc,landAssetId) = if ((landAssetId == ""))
475- then throw("landAssetId is required")
476- else {
477- let stakedTime = valueOrElse(getInteger(stakingContract, keyStakedTimeByAssetId(landAssetId)), -1)
478- let owner = if ((stakedTime > 0))
479- then value(getString(stakingContract, keyLandAssetIdToOwner(landAssetId)))
480- else ""
481- (acc :+ landInfoArray(landAssetId, owner, stakedTime))
1510+ (result :+ prologAction)
4821511 }
483-
484- let r = {
485- let $l = landAssetIds
486- let $s = size($l)
487- let $acc0 = nil
488- func $f0_1 ($a,$i) = if (($i >= $s))
489- then $a
490- else oneLand($a, $l[$i])
491-
492- func $f0_2 ($a,$i) = if (($i >= $s))
493- then $a
494- else throw("List size exceeds 100")
495-
496- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40), 41), 42), 43), 44), 45), 46), 47), 48), 49), 50), 51), 52), 53), 54), 55), 56), 57), 58), 59), 60), 61), 62), 63), 64), 65), 66), 67), 68), 69), 70), 71), 72), 73), 74), 75), 76), 77), 78), 79), 80), 81), 82), 83), 84), 85), 86), 87), 88), 89), 90), 91), 92), 93), 94), 95), 96), 97), 98), 99), 100)
497- }
498- $Tuple2(nil, r)
4991512 }
5001513
5011514
5021515
5031516 @Callable(i)
504-func warehouseOrderByAssetIdInfoREADONLY (landAssetId) = if ((landAssetId == ""))
505- then throw("landAssetId is required")
506- else {
507- let stakedTime = valueOrElse(getInteger(stakingContract, keyStakedTimeByAssetId(landAssetId)), -1)
508- let owner = if ((stakedTime > 0))
509- then value(getString(stakingContract, keyLandAssetIdToOwner(landAssetId)))
510- else ""
511- $Tuple2(nil, landOrderInfoArray(landAssetId, owner))
512- }
513-
514-
515-
516-@Callable(i)
517-func ordersByLandIdsInfoREADONLY (landAssetIds) = {
518- func oneLand (acc,landAssetId) = if ((landAssetId == ""))
519- then throw("landAssetId is required")
1517+func mergeLands (landAssetIds) = {
1518+ let prologAction = prolog(i)
1519+ if ((size(i.payments) != 0))
1520+ then throw("Lands merging doesn't require any payments")
5201521 else {
521- let stakedTime = valueOrElse(getInteger(stakingContract, keyStakedTimeByAssetId(landAssetId)), -1)
522- let owner = if ((stakedTime > 0))
523- then value(getString(stakingContract, keyLandAssetIdToOwner(landAssetId)))
524- else ""
525- (acc :+ landOrderInfoArray(landAssetId, owner))
1522+ let result = mergeCommon(true, toString(i.caller), 0, landAssetIds, i.transactionId)
1523+ $Tuple2((result._1 :+ prologAction), result._2)
5261524 }
527-
528- let r = {
529- let $l = landAssetIds
530- let $s = size($l)
531- let $acc0 = nil
532- func $f0_1 ($a,$i) = if (($i >= $s))
533- then $a
534- else oneLand($a, $l[$i])
535-
536- func $f0_2 ($a,$i) = if (($i >= $s))
537- then $a
538- else throw("List size exceeds 100")
539-
540- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40), 41), 42), 43), 44), 45), 46), 47), 48), 49), 50), 51), 52), 53), 54), 55), 56), 57), 58), 59), 60), 61), 62), 63), 64), 65), 66), 67), 68), 69), 70), 71), 72), 73), 74), 75), 76), 77), 78), 79), 80), 81), 82), 83), 84), 85), 86), 87), 88), 89), 90), 91), 92), 93), 94), 95), 96), 97), 98), 99), 100)
541- }
542- $Tuple2(nil, r)
5431525 }
5441526
5451527
5461528
5471529 @Callable(i)
548-func cancelWarehouseOrders (landAssetIds) = if ((i.caller != this))
549- then throw("permission denied")
550- else {
551- let blocked = getBoolean(stakingContract, keyBlocked())
552- if (if (!(isDefined(blocked)))
553- then true
554- else (value(blocked) == false))
555- then throw("Contracts should be blocked before canceling orders")
556- else {
557- func oneLand (a,landAssetId) = if ((landAssetId == ""))
558- then throw("landAssetId is required")
559- else {
560- let c = asBoolean(invoke(economyContract, "setWarehouseOrder", ["0@0_0@0_0@0_0@0_0@0_0@0:0@0_0@0_0@0_0@0_0@0_0@0:", landAssetId], nil))
561- if (if (a)
562- then true
563- else c)
564- then !(if (a)
565- then c
566- else false)
567- else false
568- }
1530+func mergeLandsUsdn (landAssetIds) = {
1531+ let prologAction = prolog(i)
1532+ if ((size(i.payments) != 1))
1533+ then throw("Exactly one payment required")
1534+ else {
1535+ let pmt = value(i.payments[0])
1536+ if ((pmt.assetId != usdnAssetId))
1537+ then throw("Allowed USDN payment only!")
1538+ else {
1539+ let result = mergeCommon(false, toString(i.caller), pmt.amount, landAssetIds, i.transactionId)
1540+ $Tuple2(((result._1 :+ ScriptTransfer(economyContract, pmt.amount, usdnAssetId)) :+ prologAction), result._2)
1541+ }
1542+ }
1543+ }
5691544
570- let r = {
571- let $l = landAssetIds
572- let $s = size($l)
573- let $acc0 = false
574- func $f0_1 ($a,$i) = if (($i >= $s))
575- then $a
576- else oneLand($a, $l[$i])
5771545
578- func $f0_2 ($a,$i) = if (($i >= $s))
579- then $a
580- else throw("List size exceeds 30")
5811546
582- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30)
1547+@Callable(i)
1548+func cargoExchange (cargoListStr,landAssetId) = {
1549+ let prologAction = prolog(i)
1550+ let cargoParts = split_4C(cargoListStr, ":")
1551+ let addr = toString(i.originCaller)
1552+ let asset = value(assetInfo(fromBase58String(landAssetId)))
1553+ let timeKey = keyStakedTimeByAssetId(landAssetId)
1554+ if (!(isDefined(getInteger(timeKey))))
1555+ then throw((asset.name + " is not staked"))
1556+ else {
1557+ let owner = valueOrErrorMessage(getString(keyLandAssetIdToOwner(landAssetId)), (("NFT " + asset.name) + " is orphaned"))
1558+ if ((owner != addr))
1559+ then throw((LANDPREFIX + " is not yours"))
1560+ else {
1561+ let landIndex = (numPiecesBySize(split(asset.description, "_")[recLandSize]) / SSIZE)
1562+ let infraLevel = valueOrElse(getInteger(keyInfraLevelByAssetId(landAssetId)), 0)
1563+ let duckAssetId = valueOrErrorMessage(getString(keyStakedDuckByOwner(addr)), "You don't have a duck staked")
1564+ let curLocation = valueOrElse(getString(keyDuckLocation(duckAssetId)), DEFAULTLOCATION)
1565+ let loc = split(value(curLocation), "_")
1566+ if ((loc[locIdxType] != "L"))
1567+ then throw((("Duck location type is " + loc[locIdxType]) + ", but should be L"))
1568+ else if ((loc[locIdxId] != landAssetId))
1569+ then throw(("Duck should be on the land " + landAssetId))
1570+ else {
1571+ let whKey = keyWarehouseByLand(landAssetId)
1572+ let currentWh = getWarehouse(whKey, landIndex, infraLevel)
1573+ let bpKey = keyBackpackByDuck(duckAssetId)
1574+ let currentPack = getBackpack(bpKey)
1575+ let result = moveStuff(cargoParts, currentWh, currentPack)
1576+[StringEntry(bpKey, makeString([currentPack[bpIdxLevel], result._4, result._5, result._6], ":")), StringEntry(whKey, makeString([currentWh[whIdxVol], result._1, result._2, result._3, currentWh[whIdxLockedVol]], ":")), prologAction]
1577+ }
5831578 }
584- $Tuple2(nil, r)
585- }
586- }
1579+ }
1580+ }
1581+
1582+
1583+
1584+@Callable(i)
1585+func saveWarehouse (whStr,landAssetId) = {
1586+ let prologAction = prolog(i)
1587+ if ((i.caller != economyContract))
1588+ then throw("Access denied")
1589+ else {
1590+ let whKey = keyWarehouseByLand(landAssetId)
1591+ if ((size(split_4C(whStr, ":")) != 5))
1592+ then throw("warehouse string should contain 4 ':' separators")
1593+ else $Tuple2([StringEntry(whKey, whStr), prologAction], whStr)
1594+ }
1595+ }
1596+
1597+
1598+
1599+@Callable(i)
1600+func splitByGlobalWeightsREADONLY (amount) = $Tuple2(nil, getNeededMaterials(amount))
1601+
1602+
1603+
1604+@Callable(i)
1605+func splitByGlobalAndLocalWeightsREADONLY (matAmount,resAmount,terrains) = {
1606+ let terrainCounts = countTerrains(terrains)
1607+ $Tuple2(nil, $Tuple2(getNeededMaterials(matAmount), distributeByWeights(resAmount, terrainCounts)))
1608+ }
1609+
1610+
1611+
1612+@Callable(i)
1613+func getBackpackREADONLY (duckAssetId) = $Tuple2(nil, makeString(getBackpack(keyBackpackByDuck(duckAssetId)), ":"))
1614+
1615+
1616+
1617+@Callable(i)
1618+func getWarehouseREADONLY (landAssetId) = {
1619+ let asset = value(assetInfo(fromBase58String(landAssetId)))
1620+ let landIndex = (numPiecesBySize(split(asset.description, "_")[recLandSize]) / SSIZE)
1621+ let infraLevel = valueOrElse(getInteger(keyInfraLevelByAssetId(landAssetId)), 0)
1622+ $Tuple2(nil, makeString_2C(getWarehouse(keyWarehouseByLand(landAssetId), landIndex, infraLevel), ":"))
1623+ }
5871624
5881625
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 let chain = take(drop(this.bytes, 1), 1)
55
66 let usdnAssetId = match chain {
77 case _ =>
88 if ((base58'2W' == $match0))
99 then base58'DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p'
1010 else if ((base58'2T' == $match0))
1111 then base58'HezsdQuRDtzksAYUy97gfhKy7Z1NW2uXYSHA3bgqenNZ'
1212 else throw("Unknown chain")
1313 }
1414
15-let InfraUpgradeCostS = match chain {
15+let incubatorAddr = match chain {
1616 case _ =>
1717 if ((base58'2W' == $match0))
18- then 6307198406
18+ then addressFromStringValue("3PEktVux2RhchSN63DsDo4b4mz4QqzKSeDv")
1919 else if ((base58'2T' == $match0))
20- then 63071984
20+ then this
2121 else throw("Unknown chain")
2222 }
23+
24+let breederAddr = match chain {
25+ case _ =>
26+ if ((base58'2W' == $match0))
27+ then addressFromStringValue("3PDVuU45H7Eh5dmtNbnRNRStGwULA7NY6Hb")
28+ else if ((base58'2T' == $match0))
29+ then this
30+ else throw("Unknown chain")
31+}
32+
33+let defaultRestAddressStr = match chain {
34+ case _ =>
35+ if ((base58'2W' == $match0))
36+ then "3PQCuvFbvh4LkPUnrnU1z3jnbA1p9m3WNhv"
37+ else if ((base58'2T' == $match0))
38+ then "3MumkGGztCKAXpWDqxkddofqXSUbqQkvSJy"
39+ else throw("Unknown chain")
40+}
41+
42+let pub = base58'6LfPuKJjLgekmncBhMg2LZyMTNVzZBccXR28ySXm9uXD'
43+
44+let HEALCOST = 10000
2345
2446 let LANDPREFIX = "LAND"
2547
2648 let DUCKPREFIX = "DUCK"
2749
28-let SEP = "__"
29-
30-let ARTPRESALE = "PRESALE"
31-
32-let DAILYRESBYPIECE = 3456000
33-
34-let DAYMILLIS = 86400000
50+let DEFAULTLOCATION = "Africa_F_Africa"
3551
3652 let NUMRES = 6
3753
3854 let SSIZE = 25
3955
4056 let MSIZE = 100
4157
4258 let LSIZE = 225
4359
4460 let XLSIZE = 400
4561
4662 let XXLSIZE = 625
4763
48-let recLandNum = 0
64+let DAILYRESBYPIECE = 3456000
4965
50-let recLandSize = 1
66+let DAYMILLIS = 86400000
5167
52-let recTerrains = 2
68+let FIVEMINUTESMILLIS = 300000
5369
54-let recContinent = 3
70+let RESOURCEPRICEMIN = 158549
5571
56-let whIdxVol = 0
72+let WHMULTIPLIER = 10000000000
5773
58-let whIdxRes = 1
74+let InfraUpgradeCostS = match chain {
75+ case _ =>
76+ if ((base58'2W' == $match0))
77+ then 6307198406
78+ else if ((base58'2T' == $match0))
79+ then 63071984
80+ else throw("Unknown chain")
81+}
5982
60-let whIdxMat = 2
83+let InfraUpgradeCostSUsdn = match chain {
84+ case _ =>
85+ if ((base58'2W' == $match0))
86+ then 40000000
87+ else if ((base58'2T' == $match0))
88+ then 400000
89+ else throw("Unknown chain")
90+}
6191
62-let whIdxProd = 3
92+let EXPMATERIALS = match chain {
93+ case _ =>
94+ if ((base58'2W' == $match0))
95+ then 157679960139
96+ else if ((base58'2T' == $match0))
97+ then 1576799601
98+ else throw("Unknown chain")
99+}
63100
64-let whIdxLockedVol = 4
101+let EXPUSDN = match chain {
102+ case _ =>
103+ if ((base58'2W' == $match0))
104+ then 1000000000
105+ else if ((base58'2T' == $match0))
106+ then 10000000
107+ else throw("Unknown chain")
108+}
65109
66-func keyRestCfg () = "%s__restConfig"
110+let SEP = "__"
111+
112+let MULT6 = 1000000
113+
114+let FIVEX = toBigInt(5)
115+
116+let TWENTYX = toBigInt(20)
117+
118+let TWENTY2X = toBigInt((20 * 20))
119+
120+let TWENTY3X = toBigInt(((20 * 20) * 20))
121+
122+let TWENTY4X = toBigInt((((20 * 20) * 20) * 20))
123+
124+let TWENTY5X = toBigInt(((((20 * 20) * 20) * 20) * 20))
125+
126+let matTypes = ["Fuel", "Metal", "Plank", "Glass", "Plastic", "Protein"]
127+
128+let continents = ["Asia", "Europe", "Americas", "Oceania", "Africa"]
129+
130+let ARTPRESALE = "PRESALE"
131+
132+let PRESALENUMLANDS = 500
133+
134+func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), makeString(["mandatory ", toString(address), ".", key, " is not defined"], ""))
135+
136+
137+func getIntOrElse (key,defaultVal) = valueOrElse(getInteger(this, key), defaultVal)
67138
68139
69140 let IdxCfgStakingDapp = 1
70141
71142 let IdxCfgEconomyDapp = 2
72143
73144 let IdxCfgGovernanceDapp = 3
74145
75-func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), makeString(["mandatory ", toString(address), ".", key, " is not defined"], ""))
146+func keyRestCfg () = "%s__restConfig"
76147
77148
78-func readRestCfgOrFail () = split_4C(getStringOrFail(this, keyRestCfg()), SEP)
149+func keyRestAddress () = "%s__restAddr"
150+
151+
152+func readRestCfgOrFail (rest) = split_4C(getStringOrFail(rest, keyRestCfg()), SEP)
79153
80154
81155 func getContractAddressOrFail (restCfg,idx) = valueOrErrorMessage(addressFromString(restCfg[idx]), ("Rest cfg doesn't contain address at index " + toString(idx)))
82156
83157
84-let restCfg = readRestCfgOrFail()
158+let restContract = addressFromStringValue(valueOrElse(getString(this, keyRestAddress()), defaultRestAddressStr))
85159
86-let stakingContract = getContractAddressOrFail(restCfg, IdxCfgStakingDapp)
160+let restCfg = readRestCfgOrFail(restContract)
87161
88162 let economyContract = getContractAddressOrFail(restCfg, IdxCfgEconomyDapp)
89163
90-let governanceContract = getContractAddressOrFail(restCfg, IdxCfgEconomyDapp)
164+let govContract = getContractAddressOrFail(restCfg, IdxCfgGovernanceDapp)
91165
92-func keyBlocked () = "contractsBlocked"
166+func keyLastTxIdByUser (addr) = ("lastTxIdByUser_" + addr)
167+
168+
169+func keyNextFreeLandNum () = "nextLandNum"
170+
171+
172+func keyLandToAssetId (landNum) = ("landToAsset_" + landNum)
173+
174+
175+func keyNftName (landNum,landSize) = ((LANDPREFIX + landNum) + landSize)
176+
177+
178+func keyLandAssetIdToOwner (assetId) = ("nftOwner_" + assetId)
93179
94180
95181 func keyDuckIdToOwner (assetId) = ("duckOwner_" + assetId)
96182
97183
98184 func keyStakedTimeByAssetId (assetId) = ("stakedTime_" + assetId)
99185
100186
187+func keyInfraLevelByAssetId (assetId) = ("infraLevel_" + assetId)
188+
189+
190+func keyInfraLevelByAssetIdAndOwner (assetId,ownerAddr) = ((("infraLevelByAssetIdAndOwner_" + assetId) + "_") + ownerAddr)
191+
192+
193+func keyPresaleArtActivatedByAssetId (assetId) = ("presaleArtActivated_" + assetId)
194+
195+
196+func keyPresaleArtActivatedByAssetIdAndOwner (assetId,ownerAddr) = ((("presaleArtActivatedByAssetIdAndOwner_" + assetId) + "_") + ownerAddr)
197+
198+
199+func keyLandArtStatusByTypeAndAssetId (type,assetId) = makeString(["landArtStatus", type, assetId], "_")
200+
201+
202+func keyLandArtStatusByTypeAssetIdAndOwner (type,assetId,ownerAddr) = makeString(["landArtStatusByTypeAssetIdAndOwner", type, assetId, ownerAddr], "_")
203+
204+
101205 func keyStakedDuckByOwner (ownerAddr) = ("stakedDuckByOwner_" + ownerAddr)
102206
103207
104208 func keyStakedTimeByTypeAssetIdAndOwner (nftType,assetId,ownerAddr) = ((((("stakedTimeByTypeAssetIdAndOwner_" + nftType) + "_") + assetId) + "_") + ownerAddr)
209+
210+
211+func keyLandNumToOwner (landNum) = ("landOwner_" + landNum)
105212
106213
107214 func keyBackpackByDuck (duckAssetId) = ("backPack_" + duckAssetId)
108215
109216
110217 func keyWarehouseByLand (landAssetId) = ("wareHouse_" + landAssetId)
111218
112219
113220 func keyDuckLocation (duckAssetId) = ("duckLocation_" + duckAssetId)
114221
115222
116223 func keyDuckHealth (duckAssetId) = ("duckHealth_" + duckAssetId)
117224
118225
119-func keyLandAssetIdToOwner (assetId) = ("nftOwner_" + assetId)
120-
121-
122-func keyInfraLevelByAssetId (assetId) = ("infraLevel_" + assetId)
123-
124-
125-func keyLandArtStatusByTypeAndAssetId (type,assetId) = makeString(["landArtStatus", type, assetId], "_")
126-
127-
128-func keyPresaleArtActivatedByAssetId (assetId) = ("presaleArtActivated_" + assetId)
226+func keyResProportions () = "resTypesProportions"
129227
130228
131229 func keyStakedLandsByOwner (ownerAddr) = ("stakedLandsByOwner_" + ownerAddr)
132230
133231
134-func keyOrderByLand (landAssetId) = ("landOrder_" + landAssetId)
232+func keyBlocked () = "contractsBlocked"
135233
234+
235+func keyUserGwlReleaseTime (userAddr) = ("%s%s__userGwlReleaseTime__" + userAddr)
236+
237+
238+let recLandNum = 0
239+
240+let recLandSize = 1
241+
242+let recTerrains = 2
243+
244+let recContinent = 3
245+
246+let locIdxContinent = 0
247+
248+let locIdxType = 1
249+
250+let locIdxId = 2
251+
252+let bpIdxLevel = 0
253+
254+let bpIdxRes = 1
255+
256+let bpIdxMat = 2
257+
258+let bpIdxProd = 3
259+
260+let whIdxVol = 0
261+
262+let whIdxRes = 1
263+
264+let whIdxMat = 2
265+
266+let whIdxProd = 3
267+
268+let whIdxLockedVol = 4
269+
270+let claimModeWh = 0
271+
272+let claimModeDuck = 1
273+
274+let claimModeWhThenDuck = 2
136275
137276 func asString (v) = match v {
138277 case s: String =>
139278 s
140279 case _ =>
141280 throw("fail to cast into String")
142281 }
143282
144283
145-func asBoolean (v) = match v {
146- case s: Boolean =>
147- s
148- case _ =>
149- throw("fail to cast into Boolean")
150-}
284+func distributeByWeights (total,weights) = {
285+ let sum = (((((weights[0] + weights[1]) + weights[2]) + weights[3]) + weights[4]) + weights[5])
286+ if ((0 >= sum))
287+ then throw("Zero weights sum")
288+ else {
289+ let norm6 = fraction(total, MULT6, sum)
290+ func normalizer (acc,elem) = (acc :+ fraction(elem, norm6, MULT6))
151291
292+ let $l = weights
293+ let $s = size($l)
294+ let $acc0 = nil
295+ func $f0_1 ($a,$i) = if (($i >= $s))
296+ then $a
297+ else normalizer($a, $l[$i])
152298
153-func asListIntCompacted (val) = match val {
154- case valAnyList: List[Any] =>
155- if ((size(valAnyList) != NUMRES))
156- then throw(("Array size is " + toString(size(valAnyList))))
157- else {
158- func conv (acc,item) = match item {
159- case it: Int =>
160- (acc :+ toString(it))
161- case _ =>
162- throw("List type is not Int")
163- }
299+ func $f0_2 ($a,$i) = if (($i >= $s))
300+ then $a
301+ else throw("List size exceeds 6")
164302
165- let r = {
166- let $l = valAnyList
167- let $s = size($l)
168- let $acc0 = nil
169- func $f0_1 ($a,$i) = if (($i >= $s))
170- then $a
171- else conv($a, $l[$i])
172-
173- func $f0_2 ($a,$i) = if (($i >= $s))
174- then $a
175- else throw("List size exceeds 6")
176-
177- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
178- }
179- makeString(r, "_")
180- }
181- case _ =>
182- throw("fail to cast into List")
183-}
184-
185-
186-func asSplitResult (val) = match val {
187- case t2: (List[Any], List[Any]) =>
188- $Tuple2(asListIntCompacted(t2._1), asListIntCompacted(t2._2))
189- case _ =>
190- throw("fail to cast into (List, List)")
191-}
192-
193-
194-func walletInternal (userAddressOpt) = {
195- let addr = addressFromString(userAddressOpt)
196- let balance = if (isDefined(addr))
197- then wavesBalance(value(addr))
198- else BalanceDetails(0, 0, 0, 0)
199- let usdnBalance = if (isDefined(addr))
200- then assetBalance(value(addr), usdnAssetId)
201- else 0
202- makeString(["%s%d%d", "wallet", toString(balance.available), toString(usdnBalance)], SEP)
303+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
304+ }
203305 }
204306
205307
206-func applyBonuses (landAssetId,pieces) = {
207- let infraLevel = valueOrElse(getInteger(stakingContract, keyInfraLevelByAssetId(landAssetId)), 0)
208- let artPieces = valueOrElse(getInteger(stakingContract, keyLandArtStatusByTypeAndAssetId(ARTPRESALE, landAssetId)), if (valueOrElse(getBoolean(stakingContract, keyPresaleArtActivatedByAssetId(landAssetId)), false))
209- then pieces
210- else 0)
211- $Tuple3(infraLevel, artPieces, ((DAILYRESBYPIECE + fraction(DAILYRESBYPIECE, infraLevel, 4)) + fraction(DAILYRESBYPIECE, (artPieces * 3), (pieces * 20))))
308+func getNeededMaterials (total) = {
309+ let props = split(value(getString(keyResProportions())), "_")
310+ if ((size(props) != NUMRES))
311+ then throw("Wrong proportions data")
312+ else {
313+ let r = [parseIntValue(props[0]), parseIntValue(props[1]), parseIntValue(props[2]), parseIntValue(props[3]), parseIntValue(props[4]), parseIntValue(props[5])]
314+ distributeByWeights(total, r)
315+ }
212316 }
317+
318+
319+func subtractMaterials (shouldUseMat,has,totalNeed) = {
320+ let need = getNeededMaterials(totalNeed)
321+ func subtractor (acc,idx) = {
322+ let result = (parseIntValue(has[idx]) - need[idx])
323+ if ((0 > result))
324+ then throw(((((("Not enough material idx=" + toString(idx)) + ", you have ") + has[idx]) + ", but need ") + toString(need[idx])))
325+ else (acc :+ toString(result))
326+ }
327+
328+ if (shouldUseMat)
329+ then {
330+ let $l = [0, 1, 2, 3, 4, 5]
331+ let $s = size($l)
332+ let $acc0 = nil
333+ func $f0_1 ($a,$i) = if (($i >= $s))
334+ then $a
335+ else subtractor($a, $l[$i])
336+
337+ func $f0_2 ($a,$i) = if (($i >= $s))
338+ then $a
339+ else throw("List size exceeds 6")
340+
341+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
342+ }
343+ else has
344+ }
345+
346+
347+func updateProportionsInternal (propList,terrainCounts,landSizeIndex,sign) = if ((size(propList) != NUMRES))
348+ then throw("Wrong proportions data")
349+ else {
350+ func updater (acc,i) = {
351+ let result = (parseIntValue(propList[i]) + ((sign * terrainCounts[i]) * landSizeIndex))
352+ if ((0 > result))
353+ then throw(((((((("Panic! Pieces of type=" + toString(i)) + ", sign=") + toString(sign)) + ", terrainCounts[i]=") + toString(terrainCounts[i])) + ", landSizeIndex=") + toString(landSizeIndex)))
354+ else (acc :+ toString(result))
355+ }
356+
357+ let r = {
358+ let $l = [0, 1, 2, 3, 4, 5]
359+ let $s = size($l)
360+ let $acc0 = nil
361+ func $f0_1 ($a,$i) = if (($i >= $s))
362+ then $a
363+ else updater($a, $l[$i])
364+
365+ func $f0_2 ($a,$i) = if (($i >= $s))
366+ then $a
367+ else throw("List size exceeds 6")
368+
369+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
370+ }
371+ makeString(r, "_")
372+ }
373+
374+
375+func updateProportions (terrainCounts,landSizeIndex,sign) = {
376+ let propList = split(valueOrElse(getString(keyResProportions()), "0_0_0_0_0_0"), "_")
377+ updateProportionsInternal(propList, terrainCounts, landSizeIndex, sign)
378+ }
379+
380+
381+func countTerrains (terrains) = [(size(split(terrains, "A")) - 1), (size(split(terrains, "B")) - 1), (size(split(terrains, "C")) - 1), (size(split(terrains, "D")) - 1), (size(split(terrains, "E")) - 1), (size(split(terrains, "F")) - 1)]
213382
214383
215384 func numPiecesBySize (landSize) = match landSize {
216385 case _ =>
217386 if (("S" == $match0))
218387 then SSIZE
219388 else if (("M" == $match0))
220389 then MSIZE
221390 else if (("L" == $match0))
222391 then LSIZE
223392 else if (("XL" == $match0))
224393 then XLSIZE
225394 else if (("XXL" == $match0))
226395 then XXLSIZE
227396 else throw("Unknown land size")
228397 }
229398
230399
400+func subOneInList (aList,idx,amount) = {
401+ func subber (acc,i) = (acc :+ (if ((i == idx))
402+ then toString((parseIntValue(aList[i]) - amount))
403+ else aList[i]))
404+
405+ let r = {
406+ let $l = [0, 1, 2, 3, 4, 5]
407+ let $s = size($l)
408+ let $acc0 = nil
409+ func $f0_1 ($a,$i) = if (($i >= $s))
410+ then $a
411+ else subber($a, $l[$i])
412+
413+ func $f0_2 ($a,$i) = if (($i >= $s))
414+ then $a
415+ else throw("List size exceeds 6")
416+
417+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
418+ }
419+ makeString(r, "_")
420+ }
421+
422+
423+func addRes (currentRes,terrainCounts,deltaTime,landSizeIndex,dailyByPieceWithBonuses) = {
424+ func adder (acc,i) = {
425+ let resOfType = ((fraction(deltaTime, dailyByPieceWithBonuses, DAYMILLIS) * terrainCounts[i]) * landSizeIndex)
426+ (acc :+ toString((parseIntValue(currentRes[i]) + resOfType)))
427+ }
428+
429+ let r = {
430+ let $l = [0, 1, 2, 3, 4, 5]
431+ let $s = size($l)
432+ let $acc0 = nil
433+ func $f0_1 ($a,$i) = if (($i >= $s))
434+ then $a
435+ else adder($a, $l[$i])
436+
437+ func $f0_2 ($a,$i) = if (($i >= $s))
438+ then $a
439+ else throw("List size exceeds 6")
440+
441+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
442+ }
443+ makeString(r, "_")
444+ }
445+
446+
447+func virtClaim (terrainCounts,deltaTime,landSizeIndex,dailyByPieceWithBonuses) = {
448+ func adder (acc,i) = {
449+ let resOfType = ((fraction(deltaTime, dailyByPieceWithBonuses, DAYMILLIS) * terrainCounts[i]) * landSizeIndex)
450+ $Tuple2((acc._1 :+ resOfType), (acc._2 + resOfType))
451+ }
452+
453+ let $l = [0, 1, 2, 3, 4, 5]
454+ let $s = size($l)
455+ let $acc0 = $Tuple2(nil, 0)
456+ func $f0_1 ($a,$i) = if (($i >= $s))
457+ then $a
458+ else adder($a, $l[$i])
459+
460+ func $f0_2 ($a,$i) = if (($i >= $s))
461+ then $a
462+ else throw("List size exceeds 6")
463+
464+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
465+ }
466+
467+
468+func distributeRes (currentWhRes,currentPackRes,resToClaim,whSpaceLeft) = {
469+ let resListToClaim = resToClaim._1
470+ let resAmToClaim = resToClaim._2
471+ if ((resAmToClaim == 0))
472+ then $Tuple2(makeString(currentWhRes, "_"), makeString(currentPackRes, "_"))
473+ else if ((whSpaceLeft >= resAmToClaim))
474+ then {
475+ func addLists (acc,i) = (acc :+ toString((parseIntValue(currentWhRes[i]) + resListToClaim[i])))
476+
477+ let r = {
478+ let $l = [0, 1, 2, 3, 4, 5]
479+ let $s = size($l)
480+ let $acc0 = nil
481+ func $f0_1 ($a,$i) = if (($i >= $s))
482+ then $a
483+ else addLists($a, $l[$i])
484+
485+ func $f0_2 ($a,$i) = if (($i >= $s))
486+ then $a
487+ else throw("List size exceeds 6")
488+
489+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
490+ }
491+ $Tuple2(makeString(r, "_"), makeString(currentPackRes, "_"))
492+ }
493+ else {
494+ func addPartLists (acc,i) = {
495+ let whPart = fraction(resListToClaim[i], whSpaceLeft, resAmToClaim)
496+ $Tuple2((acc._1 :+ toString((parseIntValue(currentWhRes[i]) + whPart))), (acc._2 :+ toString(((parseIntValue(currentPackRes[i]) + resListToClaim[i]) - whPart))))
497+ }
498+
499+ let r = {
500+ let $l = [0, 1, 2, 3, 4, 5]
501+ let $s = size($l)
502+ let $acc0 = $Tuple2(nil, nil)
503+ func $f0_1 ($a,$i) = if (($i >= $s))
504+ then $a
505+ else addPartLists($a, $l[$i])
506+
507+ func $f0_2 ($a,$i) = if (($i >= $s))
508+ then $a
509+ else throw("List size exceeds 6")
510+
511+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
512+ }
513+ $Tuple2(makeString(r._1, "_"), makeString(r._2, "_"))
514+ }
515+ }
516+
517+
518+func abs (x) = if ((x >= toBigInt(0)))
519+ then x
520+ else -(x)
521+
522+
523+let freq = [[1, 4, 9, 10, 15], [5, 8, 13, 14, 15], [6, 9, 14, 15, 16], [4, 7, 8, 13, 18], [1, 6, 7, 15, 19]]
524+
525+func genChar (n,freqs) = {
526+ let rem = toInt((n % TWENTYX))
527+ let letter = if ((freqs[0] > rem))
528+ then "A"
529+ else if ((freqs[1] > rem))
530+ then "B"
531+ else if ((freqs[2] > rem))
532+ then "C"
533+ else if ((freqs[3] > rem))
534+ then "D"
535+ else if ((freqs[4] > rem))
536+ then "E"
537+ else "F"
538+ letter
539+ }
540+
541+
542+func genTerrains (seed,continentIdx) = {
543+ let f = freq[continentIdx]
544+ func terrainGenerator (acc,elem) = $Tuple2((((((acc._1 + genChar(acc._2, f)) + genChar((acc._2 / TWENTYX), f)) + genChar((acc._2 / TWENTY2X), f)) + genChar((acc._2 / TWENTY3X), f)) + genChar((acc._2 / TWENTY4X), f)), (acc._2 / TWENTY5X))
545+
546+ let t = {
547+ let $l = [1, 2, 3, 4, 5]
548+ let $s = size($l)
549+ let $acc0 = $Tuple2("", (seed / FIVEX))
550+ func $f0_1 ($a,$i) = if (($i >= $s))
551+ then $a
552+ else terrainGenerator($a, $l[$i])
553+
554+ func $f0_2 ($a,$i) = if (($i >= $s))
555+ then $a
556+ else throw("List size exceeds 5")
557+
558+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5)
559+ }
560+ t._1
561+ }
562+
563+
564+func getBackpack (bpKey) = {
565+ let p = split(valueOrElse(getString(bpKey), "0:0_0_0_0_0_0:0_0_0_0_0_0:"), ":")
566+[toString(valueOrElse(parseInt(p[bpIdxLevel]), 0)), if ((size(split(p[bpIdxRes], "_")) == NUMRES))
567+ then p[bpIdxRes]
568+ else "0_0_0_0_0_0", if ((size(split(p[bpIdxMat], "_")) == NUMRES))
569+ then p[bpIdxMat]
570+ else "0_0_0_0_0_0", p[bpIdxProd]]
571+ }
572+
573+
574+func getWarehouseVolume (volPrefix) = {
575+ let parts = split(volPrefix, "_")
576+ ((WHMULTIPLIER * (parseIntValue(parts[1]) + 1)) * parseIntValue(parts[0]))
577+ }
578+
579+
231580 func getWarehouse (whKey,landIndex,infraLevel) = {
232581 let volPrefix = ((toString(landIndex) + "_") + toString(infraLevel))
233- let p = split(valueOrElse(getString(stakingContract, whKey), (volPrefix + ":0_0_0_0_0_0:0_0_0_0_0_0::0")), ":")
582+ let p = split(valueOrElse(getString(whKey), (volPrefix + ":0_0_0_0_0_0:0_0_0_0_0_0::0")), ":")
234583 [p[whIdxVol], if ((size(split(p[whIdxRes], "_")) == NUMRES))
235584 then p[whIdxRes]
236585 else "0_0_0_0_0_0", if ((size(split(p[whIdxMat], "_")) == NUMRES))
237586 then p[whIdxMat]
238587 else "0_0_0_0_0_0", p[whIdxProd], if ((5 > size(p)))
239588 then "0"
240589 else p[whIdxLockedVol]]
241590 }
242591
243592
244-func duckInfoTuple (duckAssetId) = $Tuple5(valueOrElse(getInteger(stakingContract, keyStakedTimeByAssetId(duckAssetId)), -1), value(assetInfo(fromBase58String(duckAssetId))).name, valueOrElse(getString(stakingContract, keyDuckLocation(duckAssetId)), ""), valueOrElse(getInteger(stakingContract, keyDuckHealth(duckAssetId)), -1), asString(invoke(stakingContract, "getBackpackREADONLY", [duckAssetId], nil)))
593+func getWarehouseCurrResVolume (currentWh) = {
594+ func sum (acc,item) = (acc + parseIntValue(item))
595+
596+ let $l = split(currentWh[whIdxRes], "_")
597+ let $s = size($l)
598+ let $acc0 = 0
599+ func $f0_1 ($a,$i) = if (($i >= $s))
600+ then $a
601+ else sum($a, $l[$i])
602+
603+ func $f0_2 ($a,$i) = if (($i >= $s))
604+ then $a
605+ else throw("List size exceeds 6")
606+
607+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
608+ }
245609
246610
247-func duckInfoArray (duckAssetId,owner,duckInf) = [("%s%s__assetId__" + duckAssetId), ("%s%s__owner__" + owner), ("%s%d__stakedTime__" + toString(duckInf._1)), ("%s%s__name__" + duckInf._2), ("%s%s__location__" + duckInf._3), ("%s%d__health__" + toString(duckInf._4)), ("%s%s__backPack__" + duckInf._5)]
611+func getWarehouseCurrMatVolume (currentWh) = {
612+ func sum (acc,item) = (acc + parseIntValue(item))
613+
614+ let $l = split(currentWh[whIdxMat], "_")
615+ let $s = size($l)
616+ let $acc0 = 0
617+ func $f0_1 ($a,$i) = if (($i >= $s))
618+ then $a
619+ else sum($a, $l[$i])
620+
621+ func $f0_2 ($a,$i) = if (($i >= $s))
622+ then $a
623+ else throw("List size exceeds 6")
624+
625+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
626+ }
248627
249628
250-func landInfoArray (landAssetId,owner,stakedTime) = if ((landAssetId == ""))
251- then throw("landAssetId is required")
629+func getWarehouseCurrGoodsVolume (currentWh) = {
630+ let goods = currentWh[whIdxProd]
631+ if ((goods == ""))
632+ then 0
633+ else {
634+ func sum (acc,item) = (acc + parseIntValue(item))
635+
636+ let $l = split_4C(goods, "_")
637+ let $s = size($l)
638+ let $acc0 = 0
639+ func $f0_1 ($a,$i) = if (($i >= $s))
640+ then $a
641+ else sum($a, $l[$i])
642+
643+ func $f0_2 ($a,$i) = if (($i >= $s))
644+ then $a
645+ else throw("List size exceeds 50")
646+
647+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40), 41), 42), 43), 44), 45), 46), 47), 48), 49), 50)
648+ }
649+ }
650+
651+
652+func moveStuff (cargoParts,currentWh,currentPack) = if ((size(cargoParts) != 3))
653+ then throw("cargoListStr should contain exactly 2 ':' separators")
252654 else {
253- let a = value(assetInfo(fromBase58String(landAssetId)))
254- let d = split(a.description, "_")
255- let landNum = if ((a.quantity > 0))
256- then d[recLandNum]
257- else ("-" + d[recLandNum])
258- let pieces = numPiecesBySize(d[recLandSize])
259- let productivity = applyBonuses(landAssetId, pieces)
260- let deltaTime = (lastBlock.timestamp - stakedTime)
261- let availRes = if ((stakedTime > 0))
262- then fraction(deltaTime, (productivity._3 * pieces), DAYMILLIS)
263- else 0
264- let needMat = fraction(InfraUpgradeCostS, (pieces * (productivity._1 + 1)), SSIZE)
265- let globalAndLocal = if ((stakedTime > 0))
266- then asSplitResult(invoke(stakingContract, "splitByGlobalAndLocalWeightsREADONLY", [needMat, availRes, d[recTerrains]], nil))
267- else $Tuple2(asListIntCompacted(invoke(stakingContract, "splitByGlobalWeightsREADONLY", [needMat], nil)), "")
268-[("%s%s__assetId__" + landAssetId), ("%s%s__owner__" + owner), ("%s%d__stakedTime__" + toString(stakedTime)), ("%s%s__description__" + makeString([landNum, d[recLandSize], d[recTerrains], d[recContinent]], "_")), ("%s%d__infraLevel__" + toString(productivity._1)), ("%s%s__availResByType__" + globalAndLocal._2), ("%s%d__availResTotal__" + toString(availRes)), ("%s%s__needMaterial__" + globalAndLocal._1), makeString(["%s%s", "landArtefacts", ("PRESALE:" + toString(productivity._2))], SEP), ("%s%s__warehouse__" + makeString(getWarehouse(keyWarehouseByLand(landAssetId), (pieces / SSIZE), productivity._1), ":")), ("%s%s__landOrder__" + valueOrElse(getString(economyContract, keyOrderByLand(landAssetId)), "0@0_0@0_0@0_0@0_0@0_0@0:0@0_0@0_0@0_0@0_0@0_0@0:"))]
655+ let resParts = split(cargoParts[0], "_")
656+ let matParts = split(cargoParts[1], "_")
657+ let prodParts = if ((cargoParts[2] == ""))
658+ then nil
659+ else split(cargoParts[2], "_")
660+ if ((size(resParts) != NUMRES))
661+ then throw("All 6 resources should be passed")
662+ else if ((size(matParts) != NUMRES))
663+ then throw("All 6 materials should be passed")
664+ else {
665+ let currWhResVol = getWarehouseCurrResVolume(currentWh)
666+ let currWhMatVol = getWarehouseCurrMatVolume(currentWh)
667+ let currWhGoodsVol = getWarehouseCurrGoodsVolume(currentWh)
668+ let currWhLockedVol = parseIntValue(currentWh[whIdxLockedVol])
669+ let whSpaceLeft = ((((getWarehouseVolume(currentWh[whIdxVol]) - currWhResVol) - currWhMatVol) - currWhGoodsVol) - currWhLockedVol)
670+ let currWhRes = split(currentWh[whIdxRes], "_")
671+ let currWhMat = split(currentWh[whIdxMat], "_")
672+ let currWhProd = if ((currentWh[whIdxProd] == ""))
673+ then nil
674+ else split(currentWh[whIdxProd], "_")
675+ let currentPackRes = split(currentPack[bpIdxRes], "_")
676+ let currentPackMat = split(currentPack[bpIdxMat], "_")
677+ let currentPackProd = if ((currentPack[bpIdxProd] == ""))
678+ then nil
679+ else split(currentPack[bpIdxProd], "_")
680+ func mvR (acc,item) = {
681+ let i = acc._1
682+ let am = parseIntValue(item)
683+ let whr = parseIntValue(currWhRes[i])
684+ let bpr = parseIntValue(currentPackRes[i])
685+ if ((am == 0))
686+ then $Tuple4((i + 1), (acc._2 :+ currWhRes[i]), (acc._3 :+ currentPackRes[i]), acc._4)
687+ else if ((am > 0))
688+ then if ((am > bpr))
689+ then throw((((("Attempt to take " + item) + " from backpack, but only ") + toString(bpr)) + " available"))
690+ else $Tuple4((i + 1), (acc._2 :+ toString((whr + am))), (acc._3 :+ toString((bpr - am))), (acc._4 + am))
691+ else if ((-(am) > whr))
692+ then throw((((("Attempt to take " + toString(-(am))) + " from warehouse, but only ") + toString(whr)) + " available"))
693+ else $Tuple4((i + 1), (acc._2 :+ toString((whr + am))), (acc._3 :+ toString((bpr - am))), (acc._4 + am))
694+ }
695+
696+ let r = {
697+ let $l = resParts
698+ let $s = size($l)
699+ let $acc0 = $Tuple4(0, nil, nil, 0)
700+ func $f0_1 ($a,$i) = if (($i >= $s))
701+ then $a
702+ else mvR($a, $l[$i])
703+
704+ func $f0_2 ($a,$i) = if (($i >= $s))
705+ then $a
706+ else throw("List size exceeds 6")
707+
708+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
709+ }
710+ func mvM (acc,item) = {
711+ let i = acc._1
712+ let am = parseIntValue(item)
713+ let whm = parseIntValue(currWhMat[i])
714+ let bpm = parseIntValue(currentPackMat[i])
715+ if ((am == 0))
716+ then $Tuple4((i + 1), (acc._2 :+ currWhMat[i]), (acc._3 :+ currentPackMat[i]), acc._4)
717+ else if ((am > 0))
718+ then if ((am > bpm))
719+ then throw((((("Attempt to take " + item) + " from backpack, but only ") + toString(bpm)) + " available"))
720+ else $Tuple4((i + 1), (acc._2 :+ toString((whm + am))), (acc._3 :+ toString((bpm - am))), (acc._4 + am))
721+ else if ((-(am) > whm))
722+ then throw((((("Attempt to take " + toString(-(am))) + " from warehouse, but only ") + toString(whm)) + " available"))
723+ else $Tuple4((i + 1), (acc._2 :+ toString((whm + am))), (acc._3 :+ toString((bpm - am))), (acc._4 + am))
724+ }
725+
726+ let m = {
727+ let $l = matParts
728+ let $s = size($l)
729+ let $acc0 = $Tuple4(0, nil, nil, r._4)
730+ func $f1_1 ($a,$i) = if (($i >= $s))
731+ then $a
732+ else mvM($a, $l[$i])
733+
734+ func $f1_2 ($a,$i) = if (($i >= $s))
735+ then $a
736+ else throw("List size exceeds 6")
737+
738+ $f1_2($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($acc0, 0), 1), 2), 3), 4), 5), 6)
739+ }
740+ func mvP (acc,item) = {
741+ let i = acc._1
742+ let am = parseIntValue(item)
743+ let whp = parseIntValue(currWhProd[i])
744+ let bpp = parseIntValue(currentPackProd[i])
745+ if ((am == 0))
746+ then $Tuple4((i + 1), (acc._2 :+ currWhProd[i]), (acc._3 :+ currentPackProd[i]), acc._4)
747+ else if ((am > 0))
748+ then if ((am > bpp))
749+ then throw((((("Attempt to take " + item) + " from backpack, but only ") + toString(bpp)) + " available"))
750+ else $Tuple4((i + 1), (acc._2 :+ toString((whp + am))), (acc._3 :+ toString((bpp - am))), (acc._4 + am))
751+ else if ((-(am) > whp))
752+ then throw((((("Attempt to take " + toString(-(am))) + " from warehouse, but only ") + toString(whp)) + " available"))
753+ else $Tuple4((i + 1), (acc._2 :+ toString((whp + am))), (acc._3 :+ toString((bpp - am))), (acc._4 + am))
754+ }
755+
756+ let p = {
757+ let $l = prodParts
758+ let $s = size($l)
759+ let $acc0 = $Tuple4(0, nil, nil, m._4)
760+ func $f2_1 ($a,$i) = if (($i >= $s))
761+ then $a
762+ else mvP($a, $l[$i])
763+
764+ func $f2_2 ($a,$i) = if (($i >= $s))
765+ then $a
766+ else throw("List size exceeds 50")
767+
768+ $f2_2($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40), 41), 42), 43), 44), 45), 46), 47), 48), 49), 50)
769+ }
770+ let volSaldo = p._4
771+ if ((volSaldo > whSpaceLeft))
772+ then throw((((("Attempt to put total " + toString(volSaldo)) + " stuff, but only ") + toString(whSpaceLeft)) + " warehouse space left"))
773+ else $Tuple6(makeString(r._2, "_"), makeString(m._2, "_"), makeString(p._2, "_"), makeString(r._3, "_"), makeString(m._3, "_"), makeString(p._3, "_"))
774+ }
269775 }
270776
271777
272-func landOrderInfoArray (landAssetId,owner) = if ((landAssetId == ""))
273- then throw("landAssetId is required")
778+func expeditionInternal (caller,txId) = {
779+ let userAddr = toString(caller)
780+ let bigNum = abs(toBigInt(txId))
781+ let freeNum = valueOrElse(getInteger(keyNextFreeLandNum()), (PRESALENUMLANDS + 1))
782+ let landNum = toString(freeNum)
783+ let continentIdx = toInt((bigNum % FIVEX))
784+ let terrains = genTerrains(bigNum, continentIdx)
785+ let continent = continents[continentIdx]
786+ let issue = Issue(keyNftName(landNum, "S"), makeString([landNum, "S", terrains, continent], "_"), 1, 0, false)
787+ let assetId = calculateAssetId(issue)
788+ let id = toBase58String(assetId)
789+ $Tuple2([IntegerEntry(keyNextFreeLandNum(), (freeNum + 1)), issue, StringEntry(keyLandToAssetId(landNum), id), StringEntry(keyLandAssetIdToOwner(id), userAddr), StringEntry(keyLandNumToOwner(landNum), userAddr), IntegerEntry(keyInfraLevelByAssetId(id), 0), IntegerEntry(keyInfraLevelByAssetIdAndOwner(id, userAddr), 0), ScriptTransfer(caller, 1, assetId)], $Tuple2(id, continent))
790+ }
791+
792+
793+func expeditionCommon (shouldUseMat,caller,txId,message,sig) = if (!(sigVerify_8Kb(message, sig, pub)))
794+ then throw("signature does not match")
274795 else {
275- let a = value(assetInfo(fromBase58String(landAssetId)))
276- let d = split(a.description, "_")
277- let pieces = numPiecesBySize(d[recLandSize])
278- let productivity = applyBonuses(landAssetId, pieces)
279-[("%s%s__assetId__" + landAssetId), ("%s%s__owner__" + owner), ("%s%s__warehouse__" + makeString(getWarehouse(keyWarehouseByLand(landAssetId), (pieces / SSIZE), productivity._1), ":")), ("%s%s__landOrder__" + valueOrElse(getString(economyContract, keyOrderByLand(landAssetId)), "0@0_0@0_0@0_0@0_0@0_0@0:0@0_0@0_0@0_0@0_0@0_0@0:"))]
796+ let parts = split(toUtf8String(message), ";")
797+ let hp = split(split(parts[0], "|")[0], "_")
798+ let curHP = parseIntValue(hp[0])
799+ let newHP = parseIntValue(hp[1])
800+ let locAndTime = split(parts[1], ":")
801+ let targetLocation = split(locAndTime[0], "_")
802+ if ((targetLocation[1] != "E"))
803+ then throw("expedition target location type should be E")
804+ else {
805+ let time = parseIntValue(locAndTime[1])
806+ if (if ((time > (lastBlock.timestamp + FIVEMINUTESMILLIS)))
807+ then true
808+ else ((lastBlock.timestamp - FIVEMINUTESMILLIS) > time))
809+ then throw("signature outdated")
810+ else {
811+ let userAddr = toString(caller)
812+ let duckAssetId = valueOrErrorMessage(getString(keyStakedDuckByOwner(userAddr)), "You don't have a duck staked")
813+ let keyHealth = keyDuckHealth(duckAssetId)
814+ let oldFromState = valueOrElse(getInteger(keyHealth), 100)
815+ if ((oldFromState != curHP))
816+ then throw(((("oldHealth=" + toString(valueOrElse(getInteger(keyHealth), 100))) + " from state does not match one from flight log=") + toString(curHP)))
817+ else if ((0 >= curHP))
818+ then throw("You can't fly with zero health")
819+ else if ((0 >= newHP))
820+ then $Tuple2(((if (!(shouldUseMat))
821+ then [ScriptTransfer(caller, EXPUSDN, usdnAssetId)]
822+ else nil) :+ IntegerEntry(keyHealth, 0)), "")
823+ else {
824+ let bpKey = keyBackpackByDuck(duckAssetId)
825+ let currentPack = getBackpack(bpKey)
826+ let mList = split(currentPack[bpIdxMat], "_")
827+ let newMat = makeString(subtractMaterials(shouldUseMat, mList, EXPMATERIALS), "_")
828+ let e = expeditionInternal(caller, txId)
829+ let id = e._2._1
830+ $Tuple2((((e._1 :+ StringEntry(keyDuckLocation(duckAssetId), makeString([e._2._2, "L", id], "_"))) :+ IntegerEntry(keyHealth, newHP)) :+ StringEntry(bpKey, makeString([currentPack[bpIdxLevel], currentPack[bpIdxRes], newMat, currentPack[bpIdxProd]], ":"))), id)
831+ }
832+ }
833+ }
280834 }
281835
282836
837+func applyBonuses (landAssetId,pieces) = {
838+ let infraLevel = valueOrElse(getInteger(keyInfraLevelByAssetId(landAssetId)), 0)
839+ let artPieces = valueOrElse(getInteger(keyLandArtStatusByTypeAndAssetId(ARTPRESALE, landAssetId)), if (valueOrElse(getBoolean(keyPresaleArtActivatedByAssetId(landAssetId)), false))
840+ then pieces
841+ else 0)
842+ ((DAILYRESBYPIECE + fraction(DAILYRESBYPIECE, infraLevel, 4)) + fraction(DAILYRESBYPIECE, (artPieces * 3), (pieces * 20)))
843+ }
844+
845+
846+func checkClaimConditions (addr,claimMode,landAssetIdIn) = {
847+ let $t02363024169 = if ((claimMode == claimModeWh))
848+ then $Tuple2(landAssetIdIn, valueOrElse(getString(keyStakedDuckByOwner(addr)), ""))
849+ else {
850+ let duckAssetId = valueOrErrorMessage(getString(keyStakedDuckByOwner(addr)), "You don't have a duck staked")
851+ let curLocation = valueOrElse(getString(keyDuckLocation(duckAssetId)), DEFAULTLOCATION)
852+ let loc = split(value(curLocation), "_")
853+ if ((loc[locIdxType] != "L"))
854+ then throw((("Duck location type is " + loc[locIdxType]) + ", but should be L"))
855+ else $Tuple2(loc[locIdxId], duckAssetId)
856+ }
857+ let landAssetId = $t02363024169._1
858+ let duckId = $t02363024169._2
859+ let asset = value(assetInfo(fromBase58String(landAssetId)))
860+ let timeKey = keyStakedTimeByAssetId(landAssetId)
861+ let savedTime = valueOrErrorMessage(getInteger(timeKey), (("Land " + asset.name) + " is not staked"))
862+ let owner = valueOrErrorMessage(getString(keyLandAssetIdToOwner(landAssetId)), (("NFT " + asset.name) + " is orphaned"))
863+ if ((owner != addr))
864+ then throw((LANDPREFIX + " is not yours"))
865+ else {
866+ let d = split(asset.description, "_")
867+ $Tuple4(duckId, landAssetId, d, savedTime)
868+ }
869+ }
870+
871+
872+func claimResInternal (addr,amount,claimMode,landAssetIdIn) = if ((0 > amount))
873+ then throw("Negative amount")
874+ else {
875+ let c = checkClaimConditions(addr, claimMode, landAssetIdIn)
876+ let landSize = c._3[recLandSize]
877+ let terrainCounts = countTerrains(c._3[recTerrains])
878+ let deltaTime = (lastBlock.timestamp - c._4)
879+ if ((0 > deltaTime))
880+ then throw(((("Saved timestamp is in future, saved = " + toString(c._4)) + ", current = ") + toString(lastBlock.timestamp)))
881+ else {
882+ let pieces = numPiecesBySize(landSize)
883+ let dailyProductionByPiece = applyBonuses(c._2, pieces)
884+ let availRes = fraction(deltaTime, (dailyProductionByPiece * pieces), DAYMILLIS)
885+ if ((amount > availRes))
886+ then throw(((("Not enough resources, available = " + toString(availRes)) + ", requested = ") + toString(amount)))
887+ else {
888+ let newDeltaTime = fraction((availRes - amount), DAYMILLIS, (dailyProductionByPiece * pieces))
889+ let newTimestamp = (lastBlock.timestamp - newDeltaTime)
890+ let landIndex = (pieces / SSIZE)
891+ let resToClaim = virtClaim(terrainCounts, (deltaTime - newDeltaTime), landIndex, dailyProductionByPiece)
892+ let whKey = keyWarehouseByLand(c._2)
893+ let infraLevel = valueOrElse(getInteger(keyInfraLevelByAssetId(c._2)), 0)
894+ let currentWh = getWarehouse(whKey, landIndex, infraLevel)
895+ let currWhResVol = getWarehouseCurrResVolume(currentWh)
896+ let currWhMatVol = getWarehouseCurrMatVolume(currentWh)
897+ let currWhGoodsVol = getWarehouseCurrGoodsVolume(currentWh)
898+ let currWhLockedVol = parseIntValue(currentWh[whIdxLockedVol])
899+ let whSpaceLeft = ((((getWarehouseVolume(currentWh[whIdxVol]) - currWhResVol) - currWhMatVol) - currWhGoodsVol) - currWhLockedVol)
900+ if (if ((claimMode == claimModeWh))
901+ then (amount > whSpaceLeft)
902+ else false)
903+ then throw((("Only " + toString(whSpaceLeft)) + " space left in warehouse"))
904+ else {
905+ let bpKey = keyBackpackByDuck(c._1)
906+ let currentPack = getBackpack(bpKey)
907+ let currentPackRes = split(currentPack[bpIdxRes], "_")
908+ let currentWhRes = split(currentWh[whIdxRes], "_")
909+ let $t02681727320 = if ((claimMode == claimModeWh))
910+ then $Tuple2(addRes(currentWhRes, terrainCounts, (deltaTime - newDeltaTime), landIndex, dailyProductionByPiece), currentPack[bpIdxRes])
911+ else if ((claimMode == claimModeDuck))
912+ then $Tuple2(currentWh[whIdxRes], addRes(currentPackRes, terrainCounts, (deltaTime - newDeltaTime), landIndex, dailyProductionByPiece))
913+ else distributeRes(currentWhRes, currentPackRes, resToClaim, whSpaceLeft)
914+ let whRes = $t02681727320._1
915+ let bpRes = $t02681727320._2
916+ $Tuple5([IntegerEntry(keyStakedTimeByAssetId(c._2), newTimestamp), IntegerEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, c._2, addr), newTimestamp)], bpKey, [currentPack[bpIdxLevel], bpRes, currentPack[bpIdxMat], currentPack[bpIdxProd]], whKey, [currentWh[whIdxVol], whRes, currentWh[whIdxMat], currentWh[whIdxProd], currentWh[whIdxLockedVol]])
917+ }
918+ }
919+ }
920+ }
921+
922+
923+func claimAll (addr,landAssetId,pieces,claimMode) = {
924+ let timeKey = keyStakedTimeByAssetId(landAssetId)
925+ let savedTime = value(getInteger(timeKey))
926+ let availRes = (fraction((lastBlock.timestamp - savedTime), applyBonuses(landAssetId, pieces), DAYMILLIS) * pieces)
927+ claimResInternal(addr, availRes, claimMode, landAssetId)
928+ }
929+
930+
931+func upInfraCommon (shouldUseMat,caller,paymentAmount,landAssetId) = {
932+ let addr = toString(caller)
933+ let c = checkClaimConditions(addr, claimModeWhThenDuck, landAssetId)
934+ let pieces = numPiecesBySize(c._3[recLandSize])
935+ let infraKey = keyInfraLevelByAssetId(c._2)
936+ let curLevel = valueOrElse(getInteger(infraKey), 0)
937+ if ((curLevel >= 3))
938+ then throw("Currently max infrastructure level = 3")
939+ else {
940+ let newLevel = (curLevel + 1)
941+ let cost = fraction(InfraUpgradeCostSUsdn, (pieces * newLevel), SSIZE)
942+ if (if (!(shouldUseMat))
943+ then (paymentAmount != cost)
944+ else false)
945+ then throw(("Payment attached should be " + toString(cost)))
946+ else {
947+ let bpKey = keyBackpackByDuck(c._1)
948+ let currentPack = getBackpack(bpKey)
949+ let mList = split(currentPack[bpIdxMat], "_")
950+ let newMat = makeString(subtractMaterials(shouldUseMat, mList, fraction(InfraUpgradeCostS, (pieces * newLevel), SSIZE)), "_")
951+ let claimResult = claimAll(addr, c._2, pieces, claimModeWhThenDuck)
952+ let whData = claimResult._5
953+ let newVolData = makeString([split(whData[whIdxVol], "_")[0], toString(newLevel)], "_")
954+ $Tuple2(([IntegerEntry(infraKey, newLevel), IntegerEntry(keyInfraLevelByAssetIdAndOwner(c._2, addr), newLevel), StringEntry(bpKey, makeString([currentPack[bpIdxLevel], claimResult._3[bpIdxRes], newMat, currentPack[bpIdxProd]], ":")), StringEntry(claimResult._4, makeString([newVolData, whData[whIdxRes], whData[whIdxMat], whData[whIdxProd], whData[whIdxLockedVol]], ":"))] ++ claimResult._1), newLevel)
955+ }
956+ }
957+ }
958+
959+
960+func activatePresaleArt (addr,landAssetIdIn) = {
961+ let c = checkClaimConditions(addr, claimModeWhThenDuck, landAssetIdIn)
962+ let landAssetId = c._2
963+ let activationKey = keyPresaleArtActivatedByAssetId(landAssetId)
964+ if (valueOrElse(getBoolean(activationKey), false))
965+ then throw("Presale artifact is already activated")
966+ else if ((parseIntValue(c._3[recLandNum]) > PRESALENUMLANDS))
967+ then throw((((LANDPREFIX + " ") + landAssetId) + " is not eligible for presale artifact"))
968+ else {
969+ let pieces = numPiecesBySize(c._3[recLandSize])
970+ let claimResult = claimAll(addr, landAssetId, pieces, claimModeWhThenDuck)
971+ ((((((claimResult._1 :+ BooleanEntry(activationKey, true)) :+ BooleanEntry(keyPresaleArtActivatedByAssetIdAndOwner(landAssetId, addr), true)) :+ IntegerEntry(keyLandArtStatusByTypeAndAssetId(ARTPRESALE, landAssetId), pieces)) :+ IntegerEntry(keyLandArtStatusByTypeAssetIdAndOwner(ARTPRESALE, landAssetId, addr), pieces)) :+ StringEntry(claimResult._2, makeString(claimResult._3, ":"))) :+ StringEntry(claimResult._4, makeString(claimResult._5, ":")))
972+ }
973+ }
974+
975+
976+func mergeInternal (newLandSize,newLevel,formula,addr,landAssetIds,txId,needMat) = {
977+ let duckAssetId = valueOrErrorMessage(getString(keyStakedDuckByOwner(addr)), "You don't have a duck staked")
978+ func checkMerge (acc,landAssetId) = {
979+ let asset = value(assetInfo(fromBase58String(landAssetId)))
980+ let timeKey = keyStakedTimeByAssetId(landAssetId)
981+ let savedTime = valueOrErrorMessage(getInteger(timeKey), (("NFT " + asset.name) + " is not staked"))
982+ let owner = valueOrErrorMessage(getString(keyLandAssetIdToOwner(landAssetId)), (("NFT " + asset.name) + " is orphaned"))
983+ if ((owner != addr))
984+ then throw((LANDPREFIX + " is not yours"))
985+ else {
986+ let d = split(asset.description, "_")
987+ let continent = d[recContinent]
988+ if (if ((acc._3 != ""))
989+ then (acc._3 != continent)
990+ else false)
991+ then throw("Lands should be on the same continent to merge")
992+ else {
993+ let landSize = d[recLandSize]
994+ let sizesIn = acc._1
995+ let i = valueOrErrorMessage(indexOf(sizesIn, landSize), "You haven't passed all the lands needed")
996+ let sizesOut = (take(sizesIn, i) + drop(sizesIn, (i + 1)))
997+ let pieces = numPiecesBySize(landSize)
998+ let arts = (acc._2 + valueOrElse(getInteger(keyLandArtStatusByTypeAndAssetId(ARTPRESALE, landAssetId)), if (valueOrElse(getBoolean(keyPresaleArtActivatedByAssetId(landAssetId)), false))
999+ then pieces
1000+ else 0))
1001+ let infraLevel = valueOrElse(getInteger(keyInfraLevelByAssetId(landAssetId)), 0)
1002+ let reqLevel = match landSize {
1003+ case _ =>
1004+ if (("S" == $match0))
1005+ then 3
1006+ else if (("M" == $match0))
1007+ then 4
1008+ else if (("L" == $match0))
1009+ then 5
1010+ else if (("XL" == $match0))
1011+ then 6
1012+ else throw("Only S, M, L, XL can merge")
1013+ }
1014+ if ((infraLevel != reqLevel))
1015+ then throw("All lands should be maxed to merge")
1016+ else {
1017+ let landNum = d[recLandNum]
1018+ let terrainCounts = countTerrains(d[recTerrains])
1019+ let deltaTime = (lastBlock.timestamp - savedTime)
1020+ if ((0 > deltaTime))
1021+ then throw(((("Saved timestamp is in future, saved = " + toString(savedTime)) + ", current = ") + toString(lastBlock.timestamp)))
1022+ else {
1023+ let dailyProductionByPiece = applyBonuses(landAssetId, pieces)
1024+ let landIndex = (pieces / SSIZE)
1025+ let bpRes = addRes(split(acc._4, "_"), terrainCounts, deltaTime, landIndex, dailyProductionByPiece)
1026+ let props = updateProportionsInternal(split(acc._6, "_"), terrainCounts, landIndex, -1)
1027+ let lands = acc._7
1028+ let idx = indexOf(lands, landAssetId)
1029+ if (!(isDefined(idx)))
1030+ then throw(("Your staked lands don't contain " + landAssetId))
1031+ else $Tuple7(sizesOut, arts, continent, bpRes, ((((((((((((((acc._5 :+ DeleteEntry(keyStakedTimeByAssetId(landAssetId))) :+ DeleteEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, landAssetId, addr))) :+ DeleteEntry(keyLandToAssetId(landNum))) :+ DeleteEntry(keyNftName(landNum, landSize))) :+ DeleteEntry(keyLandAssetIdToOwner(landAssetId))) :+ DeleteEntry(keyInfraLevelByAssetId(landAssetId))) :+ DeleteEntry(keyInfraLevelByAssetIdAndOwner(landAssetId, addr))) :+ DeleteEntry(keyPresaleArtActivatedByAssetId(landAssetId))) :+ DeleteEntry(keyPresaleArtActivatedByAssetIdAndOwner(landAssetId, addr))) :+ DeleteEntry(keyLandArtStatusByTypeAndAssetId(ARTPRESALE, landAssetId))) :+ DeleteEntry(keyLandArtStatusByTypeAssetIdAndOwner(ARTPRESALE, landAssetId, addr))) :+ DeleteEntry(keyLandNumToOwner(landNum))) :+ DeleteEntry(keyWarehouseByLand(landAssetId))) :+ Burn(fromBase58String(landAssetId), 1)), props, removeByIndex(lands, value(idx)))
1032+ }
1033+ }
1034+ }
1035+ }
1036+ }
1037+
1038+ let bpKey = keyBackpackByDuck(duckAssetId)
1039+ let currentPack = getBackpack(bpKey)
1040+ let propStr = valueOrElse(getString(keyResProportions()), "0_0_0_0_0_0")
1041+ let landsKey = keyStakedLandsByOwner(addr)
1042+ let landsStr = getString(landsKey)
1043+ let landsIn = if (isDefined(landsStr))
1044+ then split_51C(value(landsStr), "_")
1045+ else nil
1046+ let r = {
1047+ let $l = landAssetIds
1048+ let $s = size($l)
1049+ let $acc0 = $Tuple7(formula, 0, "", currentPack[bpIdxRes], nil, propStr, landsIn)
1050+ func $f0_1 ($a,$i) = if (($i >= $s))
1051+ then $a
1052+ else checkMerge($a, $l[$i])
1053+
1054+ func $f0_2 ($a,$i) = if (($i >= $s))
1055+ then $a
1056+ else throw("List size exceeds 5")
1057+
1058+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5)
1059+ }
1060+ let continent = r._3
1061+ let continentIdx = valueOrErrorMessage(indexOf(continents, continent), ("Unknown continent: " + continent))
1062+ let terrains = genTerrains(abs(toBigInt(txId)), continentIdx)
1063+ let freeNum = valueOrElse(getInteger(keyNextFreeLandNum()), (PRESALENUMLANDS + 1))
1064+ let newLandNum = toString(freeNum)
1065+ let issue = Issue(keyNftName(newLandNum, newLandSize), makeString([newLandNum, newLandSize, terrains, continent], "_"), 1, 0, false)
1066+ let assetId = calculateAssetId(issue)
1067+ let newLandAssetId = toBase58String(assetId)
1068+ let newMat = makeString(subtractMaterials((needMat > 0), split(currentPack[bpIdxMat], "_"), needMat), "_")
1069+ $Tuple2(((((((((((((((r._5 :+ (if ((size(r._7) > 0))
1070+ then StringEntry(landsKey, makeString_11C(r._7, "_"))
1071+ else DeleteEntry(landsKey))) :+ IntegerEntry(keyNextFreeLandNum(), (freeNum + 1))) :+ issue) :+ StringEntry(keyLandToAssetId(newLandNum), newLandAssetId)) :+ StringEntry(keyLandAssetIdToOwner(newLandAssetId), addr)) :+ StringEntry(keyLandNumToOwner(newLandNum), addr)) :+ IntegerEntry(keyLandArtStatusByTypeAndAssetId(ARTPRESALE, newLandAssetId), r._2)) :+ IntegerEntry(keyLandArtStatusByTypeAssetIdAndOwner(ARTPRESALE, newLandAssetId, addr), r._2)) :+ IntegerEntry(keyInfraLevelByAssetId(newLandAssetId), newLevel)) :+ IntegerEntry(keyInfraLevelByAssetIdAndOwner(newLandAssetId, addr), newLevel)) :+ StringEntry(bpKey, makeString([currentPack[bpIdxLevel], r._4, newMat, currentPack[bpIdxProd]], ":"))) :+ StringEntry(keyResProportions(), r._6)) :+ StringEntry(keyDuckLocation(duckAssetId), makeString([continent, "L", newLandAssetId], "_"))) :+ ScriptTransfer(addressFromStringValue(addr), 1, assetId)), newLandAssetId)
1072+ }
1073+
1074+
1075+func s2m (addr,landAssetIds,txId) = mergeInternal("M", 3, "SSSS", addr, landAssetIds, txId, 0)
1076+
1077+
1078+func m2l (addr,landAssetIds,txId,shouldUseMat,paymentAmount) = {
1079+ let cost = (InfraUpgradeCostSUsdn * 4)
1080+ if (if (!(shouldUseMat))
1081+ then (paymentAmount != cost)
1082+ else false)
1083+ then throw(("Payment attached should be " + toString(cost)))
1084+ else mergeInternal("L", 4, "SMM", addr, landAssetIds, txId, (InfraUpgradeCostS * 4))
1085+ }
1086+
1087+
1088+func l2xl (addr,landAssetIds,txId,shouldUseMat,paymentAmount) = {
1089+ let cost = (InfraUpgradeCostSUsdn * 47)
1090+ if (if (!(shouldUseMat))
1091+ then (paymentAmount != cost)
1092+ else false)
1093+ then throw(("Payment attached should be " + toString(cost)))
1094+ else mergeInternal("XL", 5, "SSSML", addr, landAssetIds, txId, (InfraUpgradeCostS * 47))
1095+ }
1096+
1097+
1098+func xl2xxl (addr,landAssetIds,txId,shouldUseMat,paymentAmount) = {
1099+ let cost = (InfraUpgradeCostSUsdn * 54)
1100+ if (if (!(shouldUseMat))
1101+ then (paymentAmount != cost)
1102+ else false)
1103+ then throw(("Payment attached should be " + toString(cost)))
1104+ else mergeInternal("XXL", 6, "LXL", addr, landAssetIds, txId, (InfraUpgradeCostS * 54))
1105+ }
1106+
1107+
1108+func mergeCommon (shouldUseMat,addr,paymentAmount,landAssetIds,txId) = {
1109+ let mergeResult = match size(landAssetIds) {
1110+ case _ =>
1111+ if ((4 == $match0))
1112+ then s2m(addr, landAssetIds, txId)
1113+ else if ((3 == $match0))
1114+ then m2l(addr, landAssetIds, txId, shouldUseMat, paymentAmount)
1115+ else if ((5 == $match0))
1116+ then l2xl(addr, landAssetIds, txId, shouldUseMat, paymentAmount)
1117+ else if ((2 == $match0))
1118+ then xl2xxl(addr, landAssetIds, txId, shouldUseMat, paymentAmount)
1119+ else throw("Unknown merge")
1120+ }
1121+ mergeResult
1122+ }
1123+
1124+
1125+func prolog (i) = if (if ((i.originCaller != restContract))
1126+ then valueOrElse(getBoolean(keyBlocked()), false)
1127+ else false)
1128+ then throw("Contracts are under maintenance")
1129+ else StringEntry(keyLastTxIdByUser(toString(i.originCaller)), toBase58String(i.transactionId))
1130+
1131+
2831132 @Callable(i)
284-func constructorV1 (stakingContract,economyContract,governanceContract) = if ((i.caller != this))
285- then throw("permissions denied")
286- else [StringEntry(keyRestCfg(), makeString(["%s%s%s", stakingContract, economyContract, governanceContract], SEP))]
1133+func constructorV1 (restAddr) = if ((i.caller != this))
1134+ then throw("Permission denied")
1135+ else [StringEntry(keyRestAddress(), restAddr)]
2871136
2881137
2891138
2901139 @Callable(i)
291-func walletInfoREADONLY (userAddressOpt) = $Tuple2(nil, walletInternal(userAddressOpt))
1140+func setBlocked (isBlocked) = if ((i.caller != this))
1141+ then throw("permission denied")
1142+ else [BooleanEntry(keyBlocked(), isBlocked)]
2921143
2931144
2941145
2951146 @Callable(i)
296-func duckInfoREADONLY (duckAssetId,userAddressOpt) = {
297- let addr = addressFromString(userAddressOpt)
298- let duckAsset = fromBase58String(duckAssetId)
299- if ((duckAssetId == ""))
300- then throw("duckAssetId is required")
1147+func stakeLand () = {
1148+ let prologAction = prolog(i)
1149+ if ((size(i.payments) != 1))
1150+ then throw("Exactly one payment required")
3011151 else {
302- let duckOwner = getString(stakingContract, keyDuckIdToOwner(duckAssetId))
303- let owner = if (isDefined(duckOwner))
304- then value(duckOwner)
305- else if (if (isDefined(addr))
306- then (assetBalance(value(addr), duckAsset) == 1)
307- else false)
308- then userAddressOpt
309- else ""
310- $Tuple2(nil, $Tuple2(duckInfoArray(duckAssetId, owner, duckInfoTuple(duckAssetId)), walletInternal(userAddressOpt)))
1152+ let pmt = value(i.payments[0])
1153+ let assetId = value(pmt.assetId)
1154+ let address = toString(i.caller)
1155+ if ((pmt.amount != 1))
1156+ then throw((("NFT " + LANDPREFIX) + " token should be attached as payment"))
1157+ else {
1158+ let asset = value(assetInfo(assetId))
1159+ if ((asset.issuer != this))
1160+ then throw("Unknown issuer of token")
1161+ else if (!(contains(asset.name, LANDPREFIX)))
1162+ then throw((("Only NFT " + LANDPREFIX) + " tokens are accepted"))
1163+ else {
1164+ let landNumSize = drop(asset.name, 4)
1165+ let landNum = if (contains(landNumSize, "XXL"))
1166+ then dropRight(landNumSize, 3)
1167+ else if (contains(landNumSize, "XL"))
1168+ then dropRight(landNumSize, 2)
1169+ else dropRight(landNumSize, 1)
1170+ if (!(isDefined(parseInt(landNum))))
1171+ then throw(("Cannot parse land number from " + asset.name))
1172+ else {
1173+ let landAssetId = toBase58String(assetId)
1174+ let timeKey = keyStakedTimeByAssetId(landAssetId)
1175+ if (isDefined(getInteger(timeKey)))
1176+ then throw((("NFT " + asset.name) + " is already staked"))
1177+ else {
1178+ let d = split(asset.description, "_")
1179+ let terrainCounts = countTerrains(d[recTerrains])
1180+ let props = updateProportions(terrainCounts, (numPiecesBySize(d[recLandSize]) / SSIZE), 1)
1181+ let landsStr = getString(keyStakedLandsByOwner(address))
1182+ let lands = if (isDefined(landsStr))
1183+ then split_51C(value(landsStr), "_")
1184+ else nil
1185+ if (containsElement(lands, landAssetId))
1186+ then throw(("Your staked lands already contain " + landAssetId))
1187+ else [IntegerEntry(timeKey, lastBlock.timestamp), IntegerEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, landAssetId, address), lastBlock.timestamp), StringEntry(keyStakedLandsByOwner(address), makeString_11C((lands :+ landAssetId), "_")), StringEntry(keyLandAssetIdToOwner(landAssetId), address), StringEntry(keyLandNumToOwner(landNum), address), StringEntry(keyResProportions(), props), prologAction]
1188+ }
1189+ }
1190+ }
1191+ }
3111192 }
3121193 }
3131194
3141195
3151196
3161197 @Callable(i)
317-func landInfoREADONLY (landAssetId,userAddressOpt) = {
318- let addr = addressFromString(userAddressOpt)
319- let landAsset = fromBase58String(landAssetId)
320- if ((landAssetId == ""))
321- then throw("landAssetId is required")
1198+func unstakeLand (landAssetIdIn) = {
1199+ let prologAction = prolog(i)
1200+ if ((size(i.payments) != 0))
1201+ then throw("unstake doesn't require any payments")
3221202 else {
323- let stakedTime = valueOrElse(getInteger(stakingContract, keyStakedTimeByAssetId(landAssetId)), 0)
324- let owner = if ((stakedTime > 0))
325- then value(getString(stakingContract, keyLandAssetIdToOwner(landAssetId)))
326- else if (if (isDefined(addr))
327- then (assetBalance(value(addr), landAsset) == 1)
328- else false)
329- then userAddressOpt
330- else ""
331- let stakedDuck = getString(stakingContract, keyStakedDuckByOwner(userAddressOpt))
332- let duckInf = if (if (isDefined(addr))
333- then isDefined(stakedDuck)
334- else false)
335- then {
336- let duckAssetId = value(stakedDuck)
337- $Tuple2(duckAssetId, duckInfoTuple(duckAssetId))
1203+ let addr = toString(i.caller)
1204+ let c = checkClaimConditions(addr, claimModeDuck, landAssetIdIn)
1205+ let landAssetId = c._2
1206+ let landsKey = keyStakedLandsByOwner(addr)
1207+ let terrainCounts = countTerrains(c._3[recTerrains])
1208+ let pieces = numPiecesBySize(c._3[recLandSize])
1209+ let props = updateProportions(terrainCounts, (pieces / SSIZE), -1)
1210+ let claimResult = claimAll(addr, landAssetId, pieces, claimModeDuck)
1211+ let lands = split_51C(valueOrElse(getString(landsKey), ""), "_")
1212+ let idx = indexOf(lands, landAssetId)
1213+ if (!(isDefined(idx)))
1214+ then throw(("Your staked lands don't contain " + landAssetId))
1215+ else {
1216+ let t = value(blockInfoByHeight(height)).timestamp
1217+ let releaseTime = valueOrElse(getInteger(govContract, keyUserGwlReleaseTime(addr)), 0)
1218+ if ((releaseTime >= t))
1219+ then throw(("Your gWL are taking part in voting, cannot unstake until " + toString(releaseTime)))
1220+ else [ScriptTransfer(i.caller, 1, fromBase58String(landAssetId)), DeleteEntry(keyStakedTimeByAssetId(landAssetId)), DeleteEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, landAssetId, addr)), StringEntry(keyResProportions(), props), StringEntry(claimResult._2, makeString(claimResult._3, ":")), if ((size(lands) > 1))
1221+ then StringEntry(landsKey, makeString_11C(removeByIndex(lands, value(idx)), "_"))
1222+ else DeleteEntry(landsKey), prologAction]
3381223 }
339- else $Tuple2("", $Tuple5(-1, "", "", -1, ""))
340- $Tuple2(nil, $Tuple3(landInfoArray(landAssetId, owner, stakedTime), duckInfoArray(duckInf._1, userAddressOpt, duckInf._2), walletInternal(userAddressOpt)))
3411224 }
3421225 }
3431226
3441227
3451228
3461229 @Callable(i)
347-func stakedLandsInfoREADONLY (myAddress,landOwnerAddress) = if ((landOwnerAddress == ""))
348- then throw("landOwnerAddress is required")
349- else {
350- let myAddr = addressFromString(myAddress)
351- let landsStr = getString(stakingContract, keyStakedLandsByOwner(landOwnerAddress))
352- let lands = if (isDefined(landsStr))
353- then split_51C(value(landsStr), "_")
354- else nil
355- func oneLand (acc,landAssetId) = {
356- let landAsset = fromBase58String(landAssetId)
357- if ((landAssetId == ""))
358- then throw("landAssetId is required")
1230+func stakeDuck () = {
1231+ let prologAction = prolog(i)
1232+ if ((size(i.payments) != 1))
1233+ then throw("Exactly one payment required")
1234+ else {
1235+ let pmt = value(i.payments[0])
1236+ let assetId = value(pmt.assetId)
1237+ let address = toString(i.caller)
1238+ if ((pmt.amount != 1))
1239+ then throw((("NFT " + DUCKPREFIX) + " token should be attached as payment"))
3591240 else {
360- let stakedTime = valueOrElse(getInteger(stakingContract, keyStakedTimeByAssetId(landAssetId)), 0)
361- let descr = value(assetInfo(landAsset)).description
362- let d = split(descr, "_")
363- let pieces = numPiecesBySize(d[recLandSize])
364- let productivity = applyBonuses(landAssetId, pieces)
365- let deltaTime = (lastBlock.timestamp - stakedTime)
366- let availRes = fraction(deltaTime, (productivity._3 * pieces), DAYMILLIS)
367- (acc :+ [("%s%s__landAssetId__" + landAssetId), ("%s%d__stakedTime__" + toString(stakedTime)), ("%s%s__description__" + descr), ("%s%d__infraLevel__" + toString(productivity._1)), makeString(["%s%s", "landArtefacts", ("PRESALE:" + toString(productivity._2))], SEP), ("%s%s__availRes__" + toString(availRes))])
1241+ let asset = value(assetInfo(assetId))
1242+ if (if ((asset.issuer != incubatorAddr))
1243+ then (asset.issuer != breederAddr)
1244+ else false)
1245+ then throw((("Unknown issuer of " + DUCKPREFIX) + " token"))
1246+ else if (!(contains(asset.name, DUCKPREFIX)))
1247+ then throw((("Only NFT " + DUCKPREFIX) + " tokens are accepted"))
1248+ else {
1249+ let assetIdStr = toBase58String(assetId)
1250+ let timeKey = keyStakedTimeByAssetId(assetIdStr)
1251+ if (isDefined(getInteger(timeKey)))
1252+ then throw((("NFT " + asset.name) + " is already staked"))
1253+ else if (isDefined(getString(keyStakedDuckByOwner(address))))
1254+ then throw(("You already staked one duck: " + asset.name))
1255+ else {
1256+ let locKey = keyDuckLocation(assetIdStr)
1257+ let location = getString(locKey)
1258+ let bpKey = keyBackpackByDuck(assetIdStr)
1259+ let backpack = getString(bpKey)
1260+ ([IntegerEntry(timeKey, lastBlock.timestamp), IntegerEntry(keyStakedTimeByTypeAssetIdAndOwner(DUCKPREFIX, toBase58String(assetId), address), lastBlock.timestamp), StringEntry(keyDuckIdToOwner(assetIdStr), address), StringEntry(keyStakedDuckByOwner(address), assetIdStr)] ++ (if (isDefined(location))
1261+ then nil
1262+ else ([StringEntry(locKey, DEFAULTLOCATION)] ++ (if (isDefined(backpack))
1263+ then nil
1264+ else (([StringEntry(bpKey, "0:0_0_0_0_0_0:0_0_0_0_0_0:")] :+ IntegerEntry(keyDuckHealth(assetIdStr), 100)) :+ prologAction)))))
1265+ }
1266+ }
3681267 }
3691268 }
1269+ }
3701270
371- let r = {
372- let $l = lands
373- let $s = size($l)
374- let $acc0 = nil
375- func $f0_1 ($a,$i) = if (($i >= $s))
376- then $a
377- else oneLand($a, $l[$i])
3781271
379- func $f0_2 ($a,$i) = if (($i >= $s))
380- then $a
381- else throw("List size exceeds 100")
3821272
383- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40), 41), 42), 43), 44), 45), 46), 47), 48), 49), 50), 51), 52), 53), 54), 55), 56), 57), 58), 59), 60), 61), 62), 63), 64), 65), 66), 67), 68), 69), 70), 71), 72), 73), 74), 75), 76), 77), 78), 79), 80), 81), 82), 83), 84), 85), 86), 87), 88), 89), 90), 91), 92), 93), 94), 95), 96), 97), 98), 99), 100)
1273+@Callable(i)
1274+func unstakeDuck (assetIdStr) = {
1275+ let prologAction = prolog(i)
1276+ if ((size(i.payments) != 0))
1277+ then throw("unstake doesn't require any payments")
1278+ else {
1279+ let assetId = fromBase58String(assetIdStr)
1280+ let address = toString(i.caller)
1281+ let asset = value(assetInfo(assetId))
1282+ let timeKey = keyStakedTimeByAssetId(toBase58String(assetId))
1283+ if (!(isDefined(getInteger(timeKey))))
1284+ then throw((("NFT " + asset.name) + " is not staked"))
1285+ else if (!(isDefined(getString(keyStakedDuckByOwner(address)))))
1286+ then throw((("The duck " + asset.name) + " is not staked"))
1287+ else {
1288+ let owner = valueOrErrorMessage(getString(keyDuckIdToOwner(toBase58String(assetId))), (("NFT " + asset.name) + " is orphaned"))
1289+ if ((owner != address))
1290+ then throw("Staked NFT is not yours")
1291+ else {
1292+ let keyHealth = keyDuckHealth(assetIdStr)
1293+ let health = valueOrElse(getInteger(keyHealth), 100)
1294+ if ((health != 100))
1295+ then throw("Please heal your duck before unstaking")
1296+ else [ScriptTransfer(i.caller, 1, assetId), DeleteEntry(timeKey), DeleteEntry(keyHealth), DeleteEntry(keyDuckLocation(assetIdStr)), DeleteEntry(keyDuckIdToOwner(assetIdStr)), DeleteEntry(keyStakedTimeByTypeAssetIdAndOwner(DUCKPREFIX, assetIdStr, address)), DeleteEntry(keyStakedDuckByOwner(address)), prologAction]
1297+ }
1298+ }
3841299 }
385- let stakedDuck = getString(stakingContract, keyStakedDuckByOwner(myAddress))
386- let duckInf = if (if (isDefined(myAddr))
387- then isDefined(stakedDuck)
388- else false)
389- then {
390- let duckAssetId = value(stakedDuck)
391- $Tuple2(duckAssetId, duckInfoTuple(duckAssetId))
1300+ }
1301+
1302+
1303+
1304+@Callable(i)
1305+func claimRes (amount,landAssetIdStr) = {
1306+ let prologAction = prolog(i)
1307+ if ((size(i.payments) != 0))
1308+ then throw("claimRes doesn't require any payments")
1309+ else {
1310+ let addr = toString(i.originCaller)
1311+ let result = claimResInternal(addr, amount, claimModeDuck, landAssetIdStr)
1312+ $Tuple2((((result._1 :+ StringEntry(result._2, makeString(result._3, ":"))) :+ StringEntry(result._4, makeString(result._5, ":"))) :+ prologAction), result._3[bpIdxRes])
1313+ }
1314+ }
1315+
1316+
1317+
1318+@Callable(i)
1319+func claimResToWH (amount,landAssetIdStr) = {
1320+ let prologAction = prolog(i)
1321+ if ((size(i.payments) != 0))
1322+ then throw("claimRes doesn't require any payments")
1323+ else {
1324+ let addr = toString(i.originCaller)
1325+ let result = claimResInternal(addr, amount, claimModeWh, landAssetIdStr)
1326+ $Tuple2((((result._1 :+ StringEntry(result._2, makeString(result._3, ":"))) :+ StringEntry(result._4, makeString(result._5, ":"))) :+ prologAction), result._5[whIdxRes])
1327+ }
1328+ }
1329+
1330+
1331+
1332+@Callable(i)
1333+func flight (message,sig) = {
1334+ let prologAction = prolog(i)
1335+ if (!(sigVerify_8Kb(message, sig, pub)))
1336+ then throw("signature does not match")
1337+ else if ((size(i.payments) != 0))
1338+ then throw("flight doesn't require any payments")
1339+ else {
1340+ let parts = split(toUtf8String(message), ";")
1341+ let hp = split(split(parts[0], "|")[0], "_")
1342+ let curHP = parseIntValue(hp[0])
1343+ let newHP = parseIntValue(hp[1])
1344+ let newLocAndTime = split(parts[1], ":")
1345+ let newLocation = newLocAndTime[0]
1346+ let time = parseIntValue(newLocAndTime[1])
1347+ if (if ((time > (lastBlock.timestamp + FIVEMINUTESMILLIS)))
1348+ then true
1349+ else ((lastBlock.timestamp - FIVEMINUTESMILLIS) > time))
1350+ then throw("signature outdated")
1351+ else {
1352+ let duckAssetId = valueOrErrorMessage(getString(keyStakedDuckByOwner(toString(i.caller))), "You don't have a duck staked")
1353+ let keyHealth = keyDuckHealth(duckAssetId)
1354+ let oldFromState = valueOrElse(getInteger(keyHealth), 100)
1355+ if ((oldFromState != curHP))
1356+ then throw(((("oldHealth=" + toString(valueOrElse(getInteger(keyHealth), 100))) + " from state does not match one from flight log=") + toString(curHP)))
1357+ else if ((0 >= curHP))
1358+ then throw("You can't fly with zero health")
1359+ else {
1360+ let locKey = keyDuckLocation(duckAssetId)
1361+ let curLocation = valueOrElse(getString(locKey), DEFAULTLOCATION)
1362+ if ((newLocation == curLocation))
1363+ then throw("You can't fly to the same location")
1364+ else $Tuple2([StringEntry(locKey, if ((newHP > 0))
1365+ then newLocation
1366+ else curLocation), IntegerEntry(keyHealth, newHP), prologAction], unit)
1367+ }
1368+ }
3921369 }
393- else $Tuple2("", $Tuple5(-1, "", "", -1, ""))
394- $Tuple2(nil, $Tuple3(r, duckInfoArray(duckInf._1, myAddress, duckInf._2), walletInternal(myAddress)))
1370+ }
1371+
1372+
1373+
1374+@Callable(i)
1375+func setHealth (health,duckAssetId) = {
1376+ let prologAction = prolog(i)
1377+ if (if ((0 > health))
1378+ then true
1379+ else (health > 100))
1380+ then throw("HP should be within 0..100")
1381+ else [IntegerEntry(keyDuckHealth(duckAssetId), health), prologAction]
1382+ }
1383+
1384+
1385+
1386+@Callable(i)
1387+func heal (matType,amount) = {
1388+ let prologAction = prolog(i)
1389+ if (if ((0 > matType))
1390+ then true
1391+ else (matType >= NUMRES))
1392+ then throw(("Unknown material: " + toString(matType)))
1393+ else if ((0 >= amount))
1394+ then throw(("Amount should be positive! " + toString(amount)))
1395+ else {
1396+ let duckAssetId = valueOrErrorMessage(getString(keyStakedDuckByOwner(toString(i.caller))), "You don't have a duck staked")
1397+ let keyHealth = keyDuckHealth(duckAssetId)
1398+ let oldHealth = valueOrElse(getInteger(keyHealth), 100)
1399+ if ((oldHealth >= 100))
1400+ then throw("HP should be < 100 to heal")
1401+ else {
1402+ let bpKey = keyBackpackByDuck(duckAssetId)
1403+ let currentPack = getBackpack(bpKey)
1404+ let mList = split(currentPack[bpIdxMat], "_")
1405+ let currentAmount = parseIntValue(mList[matType])
1406+ let deltaHealth = min([(amount / HEALCOST), (100 - oldHealth)])
1407+ let spendAmount = (deltaHealth * HEALCOST)
1408+ if ((spendAmount > currentAmount))
1409+ then throw(((((("You need " + toString(spendAmount)) + " of ") + matTypes[matType]) + " to heal, but you backpack contains ") + toString(currentAmount)))
1410+ else {
1411+ let newMat = subOneInList(mList, matType, spendAmount)
1412+[IntegerEntry(keyHealth, (oldHealth + deltaHealth)), StringEntry(bpKey, makeString([currentPack[bpIdxLevel], currentPack[bpIdxRes], newMat, currentPack[bpIdxProd]], ":")), prologAction]
1413+ }
1414+ }
1415+ }
1416+ }
1417+
1418+
1419+
1420+@Callable(i)
1421+func updateBackpack (duckAssetId,newPack) = {
1422+ let prologAction = prolog(i)
1423+ if ((i.caller != economyContract))
1424+ then throw("permission denied")
1425+ else $Tuple2([StringEntry(keyBackpackByDuck(duckAssetId), newPack), prologAction], newPack)
1426+ }
1427+
1428+
1429+
1430+@Callable(i)
1431+func buySLand () = if ((i.caller != this))
1432+ then throw("Permission denied")
1433+ else {
1434+ let prologAction = prolog(i)
1435+ if ((size(i.payments) != 1))
1436+ then throw("Exactly one payment required")
1437+ else {
1438+ let pmt = value(i.payments[0])
1439+ if ((pmt.assetId != usdnAssetId))
1440+ then throw("Allowed USDN payment only!")
1441+ else if ((pmt.amount != EXPUSDN))
1442+ then throw(("Payment attached should be " + toString(EXPUSDN)))
1443+ else {
1444+ let result = expeditionInternal(i.caller, i.transactionId)
1445+ $Tuple2(((result._1 :+ ScriptTransfer(economyContract, pmt.amount, usdnAssetId)) :+ prologAction), result._2._1)
1446+ }
1447+ }
3951448 }
3961449
3971450
3981451
3991452 @Callable(i)
400-func duckByOwnerInfoREADONLY (userAddress) = {
401- let stakedDuck = getString(stakingContract, keyStakedDuckByOwner(userAddress))
402- $Tuple2(nil, if (if (isDefined(addressFromString(userAddress)))
403- then isDefined(stakedDuck)
404- else false)
405- then {
406- let duckAssetId = value(stakedDuck)
407- duckInfoArray(duckAssetId, userAddress, duckInfoTuple(duckAssetId))
1453+func expedition (message,sig) = {
1454+ let prologAction = prolog(i)
1455+ if ((size(i.payments) != 0))
1456+ then throw("expedition doesn't require any payments")
1457+ else {
1458+ let result = expeditionCommon(true, i.caller, i.transactionId, message, sig)
1459+ $Tuple2((result._1 :+ prologAction), result._2)
4081460 }
409- else duckInfoArray("", userAddress, $Tuple5(-1, "", "", -1, "")))
4101461 }
4111462
4121463
4131464
4141465 @Callable(i)
415-func duckByAssetIdInfoREADONLY (duckAssetId) = {
416- let owner = getString(stakingContract, keyDuckIdToOwner(duckAssetId))
417- let duckInf = duckInfoTuple(duckAssetId)
418- $Tuple2(nil, duckInfoArray(duckAssetId, if (isDefined(owner))
419- then value(owner)
420- else "", duckInfoTuple(duckAssetId)))
1466+func upgradeInfra (landAssetId) = {
1467+ let prologAction = prolog(i)
1468+ if ((size(i.payments) != 0))
1469+ then throw("Infrastructure upgrade doesn't require any payments")
1470+ else {
1471+ let result = upInfraCommon(true, i.caller, 0, landAssetId)
1472+ $Tuple2((result._1 :+ prologAction), result._2)
1473+ }
4211474 }
4221475
4231476
4241477
4251478 @Callable(i)
426-func landByAssetIdInfoREADONLY (landAssetId) = if ((landAssetId == ""))
427- then throw("landAssetId is required")
1479+func upgradeInfraUsdn (landAssetId) = if ((i.caller != this))
1480+ then throw("Permission denied")
4281481 else {
429- let stakedTime = valueOrElse(getInteger(stakingContract, keyStakedTimeByAssetId(landAssetId)), -1)
430- let owner = if ((stakedTime > 0))
431- then value(getString(stakingContract, keyLandAssetIdToOwner(landAssetId)))
432- else ""
433- $Tuple2(nil, landInfoArray(landAssetId, owner, stakedTime))
1482+ let prologAction = prolog(i)
1483+ if ((size(i.payments) != 1))
1484+ then throw("Exactly one payment required")
1485+ else {
1486+ let pmt = value(i.payments[0])
1487+ if ((pmt.assetId != usdnAssetId))
1488+ then throw("Allowed USDN payment only!")
1489+ else {
1490+ let result = upInfraCommon(false, i.caller, pmt.amount, landAssetId)
1491+ $Tuple2(((result._1 :+ ScriptTransfer(economyContract, pmt.amount, usdnAssetId)) :+ prologAction), result._2)
1492+ }
1493+ }
4341494 }
4351495
4361496
4371497
4381498 @Callable(i)
439-func stakedLandsByOwnerInfoREADONLY (landOwnerAddress) = if ((landOwnerAddress == ""))
440- then throw("landOwnerAddress is required")
441- else {
442- let landsStr = getString(stakingContract, keyStakedLandsByOwner(landOwnerAddress))
443- let lands = if (isDefined(landsStr))
444- then split_51C(value(landsStr), "_")
445- else nil
446- func oneLand (acc,landAssetId) = if ((landAssetId == ""))
447- then throw("landAssetId is required")
448- else {
449- let stakedTime = valueOrElse(getInteger(stakingContract, keyStakedTimeByAssetId(landAssetId)), -1)
450- (acc :+ landInfoArray(landAssetId, landOwnerAddress, stakedTime))
451- }
452-
453- let r = {
454- let $l = lands
455- let $s = size($l)
456- let $acc0 = nil
457- func $f0_1 ($a,$i) = if (($i >= $s))
458- then $a
459- else oneLand($a, $l[$i])
460-
461- func $f0_2 ($a,$i) = if (($i >= $s))
462- then $a
463- else throw("List size exceeds 100")
464-
465- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40), 41), 42), 43), 44), 45), 46), 47), 48), 49), 50), 51), 52), 53), 54), 55), 56), 57), 58), 59), 60), 61), 62), 63), 64), 65), 66), 67), 68), 69), 70), 71), 72), 73), 74), 75), 76), 77), 78), 79), 80), 81), 82), 83), 84), 85), 86), 87), 88), 89), 90), 91), 92), 93), 94), 95), 96), 97), 98), 99), 100)
1499+func activateArtifact (artName,landAssetId) = {
1500+ let prologAction = prolog(i)
1501+ if ((size(i.payments) != 0))
1502+ then throw("Artifact activation doesn't require any payments")
1503+ else {
1504+ let result = match artName {
1505+ case _ =>
1506+ if (("PRESALE" == $match0))
1507+ then activatePresaleArt(toString(i.caller), landAssetId)
1508+ else throw("Unknown artifact")
4661509 }
467- $Tuple2(nil, r)
468- }
469-
470-
471-
472-@Callable(i)
473-func landsByIdsInfoREADONLY (landAssetIds) = {
474- func oneLand (acc,landAssetId) = if ((landAssetId == ""))
475- then throw("landAssetId is required")
476- else {
477- let stakedTime = valueOrElse(getInteger(stakingContract, keyStakedTimeByAssetId(landAssetId)), -1)
478- let owner = if ((stakedTime > 0))
479- then value(getString(stakingContract, keyLandAssetIdToOwner(landAssetId)))
480- else ""
481- (acc :+ landInfoArray(landAssetId, owner, stakedTime))
1510+ (result :+ prologAction)
4821511 }
483-
484- let r = {
485- let $l = landAssetIds
486- let $s = size($l)
487- let $acc0 = nil
488- func $f0_1 ($a,$i) = if (($i >= $s))
489- then $a
490- else oneLand($a, $l[$i])
491-
492- func $f0_2 ($a,$i) = if (($i >= $s))
493- then $a
494- else throw("List size exceeds 100")
495-
496- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40), 41), 42), 43), 44), 45), 46), 47), 48), 49), 50), 51), 52), 53), 54), 55), 56), 57), 58), 59), 60), 61), 62), 63), 64), 65), 66), 67), 68), 69), 70), 71), 72), 73), 74), 75), 76), 77), 78), 79), 80), 81), 82), 83), 84), 85), 86), 87), 88), 89), 90), 91), 92), 93), 94), 95), 96), 97), 98), 99), 100)
497- }
498- $Tuple2(nil, r)
4991512 }
5001513
5011514
5021515
5031516 @Callable(i)
504-func warehouseOrderByAssetIdInfoREADONLY (landAssetId) = if ((landAssetId == ""))
505- then throw("landAssetId is required")
506- else {
507- let stakedTime = valueOrElse(getInteger(stakingContract, keyStakedTimeByAssetId(landAssetId)), -1)
508- let owner = if ((stakedTime > 0))
509- then value(getString(stakingContract, keyLandAssetIdToOwner(landAssetId)))
510- else ""
511- $Tuple2(nil, landOrderInfoArray(landAssetId, owner))
512- }
513-
514-
515-
516-@Callable(i)
517-func ordersByLandIdsInfoREADONLY (landAssetIds) = {
518- func oneLand (acc,landAssetId) = if ((landAssetId == ""))
519- then throw("landAssetId is required")
1517+func mergeLands (landAssetIds) = {
1518+ let prologAction = prolog(i)
1519+ if ((size(i.payments) != 0))
1520+ then throw("Lands merging doesn't require any payments")
5201521 else {
521- let stakedTime = valueOrElse(getInteger(stakingContract, keyStakedTimeByAssetId(landAssetId)), -1)
522- let owner = if ((stakedTime > 0))
523- then value(getString(stakingContract, keyLandAssetIdToOwner(landAssetId)))
524- else ""
525- (acc :+ landOrderInfoArray(landAssetId, owner))
1522+ let result = mergeCommon(true, toString(i.caller), 0, landAssetIds, i.transactionId)
1523+ $Tuple2((result._1 :+ prologAction), result._2)
5261524 }
527-
528- let r = {
529- let $l = landAssetIds
530- let $s = size($l)
531- let $acc0 = nil
532- func $f0_1 ($a,$i) = if (($i >= $s))
533- then $a
534- else oneLand($a, $l[$i])
535-
536- func $f0_2 ($a,$i) = if (($i >= $s))
537- then $a
538- else throw("List size exceeds 100")
539-
540- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40), 41), 42), 43), 44), 45), 46), 47), 48), 49), 50), 51), 52), 53), 54), 55), 56), 57), 58), 59), 60), 61), 62), 63), 64), 65), 66), 67), 68), 69), 70), 71), 72), 73), 74), 75), 76), 77), 78), 79), 80), 81), 82), 83), 84), 85), 86), 87), 88), 89), 90), 91), 92), 93), 94), 95), 96), 97), 98), 99), 100)
541- }
542- $Tuple2(nil, r)
5431525 }
5441526
5451527
5461528
5471529 @Callable(i)
548-func cancelWarehouseOrders (landAssetIds) = if ((i.caller != this))
549- then throw("permission denied")
550- else {
551- let blocked = getBoolean(stakingContract, keyBlocked())
552- if (if (!(isDefined(blocked)))
553- then true
554- else (value(blocked) == false))
555- then throw("Contracts should be blocked before canceling orders")
556- else {
557- func oneLand (a,landAssetId) = if ((landAssetId == ""))
558- then throw("landAssetId is required")
559- else {
560- let c = asBoolean(invoke(economyContract, "setWarehouseOrder", ["0@0_0@0_0@0_0@0_0@0_0@0:0@0_0@0_0@0_0@0_0@0_0@0:", landAssetId], nil))
561- if (if (a)
562- then true
563- else c)
564- then !(if (a)
565- then c
566- else false)
567- else false
568- }
1530+func mergeLandsUsdn (landAssetIds) = {
1531+ let prologAction = prolog(i)
1532+ if ((size(i.payments) != 1))
1533+ then throw("Exactly one payment required")
1534+ else {
1535+ let pmt = value(i.payments[0])
1536+ if ((pmt.assetId != usdnAssetId))
1537+ then throw("Allowed USDN payment only!")
1538+ else {
1539+ let result = mergeCommon(false, toString(i.caller), pmt.amount, landAssetIds, i.transactionId)
1540+ $Tuple2(((result._1 :+ ScriptTransfer(economyContract, pmt.amount, usdnAssetId)) :+ prologAction), result._2)
1541+ }
1542+ }
1543+ }
5691544
570- let r = {
571- let $l = landAssetIds
572- let $s = size($l)
573- let $acc0 = false
574- func $f0_1 ($a,$i) = if (($i >= $s))
575- then $a
576- else oneLand($a, $l[$i])
5771545
578- func $f0_2 ($a,$i) = if (($i >= $s))
579- then $a
580- else throw("List size exceeds 30")
5811546
582- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30)
1547+@Callable(i)
1548+func cargoExchange (cargoListStr,landAssetId) = {
1549+ let prologAction = prolog(i)
1550+ let cargoParts = split_4C(cargoListStr, ":")
1551+ let addr = toString(i.originCaller)
1552+ let asset = value(assetInfo(fromBase58String(landAssetId)))
1553+ let timeKey = keyStakedTimeByAssetId(landAssetId)
1554+ if (!(isDefined(getInteger(timeKey))))
1555+ then throw((asset.name + " is not staked"))
1556+ else {
1557+ let owner = valueOrErrorMessage(getString(keyLandAssetIdToOwner(landAssetId)), (("NFT " + asset.name) + " is orphaned"))
1558+ if ((owner != addr))
1559+ then throw((LANDPREFIX + " is not yours"))
1560+ else {
1561+ let landIndex = (numPiecesBySize(split(asset.description, "_")[recLandSize]) / SSIZE)
1562+ let infraLevel = valueOrElse(getInteger(keyInfraLevelByAssetId(landAssetId)), 0)
1563+ let duckAssetId = valueOrErrorMessage(getString(keyStakedDuckByOwner(addr)), "You don't have a duck staked")
1564+ let curLocation = valueOrElse(getString(keyDuckLocation(duckAssetId)), DEFAULTLOCATION)
1565+ let loc = split(value(curLocation), "_")
1566+ if ((loc[locIdxType] != "L"))
1567+ then throw((("Duck location type is " + loc[locIdxType]) + ", but should be L"))
1568+ else if ((loc[locIdxId] != landAssetId))
1569+ then throw(("Duck should be on the land " + landAssetId))
1570+ else {
1571+ let whKey = keyWarehouseByLand(landAssetId)
1572+ let currentWh = getWarehouse(whKey, landIndex, infraLevel)
1573+ let bpKey = keyBackpackByDuck(duckAssetId)
1574+ let currentPack = getBackpack(bpKey)
1575+ let result = moveStuff(cargoParts, currentWh, currentPack)
1576+[StringEntry(bpKey, makeString([currentPack[bpIdxLevel], result._4, result._5, result._6], ":")), StringEntry(whKey, makeString([currentWh[whIdxVol], result._1, result._2, result._3, currentWh[whIdxLockedVol]], ":")), prologAction]
1577+ }
5831578 }
584- $Tuple2(nil, r)
585- }
586- }
1579+ }
1580+ }
1581+
1582+
1583+
1584+@Callable(i)
1585+func saveWarehouse (whStr,landAssetId) = {
1586+ let prologAction = prolog(i)
1587+ if ((i.caller != economyContract))
1588+ then throw("Access denied")
1589+ else {
1590+ let whKey = keyWarehouseByLand(landAssetId)
1591+ if ((size(split_4C(whStr, ":")) != 5))
1592+ then throw("warehouse string should contain 4 ':' separators")
1593+ else $Tuple2([StringEntry(whKey, whStr), prologAction], whStr)
1594+ }
1595+ }
1596+
1597+
1598+
1599+@Callable(i)
1600+func splitByGlobalWeightsREADONLY (amount) = $Tuple2(nil, getNeededMaterials(amount))
1601+
1602+
1603+
1604+@Callable(i)
1605+func splitByGlobalAndLocalWeightsREADONLY (matAmount,resAmount,terrains) = {
1606+ let terrainCounts = countTerrains(terrains)
1607+ $Tuple2(nil, $Tuple2(getNeededMaterials(matAmount), distributeByWeights(resAmount, terrainCounts)))
1608+ }
1609+
1610+
1611+
1612+@Callable(i)
1613+func getBackpackREADONLY (duckAssetId) = $Tuple2(nil, makeString(getBackpack(keyBackpackByDuck(duckAssetId)), ":"))
1614+
1615+
1616+
1617+@Callable(i)
1618+func getWarehouseREADONLY (landAssetId) = {
1619+ let asset = value(assetInfo(fromBase58String(landAssetId)))
1620+ let landIndex = (numPiecesBySize(split(asset.description, "_")[recLandSize]) / SSIZE)
1621+ let infraLevel = valueOrElse(getInteger(keyInfraLevelByAssetId(landAssetId)), 0)
1622+ $Tuple2(nil, makeString_2C(getWarehouse(keyWarehouseByLand(landAssetId), landIndex, infraLevel), ":"))
1623+ }
5871624
5881625

github/deemru/w8io/873ac7e 
212.64 ms