tx · 5cHQ5gvQW2PwdcQThd6VuHPW3KjzDKUsERx8Godvi4b4

3N8y4wxX3JC4TdrCJBXX16SjWf6X256hrep:  -0.01100000 Waves

2022.12.06 14:57 [2348452] smart account 3N8y4wxX3JC4TdrCJBXX16SjWf6X256hrep > SELF 0.00000000 Waves

{ "type": 13, "id": "5cHQ5gvQW2PwdcQThd6VuHPW3KjzDKUsERx8Godvi4b4", "fee": 1100000, "feeAssetId": null, "timestamp": 1670327876236, "version": 2, "chainId": 84, "sender": "3N8y4wxX3JC4TdrCJBXX16SjWf6X256hrep", "senderPublicKey": "7v5L7QkXxfkirALdyqmox38QCsa9jtfAtgUfHTh34eWq", "proofs": [ "4y81ffZHmoYwSJAS3xm8fjYPCsZnZfW15Ea1pdLFJFBqhpi2zdUbKeHmoAKGVGHv6mPxqCfZ6kiitXNHKZozaQfu" ], "script": "base64:BgIoCAISABIDCgEIEgASAwoBCBIECgIBCBIECgICAhIECgIBCBIECgIICCkAC3VzZG5Bc3NldElkASD3dur394PKZdtuE+4CO89YKZWpwdGN8kvabNgdYoDI3gANaW5jdWJhdG9yQWRkcgUEdGhpcwALYnJlZWRlckFkZHIFBHRoaXMAC2JhY2tFbmRBZGRyCQERQGV4dHJOYXRpdmUoMTA2MikBAiMzTjVTcFgyMVIzUjc1UW80ZWIzTXdGRnZXN1RVenlodmF2dgALZWNvbm9teUFkZHIJARFAZXh0ck5hdGl2ZSgxMDYyKQECIzNOOHk0d3hYM0pDNFRkckNKQlhYMTZTaldmNlgyNTZocmVwAANwdWIBIE9T4ho/VKjWnVJOEx1GJ1W9s1PzLHvJVFSw/0PBtBQoAApMQU5EUFJFRklYAgRMQU5EAApEVUNLUFJFRklYAgREVUNLAA9ERUZBVUxUTE9DQVRJT04CD0FmcmljYV9GX0FmcmljYQAPREFJTFlSRVNCWVBJRUNFAID40gEACURBWU1JTExJUwCAuJkpABFGSVZFTUlOVVRFU01JTExJUwDgpxIBEWtleUFzc2V0SWRUb093bmVyAQdhc3NldElkCQCsAgICCW5mdE93bmVyXwUHYXNzZXRJZAEQa2V5RHVja0lkVG9Pd25lcgEHYXNzZXRJZAkArAICAgpkdWNrT3duZXJfBQdhc3NldElkARZrZXlTdGFrZWRUaW1lQnlBc3NldElkAQdhc3NldElkCQCsAgICC3N0YWtlZFRpbWVfBQdhc3NldElkARRrZXlTdGFrZWREdWNrQnlPd25lcgEJb3duZXJBZGRyCQCsAgICEnN0YWtlZER1Y2tCeU93bmVyXwUJb3duZXJBZGRyASJrZXlTdGFrZWRUaW1lQnlUeXBlQXNzZXRJZEFuZE93bmVyAwduZnRUeXBlB2Fzc2V0SWQJb3duZXJBZGRyCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgIgc3Rha2VkVGltZUJ5VHlwZUFzc2V0SWRBbmRPd25lcl8FB25mdFR5cGUCAV8FB2Fzc2V0SWQCAV8FCW93bmVyQWRkcgEOa2V5TGFuZFRvT3duZXIBB2xhbmROdW0JAKwCAgIKbGFuZE93bmVyXwUHbGFuZE51bQERa2V5QmFja3BhY2tCeUR1Y2sBC2R1Y2tBc3NldElkCQCsAgICCWJhY2tQYWNrXwULZHVja0Fzc2V0SWQBD2tleUR1Y2tMb2NhdGlvbgELZHVja0Fzc2V0SWQJAKwCAgINZHVja0xvY2F0aW9uXwULZHVja0Fzc2V0SWQBDWtleUR1Y2tIZWFsdGgBC2R1Y2tBc3NldElkCQCsAgICC2R1Y2tIZWFsdGhfBQtkdWNrQXNzZXRJZAAKcmVjTGFuZE51bQAAAAtyZWNMYW5kU2l6ZQABAAtyZWNUZXJyYWlucwACAAxyZWNDb250aW5lbnQAAwAPbG9jSWR4Q29udGluZW50AAAACmxvY0lkeFR5cGUAAQAIbG9jSWR4SWQAAgAKYnBJZHhMZXZlbAAAAAhicElkeFJlcwABAAhicElkeE1hdAACAAlicElkeFByb2QAAwAEaWR4QQAAAARpZHhCAAEABGlkeEMAAgAEaWR4RAADAARpZHhFAAQABGlkeEYABQENY291bnRUZXJyYWlucwEIdGVycmFpbnMJAMwIAgkAZQIJAJADAQkAtQkCBQh0ZXJyYWlucwIBQQABCQDMCAIJAGUCCQCQAwEJALUJAgUIdGVycmFpbnMCAUIAAQkAzAgCCQBlAgkAkAMBCQC1CQIFCHRlcnJhaW5zAgFDAAEJAMwIAgkAZQIJAJADAQkAtQkCBQh0ZXJyYWlucwIBRAABCQDMCAIJAGUCCQCQAwEJALUJAgUIdGVycmFpbnMCAUUAAQkAzAgCCQBlAgkAkAMBCQC1CQIFCHRlcnJhaW5zAgFGAAEFA25pbAEPbnVtUGllY2VzQnlTaXplAQhsYW5kU2l6ZQQHJG1hdGNoMAUIbGFuZFNpemUDCQAAAgIBUwUHJG1hdGNoMAAZAwkAAAICAU0FByRtYXRjaDAAZAMJAAACAgFMBQckbWF0Y2gwAOEBAwkAAAICAlhMBQckbWF0Y2gwAJADAwkAAAICA1hYTAUHJG1hdGNoMADxBAkAAgECEVVua25vd24gbGFuZCBzaXplAQZhZGRSZXMDCmN1cnJlbnRSZXMNdGVycmFpbkNvdW50cwlkZWx0YVRpbWUKAQVhZGRlcgIDYWNjAWkECXJlc09mVHlwZQkAaAIJAGsDBQlkZWx0YVRpbWUFD0RBSUxZUkVTQllQSUVDRQUJREFZTUlMTElTCQCRAwIFDXRlcnJhaW5Db3VudHMFAWkJAM0IAgUDYWNjCQCkAwEJAGQCCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUKY3VycmVudFJlcwUBaQUJcmVzT2ZUeXBlBAFyCgACJGwJAMwIAgAACQDMCAIAAQkAzAgCAAIJAMwIAgADCQDMCAIABAkAzAgCAAUFA25pbAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEFYWRkZXICBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECE0xpc3Qgc2l6ZSBleGNlZWRzIDYJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYJALkJAgUBcgIBXwgBaQEJc3Rha2VMYW5kAAQDcG10CQEFdmFsdWUBCQCRAwIIBQFpCHBheW1lbnRzAAAEB2Fzc2V0SWQJAQV2YWx1ZQEIBQNwbXQHYXNzZXRJZAQHYWRkcmVzcwkApQgBCAUBaQZjYWxsZXIDCQECIT0CCAUDcG10BmFtb3VudAABCQACAQkArAICCQCsAgICBE5GVCAFCkxBTkRQUkVGSVgCJCB0b2tlbiBzaG91bGQgYmUgYXR0YWNoZWQgYXMgcGF5bWVudAQFYXNzZXQJAQV2YWx1ZQEJAOwHAQUHYXNzZXRJZAMJAQIhPQIIBQVhc3NldAZpc3N1ZXIFBHRoaXMJAAIBAhdVbmtub3duIGlzc3VlciBvZiB0b2tlbgMJAQEhAQkBCGNvbnRhaW5zAggFBWFzc2V0BG5hbWUFCkxBTkRQUkVGSVgJAAIBCQCsAgIJAKwCAgIJT25seSBORlQgBQpMQU5EUFJFRklYAhQgdG9rZW5zIGFyZSBhY2NlcHRlZAQLbGFuZE51bVNpemUJALACAggFBWFzc2V0BG5hbWUABAQHbGFuZE51bQMJAQhjb250YWlucwIFC2xhbmROdW1TaXplAgNYWEwJALMCAgULbGFuZE51bVNpemUAAwMJAQhjb250YWlucwIFC2xhbmROdW1TaXplAgJYTAkAswICBQtsYW5kTnVtU2l6ZQACCQCzAgIFC2xhbmROdW1TaXplAAEDCQEBIQEJAQlpc0RlZmluZWQBCQC2CQEFB2xhbmROdW0JAAIBCQCsAgICHkNhbm5vdCBwYXJzZSBsYW5kIG51bWJlciBmcm9tIAgFBWFzc2V0BG5hbWUEB3RpbWVLZXkJARZrZXlTdGFrZWRUaW1lQnlBc3NldElkAQkA2AQBBQdhc3NldElkAwkBCWlzRGVmaW5lZAEJAJ8IAQUHdGltZUtleQkAAgEJAKwCAgkArAICAgRORlQgCAUFYXNzZXQEbmFtZQISIGlzIGFscmVhZHkgc3Rha2VkCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQd0aW1lS2V5CAUJbGFzdEJsb2NrCXRpbWVzdGFtcAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBImtleVN0YWtlZFRpbWVCeVR5cGVBc3NldElkQW5kT3duZXIDBQpMQU5EUFJFRklYCQDYBAEFB2Fzc2V0SWQFB2FkZHJlc3MIBQlsYXN0QmxvY2sJdGltZXN0YW1wCQDMCAIJAQtTdHJpbmdFbnRyeQIJARFrZXlBc3NldElkVG9Pd25lcgEJANgEAQUHYXNzZXRJZAUHYWRkcmVzcwkAzAgCCQELU3RyaW5nRW50cnkCCQEOa2V5TGFuZFRvT3duZXIBBQdsYW5kTnVtBQdhZGRyZXNzBQNuaWwBaQELdW5zdGFrZUxhbmQBC2xhbmRBc3NldElkAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwAACQACAQIkdW5zdGFrZSBkb2Vzbid0IHJlcXVpcmUgYW55IHBheW1lbnRzBAdhc3NldElkCQDZBAEFC2xhbmRBc3NldElkBAdhZGRyZXNzCQClCAEIBQFpBmNhbGxlcgQFYXNzZXQJAQV2YWx1ZQEJAOwHAQUHYXNzZXRJZAMJAQIhPQIIBQVhc3NldAZpc3N1ZXIFBHRoaXMJAAIBAhdVbmtub3duIGlzc3VlciBvZiB0b2tlbgMJAQEhAQkBCGNvbnRhaW5zAggFBWFzc2V0BG5hbWUFCkxBTkRQUkVGSVgJAAIBCQCsAgIJAKwCAgIJT25seSBORlQgBQpMQU5EUFJFRklYAhcgdG9rZW5zIGNhbiBiZSB1bnN0YWtlZAQHdGltZUtleQkBFmtleVN0YWtlZFRpbWVCeUFzc2V0SWQBBQtsYW5kQXNzZXRJZAMJAQEhAQkBCWlzRGVmaW5lZAEFB3RpbWVLZXkJAAIBCQCsAgIJAKwCAgIETkZUIAgFBWFzc2V0BG5hbWUCDiBpcyBub3Qgc3Rha2VkBAVvd25lcgkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCiCAEJARFrZXlBc3NldElkVG9Pd25lcgEFC2xhbmRBc3NldElkCQCsAgIJAKwCAgIETkZUIAgFBWFzc2V0BG5hbWUCDCBpcyBvcnBoYW5lZAMJAQIhPQIFBW93bmVyBQdhZGRyZXNzCQACAQIXU3Rha2VkIE5GVCBpcyBub3QgeW91cnMJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwgFAWkGY2FsbGVyAAEFB2Fzc2V0SWQJAMwIAgkBC0RlbGV0ZUVudHJ5AQUHdGltZUtleQkAzAgCCQELRGVsZXRlRW50cnkBCQEia2V5U3Rha2VkVGltZUJ5VHlwZUFzc2V0SWRBbmRPd25lcgMFCkxBTkRQUkVGSVgFC2xhbmRBc3NldElkBQdhZGRyZXNzBQNuaWwBaQEJc3Rha2VEdWNrAAQDcG10CQEFdmFsdWUBCQCRAwIIBQFpCHBheW1lbnRzAAAEB2Fzc2V0SWQJAQV2YWx1ZQEIBQNwbXQHYXNzZXRJZAQHYWRkcmVzcwkApQgBCAUBaQZjYWxsZXIDCQECIT0CCAUDcG10BmFtb3VudAABCQACAQkArAICCQCsAgICBE5GVCAFCkRVQ0tQUkVGSVgCJCB0b2tlbiBzaG91bGQgYmUgYXR0YWNoZWQgYXMgcGF5bWVudAQFYXNzZXQJAQV2YWx1ZQEJAOwHAQUHYXNzZXRJZAMDCQECIT0CCAUFYXNzZXQGaXNzdWVyBQ1pbmN1YmF0b3JBZGRyCQECIT0CCAUFYXNzZXQGaXNzdWVyBQticmVlZGVyQWRkcgcJAAIBCQCsAgIJAKwCAgISVW5rbm93biBpc3N1ZXIgb2YgBQpEVUNLUFJFRklYAgYgdG9rZW4DCQEBIQEJAQhjb250YWlucwIIBQVhc3NldARuYW1lBQpEVUNLUFJFRklYCQACAQkArAICCQCsAgICCU9ubHkgTkZUIAUKRFVDS1BSRUZJWAIUIHRva2VucyBhcmUgYWNjZXB0ZWQECmFzc2V0SWRTdHIJANgEAQUHYXNzZXRJZAQHdGltZUtleQkBFmtleVN0YWtlZFRpbWVCeUFzc2V0SWQBBQphc3NldElkU3RyAwkBCWlzRGVmaW5lZAEJAJ8IAQUHdGltZUtleQkAAgEJAKwCAgkArAICAgRORlQgCAUFYXNzZXQEbmFtZQISIGlzIGFscmVhZHkgc3Rha2VkAwkBCWlzRGVmaW5lZAEJAKIIAQkBFGtleVN0YWtlZER1Y2tCeU93bmVyAQUHYWRkcmVzcwkAAgEJAKwCAgIdWW91IGFscmVhZHkgc3Rha2VkIG9uZSBkdWNrOiAIBQVhc3NldARuYW1lBAZsb2NLZXkJAQ9rZXlEdWNrTG9jYXRpb24BBQphc3NldElkU3RyBAhsb2NhdGlvbgkAoggBBQZsb2NLZXkECWtleUhlYWx0aAkBDWtleUR1Y2tIZWFsdGgBBQphc3NldElkU3RyBAZoZWFsdGgJAJ8IAQUJa2V5SGVhbHRoBAVicEtleQkBEWtleUJhY2twYWNrQnlEdWNrAQUKYXNzZXRJZFN0cgQIYmFja3BhY2sJAKIIAQUFYnBLZXkJAM4IAgkAzAgCCQEMSW50ZWdlckVudHJ5AgUHdGltZUtleQgFCWxhc3RCbG9jawl0aW1lc3RhbXAJAMwIAgkBDEludGVnZXJFbnRyeQIJASJrZXlTdGFrZWRUaW1lQnlUeXBlQXNzZXRJZEFuZE93bmVyAwUKRFVDS1BSRUZJWAkA2AQBBQdhc3NldElkBQdhZGRyZXNzCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAkAzAgCCQELU3RyaW5nRW50cnkCCQEQa2V5RHVja0lkVG9Pd25lcgEFCmFzc2V0SWRTdHIFB2FkZHJlc3MJAMwIAgkBC1N0cmluZ0VudHJ5AgkBFGtleVN0YWtlZER1Y2tCeU93bmVyAQUHYWRkcmVzcwUKYXNzZXRJZFN0cgUDbmlsAwkBCWlzRGVmaW5lZAEFCGxvY2F0aW9uBQNuaWwJAM4IAgkAzAgCCQELU3RyaW5nRW50cnkCBQZsb2NLZXkFD0RFRkFVTFRMT0NBVElPTgUDbmlsAwkBCWlzRGVmaW5lZAEFBmhlYWx0aAUDbmlsCQDOCAIJAMwIAgkBDEludGVnZXJFbnRyeQIFCWtleUhlYWx0aABkBQNuaWwDCQEJaXNEZWZpbmVkAQUIYmFja3BhY2sFA25pbAkAzAgCCQELU3RyaW5nRW50cnkCBQVicEtleQIPMDowXzBfMF8wXzBfMDo6BQNuaWwBaQELdW5zdGFrZUR1Y2sBCmFzc2V0SWRTdHIDCQECIT0CCQCQAwEIBQFpCHBheW1lbnRzAAAJAAIBAiR1bnN0YWtlIGRvZXNuJ3QgcmVxdWlyZSBhbnkgcGF5bWVudHMEB2Fzc2V0SWQJANkEAQUKYXNzZXRJZFN0cgQHYWRkcmVzcwkApQgBCAUBaQZjYWxsZXIEBWFzc2V0CQEFdmFsdWUBCQDsBwEFB2Fzc2V0SWQDAwkBAiE9AggFBWFzc2V0Bmlzc3VlcgUNaW5jdWJhdG9yQWRkcgkBAiE9AggFBWFzc2V0Bmlzc3VlcgULYnJlZWRlckFkZHIHCQACAQkArAICCQCsAgICElVua25vd24gaXNzdWVyIG9mIAUKRFVDS1BSRUZJWAIGIHRva2VuAwkBASEBCQEIY29udGFpbnMCCAUFYXNzZXQEbmFtZQUKRFVDS1BSRUZJWAkAAgEJAKwCAgkArAICAglPbmx5IE5GVCAFCkRVQ0tQUkVGSVgCFyB0b2tlbnMgY2FuIGJlIHVuc3Rha2VkBAd0aW1lS2V5CQEWa2V5U3Rha2VkVGltZUJ5QXNzZXRJZAEJANgEAQUHYXNzZXRJZAMJAQEhAQkBCWlzRGVmaW5lZAEFB3RpbWVLZXkJAAIBCQCsAgIJAKwCAgIETkZUIAgFBWFzc2V0BG5hbWUCDiBpcyBub3Qgc3Rha2VkAwkBASEBCQEJaXNEZWZpbmVkAQkBFGtleVN0YWtlZER1Y2tCeU93bmVyAQUHYWRkcmVzcwkAAgEJAKwCAgkArAICAglUaGUgZHVjayAIBQVhc3NldARuYW1lAg4gaXMgbm90IHN0YWtlZAQFb3duZXIJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAoggBCQEQa2V5RHVja0lkVG9Pd25lcgEJANgEAQUHYXNzZXRJZAkArAICCQCsAgICBE5GVCAIBQVhc3NldARuYW1lAgwgaXMgb3JwaGFuZWQDCQECIT0CBQVvd25lcgUHYWRkcmVzcwkAAgECF1N0YWtlZCBORlQgaXMgbm90IHlvdXJzCQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMIBQFpBmNhbGxlcgABBQdhc3NldElkCQDMCAIJAQtEZWxldGVFbnRyeQEFB3RpbWVLZXkJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBD2tleUR1Y2tMb2NhdGlvbgEFCmFzc2V0SWRTdHIJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBImtleVN0YWtlZFRpbWVCeVR5cGVBc3NldElkQW5kT3duZXIDBQpEVUNLUFJFRklYBQphc3NldElkU3RyBQdhZGRyZXNzCQDMCAIJAQtEZWxldGVFbnRyeQEJARRrZXlTdGFrZWREdWNrQnlPd25lcgEFB2FkZHJlc3MFA25pbAFpAQhjbGFpbVJlcwIGYW1vdW50C2xhbmRBc3NldElkAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwAACQACAQIlY2xhaW1SZXMgZG9lc24ndCByZXF1aXJlIGFueSBwYXltZW50cwQEYWRkcgkApQgBCAUBaQZjYWxsZXIEBWFzc2V0CQEFdmFsdWUBCQDsBwEJANkEAQULbGFuZEFzc2V0SWQDCQEBIQEJAQhjb250YWlucwIIBQVhc3NldARuYW1lBQpMQU5EUFJFRklYCQACAQkArAICCQCsAgICBE5GVCAFCkxBTkRQUkVGSVgCICB0b2tlbiBzaG91bGQgYmUgcGFzc2VkIGFzIHBhcmFtBAd0aW1lS2V5CQEWa2V5U3Rha2VkVGltZUJ5QXNzZXRJZAEFC2xhbmRBc3NldElkBAlzYXZlZFRpbWUJAJ8IAQUHdGltZUtleQMJAQEhAQkBCWlzRGVmaW5lZAEFCXNhdmVkVGltZQkAAgEJAKwCAgkArAICAgRORlQgCAUFYXNzZXQEbmFtZQIOIGlzIG5vdCBzdGFrZWQEBW93bmVyCQERQGV4dHJOYXRpdmUoMTA1OCkBCQERa2V5QXNzZXRJZFRvT3duZXIBBQtsYW5kQXNzZXRJZAMJAQIhPQIFBW93bmVyBQRhZGRyCQACAQkArAICBQpMQU5EUFJFRklYAg0gaXMgbm90IHlvdXJzBAFkCQC1CQIIBQVhc3NldAtkZXNjcmlwdGlvbgIBXwQIbGFuZFNpemUJAJEDAgUBZAULcmVjTGFuZFNpemUEDXRlcnJhaW5Db3VudHMJAQ1jb3VudFRlcnJhaW5zAQkAkQMCBQFkBQtyZWNUZXJyYWlucwQEZHVjawkAoggBCQEUa2V5U3Rha2VkRHVja0J5T3duZXIBBQRhZGRyAwkBASEBCQEJaXNEZWZpbmVkAQUEZHVjawkAAgECHFlvdSBkb24ndCBoYXZlIGEgZHVjayBzdGFrZWQEDmR1Y2tBc3NldElkU3RyCQEFdmFsdWUBBQRkdWNrBAtjdXJMb2NhdGlvbgkBC3ZhbHVlT3JFbHNlAgkAoggBCQEPa2V5RHVja0xvY2F0aW9uAQUOZHVja0Fzc2V0SWRTdHIFD0RFRkFVTFRMT0NBVElPTgQDbG9jCQC1CQIJAQV2YWx1ZQEFC2N1ckxvY2F0aW9uAgFfAwkBAiE9AgkAkQMCBQNsb2MFCmxvY0lkeFR5cGUCAUwJAAIBCQCsAgIJAKwCAgIWRHVjayBsb2NhdGlvbiB0eXBlIGlzIAkAkQMCBQNsb2MFCmxvY0lkeFR5cGUCESwgYnV0IHNob3VsZCBiZSBMAwkBAiE9AgkAkQMCBQNsb2MFCGxvY0lkeElkBQtsYW5kQXNzZXRJZAkAAgEJAKwCAgkArAICCQCsAgICFER1Y2sgbG9jYXRpb24gaWQgaXMgCQCRAwIFA2xvYwUIbG9jSWR4SWQCECwgYnV0IHNob3VsZCBiZSAFC2xhbmRBc3NldElkBAlkZWx0YVRpbWUJAGUCCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAkBBXZhbHVlAQUJc2F2ZWRUaW1lAwkAZgIAAAUJZGVsdGFUaW1lCQACAQkArAICCQCsAgIJAKwCAgImU2F2ZWQgdGltZXN0YW1wIGlzIGluIGZ1dHVyZSwgc2F2ZWQgPSAJAKQDAQkBBXZhbHVlAQUJc2F2ZWRUaW1lAgwsIGN1cnJlbnQgPSAJAKQDAQgFCWxhc3RCbG9jawl0aW1lc3RhbXAEBnBpZWNlcwkBD251bVBpZWNlc0J5U2l6ZQEFCGxhbmRTaXplBAhhdmFpbFJlcwkAaAIJAGsDBQlkZWx0YVRpbWUFD0RBSUxZUkVTQllQSUVDRQUJREFZTUlMTElTBQZwaWVjZXMDCQBmAgUGYW1vdW50BQhhdmFpbFJlcwkAAgEJAKwCAgkArAICCQCsAgICIk5vdCBlbm91Z2ggcmVzb3VyY2VzLCBhdmFpbGFibGUgPSAJAKQDAQUIYXZhaWxSZXMCDiwgcmVxdWVzdGVkID0gCQCkAwEFBmFtb3VudAQMbmV3RGVsdGFUaW1lCQBrAwkAZQIFCGF2YWlsUmVzBQZhbW91bnQFCURBWU1JTExJUwkAaAIFBnBpZWNlcwUPREFJTFlSRVNCWVBJRUNFBAxuZXdUaW1lc3RhbXAJAGUCCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAUMbmV3RGVsdGFUaW1lBAVicEtleQkBEWtleUJhY2twYWNrQnlEdWNrAQUOZHVja0Fzc2V0SWRTdHIEC2N1cnJlbnRQYWNrCQC1CQIJAQt2YWx1ZU9yRWxzZQIJAKIIAQUFYnBLZXkCDzA6MF8wXzBfMF8wXzA6OgIBOgQKY3VycmVudFJlcwkAtQkCCQCRAwIFC2N1cnJlbnRQYWNrBQhicElkeFJlcwIBXwQFYnBSZXMJAQZhZGRSZXMDBQpjdXJyZW50UmVzBQ10ZXJyYWluQ291bnRzCQBlAgUJZGVsdGFUaW1lBQxuZXdEZWx0YVRpbWUEB25ld1BhY2sJALkJAgkAzAgCCQCRAwIFC2N1cnJlbnRQYWNrBQpicElkeExldmVsCQDMCAIFBWJwUmVzCQDMCAIJAJEDAgULY3VycmVudFBhY2sFCGJwSWR4TWF0CQDMCAIJAJEDAgULY3VycmVudFBhY2sFCWJwSWR4UHJvZAUDbmlsAgE6CQCUCgIJAMwIAgkBC1N0cmluZ0VudHJ5AgUFYnBLZXkFB25ld1BhY2sJAMwIAgkBDEludGVnZXJFbnRyeQIFB3RpbWVLZXkFDG5ld1RpbWVzdGFtcAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBImtleVN0YWtlZFRpbWVCeVR5cGVBc3NldElkQW5kT3duZXIDBQpMQU5EUFJFRklYBQtsYW5kQXNzZXRJZAUFb3duZXIFDG5ld1RpbWVzdGFtcAUDbmlsBQR1bml0AWkBBmZsaWdodAIHbWVzc2FnZQNzaWcDCQEBIQEJAMQTAwUHbWVzc2FnZQUDc2lnBQNwdWIJAAIBAhhzaWduYXR1cmUgZG9lcyBub3QgbWF0Y2gDCQECIT0CCQCQAwEIBQFpCHBheW1lbnRzAAAJAAIBAiNmbGlnaHQgZG9lc24ndCByZXF1aXJlIGFueSBwYXltZW50cwQFcGFydHMJALUJAgkAsAkBBQdtZXNzYWdlAgE7BAJocAkAtQkCCQCRAwIJALUJAgkAkQMCBQVwYXJ0cwAAAgF8AAACAV8EBWN1ckhQCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUCaHAAAQQFbmV3SFAJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQJocAABBA1uZXdMb2NBbmRUaW1lCQC1CQIJAJEDAgUFcGFydHMAAQIBOgQLbmV3TG9jYXRpb24JAJEDAgUNbmV3TG9jQW5kVGltZQAABAR0aW1lCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUNbmV3TG9jQW5kVGltZQABAwMJAGYCBQR0aW1lCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAYJAGYCCQBlAggFCWxhc3RCbG9jawl0aW1lc3RhbXAFEUZJVkVNSU5VVEVTTUlMTElTBQR0aW1lCQACAQISc2lnbmF0dXJlIG91dGRhdGVkBAtkdWNrQXNzZXRJZAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCiCAEJARRrZXlTdGFrZWREdWNrQnlPd25lcgEJAKUIAQgFAWkGY2FsbGVyAhxZb3UgZG9uJ3QgaGF2ZSBhIGR1Y2sgc3Rha2VkBAlrZXlIZWFsdGgJAQ1rZXlEdWNrSGVhbHRoAQULZHVja0Fzc2V0SWQEDG9sZEZyb21TdGF0ZQkBC3ZhbHVlT3JFbHNlAgkAnwgBBQlrZXlIZWFsdGgAZAMJAQIhPQIFDG9sZEZyb21TdGF0ZQUFY3VySFAJAAIBCQCsAgIJAKwCAgkArAICAgpvbGRIZWFsdGg9CQCkAwEJAQt2YWx1ZU9yRWxzZQIJAJ8IAQUJa2V5SGVhbHRoAGQCLyBmcm9tIHN0YXRlIGRvZXMgbm90IG1hdGNoIG9uZSBmcm9tIGZsaWdodCBsb2c9CQCkAwEFBWN1ckhQBAZsb2NLZXkJAQ9rZXlEdWNrTG9jYXRpb24BBQtkdWNrQXNzZXRJZAQLY3VyTG9jYXRpb24JAQt2YWx1ZU9yRWxzZQIJAKIIAQUGbG9jS2V5BQ9ERUZBVUxUTE9DQVRJT04DCQAAAgULbmV3TG9jYXRpb24FC2N1ckxvY2F0aW9uCQACAQIiWW91IGNhbid0IGZseSB0byB0aGUgc2FtZSBsb2NhdGlvbgkAlAoCCQDMCAIJAQtTdHJpbmdFbnRyeQIFBmxvY0tleQMJAGYCBQVuZXdIUAAABQtuZXdMb2NhdGlvbgULY3VyTG9jYXRpb24JAMwIAgkBDEludGVnZXJFbnRyeQIFCWtleUhlYWx0aAUFbmV3SFAFA25pbAUEdW5pdAFpAQlzZXRIZWFsdGgCBmhlYWx0aAtkdWNrQXNzZXRJZAQOZHVja0Fzc2V0SWRTdHIJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAoggBCQEUa2V5U3Rha2VkRHVja0J5T3duZXIBCQClCAEIBQFpBmNhbGxlcgIcWW91IGRvbid0IGhhdmUgYSBkdWNrIHN0YWtlZAMDCQBmAgAABQZoZWFsdGgGCQBmAgUGaGVhbHRoAGQJAAIBAhpIUCBzaG91bGQgYmUgd2l0aGluIDAuLjEwMAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDWtleUR1Y2tIZWFsdGgBBQtkdWNrQXNzZXRJZAUGaGVhbHRoBQNuaWwBaQEOdXBkYXRlQmFja3BhY2sCC2R1Y2tBc3NldElkB25ld1BhY2sDCQECIT0CCAUBaQZjYWxsZXIFC2Vjb25vbXlBZGRyCQACAQIRcGVybWlzc2lvbiBkZW5pZWQJAJQKAgkAzAgCCQELU3RyaW5nRW50cnkCCQERa2V5QmFja3BhY2tCeUR1Y2sBBQtkdWNrQXNzZXRJZAUHbmV3UGFjawUDbmlsBQduZXdQYWNrALPSIhU=", "height": 2348452, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 7N2EXuiBVFiZofNKHDCSv4C4rwMCm9toECHF4eYEZgiZ Next: Et3s8ZDJ4U9GWbFSwaeomM5N4PJeGvvhmB7wLvbJs2D Diff:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4-let MULT6 = 1000000
4+let usdnAssetId = base58'HezsdQuRDtzksAYUy97gfhKy7Z1NW2uXYSHA3bgqenNZ'
55
6-let MULT8 = 100000000
6+let incubatorAddr = this
77
8-let usdnAssetId = base58'HezsdQuRDtzksAYUy97gfhKy7Z1NW2uXYSHA3bgqenNZ'
8+let breederAddr = this
99
1010 let backEndAddr = addressFromStringValue("3N5SpX21R3R75Qo4eb3MwFFvW7TUzyhvavv")
1111
12-let stakingContract = addressFromStringValue("3NDCyBG5q85JuaRiigUeEtainyjCQT3XpZm")
12+let economyAddr = addressFromStringValue("3N8y4wxX3JC4TdrCJBXX16SjWf6X256hrep")
13+
14+let pub = base58'6LfPuKJjLgekmncBhMg2LZyMTNVzZBccXR28ySXm9uXD'
15+
16+let LANDPREFIX = "LAND"
17+
18+let DUCKPREFIX = "DUCK"
1319
1420 let DEFAULTLOCATION = "Africa_F_Africa"
1521
16-let NUMRES = 6
22+let DAILYRESBYPIECE = 3456000
1723
18-let FACTORYMAXWAREHOUSE = 10000000000
24+let DAYMILLIS = 86400000
1925
20-let resTypes = ["Oil", "Ore", "Wood", "Sand", "Clay", "Organic"]
26+let FIVEMINUTESMILLIS = 300000
2127
22-let continents = ["Americas", "Europe", "Asia", "Africa", "Oceania"]
23-
24-func keyFactoryWarehouseByIdAndType (factoryId,resType) = ((("factoryWhByContinentAndRes_" + factoryId) + "_") + toString(resType))
28+func keyAssetIdToOwner (assetId) = ("nftOwner_" + assetId)
2529
2630
27-func keyAssetIdToOwner (assetId) = ("nftOwner_" + assetId)
31+func keyDuckIdToOwner (assetId) = ("duckOwner_" + assetId)
2832
2933
3034 func keyStakedTimeByAssetId (assetId) = ("stakedTime_" + assetId)
3337 func keyStakedDuckByOwner (ownerAddr) = ("stakedDuckByOwner_" + ownerAddr)
3438
3539
40+func keyStakedTimeByTypeAssetIdAndOwner (nftType,assetId,ownerAddr) = ((((("stakedTimeByTypeAssetIdAndOwner_" + nftType) + "_") + assetId) + "_") + ownerAddr)
41+
42+
43+func keyLandToOwner (landNum) = ("landOwner_" + landNum)
44+
45+
3646 func keyBackpackByDuck (duckAssetId) = ("backPack_" + duckAssetId)
3747
3848
3949 func keyDuckLocation (duckAssetId) = ("duckLocation_" + duckAssetId)
4050
4151
42-let idxType = 0
52+func keyDuckHealth (duckAssetId) = ("duckHealth_" + duckAssetId)
4353
44-let idxQuantity = 1
4554
46-let idxPrice = 2
55+let recLandNum = 0
56+
57+let recLandSize = 1
58+
59+let recTerrains = 2
60+
61+let recContinent = 3
4762
4863 let locIdxContinent = 0
4964
5974
6075 let bpIdxProd = 3
6176
62-func asString (v) = match v {
63- case s: String =>
64- s
77+let idxA = 0
78+
79+let idxB = 1
80+
81+let idxC = 2
82+
83+let idxD = 3
84+
85+let idxE = 4
86+
87+let idxF = 5
88+
89+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)]
90+
91+
92+func numPiecesBySize (landSize) = match landSize {
6593 case _ =>
66- throw("fail to cast into String")
94+ if (("S" == $match0))
95+ then 25
96+ else if (("M" == $match0))
97+ then 100
98+ else if (("L" == $match0))
99+ then 225
100+ else if (("XL" == $match0))
101+ then 400
102+ else if (("XXL" == $match0))
103+ then 625
104+ else throw("Unknown land size")
67105 }
68106
69107
70-func subRes (resList,resType,amount) = {
71- func subber (acc,i) = (acc :+ (if ((i == resType))
72- then toString((parseIntValue(resList[i]) - amount))
73- else resList[i]))
108+func addRes (currentRes,terrainCounts,deltaTime) = {
109+ func adder (acc,i) = {
110+ let resOfType = (fraction(deltaTime, DAILYRESBYPIECE, DAYMILLIS) * terrainCounts[i])
111+ (acc :+ toString((parseIntValue(currentRes[i]) + resOfType)))
112+ }
74113
75114 let r = {
76115 let $l = [0, 1, 2, 3, 4, 5]
78117 let $acc0 = nil
79118 func $f0_1 ($a,$i) = if (($i >= $s))
80119 then $a
81- else subber($a, $l[$i])
120+ else adder($a, $l[$i])
82121
83122 func $f0_2 ($a,$i) = if (($i >= $s))
84123 then $a
91130
92131
93132 @Callable(i)
94-func sellResource (resType,amount) = if (if ((0 > resType))
95- then true
96- else (resType >= NUMRES))
97- then throw(("Unknown resource: " + toString(resType)))
98- else if ((0 >= amount))
99- then throw(("Amount should be positive! " + toString(amount)))
133+func stakeLand () = {
134+ let pmt = value(i.payments[0])
135+ let assetId = value(pmt.assetId)
136+ let address = toString(i.caller)
137+ if ((pmt.amount != 1))
138+ then throw((("NFT " + LANDPREFIX) + " token should be attached as payment"))
100139 else {
101- let duckAssetId = valueOrErrorMessage(getString(stakingContract, keyStakedDuckByOwner(toString(i.caller))), "You don't have a duck staked")
102- if ((size(i.payments) != 0))
103- then throw("sellResources doesn't require any payments")
140+ let asset = value(assetInfo(assetId))
141+ if ((asset.issuer != this))
142+ then throw("Unknown issuer of token")
143+ else if (!(contains(asset.name, LANDPREFIX)))
144+ then throw((("Only NFT " + LANDPREFIX) + " tokens are accepted"))
145+ else {
146+ let landNumSize = drop(asset.name, 4)
147+ let landNum = if (contains(landNumSize, "XXL"))
148+ then dropRight(landNumSize, 3)
149+ else if (contains(landNumSize, "XL"))
150+ then dropRight(landNumSize, 2)
151+ else dropRight(landNumSize, 1)
152+ if (!(isDefined(parseInt(landNum))))
153+ then throw(("Cannot parse land number from " + asset.name))
154+ else {
155+ let timeKey = keyStakedTimeByAssetId(toBase58String(assetId))
156+ if (isDefined(getInteger(timeKey)))
157+ then throw((("NFT " + asset.name) + " is already staked"))
158+ else [IntegerEntry(timeKey, lastBlock.timestamp), IntegerEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, toBase58String(assetId), address), lastBlock.timestamp), StringEntry(keyAssetIdToOwner(toBase58String(assetId)), address), StringEntry(keyLandToOwner(landNum), address)]
159+ }
160+ }
161+ }
162+ }
163+
164+
165+
166+@Callable(i)
167+func unstakeLand (landAssetId) = if ((size(i.payments) != 0))
168+ then throw("unstake doesn't require any payments")
169+ else {
170+ let assetId = fromBase58String(landAssetId)
171+ let address = toString(i.caller)
172+ let asset = value(assetInfo(assetId))
173+ if ((asset.issuer != this))
174+ then throw("Unknown issuer of token")
175+ else if (!(contains(asset.name, LANDPREFIX)))
176+ then throw((("Only NFT " + LANDPREFIX) + " tokens can be unstaked"))
104177 else {
105- let curLocation = split(valueOrElse(getString(stakingContract, keyDuckLocation(duckAssetId)), DEFAULTLOCATION), "_")
106- if ((curLocation[locIdxType] != "F"))
107- then throw(("Duck location type should be Factory, but is " + curLocation[locIdxType]))
178+ let timeKey = keyStakedTimeByAssetId(landAssetId)
179+ if (!(isDefined(timeKey)))
180+ then throw((("NFT " + asset.name) + " is not staked"))
108181 else {
109- let bpKey = keyBackpackByDuck(duckAssetId)
110- let currentPack = split(valueOrElse(getString(stakingContract, bpKey), "0:0_0_0_0_0_0::"), ":")
111- let resList = split(currentPack[bpIdxRes], "_")
112- let currentRes = parseIntValue(resList[resType])
113- if ((amount > currentRes))
114- then throw(((((("You have " + toString(currentRes)) + " of ") + resTypes[resType]) + " in backpack, but tried to sell ") + toString(amount)))
182+ let owner = valueOrErrorMessage(getString(keyAssetIdToOwner(landAssetId)), (("NFT " + asset.name) + " is orphaned"))
183+ if ((owner != address))
184+ then throw("Staked NFT is not yours")
185+ else [ScriptTransfer(i.caller, 1, assetId), DeleteEntry(timeKey), DeleteEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, landAssetId, address))]
186+ }
187+ }
188+ }
189+
190+
191+
192+@Callable(i)
193+func stakeDuck () = {
194+ let pmt = value(i.payments[0])
195+ let assetId = value(pmt.assetId)
196+ let address = toString(i.caller)
197+ if ((pmt.amount != 1))
198+ then throw((("NFT " + DUCKPREFIX) + " token should be attached as payment"))
199+ else {
200+ let asset = value(assetInfo(assetId))
201+ if (if ((asset.issuer != incubatorAddr))
202+ then (asset.issuer != breederAddr)
203+ else false)
204+ then throw((("Unknown issuer of " + DUCKPREFIX) + " token"))
205+ else if (!(contains(asset.name, DUCKPREFIX)))
206+ then throw((("Only NFT " + DUCKPREFIX) + " tokens are accepted"))
207+ else {
208+ let assetIdStr = toBase58String(assetId)
209+ let timeKey = keyStakedTimeByAssetId(assetIdStr)
210+ if (isDefined(getInteger(timeKey)))
211+ then throw((("NFT " + asset.name) + " is already staked"))
212+ else if (isDefined(getString(keyStakedDuckByOwner(address))))
213+ then throw(("You already staked one duck: " + asset.name))
115214 else {
116- let whKey = keyFactoryWarehouseByIdAndType(curLocation[locIdxId], resType)
117- let w0 = valueOrElse(getInteger(whKey), 0)
118- let r0 = if ((w0 > FACTORYMAXWAREHOUSE))
119- then 0
120- else if (((w0 + amount) > FACTORYMAXWAREHOUSE))
121- then (FACTORYMAXWAREHOUSE - w0)
122- else amount
123- let usdnReceived = (fraction(r0, ((2 * MULT6) - fraction((w0 + (r0 / 2)), MULT6, FACTORYMAXWAREHOUSE)), MULT8) + ((amount - r0) / 100))
124- let bpRes = subRes(resList, resType, amount)
125- let newPack = makeString([currentPack[bpIdxLevel], bpRes, currentPack[bpIdxMat], currentPack[bpIdxProd]], ":")
126- let result = asString(invoke(stakingContract, "updateBackpack", [duckAssetId, newPack], nil))
127- $Tuple2([IntegerEntry(whKey, (w0 + amount)), ScriptTransfer(i.caller, usdnReceived, usdnAssetId)], result)
215+ let locKey = keyDuckLocation(assetIdStr)
216+ let location = getString(locKey)
217+ let keyHealth = keyDuckHealth(assetIdStr)
218+ let health = getInteger(keyHealth)
219+ let bpKey = keyBackpackByDuck(assetIdStr)
220+ let backpack = getString(bpKey)
221+ ([IntegerEntry(timeKey, lastBlock.timestamp), IntegerEntry(keyStakedTimeByTypeAssetIdAndOwner(DUCKPREFIX, toBase58String(assetId), address), lastBlock.timestamp), StringEntry(keyDuckIdToOwner(assetIdStr), address), StringEntry(keyStakedDuckByOwner(address), assetIdStr)] ++ (if (isDefined(location))
222+ then nil
223+ else ([StringEntry(locKey, DEFAULTLOCATION)] ++ (if (isDefined(health))
224+ then nil
225+ else ([IntegerEntry(keyHealth, 100)] ++ (if (isDefined(backpack))
226+ then nil
227+ else [StringEntry(bpKey, "0:0_0_0_0_0_0::")]))))))
128228 }
229+ }
230+ }
231+ }
232+
233+
234+
235+@Callable(i)
236+func unstakeDuck (assetIdStr) = if ((size(i.payments) != 0))
237+ then throw("unstake doesn't require any payments")
238+ else {
239+ let assetId = fromBase58String(assetIdStr)
240+ let address = toString(i.caller)
241+ let asset = value(assetInfo(assetId))
242+ if (if ((asset.issuer != incubatorAddr))
243+ then (asset.issuer != breederAddr)
244+ else false)
245+ then throw((("Unknown issuer of " + DUCKPREFIX) + " token"))
246+ else if (!(contains(asset.name, DUCKPREFIX)))
247+ then throw((("Only NFT " + DUCKPREFIX) + " tokens can be unstaked"))
248+ else {
249+ let timeKey = keyStakedTimeByAssetId(toBase58String(assetId))
250+ if (!(isDefined(timeKey)))
251+ then throw((("NFT " + asset.name) + " is not staked"))
252+ else if (!(isDefined(keyStakedDuckByOwner(address))))
253+ then throw((("The duck " + asset.name) + " is not staked"))
254+ else {
255+ let owner = valueOrErrorMessage(getString(keyDuckIdToOwner(toBase58String(assetId))), (("NFT " + asset.name) + " is orphaned"))
256+ if ((owner != address))
257+ then throw("Staked NFT is not yours")
258+ else [ScriptTransfer(i.caller, 1, assetId), DeleteEntry(timeKey), DeleteEntry(keyDuckLocation(assetIdStr)), DeleteEntry(keyStakedTimeByTypeAssetIdAndOwner(DUCKPREFIX, assetIdStr, address)), DeleteEntry(keyStakedDuckByOwner(address))]
259+ }
260+ }
261+ }
262+
263+
264+
265+@Callable(i)
266+func claimRes (amount,landAssetId) = if ((size(i.payments) != 0))
267+ then throw("claimRes doesn't require any payments")
268+ else {
269+ let addr = toString(i.caller)
270+ let asset = value(assetInfo(fromBase58String(landAssetId)))
271+ if (!(contains(asset.name, LANDPREFIX)))
272+ then throw((("NFT " + LANDPREFIX) + " token should be passed as param"))
273+ else {
274+ let timeKey = keyStakedTimeByAssetId(landAssetId)
275+ let savedTime = getInteger(timeKey)
276+ if (!(isDefined(savedTime)))
277+ then throw((("NFT " + asset.name) + " is not staked"))
278+ else {
279+ let owner = getStringValue(keyAssetIdToOwner(landAssetId))
280+ if ((owner != addr))
281+ then throw((LANDPREFIX + " is not yours"))
282+ else {
283+ let d = split(asset.description, "_")
284+ let landSize = d[recLandSize]
285+ let terrainCounts = countTerrains(d[recTerrains])
286+ let duck = getString(keyStakedDuckByOwner(addr))
287+ if (!(isDefined(duck)))
288+ then throw("You don't have a duck staked")
289+ else {
290+ let duckAssetIdStr = value(duck)
291+ let curLocation = valueOrElse(getString(keyDuckLocation(duckAssetIdStr)), DEFAULTLOCATION)
292+ let loc = split(value(curLocation), "_")
293+ if ((loc[locIdxType] != "L"))
294+ then throw((("Duck location type is " + loc[locIdxType]) + ", but should be L"))
295+ else if ((loc[locIdxId] != landAssetId))
296+ then throw(((("Duck location id is " + loc[locIdxId]) + ", but should be ") + landAssetId))
297+ else {
298+ let deltaTime = (lastBlock.timestamp - value(savedTime))
299+ if ((0 > deltaTime))
300+ then throw(((("Saved timestamp is in future, saved = " + toString(value(savedTime))) + ", current = ") + toString(lastBlock.timestamp)))
301+ else {
302+ let pieces = numPiecesBySize(landSize)
303+ let availRes = (fraction(deltaTime, DAILYRESBYPIECE, DAYMILLIS) * pieces)
304+ if ((amount > availRes))
305+ then throw(((("Not enough resources, available = " + toString(availRes)) + ", requested = ") + toString(amount)))
306+ else {
307+ let newDeltaTime = fraction((availRes - amount), DAYMILLIS, (pieces * DAILYRESBYPIECE))
308+ let newTimestamp = (lastBlock.timestamp - newDeltaTime)
309+ let bpKey = keyBackpackByDuck(duckAssetIdStr)
310+ let currentPack = split(valueOrElse(getString(bpKey), "0:0_0_0_0_0_0::"), ":")
311+ let currentRes = split(currentPack[bpIdxRes], "_")
312+ let bpRes = addRes(currentRes, terrainCounts, (deltaTime - newDeltaTime))
313+ let newPack = makeString([currentPack[bpIdxLevel], bpRes, currentPack[bpIdxMat], currentPack[bpIdxProd]], ":")
314+ $Tuple2([StringEntry(bpKey, newPack), IntegerEntry(timeKey, newTimestamp), IntegerEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, landAssetId, owner), newTimestamp)], unit)
315+ }
316+ }
317+ }
318+ }
319+ }
320+ }
321+ }
322+ }
323+
324+
325+
326+@Callable(i)
327+func flight (message,sig) = if (!(sigVerify_8Kb(message, sig, pub)))
328+ then throw("signature does not match")
329+ else if ((size(i.payments) != 0))
330+ then throw("flight doesn't require any payments")
331+ else {
332+ let parts = split(toUtf8String(message), ";")
333+ let hp = split(split(parts[0], "|")[0], "_")
334+ let curHP = parseIntValue(hp[1])
335+ let newHP = parseIntValue(hp[1])
336+ let newLocAndTime = split(parts[1], ":")
337+ let newLocation = newLocAndTime[0]
338+ let time = parseIntValue(newLocAndTime[1])
339+ if (if ((time > lastBlock.timestamp))
340+ then true
341+ else ((lastBlock.timestamp - FIVEMINUTESMILLIS) > time))
342+ then throw("signature outdated")
343+ else {
344+ let duckAssetId = valueOrErrorMessage(getString(keyStakedDuckByOwner(toString(i.caller))), "You don't have a duck staked")
345+ let keyHealth = keyDuckHealth(duckAssetId)
346+ let oldFromState = valueOrElse(getInteger(keyHealth), 100)
347+ if ((oldFromState != curHP))
348+ then throw(((("oldHealth=" + toString(valueOrElse(getInteger(keyHealth), 100))) + " from state does not match one from flight log=") + toString(curHP)))
349+ else {
350+ let locKey = keyDuckLocation(duckAssetId)
351+ let curLocation = valueOrElse(getString(locKey), DEFAULTLOCATION)
352+ if ((newLocation == curLocation))
353+ then throw("You can't fly to the same location")
354+ else $Tuple2([StringEntry(locKey, if ((newHP > 0))
355+ then newLocation
356+ else curLocation), IntegerEntry(keyHealth, newHP)], unit)
129357 }
130358 }
131359 }
360+
361+
362+
363+@Callable(i)
364+func setHealth (health,duckAssetId) = {
365+ let duckAssetIdStr = valueOrErrorMessage(getString(keyStakedDuckByOwner(toString(i.caller))), "You don't have a duck staked")
366+ if (if ((0 > health))
367+ then true
368+ else (health > 100))
369+ then throw("HP should be within 0..100")
370+ else [IntegerEntry(keyDuckHealth(duckAssetId), health)]
371+ }
372+
373+
374+
375+@Callable(i)
376+func updateBackpack (duckAssetId,newPack) = if ((i.caller != economyAddr))
377+ then throw("permission denied")
378+ else $Tuple2([StringEntry(keyBackpackByDuck(duckAssetId), newPack)], newPack)
132379
133380
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4-let MULT6 = 1000000
4+let usdnAssetId = base58'HezsdQuRDtzksAYUy97gfhKy7Z1NW2uXYSHA3bgqenNZ'
55
6-let MULT8 = 100000000
6+let incubatorAddr = this
77
8-let usdnAssetId = base58'HezsdQuRDtzksAYUy97gfhKy7Z1NW2uXYSHA3bgqenNZ'
8+let breederAddr = this
99
1010 let backEndAddr = addressFromStringValue("3N5SpX21R3R75Qo4eb3MwFFvW7TUzyhvavv")
1111
12-let stakingContract = addressFromStringValue("3NDCyBG5q85JuaRiigUeEtainyjCQT3XpZm")
12+let economyAddr = addressFromStringValue("3N8y4wxX3JC4TdrCJBXX16SjWf6X256hrep")
13+
14+let pub = base58'6LfPuKJjLgekmncBhMg2LZyMTNVzZBccXR28ySXm9uXD'
15+
16+let LANDPREFIX = "LAND"
17+
18+let DUCKPREFIX = "DUCK"
1319
1420 let DEFAULTLOCATION = "Africa_F_Africa"
1521
16-let NUMRES = 6
22+let DAILYRESBYPIECE = 3456000
1723
18-let FACTORYMAXWAREHOUSE = 10000000000
24+let DAYMILLIS = 86400000
1925
20-let resTypes = ["Oil", "Ore", "Wood", "Sand", "Clay", "Organic"]
26+let FIVEMINUTESMILLIS = 300000
2127
22-let continents = ["Americas", "Europe", "Asia", "Africa", "Oceania"]
23-
24-func keyFactoryWarehouseByIdAndType (factoryId,resType) = ((("factoryWhByContinentAndRes_" + factoryId) + "_") + toString(resType))
28+func keyAssetIdToOwner (assetId) = ("nftOwner_" + assetId)
2529
2630
27-func keyAssetIdToOwner (assetId) = ("nftOwner_" + assetId)
31+func keyDuckIdToOwner (assetId) = ("duckOwner_" + assetId)
2832
2933
3034 func keyStakedTimeByAssetId (assetId) = ("stakedTime_" + assetId)
3135
3236
3337 func keyStakedDuckByOwner (ownerAddr) = ("stakedDuckByOwner_" + ownerAddr)
3438
3539
40+func keyStakedTimeByTypeAssetIdAndOwner (nftType,assetId,ownerAddr) = ((((("stakedTimeByTypeAssetIdAndOwner_" + nftType) + "_") + assetId) + "_") + ownerAddr)
41+
42+
43+func keyLandToOwner (landNum) = ("landOwner_" + landNum)
44+
45+
3646 func keyBackpackByDuck (duckAssetId) = ("backPack_" + duckAssetId)
3747
3848
3949 func keyDuckLocation (duckAssetId) = ("duckLocation_" + duckAssetId)
4050
4151
42-let idxType = 0
52+func keyDuckHealth (duckAssetId) = ("duckHealth_" + duckAssetId)
4353
44-let idxQuantity = 1
4554
46-let idxPrice = 2
55+let recLandNum = 0
56+
57+let recLandSize = 1
58+
59+let recTerrains = 2
60+
61+let recContinent = 3
4762
4863 let locIdxContinent = 0
4964
5065 let locIdxType = 1
5166
5267 let locIdxId = 2
5368
5469 let bpIdxLevel = 0
5570
5671 let bpIdxRes = 1
5772
5873 let bpIdxMat = 2
5974
6075 let bpIdxProd = 3
6176
62-func asString (v) = match v {
63- case s: String =>
64- s
77+let idxA = 0
78+
79+let idxB = 1
80+
81+let idxC = 2
82+
83+let idxD = 3
84+
85+let idxE = 4
86+
87+let idxF = 5
88+
89+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)]
90+
91+
92+func numPiecesBySize (landSize) = match landSize {
6593 case _ =>
66- throw("fail to cast into String")
94+ if (("S" == $match0))
95+ then 25
96+ else if (("M" == $match0))
97+ then 100
98+ else if (("L" == $match0))
99+ then 225
100+ else if (("XL" == $match0))
101+ then 400
102+ else if (("XXL" == $match0))
103+ then 625
104+ else throw("Unknown land size")
67105 }
68106
69107
70-func subRes (resList,resType,amount) = {
71- func subber (acc,i) = (acc :+ (if ((i == resType))
72- then toString((parseIntValue(resList[i]) - amount))
73- else resList[i]))
108+func addRes (currentRes,terrainCounts,deltaTime) = {
109+ func adder (acc,i) = {
110+ let resOfType = (fraction(deltaTime, DAILYRESBYPIECE, DAYMILLIS) * terrainCounts[i])
111+ (acc :+ toString((parseIntValue(currentRes[i]) + resOfType)))
112+ }
74113
75114 let r = {
76115 let $l = [0, 1, 2, 3, 4, 5]
77116 let $s = size($l)
78117 let $acc0 = nil
79118 func $f0_1 ($a,$i) = if (($i >= $s))
80119 then $a
81- else subber($a, $l[$i])
120+ else adder($a, $l[$i])
82121
83122 func $f0_2 ($a,$i) = if (($i >= $s))
84123 then $a
85124 else throw("List size exceeds 6")
86125
87126 $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
88127 }
89128 makeString(r, "_")
90129 }
91130
92131
93132 @Callable(i)
94-func sellResource (resType,amount) = if (if ((0 > resType))
95- then true
96- else (resType >= NUMRES))
97- then throw(("Unknown resource: " + toString(resType)))
98- else if ((0 >= amount))
99- then throw(("Amount should be positive! " + toString(amount)))
133+func stakeLand () = {
134+ let pmt = value(i.payments[0])
135+ let assetId = value(pmt.assetId)
136+ let address = toString(i.caller)
137+ if ((pmt.amount != 1))
138+ then throw((("NFT " + LANDPREFIX) + " token should be attached as payment"))
100139 else {
101- let duckAssetId = valueOrErrorMessage(getString(stakingContract, keyStakedDuckByOwner(toString(i.caller))), "You don't have a duck staked")
102- if ((size(i.payments) != 0))
103- then throw("sellResources doesn't require any payments")
140+ let asset = value(assetInfo(assetId))
141+ if ((asset.issuer != this))
142+ then throw("Unknown issuer of token")
143+ else if (!(contains(asset.name, LANDPREFIX)))
144+ then throw((("Only NFT " + LANDPREFIX) + " tokens are accepted"))
145+ else {
146+ let landNumSize = drop(asset.name, 4)
147+ let landNum = if (contains(landNumSize, "XXL"))
148+ then dropRight(landNumSize, 3)
149+ else if (contains(landNumSize, "XL"))
150+ then dropRight(landNumSize, 2)
151+ else dropRight(landNumSize, 1)
152+ if (!(isDefined(parseInt(landNum))))
153+ then throw(("Cannot parse land number from " + asset.name))
154+ else {
155+ let timeKey = keyStakedTimeByAssetId(toBase58String(assetId))
156+ if (isDefined(getInteger(timeKey)))
157+ then throw((("NFT " + asset.name) + " is already staked"))
158+ else [IntegerEntry(timeKey, lastBlock.timestamp), IntegerEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, toBase58String(assetId), address), lastBlock.timestamp), StringEntry(keyAssetIdToOwner(toBase58String(assetId)), address), StringEntry(keyLandToOwner(landNum), address)]
159+ }
160+ }
161+ }
162+ }
163+
164+
165+
166+@Callable(i)
167+func unstakeLand (landAssetId) = if ((size(i.payments) != 0))
168+ then throw("unstake doesn't require any payments")
169+ else {
170+ let assetId = fromBase58String(landAssetId)
171+ let address = toString(i.caller)
172+ let asset = value(assetInfo(assetId))
173+ if ((asset.issuer != this))
174+ then throw("Unknown issuer of token")
175+ else if (!(contains(asset.name, LANDPREFIX)))
176+ then throw((("Only NFT " + LANDPREFIX) + " tokens can be unstaked"))
104177 else {
105- let curLocation = split(valueOrElse(getString(stakingContract, keyDuckLocation(duckAssetId)), DEFAULTLOCATION), "_")
106- if ((curLocation[locIdxType] != "F"))
107- then throw(("Duck location type should be Factory, but is " + curLocation[locIdxType]))
178+ let timeKey = keyStakedTimeByAssetId(landAssetId)
179+ if (!(isDefined(timeKey)))
180+ then throw((("NFT " + asset.name) + " is not staked"))
108181 else {
109- let bpKey = keyBackpackByDuck(duckAssetId)
110- let currentPack = split(valueOrElse(getString(stakingContract, bpKey), "0:0_0_0_0_0_0::"), ":")
111- let resList = split(currentPack[bpIdxRes], "_")
112- let currentRes = parseIntValue(resList[resType])
113- if ((amount > currentRes))
114- then throw(((((("You have " + toString(currentRes)) + " of ") + resTypes[resType]) + " in backpack, but tried to sell ") + toString(amount)))
182+ let owner = valueOrErrorMessage(getString(keyAssetIdToOwner(landAssetId)), (("NFT " + asset.name) + " is orphaned"))
183+ if ((owner != address))
184+ then throw("Staked NFT is not yours")
185+ else [ScriptTransfer(i.caller, 1, assetId), DeleteEntry(timeKey), DeleteEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, landAssetId, address))]
186+ }
187+ }
188+ }
189+
190+
191+
192+@Callable(i)
193+func stakeDuck () = {
194+ let pmt = value(i.payments[0])
195+ let assetId = value(pmt.assetId)
196+ let address = toString(i.caller)
197+ if ((pmt.amount != 1))
198+ then throw((("NFT " + DUCKPREFIX) + " token should be attached as payment"))
199+ else {
200+ let asset = value(assetInfo(assetId))
201+ if (if ((asset.issuer != incubatorAddr))
202+ then (asset.issuer != breederAddr)
203+ else false)
204+ then throw((("Unknown issuer of " + DUCKPREFIX) + " token"))
205+ else if (!(contains(asset.name, DUCKPREFIX)))
206+ then throw((("Only NFT " + DUCKPREFIX) + " tokens are accepted"))
207+ else {
208+ let assetIdStr = toBase58String(assetId)
209+ let timeKey = keyStakedTimeByAssetId(assetIdStr)
210+ if (isDefined(getInteger(timeKey)))
211+ then throw((("NFT " + asset.name) + " is already staked"))
212+ else if (isDefined(getString(keyStakedDuckByOwner(address))))
213+ then throw(("You already staked one duck: " + asset.name))
115214 else {
116- let whKey = keyFactoryWarehouseByIdAndType(curLocation[locIdxId], resType)
117- let w0 = valueOrElse(getInteger(whKey), 0)
118- let r0 = if ((w0 > FACTORYMAXWAREHOUSE))
119- then 0
120- else if (((w0 + amount) > FACTORYMAXWAREHOUSE))
121- then (FACTORYMAXWAREHOUSE - w0)
122- else amount
123- let usdnReceived = (fraction(r0, ((2 * MULT6) - fraction((w0 + (r0 / 2)), MULT6, FACTORYMAXWAREHOUSE)), MULT8) + ((amount - r0) / 100))
124- let bpRes = subRes(resList, resType, amount)
125- let newPack = makeString([currentPack[bpIdxLevel], bpRes, currentPack[bpIdxMat], currentPack[bpIdxProd]], ":")
126- let result = asString(invoke(stakingContract, "updateBackpack", [duckAssetId, newPack], nil))
127- $Tuple2([IntegerEntry(whKey, (w0 + amount)), ScriptTransfer(i.caller, usdnReceived, usdnAssetId)], result)
215+ let locKey = keyDuckLocation(assetIdStr)
216+ let location = getString(locKey)
217+ let keyHealth = keyDuckHealth(assetIdStr)
218+ let health = getInteger(keyHealth)
219+ let bpKey = keyBackpackByDuck(assetIdStr)
220+ let backpack = getString(bpKey)
221+ ([IntegerEntry(timeKey, lastBlock.timestamp), IntegerEntry(keyStakedTimeByTypeAssetIdAndOwner(DUCKPREFIX, toBase58String(assetId), address), lastBlock.timestamp), StringEntry(keyDuckIdToOwner(assetIdStr), address), StringEntry(keyStakedDuckByOwner(address), assetIdStr)] ++ (if (isDefined(location))
222+ then nil
223+ else ([StringEntry(locKey, DEFAULTLOCATION)] ++ (if (isDefined(health))
224+ then nil
225+ else ([IntegerEntry(keyHealth, 100)] ++ (if (isDefined(backpack))
226+ then nil
227+ else [StringEntry(bpKey, "0:0_0_0_0_0_0::")]))))))
128228 }
229+ }
230+ }
231+ }
232+
233+
234+
235+@Callable(i)
236+func unstakeDuck (assetIdStr) = if ((size(i.payments) != 0))
237+ then throw("unstake doesn't require any payments")
238+ else {
239+ let assetId = fromBase58String(assetIdStr)
240+ let address = toString(i.caller)
241+ let asset = value(assetInfo(assetId))
242+ if (if ((asset.issuer != incubatorAddr))
243+ then (asset.issuer != breederAddr)
244+ else false)
245+ then throw((("Unknown issuer of " + DUCKPREFIX) + " token"))
246+ else if (!(contains(asset.name, DUCKPREFIX)))
247+ then throw((("Only NFT " + DUCKPREFIX) + " tokens can be unstaked"))
248+ else {
249+ let timeKey = keyStakedTimeByAssetId(toBase58String(assetId))
250+ if (!(isDefined(timeKey)))
251+ then throw((("NFT " + asset.name) + " is not staked"))
252+ else if (!(isDefined(keyStakedDuckByOwner(address))))
253+ then throw((("The duck " + asset.name) + " is not staked"))
254+ else {
255+ let owner = valueOrErrorMessage(getString(keyDuckIdToOwner(toBase58String(assetId))), (("NFT " + asset.name) + " is orphaned"))
256+ if ((owner != address))
257+ then throw("Staked NFT is not yours")
258+ else [ScriptTransfer(i.caller, 1, assetId), DeleteEntry(timeKey), DeleteEntry(keyDuckLocation(assetIdStr)), DeleteEntry(keyStakedTimeByTypeAssetIdAndOwner(DUCKPREFIX, assetIdStr, address)), DeleteEntry(keyStakedDuckByOwner(address))]
259+ }
260+ }
261+ }
262+
263+
264+
265+@Callable(i)
266+func claimRes (amount,landAssetId) = if ((size(i.payments) != 0))
267+ then throw("claimRes doesn't require any payments")
268+ else {
269+ let addr = toString(i.caller)
270+ let asset = value(assetInfo(fromBase58String(landAssetId)))
271+ if (!(contains(asset.name, LANDPREFIX)))
272+ then throw((("NFT " + LANDPREFIX) + " token should be passed as param"))
273+ else {
274+ let timeKey = keyStakedTimeByAssetId(landAssetId)
275+ let savedTime = getInteger(timeKey)
276+ if (!(isDefined(savedTime)))
277+ then throw((("NFT " + asset.name) + " is not staked"))
278+ else {
279+ let owner = getStringValue(keyAssetIdToOwner(landAssetId))
280+ if ((owner != addr))
281+ then throw((LANDPREFIX + " is not yours"))
282+ else {
283+ let d = split(asset.description, "_")
284+ let landSize = d[recLandSize]
285+ let terrainCounts = countTerrains(d[recTerrains])
286+ let duck = getString(keyStakedDuckByOwner(addr))
287+ if (!(isDefined(duck)))
288+ then throw("You don't have a duck staked")
289+ else {
290+ let duckAssetIdStr = value(duck)
291+ let curLocation = valueOrElse(getString(keyDuckLocation(duckAssetIdStr)), DEFAULTLOCATION)
292+ let loc = split(value(curLocation), "_")
293+ if ((loc[locIdxType] != "L"))
294+ then throw((("Duck location type is " + loc[locIdxType]) + ", but should be L"))
295+ else if ((loc[locIdxId] != landAssetId))
296+ then throw(((("Duck location id is " + loc[locIdxId]) + ", but should be ") + landAssetId))
297+ else {
298+ let deltaTime = (lastBlock.timestamp - value(savedTime))
299+ if ((0 > deltaTime))
300+ then throw(((("Saved timestamp is in future, saved = " + toString(value(savedTime))) + ", current = ") + toString(lastBlock.timestamp)))
301+ else {
302+ let pieces = numPiecesBySize(landSize)
303+ let availRes = (fraction(deltaTime, DAILYRESBYPIECE, DAYMILLIS) * pieces)
304+ if ((amount > availRes))
305+ then throw(((("Not enough resources, available = " + toString(availRes)) + ", requested = ") + toString(amount)))
306+ else {
307+ let newDeltaTime = fraction((availRes - amount), DAYMILLIS, (pieces * DAILYRESBYPIECE))
308+ let newTimestamp = (lastBlock.timestamp - newDeltaTime)
309+ let bpKey = keyBackpackByDuck(duckAssetIdStr)
310+ let currentPack = split(valueOrElse(getString(bpKey), "0:0_0_0_0_0_0::"), ":")
311+ let currentRes = split(currentPack[bpIdxRes], "_")
312+ let bpRes = addRes(currentRes, terrainCounts, (deltaTime - newDeltaTime))
313+ let newPack = makeString([currentPack[bpIdxLevel], bpRes, currentPack[bpIdxMat], currentPack[bpIdxProd]], ":")
314+ $Tuple2([StringEntry(bpKey, newPack), IntegerEntry(timeKey, newTimestamp), IntegerEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, landAssetId, owner), newTimestamp)], unit)
315+ }
316+ }
317+ }
318+ }
319+ }
320+ }
321+ }
322+ }
323+
324+
325+
326+@Callable(i)
327+func flight (message,sig) = if (!(sigVerify_8Kb(message, sig, pub)))
328+ then throw("signature does not match")
329+ else if ((size(i.payments) != 0))
330+ then throw("flight doesn't require any payments")
331+ else {
332+ let parts = split(toUtf8String(message), ";")
333+ let hp = split(split(parts[0], "|")[0], "_")
334+ let curHP = parseIntValue(hp[1])
335+ let newHP = parseIntValue(hp[1])
336+ let newLocAndTime = split(parts[1], ":")
337+ let newLocation = newLocAndTime[0]
338+ let time = parseIntValue(newLocAndTime[1])
339+ if (if ((time > lastBlock.timestamp))
340+ then true
341+ else ((lastBlock.timestamp - FIVEMINUTESMILLIS) > time))
342+ then throw("signature outdated")
343+ else {
344+ let duckAssetId = valueOrErrorMessage(getString(keyStakedDuckByOwner(toString(i.caller))), "You don't have a duck staked")
345+ let keyHealth = keyDuckHealth(duckAssetId)
346+ let oldFromState = valueOrElse(getInteger(keyHealth), 100)
347+ if ((oldFromState != curHP))
348+ then throw(((("oldHealth=" + toString(valueOrElse(getInteger(keyHealth), 100))) + " from state does not match one from flight log=") + toString(curHP)))
349+ else {
350+ let locKey = keyDuckLocation(duckAssetId)
351+ let curLocation = valueOrElse(getString(locKey), DEFAULTLOCATION)
352+ if ((newLocation == curLocation))
353+ then throw("You can't fly to the same location")
354+ else $Tuple2([StringEntry(locKey, if ((newHP > 0))
355+ then newLocation
356+ else curLocation), IntegerEntry(keyHealth, newHP)], unit)
129357 }
130358 }
131359 }
360+
361+
362+
363+@Callable(i)
364+func setHealth (health,duckAssetId) = {
365+ let duckAssetIdStr = valueOrErrorMessage(getString(keyStakedDuckByOwner(toString(i.caller))), "You don't have a duck staked")
366+ if (if ((0 > health))
367+ then true
368+ else (health > 100))
369+ then throw("HP should be within 0..100")
370+ else [IntegerEntry(keyDuckHealth(duckAssetId), health)]
371+ }
372+
373+
374+
375+@Callable(i)
376+func updateBackpack (duckAssetId,newPack) = if ((i.caller != economyAddr))
377+ then throw("permission denied")
378+ else $Tuple2([StringEntry(keyBackpackByDuck(duckAssetId), newPack)], newPack)
132379
133380

github/deemru/w8io/873ac7e 
55.12 ms