tx · 9UucCZm2RobSgxz8zYjLzGz4wUmhKW3PYF516sUWvKab

3P36HH7i6BBuuNp7FHQd6WX8gzfogi778i6:  -0.05000000 Waves

2022.10.06 17:10 [3326048] smart account 3P36HH7i6BBuuNp7FHQd6WX8gzfogi778i6 > SELF 0.00000000 Waves

{ "type": 13, "id": "9UucCZm2RobSgxz8zYjLzGz4wUmhKW3PYF516sUWvKab", "fee": 5000000, "feeAssetId": null, "timestamp": 1665065497060, "version": 2, "chainId": 87, "sender": "3P36HH7i6BBuuNp7FHQd6WX8gzfogi778i6", "senderPublicKey": "3xRzVfzGz2mW1Y3XAqQwVN4RiiWSgAHpLFmaF24hhfY9", "proofs": [ "56HRJe1QQGduJcXyVV5mUHqz1je7mnAXbUFChDBx2LMHpyWSBQW9GypQyzop6PMDA1DPZMP1P3qCRUsjskyPcW4m" ], "script": "base64:BgIfCAISAwoBCBIAEgUKAwgIARIGCgQICAEBEgMKAQgSAB8BFHRyeUdldFN0cmluZ0V4dGVybmFsAgdhZGRyZXNzA2tleQQHJG1hdGNoMAkAnQgCBQdhZGRyZXNzBQNrZXkDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFhBQckbWF0Y2gwBQFhAgABFXRyeUdldEludGVnZXJFeHRlcm5hbAIHYWRkcmVzcwNrZXkEByRtYXRjaDAJAJoIAgUHYWRkcmVzcwUDa2V5AwkAAQIFByRtYXRjaDACA0ludAQBYgUHJG1hdGNoMAUBYgAAAQ10cnlHZXRCb29sZWFuAQNrZXkEByRtYXRjaDAJAKAIAQUDa2V5AwkAAQIFByRtYXRjaDACB0Jvb2xlYW4EAWIFByRtYXRjaDAFAWIHAQx0cnlHZXRTdHJpbmcBA2tleQkBFHRyeUdldFN0cmluZ0V4dGVybmFsAgUEdGhpcwUDa2V5AQlnZXRPcmFjbGUACQEHQWRkcmVzcwEJANkEAQkBDHRyeUdldFN0cmluZwECFHN0YXRpY19vcmFjbGVBZGRyZXNzARBnZXREdWNrbGluZ1ByaWNlAAkBFXRyeUdldEludGVnZXJFeHRlcm5hbAIJAQlnZXRPcmFjbGUAAhRzdGF0aWNfZHVja2xpbmdQcmljZQENZ2V0RWdnQXNzZXRJZAAJANkEAQkBFHRyeUdldFN0cmluZ0V4dGVybmFsAgkBCWdldE9yYWNsZQACEXN0YXRpY19lZ2dBc3NldElkAQ9nZXRTcGljZUFzc2V0SWQACQDZBAEJARR0cnlHZXRTdHJpbmdFeHRlcm5hbAIJAQlnZXRPcmFjbGUAAhNzdGF0aWNfc3BpY2VBc3NldElkARFnZXRSZWJpcnRoQWRkcmVzcwAJAQdBZGRyZXNzAQkA2QQBCQEUdHJ5R2V0U3RyaW5nRXh0ZXJuYWwCCQEJZ2V0T3JhY2xlAAIVc3RhdGljX3JlYmlydGhBZGRyZXNzARNnZXRJbmN1YmF0b3JBZGRyZXNzAAkBB0FkZHJlc3MBCQDZBAEJARR0cnlHZXRTdHJpbmdFeHRlcm5hbAIJAQlnZXRPcmFjbGUAAhdzdGF0aWNfaW5jdWJhdG9yQWRkcmVzcwERZ2V0Q291cG9uc0FkZHJlc3MACQEHQWRkcmVzcwEJANkEAQkBFHRyeUdldFN0cmluZ0V4dGVybmFsAgkBCWdldE9yYWNsZQACFXN0YXRpY19jb3Vwb25zQWRkcmVzcwEOZ2V0QnVybkFkZHJlc3MACQEHQWRkcmVzcwEJANkEAQkBFHRyeUdldFN0cmluZ0V4dGVybmFsAgkBCWdldE9yYWNsZQACEnN0YXRpY19idXJuQWRkcmVzcwANYmFja2VuZFB1YktleQkA2QQBCQERQGV4dHJOYXRpdmUoMTA1MykCCQEJZ2V0T3JhY2xlAAIUc3RhdGljX2JhY2tlbmRQdWJLZXkADURVQ0tMSU5HUFJJQ0UAgMLXLwAWcGVyY2VudEdyb3d0aFByZWNpc2lvbgCAgIT+pt7hEQAVZXhpc3RpbmdEdWNrUHJlY2lzaW9uAICA6YOx3hYAFktHbG9iYWxJc3N1ZWRUaW1lc3RhbXACF2dsb2JhbF9pc3N1ZWRfdGltZXN0YW1wAQxrZXlUb3RhbEZlZWQBCmR1Y2tsaW5nSWQJAKwCAgkArAICAglkdWNrbGluZ18FCmR1Y2tsaW5nSWQCC19mZWVkX3NwaWNlAQ9rZXlBZGRyZXNzTm9uY2UBB2FkZHJlc3MJAKwCAgkArAICAghhZGRyZXNzXwUHYWRkcmVzcwIGX25vbmNlARBrZXlEdWNrbGluZ0xldmVsAQpkdWNrbGluZ0lkCQCsAgIJAKwCAgIJZHVja2xpbmdfBQpkdWNrbGluZ0lkAgZfbGV2ZWwBEGtleUR1Y2tsaW5nR3Jvd24BCmR1Y2tsaW5nSWQJAKwCAgkArAICAglkdWNrbGluZ18FCmR1Y2tsaW5nSWQCBl9ncm93bgESa2V5U3RhcnRQZXJjZW50YWdlAQpkdWNrbGluZ0lkCQCsAgIJAKwCAgIJZHVja2xpbmdfBQpkdWNrbGluZ0lkAhBfc3RhcnRQZXJjZW50YWdlAQhrZXlPd25lcgEKZHVja2xpbmdJZAkArAICCQCsAgICCWR1Y2tsaW5nXwUKZHVja2xpbmdJZAIGX293bmVyAQ5rZXlCbGFja2xpc3RlZAEKZHVja2xpbmdJZAkArAICCQCsAgICCWR1Y2tsaW5nXwUKZHVja2xpbmdJZAIMX2JsYWNrbGlzdGVkAQ10cnlHZXRJbnRlZ2VyAQNrZXkEA3ZhbAQHJG1hdGNoMAkAmggCBQR0aGlzBQNrZXkDCQABAgUHJG1hdGNoMAIDSW50BAFiBQckbWF0Y2gwBQFiAAAFA3ZhbAEHZ2V0Qm9vbAEDa2V5BAckbWF0Y2gwCQCbCAIFBHRoaXMFA2tleQMJAAECBQckbWF0Y2gwAgdCb29sZWFuBAFiBQckbWF0Y2gwBQFiBwEVZ2V0RHVja2xpbmdQZXJjZW50YWdlAQpkdWNrbGluZ0lkBBJwZXJjZW50YWdlRHVja2xpbmcJAQ10cnlHZXRJbnRlZ2VyAQkBEmtleVN0YXJ0UGVyY2VudGFnZQEFCmR1Y2tsaW5nSWQEBGJhc2UDCQECIT0CBRJwZXJjZW50YWdlRHVja2xpbmcAAAUScGVyY2VudGFnZUR1Y2tsaW5nABQJALYCAQkAaAIFBGJhc2UFFWV4aXN0aW5nRHVja1ByZWNpc2lvbgEVZ2V0Q3VycmVudExldmVsQmlnSW50AQpkdWNrbGluZ0lkBAprRHVja0xldmVsCQEQa2V5RHVja2xpbmdMZXZlbAEFCmR1Y2tsaW5nSWQEByRtYXRjaDAJAKIIAQUKa0R1Y2tMZXZlbAMJAAECBQckbWF0Y2gwAgZTdHJpbmcEAXMFByRtYXRjaDAJAKcDAQUBcwQHJG1hdGNoMQkAoAgBCQCsAgIJAKwCAgIJZHVja2xpbmdfBQpkdWNrbGluZ0lkAhFfaXNzdWVkQnlGZWVkQ2FsbAMJAAECBQckbWF0Y2gxAgdCb29sZWFuBAFiBQckbWF0Y2gxAwkAAAIFAWIGCQC2AgEAAAkBFWdldER1Y2tsaW5nUGVyY2VudGFnZQEFCmR1Y2tsaW5nSWQJARVnZXREdWNrbGluZ1BlcmNlbnRhZ2UBBQpkdWNrbGluZ0lkARljYWxjdWxhdGVOZXdEdWNrbGluZ0xldmVsAgpkdWNrbGluZ0lkDXBheW1lbnRBbW91bnQECWN1cnJlbnRUcwgFCWxhc3RCbG9jawl0aW1lc3RhbXAEBmdyb3d0aAkAvAIDCQC2AgEFDXBheW1lbnRBbW91bnQJALYCAQUWcGVyY2VudEdyb3d0aFByZWNpc2lvbgkAtgIBBQ1EVUNLTElOR1BSSUNFBAxjdXJyZW50TGV2ZWwJARVnZXRDdXJyZW50TGV2ZWxCaWdJbnQBBQpkdWNrbGluZ0lkBAhuZXdMZXZlbAkAtwICBQxjdXJyZW50TGV2ZWwFBmdyb3d0aAQGcmVzdWx0CQCmAwEFCG5ld0xldmVsCQCUCgIFBnJlc3VsdAkAzAgCCQCsAgICDWN1cnJlbnRMZXZlbD0JAKYDAQUMY3VycmVudExldmVsCQDMCAIJAKwCAgIJbmV3TGV2ZWw9CQCmAwEFCG5ld0xldmVsCQDMCAIJAKwCAgIHZ3Jvd3RoPQkApgMBBQZncm93dGgFA25pbAEPZ2V0QmFja2VuZFByb29mAw1tYXhGZWVkQW1vdW50CXVzZXJOb25jZQdhZGRyZXNzCQC5CQIJAMwIAgkApAMBBQ1tYXhGZWVkQW1vdW50CQDMCAIJAKQDAQUJdXNlck5vbmNlCQDMCAIFB2FkZHJlc3MFA25pbAIBOwEFYXNJbnQBBXZhbHVlBAckbWF0Y2gwBQV2YWx1ZQMJAAECBQckbWF0Y2gwAgNJbnQEA2ludAUHJG1hdGNoMAUDaW50CQACAQIeQkFJOiB3cm9uZyB0eXBlLCBleHBlY3RlZDogSW50BgFpAQ9jb25maWd1cmVPcmFjbGUBBm9yYWNsZQMJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwkAAgECD0JDTzogYWRtaW4gb25seQkAzAgCCQELU3RyaW5nRW50cnkCAhRzdGF0aWNfb3JhY2xlQWRkcmVzcwUGb3JhY2xlBQNuaWwBaQELYnV5RHVja2xpbmcABApleGFjdFByaWNlCQEQZ2V0RHVja2xpbmdQcmljZQADCQBmAgCA4esXBQpleGFjdFByaWNlCQACAQIfQkJEOiBJbnZhbGlkIHByaWNlIGZyb20gb3JhY2xlIQQTYW1vdW50UGFpZEJ5Q291cG9ucwkBBWFzSW50AQkA/AcECQERZ2V0Q291cG9uc0FkZHJlc3MAAgp1c2VDb3Vwb25zCQDMCAIFCmV4YWN0UHJpY2UFA25pbAUDbmlsAwkAAAIFE2Ftb3VudFBhaWRCeUNvdXBvbnMFE2Ftb3VudFBhaWRCeUNvdXBvbnMECWxlZnRUb1BheQkAZQIFCmV4YWN0UHJpY2UFE2Ftb3VudFBhaWRCeUNvdXBvbnMEB3BheW1lbnQDCQECIT0CBQlsZWZ0VG9QYXkAAAQMZmlyc3RQYXltZW50CQEFdmFsdWUBCQCRAwIIBQFpCHBheW1lbnRzAAADCQECIT0CCAUMZmlyc3RQYXltZW50B2Fzc2V0SWQJAQ1nZXRFZ2dBc3NldElkAAkAAgEJAKwCAgJBQkJEOiBZb3UgY2FuIGF0dGFjaCBvbmx5IEVHRyB0b2tlbnMgd2l0aCB0aGUgZm9sbG93aW5nIGFzc2V0IGlkOiAJANgEAQkBDWdldEVnZ0Fzc2V0SWQAAwkBAiE9AggFDGZpcnN0UGF5bWVudAZhbW91bnQFCWxlZnRUb1BheQkAAgEJAKwCAgJIQkJEOiBUbyBidXkgYSBwZXJjaCB5b3UgY3VycmVudGx5IG5lZWQgdGhlIGZvbGxvd2luZyBhbW91bnQgb2YgRUdHbGV0czogCQCkAwEFCWxlZnRUb1BheQQIYnVybkNhbGwJAPwHBAkBDmdldEJ1cm5BZGRyZXNzAAIUYnVybkF0dGFjaGVkUGF5bWVudHMFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBDWdldEVnZ0Fzc2V0SWQABQlsZWZ0VG9QYXkFA25pbAMJAAACBQhidXJuQ2FsbAUIYnVybkNhbGwFCWxlZnRUb1BheQkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgAAAwkAAAIFB3BheW1lbnQFB3BheW1lbnQED2R1Y2tsaW5nQXNzZXRJZAkA/AcEBQR0aGlzAhFpc3N1ZUZyZWVEdWNrbGluZwkAzAgCCQClCAEIBQFpDG9yaWdpbkNhbGxlcgkAzAgCCQDYBAEIBQFpDXRyYW5zYWN0aW9uSWQJAMwIAgAABQNuaWwFA25pbAMJAAACBQ9kdWNrbGluZ0Fzc2V0SWQFD2R1Y2tsaW5nQXNzZXRJZAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBEWlzc3VlRnJlZUR1Y2tsaW5nAwdhZGRyZXNzB3R4SWRTdHIKcGVyY2VudGFnZQMDCQECIT0CCAUBaQZjYWxsZXIFBHRoaXMJAQIhPQIIBQFpBmNhbGxlcgkBEWdldFJlYmlydGhBZGRyZXNzAAcJAAIBAiNCSUZEOiBZb3UgY2FuJ3QgaXNzdWUgZnJlZSBkdWNrbGluZwQFYXNzZXQJAMMIBwIQQkFCWS0xMTExMTExMS1HWgIAAAEAAAcFBHVuaXQFBmhlaWdodAQHYXNzZXRJZAkAuAgBBQVhc3NldAkAlAoCCQDMCAIJAQtTdHJpbmdFbnRyeQIJAKwCAgkArAICCQCsAgIFB2FkZHJlc3MCAV8FB3R4SWRTdHICA19kaQkA2AQBBQdhc3NldElkCQDMCAIJAQxJbnRlZ2VyRW50cnkCAgxzdGF0c19hbW91bnQJAGQCCQENdHJ5R2V0SW50ZWdlcgECDHN0YXRzX2Ftb3VudAABCQDMCAIJAQxCb29sZWFuRW50cnkCCQCsAgIJAKwCAgIJZHVja2xpbmdfCQDYBAEFB2Fzc2V0SWQCEV9pc3N1ZWRCeUZlZWRDYWxsCQAAAggFAWkGY2FsbGVyBQR0aGlzCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQESa2V5U3RhcnRQZXJjZW50YWdlAQkA2AQBBQdhc3NldElkBQpwZXJjZW50YWdlCQDMCAIJAQtTdHJpbmdFbnRyeQIJAQhrZXlPd25lcgEJANgEAQUHYXNzZXRJZAUHYWRkcmVzcwkAzAgCBQVhc3NldAkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCQEFdmFsdWUBCQCmCAEFB2FkZHJlc3MAAQUHYXNzZXRJZAUDbmlsCQDYBAEFB2Fzc2V0SWQBaQEMZmVlZER1Y2tsaW5nBApkdWNrbGluZ0lkEGJhY2tlbmRTaWduYXR1cmUNbWF4RmVlZEFtb3VudAl1c2VyTm9uY2UEDWFkZHJlc3NTdHJpbmcJAKUIAQgFAWkGY2FsbGVyBAxiYWNrZW5kUHJvb2YJAQ9nZXRCYWNrZW5kUHJvb2YDBQ1tYXhGZWVkQW1vdW50BQl1c2VyTm9uY2UFDWFkZHJlc3NTdHJpbmcEDWtBZGRyZXNzTm9uY2UJAQ9rZXlBZGRyZXNzTm9uY2UBBQ1hZGRyZXNzU3RyaW5nBAxjdXJyZW50Tm9uY2UJAQ10cnlHZXRJbnRlZ2VyAQUNa0FkZHJlc3NOb25jZQQOcmVhbER1Y2tsaW5nSWQDCQEBIQEJAMQTAwkAmwMBBQxiYWNrZW5kUHJvb2YJANkEAQUQYmFja2VuZFNpZ25hdHVyZQUNYmFja2VuZFB1YktleQkAAgECH0JGRDogSW52YWxpZCBwcm9vZiBmcm9tIGJhY2tlbmQDAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwABBgkBAiE9AggJAQV2YWx1ZQEJAJEDAggFAWkIcGF5bWVudHMAAAdhc3NldElkCQEPZ2V0U3BpY2VBc3NldElkAAkAAgECLkJGRDogQmFkIHBheW1lbnQgYXR0YWNoZWQgKGFzc2V0W3NdIG9yIGFtb3VudCkDCQEHZ2V0Qm9vbAEJARBrZXlEdWNrbGluZ0dyb3duAQUKZHVja2xpbmdJZAkAAgECHkJGRDogRHVja2xpbmcgaXMgYWxyZWFkeSBncm93bgMJAQIhPQIFCXVzZXJOb25jZQkAZAIFDGN1cnJlbnROb25jZQABCQACAQkArAICCQCsAgIJAKwCAgIaQkZEOiBVc2VyIE5vbmNlIHNob3VsZCBiZSAJAKQDAQUMY3VycmVudE5vbmNlAhUgKyAxLCB3aGlsZSByZWNlaXZlZCAJAKQDAQUJdXNlck5vbmNlBAtibGFja0xpc3RlZAkBDXRyeUdldEJvb2xlYW4BCQEOa2V5QmxhY2tsaXN0ZWQBBQpkdWNrbGluZ0lkAwULYmxhY2tMaXN0ZWQJAAIBAidCRkQ6IENhbiBub3QgZmVlZCBibGFja2xpc3RlZCBkdWNrbGluZyEDCQAAAgUKZHVja2xpbmdJZAIACQACAQIhQkZEOiBQbGVhc2UgYnV5IGEgZHVja2xpbmcgZmlyc3QhBA9kdWNrbGluZ0lkQ2hlY2sJAQV2YWx1ZQEJAOwHAQkA2QQBBQpkdWNrbGluZ0lkAwkBAiE9AgkA8AcCCAUBaQZjYWxsZXIIBQ9kdWNrbGluZ0lkQ2hlY2sCaWQAAQkAAgECKUJGRDogWW91J3JlIG5vdCB0aGUgb3duZXIgb2YgdGhlIGR1Y2tsaW5nAwkBAiE9AggFD2R1Y2tsaW5nSWRDaGVjawZpc3N1ZXIFBHRoaXMJAAIBAiRCRkQ6IENhbnQgZmluZCBkdWNrbGluZyB3aXRoIHN1Y2ggaWQJANgEAQgFD2R1Y2tsaW5nSWRDaGVjawJpZAQOY3VycmVudFBheW1lbnQICQEFdmFsdWUBCQCRAwIIBQFpCHBheW1lbnRzAAAGYW1vdW50BAlrTmV3TGV2ZWwJARBrZXlEdWNrbGluZ0xldmVsAQUOcmVhbER1Y2tsaW5nSWQECmtUb3RhbEZlZWQJAQxrZXlUb3RhbEZlZWQBBQ5yZWFsRHVja2xpbmdJZAQJdG90YWxGZWVkCQENdHJ5R2V0SW50ZWdlcgEFCmtUb3RhbEZlZWQEDGtGZWVkVHhTdGF0cwkArAICCQCsAgIJAKwCAgIJZHVja2xpbmdfBQ5yZWFsRHVja2xpbmdJZAIGX3N0YXRfCQCkAwEIBQlsYXN0QmxvY2sJdGltZXN0YW1wAwkAZgIFDmN1cnJlbnRQYXltZW50BQ1tYXhGZWVkQW1vdW50CQACAQkArAICAj9CRkQ6IENhbm5vdCBmZWVkIGR1Y2tsaW5nIGZvciBzdWNoIGFtb3VudCwgbWF4IGZlZWQgYW1vdW50IGlzOiAJAKQDAQUNbWF4RmVlZEFtb3VudAQQY2FsY3VsYXRlUmVzdWx0cwkBGWNhbGN1bGF0ZU5ld0R1Y2tsaW5nTGV2ZWwCBQ5yZWFsRHVja2xpbmdJZAkAaQIFDmN1cnJlbnRQYXltZW50AGQEDWR1Y2tsaW5nT3duZXIJAQx0cnlHZXRTdHJpbmcBCQEIa2V5T3duZXIBBQ5yZWFsRHVja2xpbmdJZAMJAQIhPQIFDWR1Y2tsaW5nT3duZXIJAKUIAQgFAWkGY2FsbGVyCQDMCAIJAQxCb29sZWFuRW50cnkCCQEOa2V5QmxhY2tsaXN0ZWQBBQ5yZWFsRHVja2xpbmdJZAYFA25pbAkAzAgCCQEMSW50ZWdlckVudHJ5AgUNa0FkZHJlc3NOb25jZQkAZAIFDGN1cnJlbnROb25jZQABCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQprVG90YWxGZWVkCQBkAgUJdG90YWxGZWVkBQ5jdXJyZW50UGF5bWVudAkAzAgCCQEMSW50ZWdlckVudHJ5AgUMa0ZlZWRUeFN0YXRzBQ5jdXJyZW50UGF5bWVudAkAzAgCCQELU3RyaW5nRW50cnkCBQlrTmV3TGV2ZWwIBRBjYWxjdWxhdGVSZXN1bHRzAl8xCQDMCAIJAQtTdHJpbmdFbnRyeQIJAKwCAgUMa0ZlZWRUeFN0YXRzAgZfZGVidWcJALkJAggFEGNhbGN1bGF0ZVJlc3VsdHMCXzICATsFA25pbAFpAQlmaXhMZXZlbHMBC2R1Y2tsaW5nSWRzAwMJAQIhPQIIBQFpD2NhbGxlclB1YmxpY0tleQEg4jCrQaSaRY9uaPb/iI1dy/xcgsAiOBaUksF2pAJAViIJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwcJAAIBAhNCRkw6IE5vdCBhdXRob3JpemVkBA9kdWNrbGluZ0lkc0xpc3QJAQV2YWx1ZQEJALUJAgULZHVja2xpbmdJZHMCASwKAQhoYW5kbGVJZAIDYWNjAmlkBAprVG90YWxGZWVkCQEMa2V5VG90YWxGZWVkAQUCaWQECXRvdGFsRmVlZAkBDXRyeUdldEludGVnZXIBBQprVG90YWxGZWVkBAlrTmV3TGV2ZWwJARBrZXlEdWNrbGluZ0xldmVsAQUCaWQEDXN0YXJ0aW5nTGV2ZWwEByRtYXRjaDAJAKAIAQkArAICCQCsAgICCWR1Y2tsaW5nXwUCaWQCEV9pc3N1ZWRCeUZlZWRDYWxsAwkAAQIFByRtYXRjaDACB0Jvb2xlYW4EAWIFByRtYXRjaDADCQAAAgUBYgYJALYCAQAACQEVZ2V0RHVja2xpbmdQZXJjZW50YWdlAQUCaWQJARVnZXREdWNrbGluZ1BlcmNlbnRhZ2UBBQJpZAQGZ3Jvd3RoCQC8AgMJALYCAQUJdG90YWxGZWVkCQC2AgEFFnBlcmNlbnRHcm93dGhQcmVjaXNpb24JALYCAQUNRFVDS0xJTkdQUklDRQkAzggCBQNhY2MJAMwIAgkBC1N0cmluZ0VudHJ5AgUJa05ld0xldmVsCQCmAwEJALcCAgUNc3RhcnRpbmdMZXZlbAUGZ3Jvd3RoBQNuaWwKAAIkbAUPZHVja2xpbmdJZHNMaXN0CgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQhoYW5kbGVJZAIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMjAJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgALAAwADQAOAA8AEAARABIAEwAUAWkBFHR1cm5EdWNrbGluZ0ludG9EdWNrAAQHYWRkcmVzcwkApQgBCAUBaQZjYWxsZXIEBHR4SWQJANgEAQgFAWkNdHJhbnNhY3Rpb25JZAQUbGFzdElzc3VlZER1Y2tsaW5nVHMJAQ10cnlHZXRJbnRlZ2VyAQUWS0dsb2JhbElzc3VlZFRpbWVzdGFtcAQLZml2ZU1pbkluTXMJAGgCCQBoAgAFADwA6AcECHRpbWVEaWZmCQBlAggFCWxhc3RCbG9jawl0aW1lc3RhbXAJAGQCBRRsYXN0SXNzdWVkRHVja2xpbmdUcwULZml2ZU1pbkluTXMDAwkAZgIFFGxhc3RJc3N1ZWREdWNrbGluZ1RzAAAJAGYCAAAFCHRpbWVEaWZmBwkAAgEJAKwCAgkArAICAkJCVEQ6IENhbiBpc3N1ZSBkdWNrbGluZ3Mgb25seSBvbmNlIHBlciA1IG1pbnV0ZXMsIHBsZWFzZSB3YWl0IGZvciAJAKQDAQkAawMFCHRpbWVEaWZmAAEA6AcCBSBzZWMuAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwABCQACAQIuQlREOiBCYWQgcGF5bWVudCBhdHRhY2hlZCAoYXNzZXRbc10gb3IgYW1vdW50KQQDcG10CQEFdmFsdWUBCQDsBwEJAQV2YWx1ZQEICQEFdmFsdWUBCQCRAwIIBQFpCHBheW1lbnRzAAAHYXNzZXRJZAQLYmxhY2tMaXN0ZWQJAQ10cnlHZXRCb29sZWFuAQkBDmtleUJsYWNrbGlzdGVkAQkA2AQBCAUDcG10AmlkAwULYmxhY2tMaXN0ZWQJAAIBAipCVEQ6IENhbiBub3QgY29udmVydCBibGFja2xpc3RlZCBkdWNrbGluZyEDCQC/AgIJALYCAQUWcGVyY2VudEdyb3d0aFByZWNpc2lvbgkBFWdldEN1cnJlbnRMZXZlbEJpZ0ludAEJANgEAQgFA3BtdAJpZAkAAgECIUJURDogRHVja2xpbmcgaXMgbm90IGdyb3duIHlldC4uLgMJAQIhPQIIBQNwbXQGaXNzdWVyBQR0aGlzCQACAQIqQlREOiBDYW4gdXNlIG9ubHkgZHVja2xpbmdzIGZyb20gdGhpcyBkQXBwBARjYWxsCQD8BwQJARNnZXRJbmN1YmF0b3JBZGRyZXNzAAIRc3RhcnREdWNrSGF0Y2hpbmcJAMwIAgIABQNuaWwFA25pbAMJAAACBQRjYWxsBQRjYWxsBA5rRHVja2xpbmdHcm93bgkBEGtleUR1Y2tsaW5nR3Jvd24BCQDYBAEIBQNwbXQCaWQJAMwIAgkBDEJvb2xlYW5FbnRyeQIFDmtEdWNrbGluZ0dyb3duBgkAzAgCCQEMSW50ZWdlckVudHJ5AgUWS0dsb2JhbElzc3VlZFRpbWVzdGFtcAgFCWxhc3RCbG9jawl0aW1lc3RhbXAFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgECdHgBBnZlcmlmeQAJAPQDAwgFAnR4CWJvZHlCeXRlcwkAkQMCCAUCdHgGcHJvb2ZzAAAIBQJ0eA9zZW5kZXJQdWJsaWNLZXkTsoYI", "height": 3326048, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: HVSF1PzT5dhtLTYnTkeeKFRjhmvsWSQnQrwMtnwwPUEY Next: 5HpXcaWVjXEzwbZmmPFuCKkJ1oPtvLzVuFU6QDhVEWv1 Diff:
OldNewDifferences
99 }
1010
1111
12-func keyBlacklisted (ducklingId) = (("duckling_" + ducklingId) + "_blacklisted")
13-
14-
1512 func tryGetIntegerExternal (address,key) = match getInteger(address, key) {
1613 case b: Int =>
1714 b
1815 case _ =>
1916 0
17+}
18+
19+
20+func tryGetBoolean (key) = match getBoolean(key) {
21+ case b: Boolean =>
22+ b
23+ case _ =>
24+ false
2025 }
2126
2227
2631 func getOracle () = Address(fromBase58String(tryGetString("static_oracleAddress")))
2732
2833
34+func getDucklingPrice () = tryGetIntegerExternal(getOracle(), "static_ducklingPrice")
35+
36+
37+func getEggAssetId () = fromBase58String(tryGetStringExternal(getOracle(), "static_eggAssetId"))
38+
39+
2940 func getSpiceAssetId () = fromBase58String(tryGetStringExternal(getOracle(), "static_spiceAssetId"))
3041
3142
32-func getBreederAddress () = Address(fromBase58String(tryGetStringExternal(getOracle(), "static_breederAddress")))
43+func getRebirthAddress () = Address(fromBase58String(tryGetStringExternal(getOracle(), "static_rebirthAddress")))
3344
3445
35-let DUCKLINGPRICE = 10000000000
46+func getIncubatorAddress () = Address(fromBase58String(tryGetStringExternal(getOracle(), "static_incubatorAddress")))
47+
48+
49+func getCouponsAddress () = Address(fromBase58String(tryGetStringExternal(getOracle(), "static_couponsAddress")))
50+
51+
52+func getBurnAddress () = Address(fromBase58String(tryGetStringExternal(getOracle(), "static_burnAddress")))
53+
54+
55+let backendPubKey = fromBase58String(getStringValue(getOracle(), "static_backendPubKey"))
56+
57+let DUCKLINGPRICE = 100000000
58+
59+let percentGrowthPrecision = 10000000000000000
60+
61+let existingDuckPrecision = 100000000000000
3662
3763 let KGlobalIssuedTimestamp = "global_issued_timestamp"
3864
39-func keyTotalFeed (ducklingId) = (("duckling_" + ducklingId) + "_feed")
65+func keyTotalFeed (ducklingId) = (("duckling_" + ducklingId) + "_feed_spice")
4066
4167
42-func keyDucklingFedLastTimestamp (ducklingId) = (("duckling_" + ducklingId) + "_fedLastTs")
68+func keyAddressNonce (address) = (("address_" + address) + "_nonce")
4369
4470
4571 func keyDucklingLevel (ducklingId) = (("duckling_" + ducklingId) + "_level")
5278
5379
5480 func keyOwner (ducklingId) = (("duckling_" + ducklingId) + "_owner")
81+
82+
83+func keyBlacklisted (ducklingId) = (("duckling_" + ducklingId) + "_blacklisted")
5584
5685
5786 func tryGetInteger (key) = {
73102 }
74103
75104
76-func getCurrentLevelInt (ducklingId) = {
105+func getDucklingPercentage (ducklingId) = {
106+ let percentageDuckling = tryGetInteger(keyStartPercentage(ducklingId))
107+ let base = if ((percentageDuckling != 0))
108+ then percentageDuckling
109+ else 20
110+ toBigInt((base * existingDuckPrecision))
111+ }
112+
113+
114+func getCurrentLevelBigInt (ducklingId) = {
77115 let kDuckLevel = keyDucklingLevel(ducklingId)
78116 match getString(kDuckLevel) {
79117 case s: String =>
80- parseIntValue(s)
81- case u: Unit =>
82- 0
118+ parseBigIntValue(s)
83119 case _ =>
84- throw("BGCLBI: Weird value detected!")
120+ match getBoolean((("duckling_" + ducklingId) + "_issuedByFeedCall")) {
121+ case b: Boolean =>
122+ if ((b == true))
123+ then toBigInt(0)
124+ else getDucklingPercentage(ducklingId)
125+ case _ =>
126+ getDucklingPercentage(ducklingId)
127+ }
85128 }
86- }
87-
88-
89-func getLastFedTimestamp (ducklingId) = {
90- let lastFedTimestamp = tryGetInteger(keyDucklingFedLastTimestamp(ducklingId))
91- if ((lastFedTimestamp > 0))
92- then lastFedTimestamp
93- else lastBlock.timestamp
94129 }
95130
96131
97132 func calculateNewDucklingLevel (ducklingId,paymentAmount) = {
98133 let currentTs = lastBlock.timestamp
99- let lastFedTimestampChecked = getLastFedTimestamp(ducklingId)
100- let fedDiff = (currentTs - lastFedTimestampChecked)
101- let growth = paymentAmount
102- let currentLevel = getCurrentLevelInt(ducklingId)
103- let newLevel = (currentLevel + paymentAmount)
104- if ((newLevel > DUCKLINGPRICE))
105- then throw((("CBDB: You are feeding your duckling to much! Only " + toString((DUCKLINGPRICE - currentLevel))) + "needed!"))
106- else {
107- let result = toString(newLevel)
108- $Tuple2(result, [("currentLevel=" + toString(currentLevel)), ("newLevel=" + toString(newLevel)), ("growth=" + toString(growth)), ("lastFedTs=" + toString(lastFedTimestampChecked)), ("fedDiff=" + toString(fedDiff))])
109- }
134+ let growth = fraction(toBigInt(paymentAmount), toBigInt(percentGrowthPrecision), toBigInt(DUCKLINGPRICE))
135+ let currentLevel = getCurrentLevelBigInt(ducklingId)
136+ let newLevel = (currentLevel + growth)
137+ let result = toString(newLevel)
138+ $Tuple2(result, [("currentLevel=" + toString(currentLevel)), ("newLevel=" + toString(newLevel)), ("growth=" + toString(growth))])
110139 }
140+
141+
142+func getBackendProof (maxFeedAmount,userNonce,address) = makeString([toString(maxFeedAmount), toString(userNonce), address], ";")
111143
112144
113145 func asInt (value) = match value {
115147 int
116148 case _ =>
117149 throw("BAI: wrong type, expected: Int")
118-}
119-
120-
121-func tryGetBoolean (key) = match getBoolean(key) {
122- case b: Boolean =>
123- b
124- case _ =>
125- false
126150 }
127151
128152
134158
135159
136160 @Callable(i)
137-func issueDuckling (address,txIdStr) = if ((i.caller != getBreederAddress()))
161+func buyDuckling () = {
162+ let exactPrice = getDucklingPrice()
163+ if ((50000000 > exactPrice))
164+ then throw("BBD: Invalid price from oracle!")
165+ else {
166+ let amountPaidByCoupons = asInt(invoke(getCouponsAddress(), "useCoupons", [exactPrice], nil))
167+ if ((amountPaidByCoupons == amountPaidByCoupons))
168+ then {
169+ let leftToPay = (exactPrice - amountPaidByCoupons)
170+ let payment = if ((leftToPay != 0))
171+ then {
172+ let firstPayment = value(i.payments[0])
173+ if ((firstPayment.assetId != getEggAssetId()))
174+ then throw(("BBD: You can attach only EGG tokens with the following asset id: " + toBase58String(getEggAssetId())))
175+ else if ((firstPayment.amount != leftToPay))
176+ then throw(("BBD: To buy a perch you currently need the following amount of EGGlets: " + toString(leftToPay)))
177+ else {
178+ let burnCall = invoke(getBurnAddress(), "burnAttachedPayments", nil, [AttachedPayment(getEggAssetId(), leftToPay)])
179+ if ((burnCall == burnCall))
180+ then leftToPay
181+ else throw("Strict value is not equal to itself.")
182+ }
183+ }
184+ else 0
185+ if ((payment == payment))
186+ then {
187+ let ducklingAssetId = invoke(this, "issueFreeDuckling", [toString(i.originCaller), toBase58String(i.transactionId), 0], nil)
188+ if ((ducklingAssetId == ducklingAssetId))
189+ then nil
190+ else throw("Strict value is not equal to itself.")
191+ }
192+ else throw("Strict value is not equal to itself.")
193+ }
194+ else throw("Strict value is not equal to itself.")
195+ }
196+ }
197+
198+
199+
200+@Callable(i)
201+func issueFreeDuckling (address,txIdStr,percentage) = if (if ((i.caller != this))
202+ then (i.caller != getRebirthAddress())
203+ else false)
138204 then throw("BIFD: You can't issue free duckling")
139205 else {
140- let asset = Issue("BABY-11111111-HZ", "", 1, 0, false, unit, height)
206+ let asset = Issue("BABY-11111111-GZ", "", 1, 0, false, unit, height)
141207 let assetId = calculateAssetId(asset)
142- $Tuple2([StringEntry((((address + "_") + txIdStr) + "_di"), toBase58String(assetId)), IntegerEntry("stats_amount", (tryGetInteger("stats_amount") + 1)), BooleanEntry((("duckling_" + toBase58String(assetId)) + "_issuedByFeedCall"), (i.caller == this)), IntegerEntry(keyStartPercentage(toBase58String(assetId)), 0), StringEntry(keyOwner(toBase58String(assetId)), address), asset, ScriptTransfer(value(addressFromString(address)), 1, assetId)], toBase58String(assetId))
208+ $Tuple2([StringEntry((((address + "_") + txIdStr) + "_di"), toBase58String(assetId)), IntegerEntry("stats_amount", (tryGetInteger("stats_amount") + 1)), BooleanEntry((("duckling_" + toBase58String(assetId)) + "_issuedByFeedCall"), (i.caller == this)), IntegerEntry(keyStartPercentage(toBase58String(assetId)), percentage), StringEntry(keyOwner(toBase58String(assetId)), address), asset, ScriptTransfer(value(addressFromString(address)), 1, assetId)], toBase58String(assetId))
143209 }
144210
145211
146212
147213 @Callable(i)
148-func feedDuckling (ducklingId) = {
214+func feedDuckling (ducklingId,backendSignature,maxFeedAmount,userNonce) = {
149215 let addressString = toString(i.caller)
150- let realDucklingId = if (if ((size(i.payments) != 1))
151- then true
152- else (value(i.payments[0]).assetId != getSpiceAssetId()))
153- then throw("BFD: Bad payment attached (asset[s] or amount)")
154- else {
155- let blackListed = tryGetBoolean(keyBlacklisted(ducklingId))
156- if (blackListed)
157- then throw("BFD: Can not feed blacklisted duckling!")
158- else if (getBool(keyDucklingGrown(ducklingId)))
159- then throw("BFD: Duckling is already grown")
160- else if ((ducklingId == ""))
161- then throw("BFD: Please hatch a duckling first!")
162- else {
163- let ducklingOwner = tryGetString(keyOwner(ducklingId))
164- let ducklingIdCheck = value(assetInfo(fromBase58String(ducklingId)))
165- if ((assetBalance(i.caller, ducklingIdCheck.id) != 1))
166- then throw("BFD: You're not the owner of the duckling")
167- else if ((ducklingOwner != toString(i.caller)))
168- then throw("BFD: You can only feed ducklings that you won/bought yourself!")
169- else if ((ducklingIdCheck.issuer != this))
170- then throw("BFD: Cant find duckling with such id")
171- else {
172- let ducklingIdString = toBase58String(ducklingIdCheck.id)
173- ducklingIdString
174- }
175- }
176- }
177- let kDucklingLastFedTs = keyDucklingFedLastTimestamp(ducklingId)
216+ let backendProof = getBackendProof(maxFeedAmount, userNonce, addressString)
217+ let kAddressNonce = keyAddressNonce(addressString)
218+ let currentNonce = tryGetInteger(kAddressNonce)
219+ let realDucklingId = if (!(sigVerify_8Kb(toBytes(backendProof), fromBase58String(backendSignature), backendPubKey)))
220+ then throw("BFD: Invalid proof from backend")
221+ else if (if ((size(i.payments) != 1))
222+ then true
223+ else (value(i.payments[0]).assetId != getSpiceAssetId()))
224+ then throw("BFD: Bad payment attached (asset[s] or amount)")
225+ else if (getBool(keyDucklingGrown(ducklingId)))
226+ then throw("BFD: Duckling is already grown")
227+ else if ((userNonce != (currentNonce + 1)))
228+ then throw(((("BFD: User Nonce should be " + toString(currentNonce)) + " + 1, while received ") + toString(userNonce)))
229+ else {
230+ let blackListed = tryGetBoolean(keyBlacklisted(ducklingId))
231+ if (blackListed)
232+ then throw("BFD: Can not feed blacklisted duckling!")
233+ else if ((ducklingId == ""))
234+ then throw("BFD: Please buy a duckling first!")
235+ else {
236+ let ducklingIdCheck = value(assetInfo(fromBase58String(ducklingId)))
237+ if ((assetBalance(i.caller, ducklingIdCheck.id) != 1))
238+ then throw("BFD: You're not the owner of the duckling")
239+ else if ((ducklingIdCheck.issuer != this))
240+ then throw("BFD: Cant find duckling with such id")
241+ else toBase58String(ducklingIdCheck.id)
242+ }
243+ }
178244 let currentPayment = value(i.payments[0]).amount
179245 let kNewLevel = keyDucklingLevel(realDucklingId)
180246 let kTotalFeed = keyTotalFeed(realDucklingId)
181247 let totalFeed = tryGetInteger(kTotalFeed)
182248 let kFeedTxStats = ((("duckling_" + realDucklingId) + "_stat_") + toString(lastBlock.timestamp))
183- let calculateResults = calculateNewDucklingLevel(realDucklingId, currentPayment)
184-[IntegerEntry(kDucklingLastFedTs, lastBlock.timestamp), IntegerEntry(kTotalFeed, (totalFeed + currentPayment)), IntegerEntry(kFeedTxStats, currentPayment), StringEntry(kNewLevel, calculateResults._1), StringEntry((kFeedTxStats + "_debug"), makeString(calculateResults._2, ";"))]
249+ if ((currentPayment > maxFeedAmount))
250+ then throw(("BFD: Cannot feed duckling for such amount, max feed amount is: " + toString(maxFeedAmount)))
251+ else {
252+ let calculateResults = calculateNewDucklingLevel(realDucklingId, (currentPayment / 100))
253+ let ducklingOwner = tryGetString(keyOwner(realDucklingId))
254+ if ((ducklingOwner != toString(i.caller)))
255+ then [BooleanEntry(keyBlacklisted(realDucklingId), true)]
256+ else [IntegerEntry(kAddressNonce, (currentNonce + 1)), IntegerEntry(kTotalFeed, (totalFeed + currentPayment)), IntegerEntry(kFeedTxStats, currentPayment), StringEntry(kNewLevel, calculateResults._1), StringEntry((kFeedTxStats + "_debug"), makeString(calculateResults._2, ";"))]
257+ }
185258 }
186259
187260
188261
189262 @Callable(i)
190-func turnDucklingIntoDuck () = if ((i.caller != getBreederAddress()))
191- then throw("BIFD: You can't turn duckling")
263+func fixLevels (ducklingIds) = if (if ((i.callerPublicKey != base58'GDxBbsDRmeY39quNrDsTXKJzFWbQVtjxHseF4ikxZ7n9'))
264+ then (i.caller != this)
265+ else false)
266+ then throw("BFL: Not authorized")
192267 else {
193- let address = toString(i.caller)
194- let txId = toBase58String(i.transactionId)
195- let lastIssuedDucklingTs = tryGetInteger(KGlobalIssuedTimestamp)
196- let fiveMinInMs = ((1 * 60) * 1000)
197- let timeDiff = (lastBlock.timestamp - (lastIssuedDucklingTs + fiveMinInMs))
198- if (if ((lastIssuedDucklingTs > 0))
199- then (0 > timeDiff)
200- else false)
201- then throw((("BTD: Can issue ducklings only once per 1 minutes, please wait for " + toString(fraction(timeDiff, 1, 1000))) + " sec."))
202- else if ((size(i.payments) != 1))
203- then throw("BTD: Bad payment attached (asset[s] or amount)")
204- else {
205- let pmt = value(assetInfo(value(value(i.payments[0]).assetId)))
206- if ((DUCKLINGPRICE > getCurrentLevelInt(toBase58String(pmt.id))))
207- then throw(((("BTD: Duckling is not grown yet..." + toString(getCurrentLevelInt(toBase58String(pmt.id)))) + " ") + toString(DUCKLINGPRICE)))
268+ let ducklingIdsList = value(split(ducklingIds, ","))
269+ func handleId (acc,id) = {
270+ let kTotalFeed = keyTotalFeed(id)
271+ let totalFeed = tryGetInteger(kTotalFeed)
272+ let kNewLevel = keyDucklingLevel(id)
273+ let startingLevel = match getBoolean((("duckling_" + id) + "_issuedByFeedCall")) {
274+ case b: Boolean =>
275+ if ((b == true))
276+ then toBigInt(0)
277+ else getDucklingPercentage(id)
278+ case _ =>
279+ getDucklingPercentage(id)
280+ }
281+ let growth = fraction(toBigInt(totalFeed), toBigInt(percentGrowthPrecision), toBigInt(DUCKLINGPRICE))
282+ (acc ++ [StringEntry(kNewLevel, toString((startingLevel + growth)))])
283+ }
284+
285+ let $l = ducklingIdsList
286+ let $s = size($l)
287+ let $acc0 = nil
288+ func $f0_1 ($a,$i) = if (($i >= $s))
289+ then $a
290+ else handleId($a, $l[$i])
291+
292+ func $f0_2 ($a,$i) = if (($i >= $s))
293+ then $a
294+ else throw("List size exceeds 20")
295+
296+ $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($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20)
297+ }
298+
299+
300+
301+@Callable(i)
302+func turnDucklingIntoDuck () = {
303+ let address = toString(i.caller)
304+ let txId = toBase58String(i.transactionId)
305+ let lastIssuedDucklingTs = tryGetInteger(KGlobalIssuedTimestamp)
306+ let fiveMinInMs = ((5 * 60) * 1000)
307+ let timeDiff = (lastBlock.timestamp - (lastIssuedDucklingTs + fiveMinInMs))
308+ if (if ((lastIssuedDucklingTs > 0))
309+ then (0 > timeDiff)
310+ else false)
311+ then throw((("BTD: Can issue ducklings only once per 5 minutes, please wait for " + toString(fraction(timeDiff, 1, 1000))) + " sec."))
312+ else if ((size(i.payments) != 1))
313+ then throw("BTD: Bad payment attached (asset[s] or amount)")
314+ else {
315+ let pmt = value(assetInfo(value(value(i.payments[0]).assetId)))
316+ let blackListed = tryGetBoolean(keyBlacklisted(toBase58String(pmt.id)))
317+ if (blackListed)
318+ then throw("BTD: Can not convert blacklisted duckling!")
319+ else if ((toBigInt(percentGrowthPrecision) > getCurrentLevelBigInt(toBase58String(pmt.id))))
320+ then throw("BTD: Duckling is not grown yet...")
208321 else if ((pmt.issuer != this))
209322 then throw("BTD: Can use only ducklings from this dApp")
210323 else {
211- let kDucklingGrown = keyDucklingGrown(toBase58String(pmt.id))
212- $Tuple2([BooleanEntry(kDucklingGrown, true), IntegerEntry(KGlobalIssuedTimestamp, lastBlock.timestamp)], toBase58String(pmt.id))
324+ let call = invoke(getIncubatorAddress(), "startDuckHatching", [""], nil)
325+ if ((call == call))
326+ then {
327+ let kDucklingGrown = keyDucklingGrown(toBase58String(pmt.id))
328+[BooleanEntry(kDucklingGrown, true), IntegerEntry(KGlobalIssuedTimestamp, lastBlock.timestamp)]
329+ }
330+ else throw("Strict value is not equal to itself.")
213331 }
214- }
215- }
332+ }
333+ }
216334
217335
218336 @Verifier(tx)
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 func tryGetStringExternal (address,key) = match getString(address, key) {
55 case a: String =>
66 a
77 case _ =>
88 ""
99 }
1010
1111
12-func keyBlacklisted (ducklingId) = (("duckling_" + ducklingId) + "_blacklisted")
13-
14-
1512 func tryGetIntegerExternal (address,key) = match getInteger(address, key) {
1613 case b: Int =>
1714 b
1815 case _ =>
1916 0
17+}
18+
19+
20+func tryGetBoolean (key) = match getBoolean(key) {
21+ case b: Boolean =>
22+ b
23+ case _ =>
24+ false
2025 }
2126
2227
2328 func tryGetString (key) = tryGetStringExternal(this, key)
2429
2530
2631 func getOracle () = Address(fromBase58String(tryGetString("static_oracleAddress")))
2732
2833
34+func getDucklingPrice () = tryGetIntegerExternal(getOracle(), "static_ducklingPrice")
35+
36+
37+func getEggAssetId () = fromBase58String(tryGetStringExternal(getOracle(), "static_eggAssetId"))
38+
39+
2940 func getSpiceAssetId () = fromBase58String(tryGetStringExternal(getOracle(), "static_spiceAssetId"))
3041
3142
32-func getBreederAddress () = Address(fromBase58String(tryGetStringExternal(getOracle(), "static_breederAddress")))
43+func getRebirthAddress () = Address(fromBase58String(tryGetStringExternal(getOracle(), "static_rebirthAddress")))
3344
3445
35-let DUCKLINGPRICE = 10000000000
46+func getIncubatorAddress () = Address(fromBase58String(tryGetStringExternal(getOracle(), "static_incubatorAddress")))
47+
48+
49+func getCouponsAddress () = Address(fromBase58String(tryGetStringExternal(getOracle(), "static_couponsAddress")))
50+
51+
52+func getBurnAddress () = Address(fromBase58String(tryGetStringExternal(getOracle(), "static_burnAddress")))
53+
54+
55+let backendPubKey = fromBase58String(getStringValue(getOracle(), "static_backendPubKey"))
56+
57+let DUCKLINGPRICE = 100000000
58+
59+let percentGrowthPrecision = 10000000000000000
60+
61+let existingDuckPrecision = 100000000000000
3662
3763 let KGlobalIssuedTimestamp = "global_issued_timestamp"
3864
39-func keyTotalFeed (ducklingId) = (("duckling_" + ducklingId) + "_feed")
65+func keyTotalFeed (ducklingId) = (("duckling_" + ducklingId) + "_feed_spice")
4066
4167
42-func keyDucklingFedLastTimestamp (ducklingId) = (("duckling_" + ducklingId) + "_fedLastTs")
68+func keyAddressNonce (address) = (("address_" + address) + "_nonce")
4369
4470
4571 func keyDucklingLevel (ducklingId) = (("duckling_" + ducklingId) + "_level")
4672
4773
4874 func keyDucklingGrown (ducklingId) = (("duckling_" + ducklingId) + "_grown")
4975
5076
5177 func keyStartPercentage (ducklingId) = (("duckling_" + ducklingId) + "_startPercentage")
5278
5379
5480 func keyOwner (ducklingId) = (("duckling_" + ducklingId) + "_owner")
81+
82+
83+func keyBlacklisted (ducklingId) = (("duckling_" + ducklingId) + "_blacklisted")
5584
5685
5786 func tryGetInteger (key) = {
5887 let val = match getInteger(this, key) {
5988 case b: Int =>
6089 b
6190 case _ =>
6291 0
6392 }
6493 val
6594 }
6695
6796
6897 func getBool (key) = match getBoolean(this, key) {
6998 case b: Boolean =>
7099 b
71100 case _ =>
72101 false
73102 }
74103
75104
76-func getCurrentLevelInt (ducklingId) = {
105+func getDucklingPercentage (ducklingId) = {
106+ let percentageDuckling = tryGetInteger(keyStartPercentage(ducklingId))
107+ let base = if ((percentageDuckling != 0))
108+ then percentageDuckling
109+ else 20
110+ toBigInt((base * existingDuckPrecision))
111+ }
112+
113+
114+func getCurrentLevelBigInt (ducklingId) = {
77115 let kDuckLevel = keyDucklingLevel(ducklingId)
78116 match getString(kDuckLevel) {
79117 case s: String =>
80- parseIntValue(s)
81- case u: Unit =>
82- 0
118+ parseBigIntValue(s)
83119 case _ =>
84- throw("BGCLBI: Weird value detected!")
120+ match getBoolean((("duckling_" + ducklingId) + "_issuedByFeedCall")) {
121+ case b: Boolean =>
122+ if ((b == true))
123+ then toBigInt(0)
124+ else getDucklingPercentage(ducklingId)
125+ case _ =>
126+ getDucklingPercentage(ducklingId)
127+ }
85128 }
86- }
87-
88-
89-func getLastFedTimestamp (ducklingId) = {
90- let lastFedTimestamp = tryGetInteger(keyDucklingFedLastTimestamp(ducklingId))
91- if ((lastFedTimestamp > 0))
92- then lastFedTimestamp
93- else lastBlock.timestamp
94129 }
95130
96131
97132 func calculateNewDucklingLevel (ducklingId,paymentAmount) = {
98133 let currentTs = lastBlock.timestamp
99- let lastFedTimestampChecked = getLastFedTimestamp(ducklingId)
100- let fedDiff = (currentTs - lastFedTimestampChecked)
101- let growth = paymentAmount
102- let currentLevel = getCurrentLevelInt(ducklingId)
103- let newLevel = (currentLevel + paymentAmount)
104- if ((newLevel > DUCKLINGPRICE))
105- then throw((("CBDB: You are feeding your duckling to much! Only " + toString((DUCKLINGPRICE - currentLevel))) + "needed!"))
106- else {
107- let result = toString(newLevel)
108- $Tuple2(result, [("currentLevel=" + toString(currentLevel)), ("newLevel=" + toString(newLevel)), ("growth=" + toString(growth)), ("lastFedTs=" + toString(lastFedTimestampChecked)), ("fedDiff=" + toString(fedDiff))])
109- }
134+ let growth = fraction(toBigInt(paymentAmount), toBigInt(percentGrowthPrecision), toBigInt(DUCKLINGPRICE))
135+ let currentLevel = getCurrentLevelBigInt(ducklingId)
136+ let newLevel = (currentLevel + growth)
137+ let result = toString(newLevel)
138+ $Tuple2(result, [("currentLevel=" + toString(currentLevel)), ("newLevel=" + toString(newLevel)), ("growth=" + toString(growth))])
110139 }
140+
141+
142+func getBackendProof (maxFeedAmount,userNonce,address) = makeString([toString(maxFeedAmount), toString(userNonce), address], ";")
111143
112144
113145 func asInt (value) = match value {
114146 case int: Int =>
115147 int
116148 case _ =>
117149 throw("BAI: wrong type, expected: Int")
118-}
119-
120-
121-func tryGetBoolean (key) = match getBoolean(key) {
122- case b: Boolean =>
123- b
124- case _ =>
125- false
126150 }
127151
128152
129153 @Callable(i)
130154 func configureOracle (oracle) = if ((i.caller != this))
131155 then throw("BCO: admin only")
132156 else [StringEntry("static_oracleAddress", oracle)]
133157
134158
135159
136160 @Callable(i)
137-func issueDuckling (address,txIdStr) = if ((i.caller != getBreederAddress()))
161+func buyDuckling () = {
162+ let exactPrice = getDucklingPrice()
163+ if ((50000000 > exactPrice))
164+ then throw("BBD: Invalid price from oracle!")
165+ else {
166+ let amountPaidByCoupons = asInt(invoke(getCouponsAddress(), "useCoupons", [exactPrice], nil))
167+ if ((amountPaidByCoupons == amountPaidByCoupons))
168+ then {
169+ let leftToPay = (exactPrice - amountPaidByCoupons)
170+ let payment = if ((leftToPay != 0))
171+ then {
172+ let firstPayment = value(i.payments[0])
173+ if ((firstPayment.assetId != getEggAssetId()))
174+ then throw(("BBD: You can attach only EGG tokens with the following asset id: " + toBase58String(getEggAssetId())))
175+ else if ((firstPayment.amount != leftToPay))
176+ then throw(("BBD: To buy a perch you currently need the following amount of EGGlets: " + toString(leftToPay)))
177+ else {
178+ let burnCall = invoke(getBurnAddress(), "burnAttachedPayments", nil, [AttachedPayment(getEggAssetId(), leftToPay)])
179+ if ((burnCall == burnCall))
180+ then leftToPay
181+ else throw("Strict value is not equal to itself.")
182+ }
183+ }
184+ else 0
185+ if ((payment == payment))
186+ then {
187+ let ducklingAssetId = invoke(this, "issueFreeDuckling", [toString(i.originCaller), toBase58String(i.transactionId), 0], nil)
188+ if ((ducklingAssetId == ducklingAssetId))
189+ then nil
190+ else throw("Strict value is not equal to itself.")
191+ }
192+ else throw("Strict value is not equal to itself.")
193+ }
194+ else throw("Strict value is not equal to itself.")
195+ }
196+ }
197+
198+
199+
200+@Callable(i)
201+func issueFreeDuckling (address,txIdStr,percentage) = if (if ((i.caller != this))
202+ then (i.caller != getRebirthAddress())
203+ else false)
138204 then throw("BIFD: You can't issue free duckling")
139205 else {
140- let asset = Issue("BABY-11111111-HZ", "", 1, 0, false, unit, height)
206+ let asset = Issue("BABY-11111111-GZ", "", 1, 0, false, unit, height)
141207 let assetId = calculateAssetId(asset)
142- $Tuple2([StringEntry((((address + "_") + txIdStr) + "_di"), toBase58String(assetId)), IntegerEntry("stats_amount", (tryGetInteger("stats_amount") + 1)), BooleanEntry((("duckling_" + toBase58String(assetId)) + "_issuedByFeedCall"), (i.caller == this)), IntegerEntry(keyStartPercentage(toBase58String(assetId)), 0), StringEntry(keyOwner(toBase58String(assetId)), address), asset, ScriptTransfer(value(addressFromString(address)), 1, assetId)], toBase58String(assetId))
208+ $Tuple2([StringEntry((((address + "_") + txIdStr) + "_di"), toBase58String(assetId)), IntegerEntry("stats_amount", (tryGetInteger("stats_amount") + 1)), BooleanEntry((("duckling_" + toBase58String(assetId)) + "_issuedByFeedCall"), (i.caller == this)), IntegerEntry(keyStartPercentage(toBase58String(assetId)), percentage), StringEntry(keyOwner(toBase58String(assetId)), address), asset, ScriptTransfer(value(addressFromString(address)), 1, assetId)], toBase58String(assetId))
143209 }
144210
145211
146212
147213 @Callable(i)
148-func feedDuckling (ducklingId) = {
214+func feedDuckling (ducklingId,backendSignature,maxFeedAmount,userNonce) = {
149215 let addressString = toString(i.caller)
150- let realDucklingId = if (if ((size(i.payments) != 1))
151- then true
152- else (value(i.payments[0]).assetId != getSpiceAssetId()))
153- then throw("BFD: Bad payment attached (asset[s] or amount)")
154- else {
155- let blackListed = tryGetBoolean(keyBlacklisted(ducklingId))
156- if (blackListed)
157- then throw("BFD: Can not feed blacklisted duckling!")
158- else if (getBool(keyDucklingGrown(ducklingId)))
159- then throw("BFD: Duckling is already grown")
160- else if ((ducklingId == ""))
161- then throw("BFD: Please hatch a duckling first!")
162- else {
163- let ducklingOwner = tryGetString(keyOwner(ducklingId))
164- let ducklingIdCheck = value(assetInfo(fromBase58String(ducklingId)))
165- if ((assetBalance(i.caller, ducklingIdCheck.id) != 1))
166- then throw("BFD: You're not the owner of the duckling")
167- else if ((ducklingOwner != toString(i.caller)))
168- then throw("BFD: You can only feed ducklings that you won/bought yourself!")
169- else if ((ducklingIdCheck.issuer != this))
170- then throw("BFD: Cant find duckling with such id")
171- else {
172- let ducklingIdString = toBase58String(ducklingIdCheck.id)
173- ducklingIdString
174- }
175- }
176- }
177- let kDucklingLastFedTs = keyDucklingFedLastTimestamp(ducklingId)
216+ let backendProof = getBackendProof(maxFeedAmount, userNonce, addressString)
217+ let kAddressNonce = keyAddressNonce(addressString)
218+ let currentNonce = tryGetInteger(kAddressNonce)
219+ let realDucklingId = if (!(sigVerify_8Kb(toBytes(backendProof), fromBase58String(backendSignature), backendPubKey)))
220+ then throw("BFD: Invalid proof from backend")
221+ else if (if ((size(i.payments) != 1))
222+ then true
223+ else (value(i.payments[0]).assetId != getSpiceAssetId()))
224+ then throw("BFD: Bad payment attached (asset[s] or amount)")
225+ else if (getBool(keyDucklingGrown(ducklingId)))
226+ then throw("BFD: Duckling is already grown")
227+ else if ((userNonce != (currentNonce + 1)))
228+ then throw(((("BFD: User Nonce should be " + toString(currentNonce)) + " + 1, while received ") + toString(userNonce)))
229+ else {
230+ let blackListed = tryGetBoolean(keyBlacklisted(ducklingId))
231+ if (blackListed)
232+ then throw("BFD: Can not feed blacklisted duckling!")
233+ else if ((ducklingId == ""))
234+ then throw("BFD: Please buy a duckling first!")
235+ else {
236+ let ducklingIdCheck = value(assetInfo(fromBase58String(ducklingId)))
237+ if ((assetBalance(i.caller, ducklingIdCheck.id) != 1))
238+ then throw("BFD: You're not the owner of the duckling")
239+ else if ((ducklingIdCheck.issuer != this))
240+ then throw("BFD: Cant find duckling with such id")
241+ else toBase58String(ducklingIdCheck.id)
242+ }
243+ }
178244 let currentPayment = value(i.payments[0]).amount
179245 let kNewLevel = keyDucklingLevel(realDucklingId)
180246 let kTotalFeed = keyTotalFeed(realDucklingId)
181247 let totalFeed = tryGetInteger(kTotalFeed)
182248 let kFeedTxStats = ((("duckling_" + realDucklingId) + "_stat_") + toString(lastBlock.timestamp))
183- let calculateResults = calculateNewDucklingLevel(realDucklingId, currentPayment)
184-[IntegerEntry(kDucklingLastFedTs, lastBlock.timestamp), IntegerEntry(kTotalFeed, (totalFeed + currentPayment)), IntegerEntry(kFeedTxStats, currentPayment), StringEntry(kNewLevel, calculateResults._1), StringEntry((kFeedTxStats + "_debug"), makeString(calculateResults._2, ";"))]
249+ if ((currentPayment > maxFeedAmount))
250+ then throw(("BFD: Cannot feed duckling for such amount, max feed amount is: " + toString(maxFeedAmount)))
251+ else {
252+ let calculateResults = calculateNewDucklingLevel(realDucklingId, (currentPayment / 100))
253+ let ducklingOwner = tryGetString(keyOwner(realDucklingId))
254+ if ((ducklingOwner != toString(i.caller)))
255+ then [BooleanEntry(keyBlacklisted(realDucklingId), true)]
256+ else [IntegerEntry(kAddressNonce, (currentNonce + 1)), IntegerEntry(kTotalFeed, (totalFeed + currentPayment)), IntegerEntry(kFeedTxStats, currentPayment), StringEntry(kNewLevel, calculateResults._1), StringEntry((kFeedTxStats + "_debug"), makeString(calculateResults._2, ";"))]
257+ }
185258 }
186259
187260
188261
189262 @Callable(i)
190-func turnDucklingIntoDuck () = if ((i.caller != getBreederAddress()))
191- then throw("BIFD: You can't turn duckling")
263+func fixLevels (ducklingIds) = if (if ((i.callerPublicKey != base58'GDxBbsDRmeY39quNrDsTXKJzFWbQVtjxHseF4ikxZ7n9'))
264+ then (i.caller != this)
265+ else false)
266+ then throw("BFL: Not authorized")
192267 else {
193- let address = toString(i.caller)
194- let txId = toBase58String(i.transactionId)
195- let lastIssuedDucklingTs = tryGetInteger(KGlobalIssuedTimestamp)
196- let fiveMinInMs = ((1 * 60) * 1000)
197- let timeDiff = (lastBlock.timestamp - (lastIssuedDucklingTs + fiveMinInMs))
198- if (if ((lastIssuedDucklingTs > 0))
199- then (0 > timeDiff)
200- else false)
201- then throw((("BTD: Can issue ducklings only once per 1 minutes, please wait for " + toString(fraction(timeDiff, 1, 1000))) + " sec."))
202- else if ((size(i.payments) != 1))
203- then throw("BTD: Bad payment attached (asset[s] or amount)")
204- else {
205- let pmt = value(assetInfo(value(value(i.payments[0]).assetId)))
206- if ((DUCKLINGPRICE > getCurrentLevelInt(toBase58String(pmt.id))))
207- then throw(((("BTD: Duckling is not grown yet..." + toString(getCurrentLevelInt(toBase58String(pmt.id)))) + " ") + toString(DUCKLINGPRICE)))
268+ let ducklingIdsList = value(split(ducklingIds, ","))
269+ func handleId (acc,id) = {
270+ let kTotalFeed = keyTotalFeed(id)
271+ let totalFeed = tryGetInteger(kTotalFeed)
272+ let kNewLevel = keyDucklingLevel(id)
273+ let startingLevel = match getBoolean((("duckling_" + id) + "_issuedByFeedCall")) {
274+ case b: Boolean =>
275+ if ((b == true))
276+ then toBigInt(0)
277+ else getDucklingPercentage(id)
278+ case _ =>
279+ getDucklingPercentage(id)
280+ }
281+ let growth = fraction(toBigInt(totalFeed), toBigInt(percentGrowthPrecision), toBigInt(DUCKLINGPRICE))
282+ (acc ++ [StringEntry(kNewLevel, toString((startingLevel + growth)))])
283+ }
284+
285+ let $l = ducklingIdsList
286+ let $s = size($l)
287+ let $acc0 = nil
288+ func $f0_1 ($a,$i) = if (($i >= $s))
289+ then $a
290+ else handleId($a, $l[$i])
291+
292+ func $f0_2 ($a,$i) = if (($i >= $s))
293+ then $a
294+ else throw("List size exceeds 20")
295+
296+ $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($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20)
297+ }
298+
299+
300+
301+@Callable(i)
302+func turnDucklingIntoDuck () = {
303+ let address = toString(i.caller)
304+ let txId = toBase58String(i.transactionId)
305+ let lastIssuedDucklingTs = tryGetInteger(KGlobalIssuedTimestamp)
306+ let fiveMinInMs = ((5 * 60) * 1000)
307+ let timeDiff = (lastBlock.timestamp - (lastIssuedDucklingTs + fiveMinInMs))
308+ if (if ((lastIssuedDucklingTs > 0))
309+ then (0 > timeDiff)
310+ else false)
311+ then throw((("BTD: Can issue ducklings only once per 5 minutes, please wait for " + toString(fraction(timeDiff, 1, 1000))) + " sec."))
312+ else if ((size(i.payments) != 1))
313+ then throw("BTD: Bad payment attached (asset[s] or amount)")
314+ else {
315+ let pmt = value(assetInfo(value(value(i.payments[0]).assetId)))
316+ let blackListed = tryGetBoolean(keyBlacklisted(toBase58String(pmt.id)))
317+ if (blackListed)
318+ then throw("BTD: Can not convert blacklisted duckling!")
319+ else if ((toBigInt(percentGrowthPrecision) > getCurrentLevelBigInt(toBase58String(pmt.id))))
320+ then throw("BTD: Duckling is not grown yet...")
208321 else if ((pmt.issuer != this))
209322 then throw("BTD: Can use only ducklings from this dApp")
210323 else {
211- let kDucklingGrown = keyDucklingGrown(toBase58String(pmt.id))
212- $Tuple2([BooleanEntry(kDucklingGrown, true), IntegerEntry(KGlobalIssuedTimestamp, lastBlock.timestamp)], toBase58String(pmt.id))
324+ let call = invoke(getIncubatorAddress(), "startDuckHatching", [""], nil)
325+ if ((call == call))
326+ then {
327+ let kDucklingGrown = keyDucklingGrown(toBase58String(pmt.id))
328+[BooleanEntry(kDucklingGrown, true), IntegerEntry(KGlobalIssuedTimestamp, lastBlock.timestamp)]
329+ }
330+ else throw("Strict value is not equal to itself.")
213331 }
214- }
215- }
332+ }
333+ }
216334
217335
218336 @Verifier(tx)
219337 func verify () = sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
220338

github/deemru/w8io/3ef1775 
71.91 ms