diff --git a/projects/bay-workshop-2024/smart_contracts/artifacts/personal_bank/PersonalBank.approval.teal b/projects/bay-workshop-2024/smart_contracts/artifacts/personal_bank/PersonalBank.approval.teal index 83c1548..de18b4f 100644 --- a/projects/bay-workshop-2024/smart_contracts/artifacts/personal_bank/PersonalBank.approval.teal +++ b/projects/bay-workshop-2024/smart_contracts/artifacts/personal_bank/PersonalBank.approval.teal @@ -31,7 +31,7 @@ main_opt_in_to_app_route@4: return main_deposit_route@5: - // smart_contracts/personal_bank/contract.py:18 + // smart_contracts/personal_bank/contract.py:19 // @arc4.abimethod txn OnCompletion ! @@ -48,7 +48,7 @@ main_deposit_route@5: int pay == assert // transaction type is pay - // smart_contracts/personal_bank/contract.py:18 + // smart_contracts/personal_bank/contract.py:19 // @arc4.abimethod callsub deposit itob @@ -60,7 +60,7 @@ main_deposit_route@5: return main_withdraw_route@6: - // smart_contracts/personal_bank/contract.py:32 + // smart_contracts/personal_bank/contract.py:35 // @arc4.abimethod(allow_actions=["CloseOut"]) txn OnCompletion int CloseOut @@ -97,7 +97,7 @@ opt_in_to_app: // def opt_in_to_app(self) -> None: proto 0 0 // smart_contracts/personal_bank/contract.py:12 - // result , exists = self.optedIn.maybe(Txn.sender) + // result, exists = self.optedIn.maybe(Txn.sender) txn Sender int 0 byte "optedIn" @@ -107,19 +107,19 @@ opt_in_to_app: // assert not exists, "User already opted in" ! assert // User already opted in - // smart_contracts/personal_bank/contract.py:14 + // smart_contracts/personal_bank/contract.py:15 // self.balance[Txn.sender] = UInt64(0) txn Sender byte "balance" int 0 app_local_put - // smart_contracts/personal_bank/contract.py:15 + // smart_contracts/personal_bank/contract.py:16 // self.optedIn[Txn.sender] = True txn Sender byte "optedIn" int 1 app_local_put - // smart_contracts/personal_bank/contract.py:16 + // smart_contracts/personal_bank/contract.py:17 // self.depositors += 1 int 0 byte "depositors" @@ -135,41 +135,47 @@ opt_in_to_app: // smart_contracts.personal_bank.contract.PersonalBank.deposit(ptxn: uint64) -> uint64: deposit: - // smart_contracts/personal_bank/contract.py:18-19 + // smart_contracts/personal_bank/contract.py:19-20 // @arc4.abimethod // def deposit(self, ptxn: gtxn.PaymentTransaction) -> UInt64: proto 1 1 - // smart_contracts/personal_bank/contract.py:20 + // smart_contracts/personal_bank/contract.py:21 // assert ptxn.amount > 0, "Deposit amount must be greater than 0" frame_dig -1 gtxns Amount dup assert // Deposit amount must be greater than 0 - // smart_contracts/personal_bank/contract.py:22 + // smart_contracts/personal_bank/contract.py:23 // ptxn.receiver == Global.current_application_address frame_dig -1 gtxns Receiver global CurrentApplicationAddress == - // smart_contracts/personal_bank/contract.py:21-23 + // smart_contracts/personal_bank/contract.py:22-24 // assert ( // ptxn.receiver == Global.current_application_address // ), "Deposit receiver must be the contract address" assert // Deposit receiver must be the contract address - // smart_contracts/personal_bank/contract.py:24 + // smart_contracts/personal_bank/contract.py:25 // assert ptxn.sender == Txn.sender, "Deposit sender must be the caller" frame_dig -1 gtxns Sender txn Sender == assert // Deposit sender must be the caller - // smart_contracts/personal_bank/contract.py:25 - // assert Txn.sender.is_opted_in(Global.current_application_id), "Deposit sender must opt-in to the app first." + // smart_contracts/personal_bank/contract.py:26 + // assert Txn.sender.is_opted_in( txn Sender + // smart_contracts/personal_bank/contract.py:27 + // Global.current_application_id global CurrentApplicationID + // smart_contracts/personal_bank/contract.py:26-28 + // assert Txn.sender.is_opted_in( + // Global.current_application_id + // ), "Deposit sender must opt-in to the app first." app_opted_in assert // Deposit sender must opt-in to the app first. - // smart_contracts/personal_bank/contract.py:27 + // smart_contracts/personal_bank/contract.py:30 // self.balance[Txn.sender] += ptxn.amount txn Sender int 0 @@ -181,25 +187,25 @@ deposit: byte "balance" uncover 2 app_local_put - // smart_contracts/personal_bank/contract.py:28 + // smart_contracts/personal_bank/contract.py:31 // user_balance = self.balance[Txn.sender] txn Sender int 0 byte "balance" app_local_get_ex assert // check balance exists for account - // smart_contracts/personal_bank/contract.py:30 + // smart_contracts/personal_bank/contract.py:33 // return user_balance retsub // smart_contracts.personal_bank.contract.PersonalBank.withdraw() -> uint64: withdraw: - // smart_contracts/personal_bank/contract.py:32-33 + // smart_contracts/personal_bank/contract.py:35-36 // @arc4.abimethod(allow_actions=["CloseOut"]) // def withdraw(self) -> UInt64: proto 0 1 - // smart_contracts/personal_bank/contract.py:34 + // smart_contracts/personal_bank/contract.py:37 // assert self.balance[Txn.sender] > 0, "User balance must be greater than 0" txn Sender int 0 @@ -207,14 +213,14 @@ withdraw: app_local_get_ex assert // check balance exists for account assert // User balance must be greater than 0 - // smart_contracts/personal_bank/contract.py:36 + // smart_contracts/personal_bank/contract.py:39 // userBalance = self.balance[Txn.sender] txn Sender int 0 byte "balance" app_local_get_ex assert // check balance exists for account - // smart_contracts/personal_bank/contract.py:38-43 + // smart_contracts/personal_bank/contract.py:41-46 // itxn.Payment( // receiver=Txn.sender, // sender=Global.current_application_address, @@ -222,25 +228,25 @@ withdraw: // fee=0, // ).submit() itxn_begin - // smart_contracts/personal_bank/contract.py:39 + // smart_contracts/personal_bank/contract.py:42 // receiver=Txn.sender, txn Sender - // smart_contracts/personal_bank/contract.py:40 + // smart_contracts/personal_bank/contract.py:43 // sender=Global.current_application_address, global CurrentApplicationAddress dig 2 itxn_field Amount itxn_field Sender itxn_field Receiver - // smart_contracts/personal_bank/contract.py:38 + // smart_contracts/personal_bank/contract.py:41 // itxn.Payment( int pay itxn_field TypeEnum - // smart_contracts/personal_bank/contract.py:42 + // smart_contracts/personal_bank/contract.py:45 // fee=0, int 0 itxn_field Fee - // smart_contracts/personal_bank/contract.py:38-43 + // smart_contracts/personal_bank/contract.py:41-46 // itxn.Payment( // receiver=Txn.sender, // sender=Global.current_application_address, @@ -248,7 +254,7 @@ withdraw: // fee=0, // ).submit() itxn_submit - // smart_contracts/personal_bank/contract.py:45 + // smart_contracts/personal_bank/contract.py:48 // self.depositors -= 1 int 0 byte "depositors" @@ -259,7 +265,7 @@ withdraw: byte "depositors" swap app_global_put - // smart_contracts/personal_bank/contract.py:47 + // smart_contracts/personal_bank/contract.py:50 // return userBalance retsub diff --git a/projects/bay-workshop-2024/smart_contracts/artifacts/personal_bank/PersonalBank.arc32.json b/projects/bay-workshop-2024/smart_contracts/artifacts/personal_bank/PersonalBank.arc32.json index 823cec9..064a782 100644 --- a/projects/bay-workshop-2024/smart_contracts/artifacts/personal_bank/PersonalBank.arc32.json +++ b/projects/bay-workshop-2024/smart_contracts/artifacts/personal_bank/PersonalBank.arc32.json @@ -17,7 +17,7 @@ } }, "source": { - "approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgpzbWFydF9jb250cmFjdHMucGVyc29uYWxfYmFuay5jb250cmFjdC5QZXJzb25hbEJhbmsuYXBwcm92YWxfcHJvZ3JhbToKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBibnogbWFpbl9lbnRyeXBvaW50QDIKICAgIGNhbGxzdWIgX19pbml0X18KCm1haW5fZW50cnlwb2ludEAyOgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6NAogICAgLy8gY2xhc3MgUGVyc29uYWxCYW5rKEFSQzRDb250cmFjdCk6CiAgICB0eG4gTnVtQXBwQXJncwogICAgYnogbWFpbl9iYXJlX3JvdXRpbmdAOQogICAgbWV0aG9kICJvcHRfaW5fdG9fYXBwKCl2b2lkIgogICAgbWV0aG9kICJkZXBvc2l0KHBheSl1aW50NjQiCiAgICBtZXRob2QgIndpdGhkcmF3KCl1aW50NjQiCiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAwCiAgICBtYXRjaCBtYWluX29wdF9pbl90b19hcHBfcm91dGVANCBtYWluX2RlcG9zaXRfcm91dGVANSBtYWluX3dpdGhkcmF3X3JvdXRlQDYKICAgIGVyciAvLyByZWplY3QgdHJhbnNhY3Rpb24KCm1haW5fb3B0X2luX3RvX2FwcF9yb3V0ZUA0OgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MTAKICAgIC8vIEBhcmM0LmFiaW1ldGhvZChhbGxvd19hY3Rpb25zPVsiT3B0SW4iXSkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgIGludCBPcHRJbgogICAgPT0KICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgT3B0SW4KICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gaXMgbm90IGNyZWF0aW5nCiAgICBjYWxsc3ViIG9wdF9pbl90b19hcHAKICAgIGludCAxCiAgICByZXR1cm4KCm1haW5fZGVwb3NpdF9yb3V0ZUA1OgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MTgKICAgIC8vIEBhcmM0LmFiaW1ldGhvZAogICAgdHhuIE9uQ29tcGxldGlvbgogICAgIQogICAgYXNzZXJ0IC8vIE9uQ29tcGxldGlvbiBpcyBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGlzIG5vdCBjcmVhdGluZwogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6NAogICAgLy8gY2xhc3MgUGVyc29uYWxCYW5rKEFSQzRDb250cmFjdCk6CiAgICB0eG4gR3JvdXBJbmRleAogICAgaW50IDEKICAgIC0KICAgIGR1cAogICAgZ3R4bnMgVHlwZUVudW0KICAgIGludCBwYXkKICAgID09CiAgICBhc3NlcnQgLy8gdHJhbnNhY3Rpb24gdHlwZSBpcyBwYXkKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjE4CiAgICAvLyBAYXJjNC5hYmltZXRob2QKICAgIGNhbGxzdWIgZGVwb3NpdAogICAgaXRvYgogICAgYnl0ZSAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50IDEKICAgIHJldHVybgoKbWFpbl93aXRoZHJhd19yb3V0ZUA2OgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MzIKICAgIC8vIEBhcmM0LmFiaW1ldGhvZChhbGxvd19hY3Rpb25zPVsiQ2xvc2VPdXQiXSkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgIGludCBDbG9zZU91dAogICAgPT0KICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgQ2xvc2VPdXQKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gaXMgbm90IGNyZWF0aW5nCiAgICBjYWxsc3ViIHdpdGhkcmF3CiAgICBpdG9iCiAgICBieXRlIDB4MTUxZjdjNzUKICAgIHN3YXAKICAgIGNvbmNhdAogICAgbG9nCiAgICBpbnQgMQogICAgcmV0dXJuCgptYWluX2JhcmVfcm91dGluZ0A5OgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6NAogICAgLy8gY2xhc3MgUGVyc29uYWxCYW5rKEFSQzRDb250cmFjdCk6CiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gcmVqZWN0IHRyYW5zYWN0aW9uCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgIQogICAgYXNzZXJ0IC8vIGlzIGNyZWF0aW5nCiAgICBpbnQgMQogICAgcmV0dXJuCgoKLy8gc21hcnRfY29udHJhY3RzLnBlcnNvbmFsX2JhbmsuY29udHJhY3QuUGVyc29uYWxCYW5rLm9wdF9pbl90b19hcHAoKSAtPiB2b2lkOgpvcHRfaW5fdG9fYXBwOgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MTAtMTEKICAgIC8vIEBhcmM0LmFiaW1ldGhvZChhbGxvd19hY3Rpb25zPVsiT3B0SW4iXSkKICAgIC8vIGRlZiBvcHRfaW5fdG9fYXBwKHNlbGYpIC0+IE5vbmU6CiAgICBwcm90byAwIDAKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjEyCiAgICAvLyByZXN1bHQgLCBleGlzdHMgPSBzZWxmLm9wdGVkSW4ubWF5YmUoVHhuLnNlbmRlcikKICAgIHR4biBTZW5kZXIKICAgIGludCAwCiAgICBieXRlICJvcHRlZEluIgogICAgYXBwX2xvY2FsX2dldF9leAogICAgYnVyeSAxCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weToxMwogICAgLy8gYXNzZXJ0IG5vdCBleGlzdHMsICJVc2VyIGFscmVhZHkgb3B0ZWQgaW4iCiAgICAhCiAgICBhc3NlcnQgLy8gVXNlciBhbHJlYWR5IG9wdGVkIGluCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weToxNAogICAgLy8gc2VsZi5iYWxhbmNlW1R4bi5zZW5kZXJdID0gVUludDY0KDApCiAgICB0eG4gU2VuZGVyCiAgICBieXRlICJiYWxhbmNlIgogICAgaW50IDAKICAgIGFwcF9sb2NhbF9wdXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjE1CiAgICAvLyBzZWxmLm9wdGVkSW5bVHhuLnNlbmRlcl0gPSBUcnVlCiAgICB0eG4gU2VuZGVyCiAgICBieXRlICJvcHRlZEluIgogICAgaW50IDEKICAgIGFwcF9sb2NhbF9wdXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjE2CiAgICAvLyBzZWxmLmRlcG9zaXRvcnMgKz0gMQogICAgaW50IDAKICAgIGJ5dGUgImRlcG9zaXRvcnMiCiAgICBhcHBfZ2xvYmFsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIGRlcG9zaXRvcnMgZXhpc3RzCiAgICBpbnQgMQogICAgKwogICAgYnl0ZSAiZGVwb3NpdG9ycyIKICAgIHN3YXAKICAgIGFwcF9nbG9iYWxfcHV0CiAgICByZXRzdWIKCgovLyBzbWFydF9jb250cmFjdHMucGVyc29uYWxfYmFuay5jb250cmFjdC5QZXJzb25hbEJhbmsuZGVwb3NpdChwdHhuOiB1aW50NjQpIC0+IHVpbnQ2NDoKZGVwb3NpdDoKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjE4LTE5CiAgICAvLyBAYXJjNC5hYmltZXRob2QKICAgIC8vIGRlZiBkZXBvc2l0KHNlbGYsIHB0eG46IGd0eG4uUGF5bWVudFRyYW5zYWN0aW9uKSAtPiBVSW50NjQ6CiAgICBwcm90byAxIDEKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjIwCiAgICAvLyBhc3NlcnQgcHR4bi5hbW91bnQgPiAwLCAiRGVwb3NpdCBhbW91bnQgbXVzdCBiZSBncmVhdGVyIHRoYW4gMCIKICAgIGZyYW1lX2RpZyAtMQogICAgZ3R4bnMgQW1vdW50CiAgICBkdXAKICAgIGFzc2VydCAvLyBEZXBvc2l0IGFtb3VudCBtdXN0IGJlIGdyZWF0ZXIgdGhhbiAwCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weToyMgogICAgLy8gcHR4bi5yZWNlaXZlciA9PSBHbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzCiAgICBmcmFtZV9kaWcgLTEKICAgIGd0eG5zIFJlY2VpdmVyCiAgICBnbG9iYWwgQ3VycmVudEFwcGxpY2F0aW9uQWRkcmVzcwogICAgPT0KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjIxLTIzCiAgICAvLyBhc3NlcnQgKAogICAgLy8gICAgIHB0eG4ucmVjZWl2ZXIgPT0gR2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcwogICAgLy8gKSwgIkRlcG9zaXQgcmVjZWl2ZXIgbXVzdCBiZSB0aGUgY29udHJhY3QgYWRkcmVzcyIKICAgIGFzc2VydCAvLyBEZXBvc2l0IHJlY2VpdmVyIG11c3QgYmUgdGhlIGNvbnRyYWN0IGFkZHJlc3MKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjI0CiAgICAvLyBhc3NlcnQgcHR4bi5zZW5kZXIgPT0gVHhuLnNlbmRlciwgIkRlcG9zaXQgc2VuZGVyIG11c3QgYmUgdGhlIGNhbGxlciIKICAgIGZyYW1lX2RpZyAtMQogICAgZ3R4bnMgU2VuZGVyCiAgICB0eG4gU2VuZGVyCiAgICA9PQogICAgYXNzZXJ0IC8vIERlcG9zaXQgc2VuZGVyIG11c3QgYmUgdGhlIGNhbGxlcgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MjUKICAgIC8vIGFzc2VydCBUeG4uc2VuZGVyLmlzX29wdGVkX2luKEdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2lkKSwgIkRlcG9zaXQgc2VuZGVyIG11c3Qgb3B0LWluIHRvIHRoZSBhcHAgZmlyc3QuIgogICAgdHhuIFNlbmRlcgogICAgZ2xvYmFsIEN1cnJlbnRBcHBsaWNhdGlvbklECiAgICBhcHBfb3B0ZWRfaW4KICAgIGFzc2VydCAvLyBEZXBvc2l0IHNlbmRlciBtdXN0IG9wdC1pbiB0byB0aGUgYXBwIGZpcnN0LgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MjcKICAgIC8vIHNlbGYuYmFsYW5jZVtUeG4uc2VuZGVyXSArPSBwdHhuLmFtb3VudAogICAgdHhuIFNlbmRlcgogICAgaW50IDAKICAgIGJ5dGUgImJhbGFuY2UiCiAgICBhcHBfbG9jYWxfZ2V0X2V4CiAgICBhc3NlcnQgLy8gY2hlY2sgYmFsYW5jZSBleGlzdHMgZm9yIGFjY291bnQKICAgICsKICAgIHR4biBTZW5kZXIKICAgIGJ5dGUgImJhbGFuY2UiCiAgICB1bmNvdmVyIDIKICAgIGFwcF9sb2NhbF9wdXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjI4CiAgICAvLyB1c2VyX2JhbGFuY2UgPSBzZWxmLmJhbGFuY2VbVHhuLnNlbmRlcl0KICAgIHR4biBTZW5kZXIKICAgIGludCAwCiAgICBieXRlICJiYWxhbmNlIgogICAgYXBwX2xvY2FsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIGJhbGFuY2UgZXhpc3RzIGZvciBhY2NvdW50CiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTozMAogICAgLy8gcmV0dXJuIHVzZXJfYmFsYW5jZQogICAgcmV0c3ViCgoKLy8gc21hcnRfY29udHJhY3RzLnBlcnNvbmFsX2JhbmsuY29udHJhY3QuUGVyc29uYWxCYW5rLndpdGhkcmF3KCkgLT4gdWludDY0Ogp3aXRoZHJhdzoKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjMyLTMzCiAgICAvLyBAYXJjNC5hYmltZXRob2QoYWxsb3dfYWN0aW9ucz1bIkNsb3NlT3V0Il0pCiAgICAvLyBkZWYgd2l0aGRyYXcoc2VsZikgLT4gVUludDY0OgogICAgcHJvdG8gMCAxCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTozNAogICAgLy8gYXNzZXJ0IHNlbGYuYmFsYW5jZVtUeG4uc2VuZGVyXSA+IDAsICJVc2VyIGJhbGFuY2UgbXVzdCBiZSBncmVhdGVyIHRoYW4gMCIKICAgIHR4biBTZW5kZXIKICAgIGludCAwCiAgICBieXRlICJiYWxhbmNlIgogICAgYXBwX2xvY2FsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIGJhbGFuY2UgZXhpc3RzIGZvciBhY2NvdW50CiAgICBhc3NlcnQgLy8gVXNlciBiYWxhbmNlIG11c3QgYmUgZ3JlYXRlciB0aGFuIDAKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjM2CiAgICAvLyB1c2VyQmFsYW5jZSA9IHNlbGYuYmFsYW5jZVtUeG4uc2VuZGVyXQogICAgdHhuIFNlbmRlcgogICAgaW50IDAKICAgIGJ5dGUgImJhbGFuY2UiCiAgICBhcHBfbG9jYWxfZ2V0X2V4CiAgICBhc3NlcnQgLy8gY2hlY2sgYmFsYW5jZSBleGlzdHMgZm9yIGFjY291bnQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjM4LTQzCiAgICAvLyBpdHhuLlBheW1lbnQoCiAgICAvLyAgICAgcmVjZWl2ZXI9VHhuLnNlbmRlciwKICAgIC8vICAgICBzZW5kZXI9R2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcywKICAgIC8vICAgICBhbW91bnQ9dXNlckJhbGFuY2UsCiAgICAvLyAgICAgZmVlPTAsCiAgICAvLyApLnN1Ym1pdCgpCiAgICBpdHhuX2JlZ2luCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTozOQogICAgLy8gcmVjZWl2ZXI9VHhuLnNlbmRlciwKICAgIHR4biBTZW5kZXIKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjQwCiAgICAvLyBzZW5kZXI9R2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcywKICAgIGdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCiAgICBkaWcgMgogICAgaXR4bl9maWVsZCBBbW91bnQKICAgIGl0eG5fZmllbGQgU2VuZGVyCiAgICBpdHhuX2ZpZWxkIFJlY2VpdmVyCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTozOAogICAgLy8gaXR4bi5QYXltZW50KAogICAgaW50IHBheQogICAgaXR4bl9maWVsZCBUeXBlRW51bQogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6NDIKICAgIC8vIGZlZT0wLAogICAgaW50IDAKICAgIGl0eG5fZmllbGQgRmVlCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTozOC00MwogICAgLy8gaXR4bi5QYXltZW50KAogICAgLy8gICAgIHJlY2VpdmVyPVR4bi5zZW5kZXIsCiAgICAvLyAgICAgc2VuZGVyPUdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2FkZHJlc3MsCiAgICAvLyAgICAgYW1vdW50PXVzZXJCYWxhbmNlLAogICAgLy8gICAgIGZlZT0wLAogICAgLy8gKS5zdWJtaXQoKQogICAgaXR4bl9zdWJtaXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjQ1CiAgICAvLyBzZWxmLmRlcG9zaXRvcnMgLT0gMQogICAgaW50IDAKICAgIGJ5dGUgImRlcG9zaXRvcnMiCiAgICBhcHBfZ2xvYmFsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIGRlcG9zaXRvcnMgZXhpc3RzCiAgICBpbnQgMQogICAgLQogICAgYnl0ZSAiZGVwb3NpdG9ycyIKICAgIHN3YXAKICAgIGFwcF9nbG9iYWxfcHV0CiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTo0NwogICAgLy8gcmV0dXJuIHVzZXJCYWxhbmNlCiAgICByZXRzdWIKCgovLyBzbWFydF9jb250cmFjdHMucGVyc29uYWxfYmFuay5jb250cmFjdC5QZXJzb25hbEJhbmsuX19pbml0X18oKSAtPiB2b2lkOgpfX2luaXRfXzoKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjUKICAgIC8vIGRlZiBfX2luaXRfXyhzZWxmKSAtPiBOb25lOgogICAgcHJvdG8gMCAwCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTo4CiAgICAvLyBzZWxmLmRlcG9zaXRvcnMgPSBVSW50NjQoMCkKICAgIGJ5dGUgImRlcG9zaXRvcnMiCiAgICBpbnQgMAogICAgYXBwX2dsb2JhbF9wdXQKICAgIHJldHN1Ygo=", + "approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgpzbWFydF9jb250cmFjdHMucGVyc29uYWxfYmFuay5jb250cmFjdC5QZXJzb25hbEJhbmsuYXBwcm92YWxfcHJvZ3JhbToKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBibnogbWFpbl9lbnRyeXBvaW50QDIKICAgIGNhbGxzdWIgX19pbml0X18KCm1haW5fZW50cnlwb2ludEAyOgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6NAogICAgLy8gY2xhc3MgUGVyc29uYWxCYW5rKEFSQzRDb250cmFjdCk6CiAgICB0eG4gTnVtQXBwQXJncwogICAgYnogbWFpbl9iYXJlX3JvdXRpbmdAOQogICAgbWV0aG9kICJvcHRfaW5fdG9fYXBwKCl2b2lkIgogICAgbWV0aG9kICJkZXBvc2l0KHBheSl1aW50NjQiCiAgICBtZXRob2QgIndpdGhkcmF3KCl1aW50NjQiCiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAwCiAgICBtYXRjaCBtYWluX29wdF9pbl90b19hcHBfcm91dGVANCBtYWluX2RlcG9zaXRfcm91dGVANSBtYWluX3dpdGhkcmF3X3JvdXRlQDYKICAgIGVyciAvLyByZWplY3QgdHJhbnNhY3Rpb24KCm1haW5fb3B0X2luX3RvX2FwcF9yb3V0ZUA0OgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MTAKICAgIC8vIEBhcmM0LmFiaW1ldGhvZChhbGxvd19hY3Rpb25zPVsiT3B0SW4iXSkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgIGludCBPcHRJbgogICAgPT0KICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgT3B0SW4KICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gaXMgbm90IGNyZWF0aW5nCiAgICBjYWxsc3ViIG9wdF9pbl90b19hcHAKICAgIGludCAxCiAgICByZXR1cm4KCm1haW5fZGVwb3NpdF9yb3V0ZUA1OgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MTkKICAgIC8vIEBhcmM0LmFiaW1ldGhvZAogICAgdHhuIE9uQ29tcGxldGlvbgogICAgIQogICAgYXNzZXJ0IC8vIE9uQ29tcGxldGlvbiBpcyBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGlzIG5vdCBjcmVhdGluZwogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6NAogICAgLy8gY2xhc3MgUGVyc29uYWxCYW5rKEFSQzRDb250cmFjdCk6CiAgICB0eG4gR3JvdXBJbmRleAogICAgaW50IDEKICAgIC0KICAgIGR1cAogICAgZ3R4bnMgVHlwZUVudW0KICAgIGludCBwYXkKICAgID09CiAgICBhc3NlcnQgLy8gdHJhbnNhY3Rpb24gdHlwZSBpcyBwYXkKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjE5CiAgICAvLyBAYXJjNC5hYmltZXRob2QKICAgIGNhbGxzdWIgZGVwb3NpdAogICAgaXRvYgogICAgYnl0ZSAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50IDEKICAgIHJldHVybgoKbWFpbl93aXRoZHJhd19yb3V0ZUA2OgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MzUKICAgIC8vIEBhcmM0LmFiaW1ldGhvZChhbGxvd19hY3Rpb25zPVsiQ2xvc2VPdXQiXSkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgIGludCBDbG9zZU91dAogICAgPT0KICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgQ2xvc2VPdXQKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gaXMgbm90IGNyZWF0aW5nCiAgICBjYWxsc3ViIHdpdGhkcmF3CiAgICBpdG9iCiAgICBieXRlIDB4MTUxZjdjNzUKICAgIHN3YXAKICAgIGNvbmNhdAogICAgbG9nCiAgICBpbnQgMQogICAgcmV0dXJuCgptYWluX2JhcmVfcm91dGluZ0A5OgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6NAogICAgLy8gY2xhc3MgUGVyc29uYWxCYW5rKEFSQzRDb250cmFjdCk6CiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gcmVqZWN0IHRyYW5zYWN0aW9uCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgIQogICAgYXNzZXJ0IC8vIGlzIGNyZWF0aW5nCiAgICBpbnQgMQogICAgcmV0dXJuCgoKLy8gc21hcnRfY29udHJhY3RzLnBlcnNvbmFsX2JhbmsuY29udHJhY3QuUGVyc29uYWxCYW5rLm9wdF9pbl90b19hcHAoKSAtPiB2b2lkOgpvcHRfaW5fdG9fYXBwOgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MTAtMTEKICAgIC8vIEBhcmM0LmFiaW1ldGhvZChhbGxvd19hY3Rpb25zPVsiT3B0SW4iXSkKICAgIC8vIGRlZiBvcHRfaW5fdG9fYXBwKHNlbGYpIC0+IE5vbmU6CiAgICBwcm90byAwIDAKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjEyCiAgICAvLyByZXN1bHQsIGV4aXN0cyA9IHNlbGYub3B0ZWRJbi5tYXliZShUeG4uc2VuZGVyKQogICAgdHhuIFNlbmRlcgogICAgaW50IDAKICAgIGJ5dGUgIm9wdGVkSW4iCiAgICBhcHBfbG9jYWxfZ2V0X2V4CiAgICBidXJ5IDEKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjEzCiAgICAvLyBhc3NlcnQgbm90IGV4aXN0cywgIlVzZXIgYWxyZWFkeSBvcHRlZCBpbiIKICAgICEKICAgIGFzc2VydCAvLyBVc2VyIGFscmVhZHkgb3B0ZWQgaW4KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjE1CiAgICAvLyBzZWxmLmJhbGFuY2VbVHhuLnNlbmRlcl0gPSBVSW50NjQoMCkKICAgIHR4biBTZW5kZXIKICAgIGJ5dGUgImJhbGFuY2UiCiAgICBpbnQgMAogICAgYXBwX2xvY2FsX3B1dAogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MTYKICAgIC8vIHNlbGYub3B0ZWRJbltUeG4uc2VuZGVyXSA9IFRydWUKICAgIHR4biBTZW5kZXIKICAgIGJ5dGUgIm9wdGVkSW4iCiAgICBpbnQgMQogICAgYXBwX2xvY2FsX3B1dAogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MTcKICAgIC8vIHNlbGYuZGVwb3NpdG9ycyArPSAxCiAgICBpbnQgMAogICAgYnl0ZSAiZGVwb3NpdG9ycyIKICAgIGFwcF9nbG9iYWxfZ2V0X2V4CiAgICBhc3NlcnQgLy8gY2hlY2sgZGVwb3NpdG9ycyBleGlzdHMKICAgIGludCAxCiAgICArCiAgICBieXRlICJkZXBvc2l0b3JzIgogICAgc3dhcAogICAgYXBwX2dsb2JhbF9wdXQKICAgIHJldHN1YgoKCi8vIHNtYXJ0X2NvbnRyYWN0cy5wZXJzb25hbF9iYW5rLmNvbnRyYWN0LlBlcnNvbmFsQmFuay5kZXBvc2l0KHB0eG46IHVpbnQ2NCkgLT4gdWludDY0OgpkZXBvc2l0OgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MTktMjAKICAgIC8vIEBhcmM0LmFiaW1ldGhvZAogICAgLy8gZGVmIGRlcG9zaXQoc2VsZiwgcHR4bjogZ3R4bi5QYXltZW50VHJhbnNhY3Rpb24pIC0+IFVJbnQ2NDoKICAgIHByb3RvIDEgMQogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MjEKICAgIC8vIGFzc2VydCBwdHhuLmFtb3VudCA+IDAsICJEZXBvc2l0IGFtb3VudCBtdXN0IGJlIGdyZWF0ZXIgdGhhbiAwIgogICAgZnJhbWVfZGlnIC0xCiAgICBndHhucyBBbW91bnQKICAgIGR1cAogICAgYXNzZXJ0IC8vIERlcG9zaXQgYW1vdW50IG11c3QgYmUgZ3JlYXRlciB0aGFuIDAKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjIzCiAgICAvLyBwdHhuLnJlY2VpdmVyID09IEdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2FkZHJlc3MKICAgIGZyYW1lX2RpZyAtMQogICAgZ3R4bnMgUmVjZWl2ZXIKICAgIGdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCiAgICA9PQogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MjItMjQKICAgIC8vIGFzc2VydCAoCiAgICAvLyAgICAgcHR4bi5yZWNlaXZlciA9PSBHbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzCiAgICAvLyApLCAiRGVwb3NpdCByZWNlaXZlciBtdXN0IGJlIHRoZSBjb250cmFjdCBhZGRyZXNzIgogICAgYXNzZXJ0IC8vIERlcG9zaXQgcmVjZWl2ZXIgbXVzdCBiZSB0aGUgY29udHJhY3QgYWRkcmVzcwogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MjUKICAgIC8vIGFzc2VydCBwdHhuLnNlbmRlciA9PSBUeG4uc2VuZGVyLCAiRGVwb3NpdCBzZW5kZXIgbXVzdCBiZSB0aGUgY2FsbGVyIgogICAgZnJhbWVfZGlnIC0xCiAgICBndHhucyBTZW5kZXIKICAgIHR4biBTZW5kZXIKICAgID09CiAgICBhc3NlcnQgLy8gRGVwb3NpdCBzZW5kZXIgbXVzdCBiZSB0aGUgY2FsbGVyCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weToyNgogICAgLy8gYXNzZXJ0IFR4bi5zZW5kZXIuaXNfb3B0ZWRfaW4oCiAgICB0eG4gU2VuZGVyCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weToyNwogICAgLy8gR2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25faWQKICAgIGdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25JRAogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MjYtMjgKICAgIC8vIGFzc2VydCBUeG4uc2VuZGVyLmlzX29wdGVkX2luKAogICAgLy8gICAgIEdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2lkCiAgICAvLyApLCAiRGVwb3NpdCBzZW5kZXIgbXVzdCBvcHQtaW4gdG8gdGhlIGFwcCBmaXJzdC4iCiAgICBhcHBfb3B0ZWRfaW4KICAgIGFzc2VydCAvLyBEZXBvc2l0IHNlbmRlciBtdXN0IG9wdC1pbiB0byB0aGUgYXBwIGZpcnN0LgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MzAKICAgIC8vIHNlbGYuYmFsYW5jZVtUeG4uc2VuZGVyXSArPSBwdHhuLmFtb3VudAogICAgdHhuIFNlbmRlcgogICAgaW50IDAKICAgIGJ5dGUgImJhbGFuY2UiCiAgICBhcHBfbG9jYWxfZ2V0X2V4CiAgICBhc3NlcnQgLy8gY2hlY2sgYmFsYW5jZSBleGlzdHMgZm9yIGFjY291bnQKICAgICsKICAgIHR4biBTZW5kZXIKICAgIGJ5dGUgImJhbGFuY2UiCiAgICB1bmNvdmVyIDIKICAgIGFwcF9sb2NhbF9wdXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjMxCiAgICAvLyB1c2VyX2JhbGFuY2UgPSBzZWxmLmJhbGFuY2VbVHhuLnNlbmRlcl0KICAgIHR4biBTZW5kZXIKICAgIGludCAwCiAgICBieXRlICJiYWxhbmNlIgogICAgYXBwX2xvY2FsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIGJhbGFuY2UgZXhpc3RzIGZvciBhY2NvdW50CiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTozMwogICAgLy8gcmV0dXJuIHVzZXJfYmFsYW5jZQogICAgcmV0c3ViCgoKLy8gc21hcnRfY29udHJhY3RzLnBlcnNvbmFsX2JhbmsuY29udHJhY3QuUGVyc29uYWxCYW5rLndpdGhkcmF3KCkgLT4gdWludDY0Ogp3aXRoZHJhdzoKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjM1LTM2CiAgICAvLyBAYXJjNC5hYmltZXRob2QoYWxsb3dfYWN0aW9ucz1bIkNsb3NlT3V0Il0pCiAgICAvLyBkZWYgd2l0aGRyYXcoc2VsZikgLT4gVUludDY0OgogICAgcHJvdG8gMCAxCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTozNwogICAgLy8gYXNzZXJ0IHNlbGYuYmFsYW5jZVtUeG4uc2VuZGVyXSA+IDAsICJVc2VyIGJhbGFuY2UgbXVzdCBiZSBncmVhdGVyIHRoYW4gMCIKICAgIHR4biBTZW5kZXIKICAgIGludCAwCiAgICBieXRlICJiYWxhbmNlIgogICAgYXBwX2xvY2FsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIGJhbGFuY2UgZXhpc3RzIGZvciBhY2NvdW50CiAgICBhc3NlcnQgLy8gVXNlciBiYWxhbmNlIG11c3QgYmUgZ3JlYXRlciB0aGFuIDAKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjM5CiAgICAvLyB1c2VyQmFsYW5jZSA9IHNlbGYuYmFsYW5jZVtUeG4uc2VuZGVyXQogICAgdHhuIFNlbmRlcgogICAgaW50IDAKICAgIGJ5dGUgImJhbGFuY2UiCiAgICBhcHBfbG9jYWxfZ2V0X2V4CiAgICBhc3NlcnQgLy8gY2hlY2sgYmFsYW5jZSBleGlzdHMgZm9yIGFjY291bnQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjQxLTQ2CiAgICAvLyBpdHhuLlBheW1lbnQoCiAgICAvLyAgICAgcmVjZWl2ZXI9VHhuLnNlbmRlciwKICAgIC8vICAgICBzZW5kZXI9R2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcywKICAgIC8vICAgICBhbW91bnQ9dXNlckJhbGFuY2UsCiAgICAvLyAgICAgZmVlPTAsCiAgICAvLyApLnN1Ym1pdCgpCiAgICBpdHhuX2JlZ2luCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTo0MgogICAgLy8gcmVjZWl2ZXI9VHhuLnNlbmRlciwKICAgIHR4biBTZW5kZXIKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjQzCiAgICAvLyBzZW5kZXI9R2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcywKICAgIGdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCiAgICBkaWcgMgogICAgaXR4bl9maWVsZCBBbW91bnQKICAgIGl0eG5fZmllbGQgU2VuZGVyCiAgICBpdHhuX2ZpZWxkIFJlY2VpdmVyCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTo0MQogICAgLy8gaXR4bi5QYXltZW50KAogICAgaW50IHBheQogICAgaXR4bl9maWVsZCBUeXBlRW51bQogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6NDUKICAgIC8vIGZlZT0wLAogICAgaW50IDAKICAgIGl0eG5fZmllbGQgRmVlCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTo0MS00NgogICAgLy8gaXR4bi5QYXltZW50KAogICAgLy8gICAgIHJlY2VpdmVyPVR4bi5zZW5kZXIsCiAgICAvLyAgICAgc2VuZGVyPUdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2FkZHJlc3MsCiAgICAvLyAgICAgYW1vdW50PXVzZXJCYWxhbmNlLAogICAgLy8gICAgIGZlZT0wLAogICAgLy8gKS5zdWJtaXQoKQogICAgaXR4bl9zdWJtaXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjQ4CiAgICAvLyBzZWxmLmRlcG9zaXRvcnMgLT0gMQogICAgaW50IDAKICAgIGJ5dGUgImRlcG9zaXRvcnMiCiAgICBhcHBfZ2xvYmFsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIGRlcG9zaXRvcnMgZXhpc3RzCiAgICBpbnQgMQogICAgLQogICAgYnl0ZSAiZGVwb3NpdG9ycyIKICAgIHN3YXAKICAgIGFwcF9nbG9iYWxfcHV0CiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTo1MAogICAgLy8gcmV0dXJuIHVzZXJCYWxhbmNlCiAgICByZXRzdWIKCgovLyBzbWFydF9jb250cmFjdHMucGVyc29uYWxfYmFuay5jb250cmFjdC5QZXJzb25hbEJhbmsuX19pbml0X18oKSAtPiB2b2lkOgpfX2luaXRfXzoKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjUKICAgIC8vIGRlZiBfX2luaXRfXyhzZWxmKSAtPiBOb25lOgogICAgcHJvdG8gMCAwCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTo4CiAgICAvLyBzZWxmLmRlcG9zaXRvcnMgPSBVSW50NjQoMCkKICAgIGJ5dGUgImRlcG9zaXRvcnMiCiAgICBpbnQgMAogICAgYXBwX2dsb2JhbF9wdXQKICAgIHJldHN1Ygo=", "clear": "I3ByYWdtYSB2ZXJzaW9uIDEwCgpzbWFydF9jb250cmFjdHMucGVyc29uYWxfYmFuay5jb250cmFjdC5QZXJzb25hbEJhbmsuY2xlYXJfc3RhdGVfcHJvZ3JhbToKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjQKICAgIC8vIGNsYXNzIFBlcnNvbmFsQmFuayhBUkM0Q29udHJhY3QpOgogICAgaW50IDEKICAgIHJldHVybgo=" }, "state": { diff --git a/projects/bay-workshop-2024/smart_contracts/artifacts/personal_bank/client.ts b/projects/bay-workshop-2024/smart_contracts/artifacts/personal_bank/client.ts index 23813a1..821ae7f 100644 --- a/projects/bay-workshop-2024/smart_contracts/artifacts/personal_bank/client.ts +++ b/projects/bay-workshop-2024/smart_contracts/artifacts/personal_bank/client.ts @@ -47,7 +47,7 @@ export const APP_SPEC: AppSpec = { } }, "source": { - "approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgpzbWFydF9jb250cmFjdHMucGVyc29uYWxfYmFuay5jb250cmFjdC5QZXJzb25hbEJhbmsuYXBwcm92YWxfcHJvZ3JhbToKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBibnogbWFpbl9lbnRyeXBvaW50QDIKICAgIGNhbGxzdWIgX19pbml0X18KCm1haW5fZW50cnlwb2ludEAyOgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6NAogICAgLy8gY2xhc3MgUGVyc29uYWxCYW5rKEFSQzRDb250cmFjdCk6CiAgICB0eG4gTnVtQXBwQXJncwogICAgYnogbWFpbl9iYXJlX3JvdXRpbmdAOQogICAgbWV0aG9kICJvcHRfaW5fdG9fYXBwKCl2b2lkIgogICAgbWV0aG9kICJkZXBvc2l0KHBheSl1aW50NjQiCiAgICBtZXRob2QgIndpdGhkcmF3KCl1aW50NjQiCiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAwCiAgICBtYXRjaCBtYWluX29wdF9pbl90b19hcHBfcm91dGVANCBtYWluX2RlcG9zaXRfcm91dGVANSBtYWluX3dpdGhkcmF3X3JvdXRlQDYKICAgIGVyciAvLyByZWplY3QgdHJhbnNhY3Rpb24KCm1haW5fb3B0X2luX3RvX2FwcF9yb3V0ZUA0OgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MTAKICAgIC8vIEBhcmM0LmFiaW1ldGhvZChhbGxvd19hY3Rpb25zPVsiT3B0SW4iXSkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgIGludCBPcHRJbgogICAgPT0KICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgT3B0SW4KICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gaXMgbm90IGNyZWF0aW5nCiAgICBjYWxsc3ViIG9wdF9pbl90b19hcHAKICAgIGludCAxCiAgICByZXR1cm4KCm1haW5fZGVwb3NpdF9yb3V0ZUA1OgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MTgKICAgIC8vIEBhcmM0LmFiaW1ldGhvZAogICAgdHhuIE9uQ29tcGxldGlvbgogICAgIQogICAgYXNzZXJ0IC8vIE9uQ29tcGxldGlvbiBpcyBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGlzIG5vdCBjcmVhdGluZwogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6NAogICAgLy8gY2xhc3MgUGVyc29uYWxCYW5rKEFSQzRDb250cmFjdCk6CiAgICB0eG4gR3JvdXBJbmRleAogICAgaW50IDEKICAgIC0KICAgIGR1cAogICAgZ3R4bnMgVHlwZUVudW0KICAgIGludCBwYXkKICAgID09CiAgICBhc3NlcnQgLy8gdHJhbnNhY3Rpb24gdHlwZSBpcyBwYXkKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjE4CiAgICAvLyBAYXJjNC5hYmltZXRob2QKICAgIGNhbGxzdWIgZGVwb3NpdAogICAgaXRvYgogICAgYnl0ZSAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50IDEKICAgIHJldHVybgoKbWFpbl93aXRoZHJhd19yb3V0ZUA2OgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MzIKICAgIC8vIEBhcmM0LmFiaW1ldGhvZChhbGxvd19hY3Rpb25zPVsiQ2xvc2VPdXQiXSkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgIGludCBDbG9zZU91dAogICAgPT0KICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgQ2xvc2VPdXQKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gaXMgbm90IGNyZWF0aW5nCiAgICBjYWxsc3ViIHdpdGhkcmF3CiAgICBpdG9iCiAgICBieXRlIDB4MTUxZjdjNzUKICAgIHN3YXAKICAgIGNvbmNhdAogICAgbG9nCiAgICBpbnQgMQogICAgcmV0dXJuCgptYWluX2JhcmVfcm91dGluZ0A5OgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6NAogICAgLy8gY2xhc3MgUGVyc29uYWxCYW5rKEFSQzRDb250cmFjdCk6CiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gcmVqZWN0IHRyYW5zYWN0aW9uCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgIQogICAgYXNzZXJ0IC8vIGlzIGNyZWF0aW5nCiAgICBpbnQgMQogICAgcmV0dXJuCgoKLy8gc21hcnRfY29udHJhY3RzLnBlcnNvbmFsX2JhbmsuY29udHJhY3QuUGVyc29uYWxCYW5rLm9wdF9pbl90b19hcHAoKSAtPiB2b2lkOgpvcHRfaW5fdG9fYXBwOgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MTAtMTEKICAgIC8vIEBhcmM0LmFiaW1ldGhvZChhbGxvd19hY3Rpb25zPVsiT3B0SW4iXSkKICAgIC8vIGRlZiBvcHRfaW5fdG9fYXBwKHNlbGYpIC0+IE5vbmU6CiAgICBwcm90byAwIDAKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjEyCiAgICAvLyByZXN1bHQgLCBleGlzdHMgPSBzZWxmLm9wdGVkSW4ubWF5YmUoVHhuLnNlbmRlcikKICAgIHR4biBTZW5kZXIKICAgIGludCAwCiAgICBieXRlICJvcHRlZEluIgogICAgYXBwX2xvY2FsX2dldF9leAogICAgYnVyeSAxCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weToxMwogICAgLy8gYXNzZXJ0IG5vdCBleGlzdHMsICJVc2VyIGFscmVhZHkgb3B0ZWQgaW4iCiAgICAhCiAgICBhc3NlcnQgLy8gVXNlciBhbHJlYWR5IG9wdGVkIGluCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weToxNAogICAgLy8gc2VsZi5iYWxhbmNlW1R4bi5zZW5kZXJdID0gVUludDY0KDApCiAgICB0eG4gU2VuZGVyCiAgICBieXRlICJiYWxhbmNlIgogICAgaW50IDAKICAgIGFwcF9sb2NhbF9wdXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjE1CiAgICAvLyBzZWxmLm9wdGVkSW5bVHhuLnNlbmRlcl0gPSBUcnVlCiAgICB0eG4gU2VuZGVyCiAgICBieXRlICJvcHRlZEluIgogICAgaW50IDEKICAgIGFwcF9sb2NhbF9wdXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjE2CiAgICAvLyBzZWxmLmRlcG9zaXRvcnMgKz0gMQogICAgaW50IDAKICAgIGJ5dGUgImRlcG9zaXRvcnMiCiAgICBhcHBfZ2xvYmFsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIGRlcG9zaXRvcnMgZXhpc3RzCiAgICBpbnQgMQogICAgKwogICAgYnl0ZSAiZGVwb3NpdG9ycyIKICAgIHN3YXAKICAgIGFwcF9nbG9iYWxfcHV0CiAgICByZXRzdWIKCgovLyBzbWFydF9jb250cmFjdHMucGVyc29uYWxfYmFuay5jb250cmFjdC5QZXJzb25hbEJhbmsuZGVwb3NpdChwdHhuOiB1aW50NjQpIC0+IHVpbnQ2NDoKZGVwb3NpdDoKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjE4LTE5CiAgICAvLyBAYXJjNC5hYmltZXRob2QKICAgIC8vIGRlZiBkZXBvc2l0KHNlbGYsIHB0eG46IGd0eG4uUGF5bWVudFRyYW5zYWN0aW9uKSAtPiBVSW50NjQ6CiAgICBwcm90byAxIDEKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjIwCiAgICAvLyBhc3NlcnQgcHR4bi5hbW91bnQgPiAwLCAiRGVwb3NpdCBhbW91bnQgbXVzdCBiZSBncmVhdGVyIHRoYW4gMCIKICAgIGZyYW1lX2RpZyAtMQogICAgZ3R4bnMgQW1vdW50CiAgICBkdXAKICAgIGFzc2VydCAvLyBEZXBvc2l0IGFtb3VudCBtdXN0IGJlIGdyZWF0ZXIgdGhhbiAwCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weToyMgogICAgLy8gcHR4bi5yZWNlaXZlciA9PSBHbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzCiAgICBmcmFtZV9kaWcgLTEKICAgIGd0eG5zIFJlY2VpdmVyCiAgICBnbG9iYWwgQ3VycmVudEFwcGxpY2F0aW9uQWRkcmVzcwogICAgPT0KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjIxLTIzCiAgICAvLyBhc3NlcnQgKAogICAgLy8gICAgIHB0eG4ucmVjZWl2ZXIgPT0gR2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcwogICAgLy8gKSwgIkRlcG9zaXQgcmVjZWl2ZXIgbXVzdCBiZSB0aGUgY29udHJhY3QgYWRkcmVzcyIKICAgIGFzc2VydCAvLyBEZXBvc2l0IHJlY2VpdmVyIG11c3QgYmUgdGhlIGNvbnRyYWN0IGFkZHJlc3MKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjI0CiAgICAvLyBhc3NlcnQgcHR4bi5zZW5kZXIgPT0gVHhuLnNlbmRlciwgIkRlcG9zaXQgc2VuZGVyIG11c3QgYmUgdGhlIGNhbGxlciIKICAgIGZyYW1lX2RpZyAtMQogICAgZ3R4bnMgU2VuZGVyCiAgICB0eG4gU2VuZGVyCiAgICA9PQogICAgYXNzZXJ0IC8vIERlcG9zaXQgc2VuZGVyIG11c3QgYmUgdGhlIGNhbGxlcgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MjUKICAgIC8vIGFzc2VydCBUeG4uc2VuZGVyLmlzX29wdGVkX2luKEdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2lkKSwgIkRlcG9zaXQgc2VuZGVyIG11c3Qgb3B0LWluIHRvIHRoZSBhcHAgZmlyc3QuIgogICAgdHhuIFNlbmRlcgogICAgZ2xvYmFsIEN1cnJlbnRBcHBsaWNhdGlvbklECiAgICBhcHBfb3B0ZWRfaW4KICAgIGFzc2VydCAvLyBEZXBvc2l0IHNlbmRlciBtdXN0IG9wdC1pbiB0byB0aGUgYXBwIGZpcnN0LgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MjcKICAgIC8vIHNlbGYuYmFsYW5jZVtUeG4uc2VuZGVyXSArPSBwdHhuLmFtb3VudAogICAgdHhuIFNlbmRlcgogICAgaW50IDAKICAgIGJ5dGUgImJhbGFuY2UiCiAgICBhcHBfbG9jYWxfZ2V0X2V4CiAgICBhc3NlcnQgLy8gY2hlY2sgYmFsYW5jZSBleGlzdHMgZm9yIGFjY291bnQKICAgICsKICAgIHR4biBTZW5kZXIKICAgIGJ5dGUgImJhbGFuY2UiCiAgICB1bmNvdmVyIDIKICAgIGFwcF9sb2NhbF9wdXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjI4CiAgICAvLyB1c2VyX2JhbGFuY2UgPSBzZWxmLmJhbGFuY2VbVHhuLnNlbmRlcl0KICAgIHR4biBTZW5kZXIKICAgIGludCAwCiAgICBieXRlICJiYWxhbmNlIgogICAgYXBwX2xvY2FsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIGJhbGFuY2UgZXhpc3RzIGZvciBhY2NvdW50CiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTozMAogICAgLy8gcmV0dXJuIHVzZXJfYmFsYW5jZQogICAgcmV0c3ViCgoKLy8gc21hcnRfY29udHJhY3RzLnBlcnNvbmFsX2JhbmsuY29udHJhY3QuUGVyc29uYWxCYW5rLndpdGhkcmF3KCkgLT4gdWludDY0Ogp3aXRoZHJhdzoKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjMyLTMzCiAgICAvLyBAYXJjNC5hYmltZXRob2QoYWxsb3dfYWN0aW9ucz1bIkNsb3NlT3V0Il0pCiAgICAvLyBkZWYgd2l0aGRyYXcoc2VsZikgLT4gVUludDY0OgogICAgcHJvdG8gMCAxCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTozNAogICAgLy8gYXNzZXJ0IHNlbGYuYmFsYW5jZVtUeG4uc2VuZGVyXSA+IDAsICJVc2VyIGJhbGFuY2UgbXVzdCBiZSBncmVhdGVyIHRoYW4gMCIKICAgIHR4biBTZW5kZXIKICAgIGludCAwCiAgICBieXRlICJiYWxhbmNlIgogICAgYXBwX2xvY2FsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIGJhbGFuY2UgZXhpc3RzIGZvciBhY2NvdW50CiAgICBhc3NlcnQgLy8gVXNlciBiYWxhbmNlIG11c3QgYmUgZ3JlYXRlciB0aGFuIDAKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjM2CiAgICAvLyB1c2VyQmFsYW5jZSA9IHNlbGYuYmFsYW5jZVtUeG4uc2VuZGVyXQogICAgdHhuIFNlbmRlcgogICAgaW50IDAKICAgIGJ5dGUgImJhbGFuY2UiCiAgICBhcHBfbG9jYWxfZ2V0X2V4CiAgICBhc3NlcnQgLy8gY2hlY2sgYmFsYW5jZSBleGlzdHMgZm9yIGFjY291bnQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjM4LTQzCiAgICAvLyBpdHhuLlBheW1lbnQoCiAgICAvLyAgICAgcmVjZWl2ZXI9VHhuLnNlbmRlciwKICAgIC8vICAgICBzZW5kZXI9R2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcywKICAgIC8vICAgICBhbW91bnQ9dXNlckJhbGFuY2UsCiAgICAvLyAgICAgZmVlPTAsCiAgICAvLyApLnN1Ym1pdCgpCiAgICBpdHhuX2JlZ2luCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTozOQogICAgLy8gcmVjZWl2ZXI9VHhuLnNlbmRlciwKICAgIHR4biBTZW5kZXIKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjQwCiAgICAvLyBzZW5kZXI9R2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcywKICAgIGdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCiAgICBkaWcgMgogICAgaXR4bl9maWVsZCBBbW91bnQKICAgIGl0eG5fZmllbGQgU2VuZGVyCiAgICBpdHhuX2ZpZWxkIFJlY2VpdmVyCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTozOAogICAgLy8gaXR4bi5QYXltZW50KAogICAgaW50IHBheQogICAgaXR4bl9maWVsZCBUeXBlRW51bQogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6NDIKICAgIC8vIGZlZT0wLAogICAgaW50IDAKICAgIGl0eG5fZmllbGQgRmVlCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTozOC00MwogICAgLy8gaXR4bi5QYXltZW50KAogICAgLy8gICAgIHJlY2VpdmVyPVR4bi5zZW5kZXIsCiAgICAvLyAgICAgc2VuZGVyPUdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2FkZHJlc3MsCiAgICAvLyAgICAgYW1vdW50PXVzZXJCYWxhbmNlLAogICAgLy8gICAgIGZlZT0wLAogICAgLy8gKS5zdWJtaXQoKQogICAgaXR4bl9zdWJtaXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjQ1CiAgICAvLyBzZWxmLmRlcG9zaXRvcnMgLT0gMQogICAgaW50IDAKICAgIGJ5dGUgImRlcG9zaXRvcnMiCiAgICBhcHBfZ2xvYmFsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIGRlcG9zaXRvcnMgZXhpc3RzCiAgICBpbnQgMQogICAgLQogICAgYnl0ZSAiZGVwb3NpdG9ycyIKICAgIHN3YXAKICAgIGFwcF9nbG9iYWxfcHV0CiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTo0NwogICAgLy8gcmV0dXJuIHVzZXJCYWxhbmNlCiAgICByZXRzdWIKCgovLyBzbWFydF9jb250cmFjdHMucGVyc29uYWxfYmFuay5jb250cmFjdC5QZXJzb25hbEJhbmsuX19pbml0X18oKSAtPiB2b2lkOgpfX2luaXRfXzoKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjUKICAgIC8vIGRlZiBfX2luaXRfXyhzZWxmKSAtPiBOb25lOgogICAgcHJvdG8gMCAwCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTo4CiAgICAvLyBzZWxmLmRlcG9zaXRvcnMgPSBVSW50NjQoMCkKICAgIGJ5dGUgImRlcG9zaXRvcnMiCiAgICBpbnQgMAogICAgYXBwX2dsb2JhbF9wdXQKICAgIHJldHN1Ygo=", + "approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgpzbWFydF9jb250cmFjdHMucGVyc29uYWxfYmFuay5jb250cmFjdC5QZXJzb25hbEJhbmsuYXBwcm92YWxfcHJvZ3JhbToKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBibnogbWFpbl9lbnRyeXBvaW50QDIKICAgIGNhbGxzdWIgX19pbml0X18KCm1haW5fZW50cnlwb2ludEAyOgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6NAogICAgLy8gY2xhc3MgUGVyc29uYWxCYW5rKEFSQzRDb250cmFjdCk6CiAgICB0eG4gTnVtQXBwQXJncwogICAgYnogbWFpbl9iYXJlX3JvdXRpbmdAOQogICAgbWV0aG9kICJvcHRfaW5fdG9fYXBwKCl2b2lkIgogICAgbWV0aG9kICJkZXBvc2l0KHBheSl1aW50NjQiCiAgICBtZXRob2QgIndpdGhkcmF3KCl1aW50NjQiCiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAwCiAgICBtYXRjaCBtYWluX29wdF9pbl90b19hcHBfcm91dGVANCBtYWluX2RlcG9zaXRfcm91dGVANSBtYWluX3dpdGhkcmF3X3JvdXRlQDYKICAgIGVyciAvLyByZWplY3QgdHJhbnNhY3Rpb24KCm1haW5fb3B0X2luX3RvX2FwcF9yb3V0ZUA0OgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MTAKICAgIC8vIEBhcmM0LmFiaW1ldGhvZChhbGxvd19hY3Rpb25zPVsiT3B0SW4iXSkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgIGludCBPcHRJbgogICAgPT0KICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgT3B0SW4KICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gaXMgbm90IGNyZWF0aW5nCiAgICBjYWxsc3ViIG9wdF9pbl90b19hcHAKICAgIGludCAxCiAgICByZXR1cm4KCm1haW5fZGVwb3NpdF9yb3V0ZUA1OgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MTkKICAgIC8vIEBhcmM0LmFiaW1ldGhvZAogICAgdHhuIE9uQ29tcGxldGlvbgogICAgIQogICAgYXNzZXJ0IC8vIE9uQ29tcGxldGlvbiBpcyBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGlzIG5vdCBjcmVhdGluZwogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6NAogICAgLy8gY2xhc3MgUGVyc29uYWxCYW5rKEFSQzRDb250cmFjdCk6CiAgICB0eG4gR3JvdXBJbmRleAogICAgaW50IDEKICAgIC0KICAgIGR1cAogICAgZ3R4bnMgVHlwZUVudW0KICAgIGludCBwYXkKICAgID09CiAgICBhc3NlcnQgLy8gdHJhbnNhY3Rpb24gdHlwZSBpcyBwYXkKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjE5CiAgICAvLyBAYXJjNC5hYmltZXRob2QKICAgIGNhbGxzdWIgZGVwb3NpdAogICAgaXRvYgogICAgYnl0ZSAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50IDEKICAgIHJldHVybgoKbWFpbl93aXRoZHJhd19yb3V0ZUA2OgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MzUKICAgIC8vIEBhcmM0LmFiaW1ldGhvZChhbGxvd19hY3Rpb25zPVsiQ2xvc2VPdXQiXSkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgIGludCBDbG9zZU91dAogICAgPT0KICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgQ2xvc2VPdXQKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gaXMgbm90IGNyZWF0aW5nCiAgICBjYWxsc3ViIHdpdGhkcmF3CiAgICBpdG9iCiAgICBieXRlIDB4MTUxZjdjNzUKICAgIHN3YXAKICAgIGNvbmNhdAogICAgbG9nCiAgICBpbnQgMQogICAgcmV0dXJuCgptYWluX2JhcmVfcm91dGluZ0A5OgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6NAogICAgLy8gY2xhc3MgUGVyc29uYWxCYW5rKEFSQzRDb250cmFjdCk6CiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gcmVqZWN0IHRyYW5zYWN0aW9uCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgIQogICAgYXNzZXJ0IC8vIGlzIGNyZWF0aW5nCiAgICBpbnQgMQogICAgcmV0dXJuCgoKLy8gc21hcnRfY29udHJhY3RzLnBlcnNvbmFsX2JhbmsuY29udHJhY3QuUGVyc29uYWxCYW5rLm9wdF9pbl90b19hcHAoKSAtPiB2b2lkOgpvcHRfaW5fdG9fYXBwOgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MTAtMTEKICAgIC8vIEBhcmM0LmFiaW1ldGhvZChhbGxvd19hY3Rpb25zPVsiT3B0SW4iXSkKICAgIC8vIGRlZiBvcHRfaW5fdG9fYXBwKHNlbGYpIC0+IE5vbmU6CiAgICBwcm90byAwIDAKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjEyCiAgICAvLyByZXN1bHQsIGV4aXN0cyA9IHNlbGYub3B0ZWRJbi5tYXliZShUeG4uc2VuZGVyKQogICAgdHhuIFNlbmRlcgogICAgaW50IDAKICAgIGJ5dGUgIm9wdGVkSW4iCiAgICBhcHBfbG9jYWxfZ2V0X2V4CiAgICBidXJ5IDEKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjEzCiAgICAvLyBhc3NlcnQgbm90IGV4aXN0cywgIlVzZXIgYWxyZWFkeSBvcHRlZCBpbiIKICAgICEKICAgIGFzc2VydCAvLyBVc2VyIGFscmVhZHkgb3B0ZWQgaW4KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjE1CiAgICAvLyBzZWxmLmJhbGFuY2VbVHhuLnNlbmRlcl0gPSBVSW50NjQoMCkKICAgIHR4biBTZW5kZXIKICAgIGJ5dGUgImJhbGFuY2UiCiAgICBpbnQgMAogICAgYXBwX2xvY2FsX3B1dAogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MTYKICAgIC8vIHNlbGYub3B0ZWRJbltUeG4uc2VuZGVyXSA9IFRydWUKICAgIHR4biBTZW5kZXIKICAgIGJ5dGUgIm9wdGVkSW4iCiAgICBpbnQgMQogICAgYXBwX2xvY2FsX3B1dAogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MTcKICAgIC8vIHNlbGYuZGVwb3NpdG9ycyArPSAxCiAgICBpbnQgMAogICAgYnl0ZSAiZGVwb3NpdG9ycyIKICAgIGFwcF9nbG9iYWxfZ2V0X2V4CiAgICBhc3NlcnQgLy8gY2hlY2sgZGVwb3NpdG9ycyBleGlzdHMKICAgIGludCAxCiAgICArCiAgICBieXRlICJkZXBvc2l0b3JzIgogICAgc3dhcAogICAgYXBwX2dsb2JhbF9wdXQKICAgIHJldHN1YgoKCi8vIHNtYXJ0X2NvbnRyYWN0cy5wZXJzb25hbF9iYW5rLmNvbnRyYWN0LlBlcnNvbmFsQmFuay5kZXBvc2l0KHB0eG46IHVpbnQ2NCkgLT4gdWludDY0OgpkZXBvc2l0OgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MTktMjAKICAgIC8vIEBhcmM0LmFiaW1ldGhvZAogICAgLy8gZGVmIGRlcG9zaXQoc2VsZiwgcHR4bjogZ3R4bi5QYXltZW50VHJhbnNhY3Rpb24pIC0+IFVJbnQ2NDoKICAgIHByb3RvIDEgMQogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MjEKICAgIC8vIGFzc2VydCBwdHhuLmFtb3VudCA+IDAsICJEZXBvc2l0IGFtb3VudCBtdXN0IGJlIGdyZWF0ZXIgdGhhbiAwIgogICAgZnJhbWVfZGlnIC0xCiAgICBndHhucyBBbW91bnQKICAgIGR1cAogICAgYXNzZXJ0IC8vIERlcG9zaXQgYW1vdW50IG11c3QgYmUgZ3JlYXRlciB0aGFuIDAKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjIzCiAgICAvLyBwdHhuLnJlY2VpdmVyID09IEdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2FkZHJlc3MKICAgIGZyYW1lX2RpZyAtMQogICAgZ3R4bnMgUmVjZWl2ZXIKICAgIGdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCiAgICA9PQogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MjItMjQKICAgIC8vIGFzc2VydCAoCiAgICAvLyAgICAgcHR4bi5yZWNlaXZlciA9PSBHbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzCiAgICAvLyApLCAiRGVwb3NpdCByZWNlaXZlciBtdXN0IGJlIHRoZSBjb250cmFjdCBhZGRyZXNzIgogICAgYXNzZXJ0IC8vIERlcG9zaXQgcmVjZWl2ZXIgbXVzdCBiZSB0aGUgY29udHJhY3QgYWRkcmVzcwogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MjUKICAgIC8vIGFzc2VydCBwdHhuLnNlbmRlciA9PSBUeG4uc2VuZGVyLCAiRGVwb3NpdCBzZW5kZXIgbXVzdCBiZSB0aGUgY2FsbGVyIgogICAgZnJhbWVfZGlnIC0xCiAgICBndHhucyBTZW5kZXIKICAgIHR4biBTZW5kZXIKICAgID09CiAgICBhc3NlcnQgLy8gRGVwb3NpdCBzZW5kZXIgbXVzdCBiZSB0aGUgY2FsbGVyCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weToyNgogICAgLy8gYXNzZXJ0IFR4bi5zZW5kZXIuaXNfb3B0ZWRfaW4oCiAgICB0eG4gU2VuZGVyCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weToyNwogICAgLy8gR2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25faWQKICAgIGdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25JRAogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MjYtMjgKICAgIC8vIGFzc2VydCBUeG4uc2VuZGVyLmlzX29wdGVkX2luKAogICAgLy8gICAgIEdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2lkCiAgICAvLyApLCAiRGVwb3NpdCBzZW5kZXIgbXVzdCBvcHQtaW4gdG8gdGhlIGFwcCBmaXJzdC4iCiAgICBhcHBfb3B0ZWRfaW4KICAgIGFzc2VydCAvLyBEZXBvc2l0IHNlbmRlciBtdXN0IG9wdC1pbiB0byB0aGUgYXBwIGZpcnN0LgogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6MzAKICAgIC8vIHNlbGYuYmFsYW5jZVtUeG4uc2VuZGVyXSArPSBwdHhuLmFtb3VudAogICAgdHhuIFNlbmRlcgogICAgaW50IDAKICAgIGJ5dGUgImJhbGFuY2UiCiAgICBhcHBfbG9jYWxfZ2V0X2V4CiAgICBhc3NlcnQgLy8gY2hlY2sgYmFsYW5jZSBleGlzdHMgZm9yIGFjY291bnQKICAgICsKICAgIHR4biBTZW5kZXIKICAgIGJ5dGUgImJhbGFuY2UiCiAgICB1bmNvdmVyIDIKICAgIGFwcF9sb2NhbF9wdXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjMxCiAgICAvLyB1c2VyX2JhbGFuY2UgPSBzZWxmLmJhbGFuY2VbVHhuLnNlbmRlcl0KICAgIHR4biBTZW5kZXIKICAgIGludCAwCiAgICBieXRlICJiYWxhbmNlIgogICAgYXBwX2xvY2FsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIGJhbGFuY2UgZXhpc3RzIGZvciBhY2NvdW50CiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTozMwogICAgLy8gcmV0dXJuIHVzZXJfYmFsYW5jZQogICAgcmV0c3ViCgoKLy8gc21hcnRfY29udHJhY3RzLnBlcnNvbmFsX2JhbmsuY29udHJhY3QuUGVyc29uYWxCYW5rLndpdGhkcmF3KCkgLT4gdWludDY0Ogp3aXRoZHJhdzoKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjM1LTM2CiAgICAvLyBAYXJjNC5hYmltZXRob2QoYWxsb3dfYWN0aW9ucz1bIkNsb3NlT3V0Il0pCiAgICAvLyBkZWYgd2l0aGRyYXcoc2VsZikgLT4gVUludDY0OgogICAgcHJvdG8gMCAxCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTozNwogICAgLy8gYXNzZXJ0IHNlbGYuYmFsYW5jZVtUeG4uc2VuZGVyXSA+IDAsICJVc2VyIGJhbGFuY2UgbXVzdCBiZSBncmVhdGVyIHRoYW4gMCIKICAgIHR4biBTZW5kZXIKICAgIGludCAwCiAgICBieXRlICJiYWxhbmNlIgogICAgYXBwX2xvY2FsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIGJhbGFuY2UgZXhpc3RzIGZvciBhY2NvdW50CiAgICBhc3NlcnQgLy8gVXNlciBiYWxhbmNlIG11c3QgYmUgZ3JlYXRlciB0aGFuIDAKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjM5CiAgICAvLyB1c2VyQmFsYW5jZSA9IHNlbGYuYmFsYW5jZVtUeG4uc2VuZGVyXQogICAgdHhuIFNlbmRlcgogICAgaW50IDAKICAgIGJ5dGUgImJhbGFuY2UiCiAgICBhcHBfbG9jYWxfZ2V0X2V4CiAgICBhc3NlcnQgLy8gY2hlY2sgYmFsYW5jZSBleGlzdHMgZm9yIGFjY291bnQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjQxLTQ2CiAgICAvLyBpdHhuLlBheW1lbnQoCiAgICAvLyAgICAgcmVjZWl2ZXI9VHhuLnNlbmRlciwKICAgIC8vICAgICBzZW5kZXI9R2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcywKICAgIC8vICAgICBhbW91bnQ9dXNlckJhbGFuY2UsCiAgICAvLyAgICAgZmVlPTAsCiAgICAvLyApLnN1Ym1pdCgpCiAgICBpdHhuX2JlZ2luCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTo0MgogICAgLy8gcmVjZWl2ZXI9VHhuLnNlbmRlciwKICAgIHR4biBTZW5kZXIKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjQzCiAgICAvLyBzZW5kZXI9R2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcywKICAgIGdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCiAgICBkaWcgMgogICAgaXR4bl9maWVsZCBBbW91bnQKICAgIGl0eG5fZmllbGQgU2VuZGVyCiAgICBpdHhuX2ZpZWxkIFJlY2VpdmVyCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTo0MQogICAgLy8gaXR4bi5QYXltZW50KAogICAgaW50IHBheQogICAgaXR4bl9maWVsZCBUeXBlRW51bQogICAgLy8gc21hcnRfY29udHJhY3RzL3BlcnNvbmFsX2JhbmsvY29udHJhY3QucHk6NDUKICAgIC8vIGZlZT0wLAogICAgaW50IDAKICAgIGl0eG5fZmllbGQgRmVlCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTo0MS00NgogICAgLy8gaXR4bi5QYXltZW50KAogICAgLy8gICAgIHJlY2VpdmVyPVR4bi5zZW5kZXIsCiAgICAvLyAgICAgc2VuZGVyPUdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2FkZHJlc3MsCiAgICAvLyAgICAgYW1vdW50PXVzZXJCYWxhbmNlLAogICAgLy8gICAgIGZlZT0wLAogICAgLy8gKS5zdWJtaXQoKQogICAgaXR4bl9zdWJtaXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjQ4CiAgICAvLyBzZWxmLmRlcG9zaXRvcnMgLT0gMQogICAgaW50IDAKICAgIGJ5dGUgImRlcG9zaXRvcnMiCiAgICBhcHBfZ2xvYmFsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIGRlcG9zaXRvcnMgZXhpc3RzCiAgICBpbnQgMQogICAgLQogICAgYnl0ZSAiZGVwb3NpdG9ycyIKICAgIHN3YXAKICAgIGFwcF9nbG9iYWxfcHV0CiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTo1MAogICAgLy8gcmV0dXJuIHVzZXJCYWxhbmNlCiAgICByZXRzdWIKCgovLyBzbWFydF9jb250cmFjdHMucGVyc29uYWxfYmFuay5jb250cmFjdC5QZXJzb25hbEJhbmsuX19pbml0X18oKSAtPiB2b2lkOgpfX2luaXRfXzoKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjUKICAgIC8vIGRlZiBfX2luaXRfXyhzZWxmKSAtPiBOb25lOgogICAgcHJvdG8gMCAwCiAgICAvLyBzbWFydF9jb250cmFjdHMvcGVyc29uYWxfYmFuay9jb250cmFjdC5weTo4CiAgICAvLyBzZWxmLmRlcG9zaXRvcnMgPSBVSW50NjQoMCkKICAgIGJ5dGUgImRlcG9zaXRvcnMiCiAgICBpbnQgMAogICAgYXBwX2dsb2JhbF9wdXQKICAgIHJldHN1Ygo=", "clear": "I3ByYWdtYSB2ZXJzaW9uIDEwCgpzbWFydF9jb250cmFjdHMucGVyc29uYWxfYmFuay5jb250cmFjdC5QZXJzb25hbEJhbmsuY2xlYXJfc3RhdGVfcHJvZ3JhbToKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9wZXJzb25hbF9iYW5rL2NvbnRyYWN0LnB5OjQKICAgIC8vIGNsYXNzIFBlcnNvbmFsQmFuayhBUkM0Q29udHJhY3QpOgogICAgaW50IDEKICAgIHJldHVybgo=" }, "state": { diff --git a/projects/coding-assignment/smart_contracts/artifacts/nft_marketplace/NftMarketplace.approval.teal b/projects/coding-assignment/smart_contracts/artifacts/nft_marketplace/NftMarketplace.approval.teal new file mode 100644 index 0000000..70e26ba --- /dev/null +++ b/projects/coding-assignment/smart_contracts/artifacts/nft_marketplace/NftMarketplace.approval.teal @@ -0,0 +1,371 @@ +#pragma version 10 + +smart_contracts.nft_marketplace.contract.NftMarketplace.approval_program: + txn ApplicationID + bnz main_entrypoint@2 + callsub __init__ + +main_entrypoint@2: + // smart_contracts/nft_marketplace/contract.py:20 + // class NftMarketplace(arc4.ARC4Contract): + txn NumAppArgs + bz main_bare_routing@9 + method "bootstrap(asset,uint64,pay)void" + method "buy(pay,uint64)void" + method "withdraw_and_delete()void" + txna ApplicationArgs 0 + match main_bootstrap_route@4 main_buy_route@5 main_withdraw_and_delete_route@6 + err // reject transaction + +main_bootstrap_route@4: + // smart_contracts/nft_marketplace/contract.py:90 + // @arc4.abimethod + txn OnCompletion + ! + assert // OnCompletion is NoOp + txn ApplicationID + assert // is not creating + // smart_contracts/nft_marketplace/contract.py:20 + // class NftMarketplace(arc4.ARC4Contract): + txna ApplicationArgs 1 + btoi + txnas Assets + txna ApplicationArgs 2 + btoi + txn GroupIndex + int 1 + - + dup + gtxns TypeEnum + int pay + == + assert // transaction type is pay + // smart_contracts/nft_marketplace/contract.py:90 + // @arc4.abimethod + callsub bootstrap + int 1 + return + +main_buy_route@5: + // smart_contracts/nft_marketplace/contract.py:142 + // @arc4.abimethod + txn OnCompletion + ! + assert // OnCompletion is NoOp + txn ApplicationID + assert // is not creating + // smart_contracts/nft_marketplace/contract.py:20 + // class NftMarketplace(arc4.ARC4Contract): + txn GroupIndex + int 1 + - + dup + gtxns TypeEnum + int pay + == + assert // transaction type is pay + txna ApplicationArgs 1 + btoi + // smart_contracts/nft_marketplace/contract.py:142 + // @arc4.abimethod + callsub buy + int 1 + return + +main_withdraw_and_delete_route@6: + // smart_contracts/nft_marketplace/contract.py:206 + // @arc4.abimethod(allow_actions=["DeleteApplication"]) + txn OnCompletion + int DeleteApplication + == + assert // OnCompletion is DeleteApplication + txn ApplicationID + assert // is not creating + callsub withdraw_and_delete + int 1 + return + +main_bare_routing@9: + // smart_contracts/nft_marketplace/contract.py:20 + // class NftMarketplace(arc4.ARC4Contract): + txn OnCompletion + ! + assert // reject transaction + txn ApplicationID + ! + assert // is creating + int 1 + return + + +// smart_contracts.nft_marketplace.contract.NftMarketplace.bootstrap(asset: uint64, unitary_price: uint64, mbr_pay: uint64) -> void: +bootstrap: + // smart_contracts/nft_marketplace/contract.py:90-93 + // @arc4.abimethod + // def bootstrap( + // self, asset: Asset, unitary_price: UInt64, mbr_pay: gtxn.PaymentTransaction + // ) -> None: + proto 3 0 + // smart_contracts/nft_marketplace/contract.py:94 + // assert Txn.sender == Global.creator_address + txn Sender + global CreatorAddress + == + assert + // smart_contracts/nft_marketplace/contract.py:95 + // assert self.bootstrapped == False + int 0 + byte "bootstrapped" + app_global_get_ex + assert // check bootstrapped exists + ! + assert + // smart_contracts/nft_marketplace/contract.py:96 + // assert mbr_pay.receiver == Global.current_application_address + frame_dig -1 + gtxns Receiver + global CurrentApplicationAddress + == + assert + // smart_contracts/nft_marketplace/contract.py:97 + // assert mbr_pay.amount == (Global.current_application_address.min_balance+Global.asset_opt_in_min_balance) + frame_dig -1 + gtxns Amount + global CurrentApplicationAddress + acct_params_get AcctMinBalance + assert // account funded + global AssetOptInMinBalance + + + == + assert + // smart_contracts/nft_marketplace/contract.py:99 + // self.asset_id = asset.id + byte "asset_id" + frame_dig -3 + app_global_put + // smart_contracts/nft_marketplace/contract.py:100 + // self.unitary_price=unitary_price + byte "unitary_price" + frame_dig -2 + app_global_put + // smart_contracts/nft_marketplace/contract.py:101 + // self.bootstrapped=True + byte "bootstrapped" + int 1 + app_global_put + // smart_contracts/nft_marketplace/contract.py:103-107 + // itxn.AssetTransfer( + // xfer_asset=self.asset_id, + // asset_receiver=Global.current_application_address, + // asset_amount=0, + // ).submit() + itxn_begin + // smart_contracts/nft_marketplace/contract.py:104 + // xfer_asset=self.asset_id, + int 0 + byte "asset_id" + app_global_get_ex + assert // check asset_id exists + // smart_contracts/nft_marketplace/contract.py:105 + // asset_receiver=Global.current_application_address, + global CurrentApplicationAddress + // smart_contracts/nft_marketplace/contract.py:106 + // asset_amount=0, + int 0 + itxn_field AssetAmount + itxn_field AssetReceiver + itxn_field XferAsset + // smart_contracts/nft_marketplace/contract.py:103 + // itxn.AssetTransfer( + int axfer + itxn_field TypeEnum + int 0 + itxn_field Fee + // smart_contracts/nft_marketplace/contract.py:103-107 + // itxn.AssetTransfer( + // xfer_asset=self.asset_id, + // asset_receiver=Global.current_application_address, + // asset_amount=0, + // ).submit() + itxn_submit + retsub + + +// smart_contracts.nft_marketplace.contract.NftMarketplace.buy(buyer_txn: uint64, quantity: uint64) -> void: +buy: + // smart_contracts/nft_marketplace/contract.py:142-147 + // @arc4.abimethod + // def buy( + // self, + // buyer_txn: gtxn.PaymentTransaction, + // quantity: UInt64, + // ) -> None: + proto 2 0 + // smart_contracts/nft_marketplace/contract.py:148 + // assert self.bootstrapped==True + int 0 + byte "bootstrapped" + app_global_get_ex + assert // check bootstrapped exists + int 1 + == + assert + // smart_contracts/nft_marketplace/contract.py:149 + // assert buyer_txn.sender == Txn.sender + frame_dig -2 + gtxns Sender + txn Sender + == + assert + // smart_contracts/nft_marketplace/contract.py:150 + // assert buyer_txn.receiver == Global.current_application_address + frame_dig -2 + gtxns Receiver + global CurrentApplicationAddress + == + assert + // smart_contracts/nft_marketplace/contract.py:151 + // assert buyer_txn.amount == self.unitary_price*quantity + frame_dig -2 + gtxns Amount + int 0 + byte "unitary_price" + app_global_get_ex + assert // check unitary_price exists + frame_dig -1 + * + == + assert + // smart_contracts/nft_marketplace/contract.py:153-157 + // itxn.AssetTransfer( + // xfer_asset=self.asset_id, + // asset_receiver=Txn.sender, + // asset_amount=quantity, + // ).submit() + itxn_begin + // smart_contracts/nft_marketplace/contract.py:154 + // xfer_asset=self.asset_id, + int 0 + byte "asset_id" + app_global_get_ex + assert // check asset_id exists + // smart_contracts/nft_marketplace/contract.py:155 + // asset_receiver=Txn.sender, + txn Sender + frame_dig -1 + itxn_field AssetAmount + itxn_field AssetReceiver + itxn_field XferAsset + // smart_contracts/nft_marketplace/contract.py:153 + // itxn.AssetTransfer( + int axfer + itxn_field TypeEnum + int 0 + itxn_field Fee + // smart_contracts/nft_marketplace/contract.py:153-157 + // itxn.AssetTransfer( + // xfer_asset=self.asset_id, + // asset_receiver=Txn.sender, + // asset_amount=quantity, + // ).submit() + itxn_submit + retsub + + +// smart_contracts.nft_marketplace.contract.NftMarketplace.withdraw_and_delete() -> void: +withdraw_and_delete: + // smart_contracts/nft_marketplace/contract.py:206-207 + // @arc4.abimethod(allow_actions=["DeleteApplication"]) + // def withdraw_and_delete(self) -> None: + proto 0 0 + // smart_contracts/nft_marketplace/contract.py:209 + // assert Txn.sender == Global.creator_address + txn Sender + global CreatorAddress + == + assert + // smart_contracts/nft_marketplace/contract.py:210-214 + // itxn.AssetTransfer( + // xfer_asset=self.asset_id, + // asset_receiver=Global.creator_address, + // asset_close_to=Global.creator_address, + // ).submit() + itxn_begin + // smart_contracts/nft_marketplace/contract.py:211 + // xfer_asset=self.asset_id, + int 0 + byte "asset_id" + app_global_get_ex + assert // check asset_id exists + // smart_contracts/nft_marketplace/contract.py:212 + // asset_receiver=Global.creator_address, + global CreatorAddress + // smart_contracts/nft_marketplace/contract.py:213 + // asset_close_to=Global.creator_address, + dup + itxn_field AssetCloseTo + itxn_field AssetReceiver + itxn_field XferAsset + // smart_contracts/nft_marketplace/contract.py:210 + // itxn.AssetTransfer( + int axfer + itxn_field TypeEnum + int 0 + itxn_field Fee + // smart_contracts/nft_marketplace/contract.py:210-214 + // itxn.AssetTransfer( + // xfer_asset=self.asset_id, + // asset_receiver=Global.creator_address, + // asset_close_to=Global.creator_address, + // ).submit() + itxn_submit + // smart_contracts/nft_marketplace/contract.py:215-218 + // itxn.Payment( + // receiver=Global.creator_address, + // close_remainder_to=Global.creator_address + // ).submit() + itxn_begin + // smart_contracts/nft_marketplace/contract.py:216 + // receiver=Global.creator_address, + global CreatorAddress + // smart_contracts/nft_marketplace/contract.py:217 + // close_remainder_to=Global.creator_address + dup + itxn_field CloseRemainderTo + itxn_field Receiver + // smart_contracts/nft_marketplace/contract.py:215 + // itxn.Payment( + int pay + itxn_field TypeEnum + int 0 + itxn_field Fee + // smart_contracts/nft_marketplace/contract.py:215-218 + // itxn.Payment( + // receiver=Global.creator_address, + // close_remainder_to=Global.creator_address + // ).submit() + itxn_submit + retsub + + +// smart_contracts.nft_marketplace.contract.NftMarketplace.__init__() -> void: +__init__: + // smart_contracts/nft_marketplace/contract.py:45 + // def __init__(self) -> None: + proto 0 0 + // smart_contracts/nft_marketplace/contract.py:47 + // self.asset_id = UInt64(0) + byte "asset_id" + int 0 + app_global_put + // smart_contracts/nft_marketplace/contract.py:48 + // self.unitary_price = UInt64(0) + byte "unitary_price" + int 0 + app_global_put + // smart_contracts/nft_marketplace/contract.py:49 + // self.bootstrapped = False + byte "bootstrapped" + int 0 + app_global_put + retsub diff --git a/projects/coding-assignment/smart_contracts/artifacts/nft_marketplace/NftMarketplace.arc32.json b/projects/coding-assignment/smart_contracts/artifacts/nft_marketplace/NftMarketplace.arc32.json new file mode 100644 index 0000000..91900fd --- /dev/null +++ b/projects/coding-assignment/smart_contracts/artifacts/nft_marketplace/NftMarketplace.arc32.json @@ -0,0 +1,110 @@ +{ + "hints": { + "bootstrap(asset,uint64,pay)void": { + "call_config": { + "no_op": "CALL" + } + }, + "buy(pay,uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "withdraw_and_delete()void": { + "call_config": { + "delete_application": "CALL" + } + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgpzbWFydF9jb250cmFjdHMubmZ0X21hcmtldHBsYWNlLmNvbnRyYWN0Lk5mdE1hcmtldHBsYWNlLmFwcHJvdmFsX3Byb2dyYW06CiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYm56IG1haW5fZW50cnlwb2ludEAyCiAgICBjYWxsc3ViIF9faW5pdF9fCgptYWluX2VudHJ5cG9pbnRAMjoKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjAKICAgIC8vIGNsYXNzIE5mdE1hcmtldHBsYWNlKGFyYzQuQVJDNENvbnRyYWN0KToKICAgIHR4biBOdW1BcHBBcmdzCiAgICBieiBtYWluX2JhcmVfcm91dGluZ0A5CiAgICBtZXRob2QgImJvb3RzdHJhcChhc3NldCx1aW50NjQscGF5KXZvaWQiCiAgICBtZXRob2QgImJ1eShwYXksdWludDY0KXZvaWQiCiAgICBtZXRob2QgIndpdGhkcmF3X2FuZF9kZWxldGUoKXZvaWQiCiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAwCiAgICBtYXRjaCBtYWluX2Jvb3RzdHJhcF9yb3V0ZUA0IG1haW5fYnV5X3JvdXRlQDUgbWFpbl93aXRoZHJhd19hbmRfZGVsZXRlX3JvdXRlQDYKICAgIGVyciAvLyByZWplY3QgdHJhbnNhY3Rpb24KCm1haW5fYm9vdHN0cmFwX3JvdXRlQDQ6CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjkwCiAgICAvLyBAYXJjNC5hYmltZXRob2QKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgTm9PcAogICAgdHhuIEFwcGxpY2F0aW9uSUQKICAgIGFzc2VydCAvLyBpcyBub3QgY3JlYXRpbmcKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjAKICAgIC8vIGNsYXNzIE5mdE1hcmtldHBsYWNlKGFyYzQuQVJDNENvbnRyYWN0KToKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFzc2V0cwogICAgdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgogICAgYnRvaQogICAgdHhuIEdyb3VwSW5kZXgKICAgIGludCAxCiAgICAtCiAgICBkdXAKICAgIGd0eG5zIFR5cGVFbnVtCiAgICBpbnQgcGF5CiAgICA9PQogICAgYXNzZXJ0IC8vIHRyYW5zYWN0aW9uIHR5cGUgaXMgcGF5CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjkwCiAgICAvLyBAYXJjNC5hYmltZXRob2QKICAgIGNhbGxzdWIgYm9vdHN0cmFwCiAgICBpbnQgMQogICAgcmV0dXJuCgptYWluX2J1eV9yb3V0ZUA1OgogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxNDIKICAgIC8vIEBhcmM0LmFiaW1ldGhvZAogICAgdHhuIE9uQ29tcGxldGlvbgogICAgIQogICAgYXNzZXJ0IC8vIE9uQ29tcGxldGlvbiBpcyBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGlzIG5vdCBjcmVhdGluZwogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMAogICAgLy8gY2xhc3MgTmZ0TWFya2V0cGxhY2UoYXJjNC5BUkM0Q29udHJhY3QpOgogICAgdHhuIEdyb3VwSW5kZXgKICAgIGludCAxCiAgICAtCiAgICBkdXAKICAgIGd0eG5zIFR5cGVFbnVtCiAgICBpbnQgcGF5CiAgICA9PQogICAgYXNzZXJ0IC8vIHRyYW5zYWN0aW9uIHR5cGUgaXMgcGF5CiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAxCiAgICBidG9pCiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjE0MgogICAgLy8gQGFyYzQuYWJpbWV0aG9kCiAgICBjYWxsc3ViIGJ1eQogICAgaW50IDEKICAgIHJldHVybgoKbWFpbl93aXRoZHJhd19hbmRfZGVsZXRlX3JvdXRlQDY6CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIwNgogICAgLy8gQGFyYzQuYWJpbWV0aG9kKGFsbG93X2FjdGlvbnM9WyJEZWxldGVBcHBsaWNhdGlvbiJdKQogICAgdHhuIE9uQ29tcGxldGlvbgogICAgaW50IERlbGV0ZUFwcGxpY2F0aW9uCiAgICA9PQogICAgYXNzZXJ0IC8vIE9uQ29tcGxldGlvbiBpcyBEZWxldGVBcHBsaWNhdGlvbgogICAgdHhuIEFwcGxpY2F0aW9uSUQKICAgIGFzc2VydCAvLyBpcyBub3QgY3JlYXRpbmcKICAgIGNhbGxzdWIgd2l0aGRyYXdfYW5kX2RlbGV0ZQogICAgaW50IDEKICAgIHJldHVybgoKbWFpbl9iYXJlX3JvdXRpbmdAOToKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjAKICAgIC8vIGNsYXNzIE5mdE1hcmtldHBsYWNlKGFyYzQuQVJDNENvbnRyYWN0KToKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyByZWplY3QgdHJhbnNhY3Rpb24KICAgIHR4biBBcHBsaWNhdGlvbklECiAgICAhCiAgICBhc3NlcnQgLy8gaXMgY3JlYXRpbmcKICAgIGludCAxCiAgICByZXR1cm4KCgovLyBzbWFydF9jb250cmFjdHMubmZ0X21hcmtldHBsYWNlLmNvbnRyYWN0Lk5mdE1hcmtldHBsYWNlLmJvb3RzdHJhcChhc3NldDogdWludDY0LCB1bml0YXJ5X3ByaWNlOiB1aW50NjQsIG1icl9wYXk6IHVpbnQ2NCkgLT4gdm9pZDoKYm9vdHN0cmFwOgogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weTo5MC05MwogICAgLy8gQGFyYzQuYWJpbWV0aG9kCiAgICAvLyBkZWYgYm9vdHN0cmFwKAogICAgLy8gICAgIHNlbGYsIGFzc2V0OiBBc3NldCwgdW5pdGFyeV9wcmljZTogVUludDY0LCBtYnJfcGF5OiBndHhuLlBheW1lbnRUcmFuc2FjdGlvbgogICAgLy8gKSAtPiBOb25lOgogICAgcHJvdG8gMyAwCiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5Ojk0CiAgICAvLyBhc3NlcnQgVHhuLnNlbmRlciA9PSBHbG9iYWwuY3JlYXRvcl9hZGRyZXNzCiAgICB0eG4gU2VuZGVyCiAgICBnbG9iYWwgQ3JlYXRvckFkZHJlc3MKICAgID09CiAgICBhc3NlcnQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6OTUKICAgIC8vIGFzc2VydCBzZWxmLmJvb3RzdHJhcHBlZCA9PSBGYWxzZQogICAgaW50IDAKICAgIGJ5dGUgImJvb3RzdHJhcHBlZCIKICAgIGFwcF9nbG9iYWxfZ2V0X2V4CiAgICBhc3NlcnQgLy8gY2hlY2sgYm9vdHN0cmFwcGVkIGV4aXN0cwogICAgIQogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5Ojk2CiAgICAvLyBhc3NlcnQgbWJyX3BheS5yZWNlaXZlciA9PSBHbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzCiAgICBmcmFtZV9kaWcgLTEKICAgIGd0eG5zIFJlY2VpdmVyCiAgICBnbG9iYWwgQ3VycmVudEFwcGxpY2F0aW9uQWRkcmVzcwogICAgPT0KICAgIGFzc2VydAogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weTo5NwogICAgLy8gYXNzZXJ0IG1icl9wYXkuYW1vdW50ID09IChHbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzLm1pbl9iYWxhbmNlK0dsb2JhbC5hc3NldF9vcHRfaW5fbWluX2JhbGFuY2UpCiAgICBmcmFtZV9kaWcgLTEKICAgIGd0eG5zIEFtb3VudAogICAgZ2xvYmFsIEN1cnJlbnRBcHBsaWNhdGlvbkFkZHJlc3MKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0TWluQmFsYW5jZQogICAgYXNzZXJ0IC8vIGFjY291bnQgZnVuZGVkCiAgICBnbG9iYWwgQXNzZXRPcHRJbk1pbkJhbGFuY2UKICAgICsKICAgID09CiAgICBhc3NlcnQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6OTkKICAgIC8vIHNlbGYuYXNzZXRfaWQgPSBhc3NldC5pZAogICAgYnl0ZSAiYXNzZXRfaWQiCiAgICBmcmFtZV9kaWcgLTMKICAgIGFwcF9nbG9iYWxfcHV0CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjEwMAogICAgLy8gc2VsZi51bml0YXJ5X3ByaWNlPXVuaXRhcnlfcHJpY2UKICAgIGJ5dGUgInVuaXRhcnlfcHJpY2UiCiAgICBmcmFtZV9kaWcgLTIKICAgIGFwcF9nbG9iYWxfcHV0CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjEwMQogICAgLy8gc2VsZi5ib290c3RyYXBwZWQ9VHJ1ZQogICAgYnl0ZSAiYm9vdHN0cmFwcGVkIgogICAgaW50IDEKICAgIGFwcF9nbG9iYWxfcHV0CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjEwMy0xMDcKICAgIC8vIGl0eG4uQXNzZXRUcmFuc2ZlcigKICAgIC8vICAgIHhmZXJfYXNzZXQ9c2VsZi5hc3NldF9pZCwKICAgIC8vICAgIGFzc2V0X3JlY2VpdmVyPUdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2FkZHJlc3MsCiAgICAvLyAgICBhc3NldF9hbW91bnQ9MCwKICAgIC8vICkuc3VibWl0KCkKICAgIGl0eG5fYmVnaW4KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTA0CiAgICAvLyB4ZmVyX2Fzc2V0PXNlbGYuYXNzZXRfaWQsCiAgICBpbnQgMAogICAgYnl0ZSAiYXNzZXRfaWQiCiAgICBhcHBfZ2xvYmFsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIGFzc2V0X2lkIGV4aXN0cwogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxMDUKICAgIC8vIGFzc2V0X3JlY2VpdmVyPUdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2FkZHJlc3MsCiAgICBnbG9iYWwgQ3VycmVudEFwcGxpY2F0aW9uQWRkcmVzcwogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxMDYKICAgIC8vIGFzc2V0X2Ftb3VudD0wLAogICAgaW50IDAKICAgIGl0eG5fZmllbGQgQXNzZXRBbW91bnQKICAgIGl0eG5fZmllbGQgQXNzZXRSZWNlaXZlcgogICAgaXR4bl9maWVsZCBYZmVyQXNzZXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTAzCiAgICAvLyBpdHhuLkFzc2V0VHJhbnNmZXIoCiAgICBpbnQgYXhmZXIKICAgIGl0eG5fZmllbGQgVHlwZUVudW0KICAgIGludCAwCiAgICBpdHhuX2ZpZWxkIEZlZQogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxMDMtMTA3CiAgICAvLyBpdHhuLkFzc2V0VHJhbnNmZXIoCiAgICAvLyAgICB4ZmVyX2Fzc2V0PXNlbGYuYXNzZXRfaWQsCiAgICAvLyAgICBhc3NldF9yZWNlaXZlcj1HbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzLAogICAgLy8gICAgYXNzZXRfYW1vdW50PTAsCiAgICAvLyApLnN1Ym1pdCgpCiAgICBpdHhuX3N1Ym1pdAogICAgcmV0c3ViCgoKLy8gc21hcnRfY29udHJhY3RzLm5mdF9tYXJrZXRwbGFjZS5jb250cmFjdC5OZnRNYXJrZXRwbGFjZS5idXkoYnV5ZXJfdHhuOiB1aW50NjQsIHF1YW50aXR5OiB1aW50NjQpIC0+IHZvaWQ6CmJ1eToKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTQyLTE0NwogICAgLy8gQGFyYzQuYWJpbWV0aG9kCiAgICAvLyBkZWYgYnV5KAogICAgLy8gICAgIHNlbGYsCiAgICAvLyAgICAgYnV5ZXJfdHhuOiBndHhuLlBheW1lbnRUcmFuc2FjdGlvbiwKICAgIC8vICAgICBxdWFudGl0eTogVUludDY0LAogICAgLy8gKSAtPiBOb25lOgogICAgcHJvdG8gMiAwCiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjE0OAogICAgLy8gYXNzZXJ0IHNlbGYuYm9vdHN0cmFwcGVkPT1UcnVlCiAgICBpbnQgMAogICAgYnl0ZSAiYm9vdHN0cmFwcGVkIgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayBib290c3RyYXBwZWQgZXhpc3RzCiAgICBpbnQgMQogICAgPT0KICAgIGFzc2VydAogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxNDkKICAgIC8vIGFzc2VydCBidXllcl90eG4uc2VuZGVyID09IFR4bi5zZW5kZXIKICAgIGZyYW1lX2RpZyAtMgogICAgZ3R4bnMgU2VuZGVyCiAgICB0eG4gU2VuZGVyCiAgICA9PQogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjE1MAogICAgLy8gYXNzZXJ0IGJ1eWVyX3R4bi5yZWNlaXZlciA9PSBHbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzCiAgICBmcmFtZV9kaWcgLTIKICAgIGd0eG5zIFJlY2VpdmVyCiAgICBnbG9iYWwgQ3VycmVudEFwcGxpY2F0aW9uQWRkcmVzcwogICAgPT0KICAgIGFzc2VydAogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxNTEKICAgIC8vIGFzc2VydCBidXllcl90eG4uYW1vdW50ID09IHNlbGYudW5pdGFyeV9wcmljZSpxdWFudGl0eQogICAgZnJhbWVfZGlnIC0yCiAgICBndHhucyBBbW91bnQKICAgIGludCAwCiAgICBieXRlICJ1bml0YXJ5X3ByaWNlIgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayB1bml0YXJ5X3ByaWNlIGV4aXN0cwogICAgZnJhbWVfZGlnIC0xCiAgICAqCiAgICA9PQogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjE1My0xNTcKICAgIC8vIGl0eG4uQXNzZXRUcmFuc2ZlcigKICAgIC8vICAgIHhmZXJfYXNzZXQ9c2VsZi5hc3NldF9pZCwKICAgIC8vICAgIGFzc2V0X3JlY2VpdmVyPVR4bi5zZW5kZXIsCiAgICAvLyAgICBhc3NldF9hbW91bnQ9cXVhbnRpdHksCiAgICAvLyApLnN1Ym1pdCgpCiAgICBpdHhuX2JlZ2luCiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjE1NAogICAgLy8geGZlcl9hc3NldD1zZWxmLmFzc2V0X2lkLAogICAgaW50IDAKICAgIGJ5dGUgImFzc2V0X2lkIgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayBhc3NldF9pZCBleGlzdHMKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTU1CiAgICAvLyBhc3NldF9yZWNlaXZlcj1UeG4uc2VuZGVyLAogICAgdHhuIFNlbmRlcgogICAgZnJhbWVfZGlnIC0xCiAgICBpdHhuX2ZpZWxkIEFzc2V0QW1vdW50CiAgICBpdHhuX2ZpZWxkIEFzc2V0UmVjZWl2ZXIKICAgIGl0eG5fZmllbGQgWGZlckFzc2V0CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjE1MwogICAgLy8gaXR4bi5Bc3NldFRyYW5zZmVyKAogICAgaW50IGF4ZmVyCiAgICBpdHhuX2ZpZWxkIFR5cGVFbnVtCiAgICBpbnQgMAogICAgaXR4bl9maWVsZCBGZWUKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTUzLTE1NwogICAgLy8gaXR4bi5Bc3NldFRyYW5zZmVyKAogICAgLy8gICAgeGZlcl9hc3NldD1zZWxmLmFzc2V0X2lkLAogICAgLy8gICAgYXNzZXRfcmVjZWl2ZXI9VHhuLnNlbmRlciwKICAgIC8vICAgIGFzc2V0X2Ftb3VudD1xdWFudGl0eSwKICAgIC8vICkuc3VibWl0KCkKICAgIGl0eG5fc3VibWl0CiAgICByZXRzdWIKCgovLyBzbWFydF9jb250cmFjdHMubmZ0X21hcmtldHBsYWNlLmNvbnRyYWN0Lk5mdE1hcmtldHBsYWNlLndpdGhkcmF3X2FuZF9kZWxldGUoKSAtPiB2b2lkOgp3aXRoZHJhd19hbmRfZGVsZXRlOgogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMDYtMjA3CiAgICAvLyBAYXJjNC5hYmltZXRob2QoYWxsb3dfYWN0aW9ucz1bIkRlbGV0ZUFwcGxpY2F0aW9uIl0pCiAgICAvLyBkZWYgd2l0aGRyYXdfYW5kX2RlbGV0ZShzZWxmKSAtPiBOb25lOgogICAgcHJvdG8gMCAwCiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIwOQogICAgLy8gYXNzZXJ0IFR4bi5zZW5kZXIgPT0gR2xvYmFsLmNyZWF0b3JfYWRkcmVzcwogICAgdHhuIFNlbmRlcgogICAgZ2xvYmFsIENyZWF0b3JBZGRyZXNzCiAgICA9PQogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIxMC0yMTQKICAgIC8vIGl0eG4uQXNzZXRUcmFuc2ZlcigKICAgIC8vICB4ZmVyX2Fzc2V0PXNlbGYuYXNzZXRfaWQsCiAgICAvLyAgYXNzZXRfcmVjZWl2ZXI9R2xvYmFsLmNyZWF0b3JfYWRkcmVzcywKICAgIC8vICBhc3NldF9jbG9zZV90bz1HbG9iYWwuY3JlYXRvcl9hZGRyZXNzLAogICAgLy8gICkuc3VibWl0KCkKICAgIGl0eG5fYmVnaW4KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjExCiAgICAvLyB4ZmVyX2Fzc2V0PXNlbGYuYXNzZXRfaWQsCiAgICBpbnQgMAogICAgYnl0ZSAiYXNzZXRfaWQiCiAgICBhcHBfZ2xvYmFsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIGFzc2V0X2lkIGV4aXN0cwogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMTIKICAgIC8vIGFzc2V0X3JlY2VpdmVyPUdsb2JhbC5jcmVhdG9yX2FkZHJlc3MsCiAgICBnbG9iYWwgQ3JlYXRvckFkZHJlc3MKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjEzCiAgICAvLyBhc3NldF9jbG9zZV90bz1HbG9iYWwuY3JlYXRvcl9hZGRyZXNzLAogICAgZHVwCiAgICBpdHhuX2ZpZWxkIEFzc2V0Q2xvc2VUbwogICAgaXR4bl9maWVsZCBBc3NldFJlY2VpdmVyCiAgICBpdHhuX2ZpZWxkIFhmZXJBc3NldAogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMTAKICAgIC8vIGl0eG4uQXNzZXRUcmFuc2ZlcigKICAgIGludCBheGZlcgogICAgaXR4bl9maWVsZCBUeXBlRW51bQogICAgaW50IDAKICAgIGl0eG5fZmllbGQgRmVlCiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIxMC0yMTQKICAgIC8vIGl0eG4uQXNzZXRUcmFuc2ZlcigKICAgIC8vICB4ZmVyX2Fzc2V0PXNlbGYuYXNzZXRfaWQsCiAgICAvLyAgYXNzZXRfcmVjZWl2ZXI9R2xvYmFsLmNyZWF0b3JfYWRkcmVzcywKICAgIC8vICBhc3NldF9jbG9zZV90bz1HbG9iYWwuY3JlYXRvcl9hZGRyZXNzLAogICAgLy8gICkuc3VibWl0KCkKICAgIGl0eG5fc3VibWl0CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIxNS0yMTgKICAgIC8vIGl0eG4uUGF5bWVudCgKICAgIC8vICByZWNlaXZlcj1HbG9iYWwuY3JlYXRvcl9hZGRyZXNzLAogICAgLy8gIGNsb3NlX3JlbWFpbmRlcl90bz1HbG9iYWwuY3JlYXRvcl9hZGRyZXNzCiAgICAvLyApLnN1Ym1pdCgpCiAgICBpdHhuX2JlZ2luCiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIxNgogICAgLy8gcmVjZWl2ZXI9R2xvYmFsLmNyZWF0b3JfYWRkcmVzcywKICAgIGdsb2JhbCBDcmVhdG9yQWRkcmVzcwogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMTcKICAgIC8vIGNsb3NlX3JlbWFpbmRlcl90bz1HbG9iYWwuY3JlYXRvcl9hZGRyZXNzCiAgICBkdXAKICAgIGl0eG5fZmllbGQgQ2xvc2VSZW1haW5kZXJUbwogICAgaXR4bl9maWVsZCBSZWNlaXZlcgogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMTUKICAgIC8vIGl0eG4uUGF5bWVudCgKICAgIGludCBwYXkKICAgIGl0eG5fZmllbGQgVHlwZUVudW0KICAgIGludCAwCiAgICBpdHhuX2ZpZWxkIEZlZQogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMTUtMjE4CiAgICAvLyBpdHhuLlBheW1lbnQoCiAgICAvLyAgcmVjZWl2ZXI9R2xvYmFsLmNyZWF0b3JfYWRkcmVzcywKICAgIC8vICBjbG9zZV9yZW1haW5kZXJfdG89R2xvYmFsLmNyZWF0b3JfYWRkcmVzcwogICAgLy8gKS5zdWJtaXQoKQogICAgaXR4bl9zdWJtaXQKICAgIHJldHN1YgoKCi8vIHNtYXJ0X2NvbnRyYWN0cy5uZnRfbWFya2V0cGxhY2UuY29udHJhY3QuTmZ0TWFya2V0cGxhY2UuX19pbml0X18oKSAtPiB2b2lkOgpfX2luaXRfXzoKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6NDUKICAgIC8vIGRlZiBfX2luaXRfXyhzZWxmKSAtPiBOb25lOgogICAgcHJvdG8gMCAwCiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjQ3CiAgICAvLyBzZWxmLmFzc2V0X2lkID0gVUludDY0KDApCiAgICBieXRlICJhc3NldF9pZCIKICAgIGludCAwCiAgICBhcHBfZ2xvYmFsX3B1dAogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weTo0OAogICAgLy8gc2VsZi51bml0YXJ5X3ByaWNlID0gVUludDY0KDApCiAgICBieXRlICJ1bml0YXJ5X3ByaWNlIgogICAgaW50IDAKICAgIGFwcF9nbG9iYWxfcHV0CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjQ5CiAgICAvLyBzZWxmLmJvb3RzdHJhcHBlZCA9IEZhbHNlCiAgICBieXRlICJib290c3RyYXBwZWQiCiAgICBpbnQgMAogICAgYXBwX2dsb2JhbF9wdXQKICAgIHJldHN1Ygo=", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDEwCgpzbWFydF9jb250cmFjdHMubmZ0X21hcmtldHBsYWNlLmNvbnRyYWN0Lk5mdE1hcmtldHBsYWNlLmNsZWFyX3N0YXRlX3Byb2dyYW06CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIwCiAgICAvLyBjbGFzcyBOZnRNYXJrZXRwbGFjZShhcmM0LkFSQzRDb250cmFjdCk6CiAgICBpbnQgMQogICAgcmV0dXJuCg==" + }, + "state": { + "global": { + "num_byte_slices": 0, + "num_uints": 3 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "schema": { + "global": { + "declared": { + "asset_id": { + "type": "uint64", + "key": "asset_id" + }, + "bootstrapped": { + "type": "uint64", + "key": "bootstrapped" + }, + "unitary_price": { + "type": "uint64", + "key": "unitary_price" + } + }, + "reserved": {} + }, + "local": { + "declared": {}, + "reserved": {} + } + }, + "contract": { + "name": "NftMarketplace", + "desc": "\n \ubb38\uc81c 1\n NftMarketplace \uc571\uc758 \uc0c1\ud0dc(state)\ub97c \uc815\uc758\ud558\uace0 \ucd08\uae30\uac12\uc744 \uc124\uc815\ud558\uc138\uc694.\n\n NftMarketplace \uc571\uc740 \uc138\uac1c\uc758 \uc0c1\ud0dc\ub97c \uac00\uc9c0\uace0 \uc788\uc2b5\ub2c8\ub2e4.\n 1. asset_id: \ud310\ub9e4\ud560 \uc5d0\uc14b(ASA)\uc758 \uc544\uc774\ub514; UInt64\ud0c0\uc785\uc744 \uac00\uc9c4 \uae00\ub85c\ubc8c \uc0c1\ud0dc(Global State) \ucd08\uae30\uac12\uc740 0\uc73c\ub85c \uc124\uc815\ud574\uc8fc\uc138\uc694.\n 2. unitary_price: \ud310\ub9e4\ud560 \uc5d0\uc14b(ASA)\uc758 \uac00\uaca9. UInt64\ud0c0\uc785\uc744 \uac00\uc9c4 \uae00\ub85c\ubc8c \uc0c1\ud0dc(Global State) \ucd08\uae30\uac12\uc740 0\uc73c\ub85c \uc124\uc815\ud574\uc8fc\uc138\uc694.\n 3. bootstrapped: \uc571\uc5d0\uc11c \uc5d0\uc14b\uc744 \ud310\ub9e4\ud560 \uc900\ube44\uac00 \ub418\uc5c8\ub294\uc9c0 \uccb4\ud06c\ud558\ub294 bool \ud0c0\uc785\uc758 \uae00\ub85c\ubc8c \uc0c1\ud0dc(Global State). \ucd08\uae30\uac12\uc740 False\ub85c \uc124\uc815\ud574\uc8fc\uc138\uc694.\n bootstrap \uba54\uc11c\ub4dc\uac00 \uc2e4\ud589\ub418\uba74 True\ub85c \ubcc0\uacbd\ub429\ub2c8\ub2e4.\n\n \uc7ac\ubc0c\ub294 \ud329\ud2b8!\n AVM\uc740 Bytes \ud0c0\uc785\uacfc UInt64 \ud0c0\uc785\ub9cc \uc9c0\uc6d0\ud569\ub2c8\ub2e4. \uadf8\ub798\uc11c \ub2e4\ub978 \ud0c0\uc785\uc744 \uc0ac\uc6a9\ud558\uace0 \uc2f6\uc73c\uba74 \ubcf4\ud1b5 arc4\ud0c0\uc785\uc744 \uc0ac\uc6a9\ud569\ub2c8\ub2e4. \ud558\uc9c0\ub9cc\n Algorand Python\uc5d0\uc11c\ub294 bool, string \ud0c0\uc785\uc740 \ud30c\uc774\uc36c \ucf54\ub4dc\uc640 \ub3d9\uc77c\ud558\uac8c \uc0ac\uc6a9\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uc608\ub97c \ub4e4\uc5b4 bool \ud0c0\uc785\uc740 True,\n False\ub85c \ud45c\ud5cc\ud558\uba74 \ub418\uace0, string \ud0c0\uc785\uc740 \"Hello, World!\"\uc640 \uac19\uc774 \ud45c\ud604\ud558\uba74 \ub429\ub2c8\ub2e4. Algorand Python\uc5d0\uc11c \ub370\uc774\ud130 \ud0c0\uc785\uc744\n \uc0ac\uc6a9\ud558\ub294 \ubc29\ubc95\uc740 \uc544\ub798 \ub9c1\ud06c\ub97c \ucc38\uace0\ud574\uc8fc\uc138\uc694.\n - arc4 \ud0c0\uc785: https://algorandfoundation.github.io/puya/lg-types.html#types\n\n \ud301!\n - Global State\ub97c \uc815\uc758\ud560\ub54c simplifed \ubc84\uc804\uc73c\ub85c \uc815\uc758\ud558\uba74 \uac04\uacb0\ud55c \ucf54\ub4dc\ub85c \uc0c1\ud0dc\ub97c \uc815\uc758\ud558\uace0 \ucd08\uae30\uac12\uc744 \uc124\uc815\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uc790\uc138\ud55c \uc0ac\ud56d\uc740 \uc544\ub798 \ud78c\ud2b8 1\uc744 \ucc38\uace0\ud574\uc8fc\uc138\uc694.\n\n \ud78c\ud2b8 1 - \uae00\ub7ec\ubc8c \uc0c1\ud0dc: https://algorandfoundation.github.io/puya/lg-storage.html#global-storage\n \ud78c\ud2b8 2 - \ucf54\ub4dc \uc608\uc2dc: https://github.com/algorandfoundation/puya/blob/11843f6bc4bb6e4c56ac53e3980f74df69d07397/examples/global_state/contract.py#L5\n ", + "methods": [ + { + "name": "bootstrap", + "args": [ + { + "type": "asset", + "name": "asset" + }, + { + "type": "uint64", + "name": "unitary_price" + }, + { + "type": "pay", + "name": "mbr_pay" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "buy", + "args": [ + { + "type": "pay", + "name": "buyer_txn" + }, + { + "type": "uint64", + "name": "quantity" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "withdraw_and_delete", + "args": [], + "returns": { + "type": "void" + }, + "desc": "\uc5ec\uae30\uc5d0 \ucf54\ub4dc \uc791\uc131" + } + ], + "networks": {} + }, + "bare_call_config": { + "no_op": "CREATE" + } +} \ No newline at end of file diff --git a/projects/coding-assignment/smart_contracts/artifacts/nft_marketplace/NftMarketplace.clear.teal b/projects/coding-assignment/smart_contracts/artifacts/nft_marketplace/NftMarketplace.clear.teal new file mode 100644 index 0000000..e79b7a3 --- /dev/null +++ b/projects/coding-assignment/smart_contracts/artifacts/nft_marketplace/NftMarketplace.clear.teal @@ -0,0 +1,7 @@ +#pragma version 10 + +smart_contracts.nft_marketplace.contract.NftMarketplace.clear_state_program: + // smart_contracts/nft_marketplace/contract.py:20 + // class NftMarketplace(arc4.ARC4Contract): + int 1 + return diff --git a/projects/coding-assignment/smart_contracts/artifacts/nft_marketplace/client.ts b/projects/coding-assignment/smart_contracts/artifacts/nft_marketplace/client.ts new file mode 100644 index 0000000..f89c36f --- /dev/null +++ b/projects/coding-assignment/smart_contracts/artifacts/nft_marketplace/client.ts @@ -0,0 +1,712 @@ +/* eslint-disable */ +/** + * This file was automatically generated by @algorandfoundation/algokit-client-generator. + * DO NOT MODIFY IT BY HAND. + * requires: @algorandfoundation/algokit-utils: ^2 + */ +import * as algokit from '@algorandfoundation/algokit-utils' +import type { + ABIAppCallArg, + AppCallTransactionResult, + AppCallTransactionResultOfType, + AppCompilationResult, + AppReference, + AppState, + AppStorageSchema, + CoreAppCallArgs, + RawAppCallArgs, + TealTemplateParams, +} from '@algorandfoundation/algokit-utils/types/app' +import type { + AppClientCallCoreParams, + AppClientCompilationParams, + AppClientDeployCoreParams, + AppDetails, + ApplicationClient, +} from '@algorandfoundation/algokit-utils/types/app-client' +import type { AppSpec } from '@algorandfoundation/algokit-utils/types/app-spec' +import type { SendTransactionResult, TransactionToSign, SendTransactionFrom, SendTransactionParams } from '@algorandfoundation/algokit-utils/types/transaction' +import type { ABIResult, TransactionWithSigner } from 'algosdk' +import { Algodv2, OnApplicationComplete, Transaction, AtomicTransactionComposer, modelsv2 } from 'algosdk' +export const APP_SPEC: AppSpec = { + "hints": { + "bootstrap(asset,uint64,pay)void": { + "call_config": { + "no_op": "CALL" + } + }, + "buy(pay,uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "withdraw_and_delete()void": { + "call_config": { + "delete_application": "CALL" + } + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgpzbWFydF9jb250cmFjdHMubmZ0X21hcmtldHBsYWNlLmNvbnRyYWN0Lk5mdE1hcmtldHBsYWNlLmFwcHJvdmFsX3Byb2dyYW06CiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYm56IG1haW5fZW50cnlwb2ludEAyCiAgICBjYWxsc3ViIF9faW5pdF9fCgptYWluX2VudHJ5cG9pbnRAMjoKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjAKICAgIC8vIGNsYXNzIE5mdE1hcmtldHBsYWNlKGFyYzQuQVJDNENvbnRyYWN0KToKICAgIHR4biBOdW1BcHBBcmdzCiAgICBieiBtYWluX2JhcmVfcm91dGluZ0A5CiAgICBtZXRob2QgImJvb3RzdHJhcChhc3NldCx1aW50NjQscGF5KXZvaWQiCiAgICBtZXRob2QgImJ1eShwYXksdWludDY0KXZvaWQiCiAgICBtZXRob2QgIndpdGhkcmF3X2FuZF9kZWxldGUoKXZvaWQiCiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAwCiAgICBtYXRjaCBtYWluX2Jvb3RzdHJhcF9yb3V0ZUA0IG1haW5fYnV5X3JvdXRlQDUgbWFpbl93aXRoZHJhd19hbmRfZGVsZXRlX3JvdXRlQDYKICAgIGVyciAvLyByZWplY3QgdHJhbnNhY3Rpb24KCm1haW5fYm9vdHN0cmFwX3JvdXRlQDQ6CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjkwCiAgICAvLyBAYXJjNC5hYmltZXRob2QKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgTm9PcAogICAgdHhuIEFwcGxpY2F0aW9uSUQKICAgIGFzc2VydCAvLyBpcyBub3QgY3JlYXRpbmcKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjAKICAgIC8vIGNsYXNzIE5mdE1hcmtldHBsYWNlKGFyYzQuQVJDNENvbnRyYWN0KToKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFzc2V0cwogICAgdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgogICAgYnRvaQogICAgdHhuIEdyb3VwSW5kZXgKICAgIGludCAxCiAgICAtCiAgICBkdXAKICAgIGd0eG5zIFR5cGVFbnVtCiAgICBpbnQgcGF5CiAgICA9PQogICAgYXNzZXJ0IC8vIHRyYW5zYWN0aW9uIHR5cGUgaXMgcGF5CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjkwCiAgICAvLyBAYXJjNC5hYmltZXRob2QKICAgIGNhbGxzdWIgYm9vdHN0cmFwCiAgICBpbnQgMQogICAgcmV0dXJuCgptYWluX2J1eV9yb3V0ZUA1OgogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxNDIKICAgIC8vIEBhcmM0LmFiaW1ldGhvZAogICAgdHhuIE9uQ29tcGxldGlvbgogICAgIQogICAgYXNzZXJ0IC8vIE9uQ29tcGxldGlvbiBpcyBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGlzIG5vdCBjcmVhdGluZwogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMAogICAgLy8gY2xhc3MgTmZ0TWFya2V0cGxhY2UoYXJjNC5BUkM0Q29udHJhY3QpOgogICAgdHhuIEdyb3VwSW5kZXgKICAgIGludCAxCiAgICAtCiAgICBkdXAKICAgIGd0eG5zIFR5cGVFbnVtCiAgICBpbnQgcGF5CiAgICA9PQogICAgYXNzZXJ0IC8vIHRyYW5zYWN0aW9uIHR5cGUgaXMgcGF5CiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAxCiAgICBidG9pCiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjE0MgogICAgLy8gQGFyYzQuYWJpbWV0aG9kCiAgICBjYWxsc3ViIGJ1eQogICAgaW50IDEKICAgIHJldHVybgoKbWFpbl93aXRoZHJhd19hbmRfZGVsZXRlX3JvdXRlQDY6CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIwNgogICAgLy8gQGFyYzQuYWJpbWV0aG9kKGFsbG93X2FjdGlvbnM9WyJEZWxldGVBcHBsaWNhdGlvbiJdKQogICAgdHhuIE9uQ29tcGxldGlvbgogICAgaW50IERlbGV0ZUFwcGxpY2F0aW9uCiAgICA9PQogICAgYXNzZXJ0IC8vIE9uQ29tcGxldGlvbiBpcyBEZWxldGVBcHBsaWNhdGlvbgogICAgdHhuIEFwcGxpY2F0aW9uSUQKICAgIGFzc2VydCAvLyBpcyBub3QgY3JlYXRpbmcKICAgIGNhbGxzdWIgd2l0aGRyYXdfYW5kX2RlbGV0ZQogICAgaW50IDEKICAgIHJldHVybgoKbWFpbl9iYXJlX3JvdXRpbmdAOToKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjAKICAgIC8vIGNsYXNzIE5mdE1hcmtldHBsYWNlKGFyYzQuQVJDNENvbnRyYWN0KToKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyByZWplY3QgdHJhbnNhY3Rpb24KICAgIHR4biBBcHBsaWNhdGlvbklECiAgICAhCiAgICBhc3NlcnQgLy8gaXMgY3JlYXRpbmcKICAgIGludCAxCiAgICByZXR1cm4KCgovLyBzbWFydF9jb250cmFjdHMubmZ0X21hcmtldHBsYWNlLmNvbnRyYWN0Lk5mdE1hcmtldHBsYWNlLmJvb3RzdHJhcChhc3NldDogdWludDY0LCB1bml0YXJ5X3ByaWNlOiB1aW50NjQsIG1icl9wYXk6IHVpbnQ2NCkgLT4gdm9pZDoKYm9vdHN0cmFwOgogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weTo5MC05MwogICAgLy8gQGFyYzQuYWJpbWV0aG9kCiAgICAvLyBkZWYgYm9vdHN0cmFwKAogICAgLy8gICAgIHNlbGYsIGFzc2V0OiBBc3NldCwgdW5pdGFyeV9wcmljZTogVUludDY0LCBtYnJfcGF5OiBndHhuLlBheW1lbnRUcmFuc2FjdGlvbgogICAgLy8gKSAtPiBOb25lOgogICAgcHJvdG8gMyAwCiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5Ojk0CiAgICAvLyBhc3NlcnQgVHhuLnNlbmRlciA9PSBHbG9iYWwuY3JlYXRvcl9hZGRyZXNzCiAgICB0eG4gU2VuZGVyCiAgICBnbG9iYWwgQ3JlYXRvckFkZHJlc3MKICAgID09CiAgICBhc3NlcnQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6OTUKICAgIC8vIGFzc2VydCBzZWxmLmJvb3RzdHJhcHBlZCA9PSBGYWxzZQogICAgaW50IDAKICAgIGJ5dGUgImJvb3RzdHJhcHBlZCIKICAgIGFwcF9nbG9iYWxfZ2V0X2V4CiAgICBhc3NlcnQgLy8gY2hlY2sgYm9vdHN0cmFwcGVkIGV4aXN0cwogICAgIQogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5Ojk2CiAgICAvLyBhc3NlcnQgbWJyX3BheS5yZWNlaXZlciA9PSBHbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzCiAgICBmcmFtZV9kaWcgLTEKICAgIGd0eG5zIFJlY2VpdmVyCiAgICBnbG9iYWwgQ3VycmVudEFwcGxpY2F0aW9uQWRkcmVzcwogICAgPT0KICAgIGFzc2VydAogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weTo5NwogICAgLy8gYXNzZXJ0IG1icl9wYXkuYW1vdW50ID09IChHbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzLm1pbl9iYWxhbmNlK0dsb2JhbC5hc3NldF9vcHRfaW5fbWluX2JhbGFuY2UpCiAgICBmcmFtZV9kaWcgLTEKICAgIGd0eG5zIEFtb3VudAogICAgZ2xvYmFsIEN1cnJlbnRBcHBsaWNhdGlvbkFkZHJlc3MKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0TWluQmFsYW5jZQogICAgYXNzZXJ0IC8vIGFjY291bnQgZnVuZGVkCiAgICBnbG9iYWwgQXNzZXRPcHRJbk1pbkJhbGFuY2UKICAgICsKICAgID09CiAgICBhc3NlcnQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6OTkKICAgIC8vIHNlbGYuYXNzZXRfaWQgPSBhc3NldC5pZAogICAgYnl0ZSAiYXNzZXRfaWQiCiAgICBmcmFtZV9kaWcgLTMKICAgIGFwcF9nbG9iYWxfcHV0CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjEwMAogICAgLy8gc2VsZi51bml0YXJ5X3ByaWNlPXVuaXRhcnlfcHJpY2UKICAgIGJ5dGUgInVuaXRhcnlfcHJpY2UiCiAgICBmcmFtZV9kaWcgLTIKICAgIGFwcF9nbG9iYWxfcHV0CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjEwMQogICAgLy8gc2VsZi5ib290c3RyYXBwZWQ9VHJ1ZQogICAgYnl0ZSAiYm9vdHN0cmFwcGVkIgogICAgaW50IDEKICAgIGFwcF9nbG9iYWxfcHV0CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjEwMy0xMDcKICAgIC8vIGl0eG4uQXNzZXRUcmFuc2ZlcigKICAgIC8vICAgIHhmZXJfYXNzZXQ9c2VsZi5hc3NldF9pZCwKICAgIC8vICAgIGFzc2V0X3JlY2VpdmVyPUdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2FkZHJlc3MsCiAgICAvLyAgICBhc3NldF9hbW91bnQ9MCwKICAgIC8vICkuc3VibWl0KCkKICAgIGl0eG5fYmVnaW4KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTA0CiAgICAvLyB4ZmVyX2Fzc2V0PXNlbGYuYXNzZXRfaWQsCiAgICBpbnQgMAogICAgYnl0ZSAiYXNzZXRfaWQiCiAgICBhcHBfZ2xvYmFsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIGFzc2V0X2lkIGV4aXN0cwogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxMDUKICAgIC8vIGFzc2V0X3JlY2VpdmVyPUdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2FkZHJlc3MsCiAgICBnbG9iYWwgQ3VycmVudEFwcGxpY2F0aW9uQWRkcmVzcwogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxMDYKICAgIC8vIGFzc2V0X2Ftb3VudD0wLAogICAgaW50IDAKICAgIGl0eG5fZmllbGQgQXNzZXRBbW91bnQKICAgIGl0eG5fZmllbGQgQXNzZXRSZWNlaXZlcgogICAgaXR4bl9maWVsZCBYZmVyQXNzZXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTAzCiAgICAvLyBpdHhuLkFzc2V0VHJhbnNmZXIoCiAgICBpbnQgYXhmZXIKICAgIGl0eG5fZmllbGQgVHlwZUVudW0KICAgIGludCAwCiAgICBpdHhuX2ZpZWxkIEZlZQogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxMDMtMTA3CiAgICAvLyBpdHhuLkFzc2V0VHJhbnNmZXIoCiAgICAvLyAgICB4ZmVyX2Fzc2V0PXNlbGYuYXNzZXRfaWQsCiAgICAvLyAgICBhc3NldF9yZWNlaXZlcj1HbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzLAogICAgLy8gICAgYXNzZXRfYW1vdW50PTAsCiAgICAvLyApLnN1Ym1pdCgpCiAgICBpdHhuX3N1Ym1pdAogICAgcmV0c3ViCgoKLy8gc21hcnRfY29udHJhY3RzLm5mdF9tYXJrZXRwbGFjZS5jb250cmFjdC5OZnRNYXJrZXRwbGFjZS5idXkoYnV5ZXJfdHhuOiB1aW50NjQsIHF1YW50aXR5OiB1aW50NjQpIC0+IHZvaWQ6CmJ1eToKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTQyLTE0NwogICAgLy8gQGFyYzQuYWJpbWV0aG9kCiAgICAvLyBkZWYgYnV5KAogICAgLy8gICAgIHNlbGYsCiAgICAvLyAgICAgYnV5ZXJfdHhuOiBndHhuLlBheW1lbnRUcmFuc2FjdGlvbiwKICAgIC8vICAgICBxdWFudGl0eTogVUludDY0LAogICAgLy8gKSAtPiBOb25lOgogICAgcHJvdG8gMiAwCiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjE0OAogICAgLy8gYXNzZXJ0IHNlbGYuYm9vdHN0cmFwcGVkPT1UcnVlCiAgICBpbnQgMAogICAgYnl0ZSAiYm9vdHN0cmFwcGVkIgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayBib290c3RyYXBwZWQgZXhpc3RzCiAgICBpbnQgMQogICAgPT0KICAgIGFzc2VydAogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxNDkKICAgIC8vIGFzc2VydCBidXllcl90eG4uc2VuZGVyID09IFR4bi5zZW5kZXIKICAgIGZyYW1lX2RpZyAtMgogICAgZ3R4bnMgU2VuZGVyCiAgICB0eG4gU2VuZGVyCiAgICA9PQogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjE1MAogICAgLy8gYXNzZXJ0IGJ1eWVyX3R4bi5yZWNlaXZlciA9PSBHbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzCiAgICBmcmFtZV9kaWcgLTIKICAgIGd0eG5zIFJlY2VpdmVyCiAgICBnbG9iYWwgQ3VycmVudEFwcGxpY2F0aW9uQWRkcmVzcwogICAgPT0KICAgIGFzc2VydAogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxNTEKICAgIC8vIGFzc2VydCBidXllcl90eG4uYW1vdW50ID09IHNlbGYudW5pdGFyeV9wcmljZSpxdWFudGl0eQogICAgZnJhbWVfZGlnIC0yCiAgICBndHhucyBBbW91bnQKICAgIGludCAwCiAgICBieXRlICJ1bml0YXJ5X3ByaWNlIgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayB1bml0YXJ5X3ByaWNlIGV4aXN0cwogICAgZnJhbWVfZGlnIC0xCiAgICAqCiAgICA9PQogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjE1My0xNTcKICAgIC8vIGl0eG4uQXNzZXRUcmFuc2ZlcigKICAgIC8vICAgIHhmZXJfYXNzZXQ9c2VsZi5hc3NldF9pZCwKICAgIC8vICAgIGFzc2V0X3JlY2VpdmVyPVR4bi5zZW5kZXIsCiAgICAvLyAgICBhc3NldF9hbW91bnQ9cXVhbnRpdHksCiAgICAvLyApLnN1Ym1pdCgpCiAgICBpdHhuX2JlZ2luCiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjE1NAogICAgLy8geGZlcl9hc3NldD1zZWxmLmFzc2V0X2lkLAogICAgaW50IDAKICAgIGJ5dGUgImFzc2V0X2lkIgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayBhc3NldF9pZCBleGlzdHMKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTU1CiAgICAvLyBhc3NldF9yZWNlaXZlcj1UeG4uc2VuZGVyLAogICAgdHhuIFNlbmRlcgogICAgZnJhbWVfZGlnIC0xCiAgICBpdHhuX2ZpZWxkIEFzc2V0QW1vdW50CiAgICBpdHhuX2ZpZWxkIEFzc2V0UmVjZWl2ZXIKICAgIGl0eG5fZmllbGQgWGZlckFzc2V0CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjE1MwogICAgLy8gaXR4bi5Bc3NldFRyYW5zZmVyKAogICAgaW50IGF4ZmVyCiAgICBpdHhuX2ZpZWxkIFR5cGVFbnVtCiAgICBpbnQgMAogICAgaXR4bl9maWVsZCBGZWUKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTUzLTE1NwogICAgLy8gaXR4bi5Bc3NldFRyYW5zZmVyKAogICAgLy8gICAgeGZlcl9hc3NldD1zZWxmLmFzc2V0X2lkLAogICAgLy8gICAgYXNzZXRfcmVjZWl2ZXI9VHhuLnNlbmRlciwKICAgIC8vICAgIGFzc2V0X2Ftb3VudD1xdWFudGl0eSwKICAgIC8vICkuc3VibWl0KCkKICAgIGl0eG5fc3VibWl0CiAgICByZXRzdWIKCgovLyBzbWFydF9jb250cmFjdHMubmZ0X21hcmtldHBsYWNlLmNvbnRyYWN0Lk5mdE1hcmtldHBsYWNlLndpdGhkcmF3X2FuZF9kZWxldGUoKSAtPiB2b2lkOgp3aXRoZHJhd19hbmRfZGVsZXRlOgogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMDYtMjA3CiAgICAvLyBAYXJjNC5hYmltZXRob2QoYWxsb3dfYWN0aW9ucz1bIkRlbGV0ZUFwcGxpY2F0aW9uIl0pCiAgICAvLyBkZWYgd2l0aGRyYXdfYW5kX2RlbGV0ZShzZWxmKSAtPiBOb25lOgogICAgcHJvdG8gMCAwCiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIwOQogICAgLy8gYXNzZXJ0IFR4bi5zZW5kZXIgPT0gR2xvYmFsLmNyZWF0b3JfYWRkcmVzcwogICAgdHhuIFNlbmRlcgogICAgZ2xvYmFsIENyZWF0b3JBZGRyZXNzCiAgICA9PQogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIxMC0yMTQKICAgIC8vIGl0eG4uQXNzZXRUcmFuc2ZlcigKICAgIC8vICB4ZmVyX2Fzc2V0PXNlbGYuYXNzZXRfaWQsCiAgICAvLyAgYXNzZXRfcmVjZWl2ZXI9R2xvYmFsLmNyZWF0b3JfYWRkcmVzcywKICAgIC8vICBhc3NldF9jbG9zZV90bz1HbG9iYWwuY3JlYXRvcl9hZGRyZXNzLAogICAgLy8gICkuc3VibWl0KCkKICAgIGl0eG5fYmVnaW4KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjExCiAgICAvLyB4ZmVyX2Fzc2V0PXNlbGYuYXNzZXRfaWQsCiAgICBpbnQgMAogICAgYnl0ZSAiYXNzZXRfaWQiCiAgICBhcHBfZ2xvYmFsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIGFzc2V0X2lkIGV4aXN0cwogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMTIKICAgIC8vIGFzc2V0X3JlY2VpdmVyPUdsb2JhbC5jcmVhdG9yX2FkZHJlc3MsCiAgICBnbG9iYWwgQ3JlYXRvckFkZHJlc3MKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjEzCiAgICAvLyBhc3NldF9jbG9zZV90bz1HbG9iYWwuY3JlYXRvcl9hZGRyZXNzLAogICAgZHVwCiAgICBpdHhuX2ZpZWxkIEFzc2V0Q2xvc2VUbwogICAgaXR4bl9maWVsZCBBc3NldFJlY2VpdmVyCiAgICBpdHhuX2ZpZWxkIFhmZXJBc3NldAogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMTAKICAgIC8vIGl0eG4uQXNzZXRUcmFuc2ZlcigKICAgIGludCBheGZlcgogICAgaXR4bl9maWVsZCBUeXBlRW51bQogICAgaW50IDAKICAgIGl0eG5fZmllbGQgRmVlCiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIxMC0yMTQKICAgIC8vIGl0eG4uQXNzZXRUcmFuc2ZlcigKICAgIC8vICB4ZmVyX2Fzc2V0PXNlbGYuYXNzZXRfaWQsCiAgICAvLyAgYXNzZXRfcmVjZWl2ZXI9R2xvYmFsLmNyZWF0b3JfYWRkcmVzcywKICAgIC8vICBhc3NldF9jbG9zZV90bz1HbG9iYWwuY3JlYXRvcl9hZGRyZXNzLAogICAgLy8gICkuc3VibWl0KCkKICAgIGl0eG5fc3VibWl0CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIxNS0yMTgKICAgIC8vIGl0eG4uUGF5bWVudCgKICAgIC8vICByZWNlaXZlcj1HbG9iYWwuY3JlYXRvcl9hZGRyZXNzLAogICAgLy8gIGNsb3NlX3JlbWFpbmRlcl90bz1HbG9iYWwuY3JlYXRvcl9hZGRyZXNzCiAgICAvLyApLnN1Ym1pdCgpCiAgICBpdHhuX2JlZ2luCiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIxNgogICAgLy8gcmVjZWl2ZXI9R2xvYmFsLmNyZWF0b3JfYWRkcmVzcywKICAgIGdsb2JhbCBDcmVhdG9yQWRkcmVzcwogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMTcKICAgIC8vIGNsb3NlX3JlbWFpbmRlcl90bz1HbG9iYWwuY3JlYXRvcl9hZGRyZXNzCiAgICBkdXAKICAgIGl0eG5fZmllbGQgQ2xvc2VSZW1haW5kZXJUbwogICAgaXR4bl9maWVsZCBSZWNlaXZlcgogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMTUKICAgIC8vIGl0eG4uUGF5bWVudCgKICAgIGludCBwYXkKICAgIGl0eG5fZmllbGQgVHlwZUVudW0KICAgIGludCAwCiAgICBpdHhuX2ZpZWxkIEZlZQogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMTUtMjE4CiAgICAvLyBpdHhuLlBheW1lbnQoCiAgICAvLyAgcmVjZWl2ZXI9R2xvYmFsLmNyZWF0b3JfYWRkcmVzcywKICAgIC8vICBjbG9zZV9yZW1haW5kZXJfdG89R2xvYmFsLmNyZWF0b3JfYWRkcmVzcwogICAgLy8gKS5zdWJtaXQoKQogICAgaXR4bl9zdWJtaXQKICAgIHJldHN1YgoKCi8vIHNtYXJ0X2NvbnRyYWN0cy5uZnRfbWFya2V0cGxhY2UuY29udHJhY3QuTmZ0TWFya2V0cGxhY2UuX19pbml0X18oKSAtPiB2b2lkOgpfX2luaXRfXzoKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9uZnRfbWFya2V0cGxhY2UvY29udHJhY3QucHk6NDUKICAgIC8vIGRlZiBfX2luaXRfXyhzZWxmKSAtPiBOb25lOgogICAgcHJvdG8gMCAwCiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjQ3CiAgICAvLyBzZWxmLmFzc2V0X2lkID0gVUludDY0KDApCiAgICBieXRlICJhc3NldF9pZCIKICAgIGludCAwCiAgICBhcHBfZ2xvYmFsX3B1dAogICAgLy8gc21hcnRfY29udHJhY3RzL25mdF9tYXJrZXRwbGFjZS9jb250cmFjdC5weTo0OAogICAgLy8gc2VsZi51bml0YXJ5X3ByaWNlID0gVUludDY0KDApCiAgICBieXRlICJ1bml0YXJ5X3ByaWNlIgogICAgaW50IDAKICAgIGFwcF9nbG9iYWxfcHV0CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjQ5CiAgICAvLyBzZWxmLmJvb3RzdHJhcHBlZCA9IEZhbHNlCiAgICBieXRlICJib290c3RyYXBwZWQiCiAgICBpbnQgMAogICAgYXBwX2dsb2JhbF9wdXQKICAgIHJldHN1Ygo=", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDEwCgpzbWFydF9jb250cmFjdHMubmZ0X21hcmtldHBsYWNlLmNvbnRyYWN0Lk5mdE1hcmtldHBsYWNlLmNsZWFyX3N0YXRlX3Byb2dyYW06CiAgICAvLyBzbWFydF9jb250cmFjdHMvbmZ0X21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIwCiAgICAvLyBjbGFzcyBOZnRNYXJrZXRwbGFjZShhcmM0LkFSQzRDb250cmFjdCk6CiAgICBpbnQgMQogICAgcmV0dXJuCg==" + }, + "state": { + "global": { + "num_byte_slices": 0, + "num_uints": 3 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "schema": { + "global": { + "declared": { + "asset_id": { + "type": "uint64", + "key": "asset_id" + }, + "bootstrapped": { + "type": "uint64", + "key": "bootstrapped" + }, + "unitary_price": { + "type": "uint64", + "key": "unitary_price" + } + }, + "reserved": {} + }, + "local": { + "declared": {}, + "reserved": {} + } + }, + "contract": { + "name": "NftMarketplace", + "desc": "\n 문제 1\n NftMarketplace 앱의 상태(state)를 정의하고 초기값을 설정하세요.\n\n NftMarketplace 앱은 세개의 상태를 가지고 있습니다.\n 1. asset_id: 판매할 에셋(ASA)의 아이디; UInt64타입을 가진 글로벌 상태(Global State) 초기값은 0으로 설정해주세요.\n 2. unitary_price: 판매할 에셋(ASA)의 가격. UInt64타입을 가진 글로벌 상태(Global State) 초기값은 0으로 설정해주세요.\n 3. bootstrapped: 앱에서 에셋을 판매할 준비가 되었는지 체크하는 bool 타입의 글로벌 상태(Global State). 초기값은 False로 설정해주세요.\n bootstrap 메서드가 실행되면 True로 변경됩니다.\n\n 재밌는 팩트!\n AVM은 Bytes 타입과 UInt64 타입만 지원합니다. 그래서 다른 타입을 사용하고 싶으면 보통 arc4타입을 사용합니다. 하지만\n Algorand Python에서는 bool, string 타입은 파이썬 코드와 동일하게 사용할 수 있습니다. 예를 들어 bool 타입은 True,\n False로 표헌하면 되고, string 타입은 \"Hello, World!\"와 같이 표현하면 됩니다. Algorand Python에서 데이터 타입을\n 사용하는 방법은 아래 링크를 참고해주세요.\n - arc4 타입: https://algorandfoundation.github.io/puya/lg-types.html#types\n\n 팁!\n - Global State를 정의할때 simplifed 버전으로 정의하면 간결한 코드로 상태를 정의하고 초기값을 설정할 수 있습니다. 자세한 사항은 아래 힌트 1을 참고해주세요.\n\n 힌트 1 - 글러벌 상태: https://algorandfoundation.github.io/puya/lg-storage.html#global-storage\n 힌트 2 - 코드 예시: https://github.com/algorandfoundation/puya/blob/11843f6bc4bb6e4c56ac53e3980f74df69d07397/examples/global_state/contract.py#L5\n ", + "methods": [ + { + "name": "bootstrap", + "args": [ + { + "type": "asset", + "name": "asset" + }, + { + "type": "uint64", + "name": "unitary_price" + }, + { + "type": "pay", + "name": "mbr_pay" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "buy", + "args": [ + { + "type": "pay", + "name": "buyer_txn" + }, + { + "type": "uint64", + "name": "quantity" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "withdraw_and_delete", + "args": [], + "returns": { + "type": "void" + }, + "desc": "여기에 코드 작성" + } + ], + "networks": {} + }, + "bare_call_config": { + "no_op": "CREATE" + } +} + +/** + * Defines an onCompletionAction of 'no_op' + */ +export type OnCompleteNoOp = { onCompleteAction?: 'no_op' | OnApplicationComplete.NoOpOC } +/** + * Defines an onCompletionAction of 'opt_in' + */ +export type OnCompleteOptIn = { onCompleteAction: 'opt_in' | OnApplicationComplete.OptInOC } +/** + * Defines an onCompletionAction of 'close_out' + */ +export type OnCompleteCloseOut = { onCompleteAction: 'close_out' | OnApplicationComplete.CloseOutOC } +/** + * Defines an onCompletionAction of 'delete_application' + */ +export type OnCompleteDelApp = { onCompleteAction: 'delete_application' | OnApplicationComplete.DeleteApplicationOC } +/** + * Defines an onCompletionAction of 'update_application' + */ +export type OnCompleteUpdApp = { onCompleteAction: 'update_application' | OnApplicationComplete.UpdateApplicationOC } +/** + * A state record containing a single unsigned integer + */ +export type IntegerState = { + /** + * Gets the state value as a BigInt. + */ + asBigInt(): bigint + /** + * Gets the state value as a number. + */ + asNumber(): number +} +/** + * A state record containing binary data + */ +export type BinaryState = { + /** + * Gets the state value as a Uint8Array + */ + asByteArray(): Uint8Array + /** + * Gets the state value as a string + */ + asString(): string +} + +export type AppCreateCallTransactionResult = AppCallTransactionResult & Partial & AppReference +export type AppUpdateCallTransactionResult = AppCallTransactionResult & Partial + +export type AppClientComposeCallCoreParams = Omit & { + sendParams?: Omit +} +export type AppClientComposeExecuteParams = Pick + +export type IncludeSchema = { + /** + * Any overrides for the storage schema to request for the created app; by default the schema indicated by the app spec is used. + */ + schema?: Partial +} + +/** + * Defines the types of available calls and state of the NftMarketplace smart contract. + */ +export type NftMarketplace = { + /** + * Maps method signatures / names to their argument and return types. + */ + methods: + & Record<'bootstrap(asset,uint64,pay)void' | 'bootstrap', { + argsObj: { + asset: number | bigint + unitaryPrice: bigint | number + mbrPay: TransactionToSign | Transaction | Promise + } + argsTuple: [asset: number | bigint, unitaryPrice: bigint | number, mbrPay: TransactionToSign | Transaction | Promise] + returns: void + }> + & Record<'buy(pay,uint64)void' | 'buy', { + argsObj: { + buyerTxn: TransactionToSign | Transaction | Promise + quantity: bigint | number + } + argsTuple: [buyerTxn: TransactionToSign | Transaction | Promise, quantity: bigint | number] + returns: void + }> + & Record<'withdraw_and_delete()void' | 'withdraw_and_delete', { + argsObj: { + } + argsTuple: [] + returns: void + }> + /** + * Defines the shape of the global and local state of the application. + */ + state: { + global: { + assetId?: IntegerState + bootstrapped?: IntegerState + unitaryPrice?: IntegerState + } + } +} +/** + * Defines the possible abi call signatures + */ +export type NftMarketplaceSig = keyof NftMarketplace['methods'] +/** + * Defines an object containing all relevant parameters for a single call to the contract. Where TSignature is undefined, a bare call is made + */ +export type TypedCallParams = { + method: TSignature + methodArgs: TSignature extends undefined ? undefined : Array +} & AppClientCallCoreParams & CoreAppCallArgs +/** + * Defines the arguments required for a bare call + */ +export type BareCallArgs = Omit +/** + * Maps a method signature from the NftMarketplace smart contract to the method's arguments in either tuple of struct form + */ +export type MethodArgs = NftMarketplace['methods'][TSignature]['argsObj' | 'argsTuple'] +/** + * Maps a method signature from the NftMarketplace smart contract to the method's return type + */ +export type MethodReturn = NftMarketplace['methods'][TSignature]['returns'] + +/** + * A factory for available 'create' calls + */ +export type NftMarketplaceCreateCalls = (typeof NftMarketplaceCallFactory)['create'] +/** + * Defines supported create methods for this smart contract + */ +export type NftMarketplaceCreateCallParams = + | (TypedCallParams & (OnCompleteNoOp)) +/** + * A factory for available 'delete' calls + */ +export type NftMarketplaceDeleteCalls = (typeof NftMarketplaceCallFactory)['delete'] +/** + * Defines supported delete methods for this smart contract + */ +export type NftMarketplaceDeleteCallParams = + | TypedCallParams<'withdraw_and_delete()void'> +/** + * Defines arguments required for the deploy method. + */ +export type NftMarketplaceDeployArgs = { + deployTimeParams?: TealTemplateParams + /** + * A delegate which takes a create call factory and returns the create call params for this smart contract + */ + createCall?: (callFactory: NftMarketplaceCreateCalls) => NftMarketplaceCreateCallParams + /** + * A delegate which takes a delete call factory and returns the delete call params for this smart contract + */ + deleteCall?: (callFactory: NftMarketplaceDeleteCalls) => NftMarketplaceDeleteCallParams +} + + +/** + * Exposes methods for constructing all available smart contract calls + */ +export abstract class NftMarketplaceCallFactory { + /** + * Gets available create call factories + */ + static get create() { + return { + /** + * Constructs a create call for the NftMarketplace smart contract using a bare call + * + * @param params Any parameters for the call + * @returns A TypedCallParams object for the call + */ + bare(params: BareCallArgs & AppClientCallCoreParams & CoreAppCallArgs & AppClientCompilationParams & (OnCompleteNoOp) = {}) { + return { + method: undefined, + methodArgs: undefined, + ...params, + } + }, + } + } + + /** + * Gets available delete call factories + */ + static get delete() { + return { + /** + * Constructs a delete call for the NftMarketplace smart contract using the withdraw_and_delete()void ABI method + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + withdrawAndDelete(args: MethodArgs<'withdraw_and_delete()void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return { + method: 'withdraw_and_delete()void' as const, + methodArgs: Array.isArray(args) ? args : [], + ...params, + } + }, + } + } + + /** + * Constructs a no op call for the bootstrap(asset,uint64,pay)void ABI method + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static bootstrap(args: MethodArgs<'bootstrap(asset,uint64,pay)void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'bootstrap(asset,uint64,pay)void' as const, + methodArgs: Array.isArray(args) ? args : [args.asset, args.unitaryPrice, args.mbrPay], + ...params, + } + } + /** + * Constructs a no op call for the buy(pay,uint64)void ABI method + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static buy(args: MethodArgs<'buy(pay,uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'buy(pay,uint64)void' as const, + methodArgs: Array.isArray(args) ? args : [args.buyerTxn, args.quantity], + ...params, + } + } +} + +/** + * A client to make calls to the NftMarketplace smart contract + */ +export class NftMarketplaceClient { + /** + * The underlying `ApplicationClient` for when you want to have more flexibility + */ + public readonly appClient: ApplicationClient + + private readonly sender: SendTransactionFrom | undefined + + /** + * Creates a new instance of `NftMarketplaceClient` + * + * @param appDetails appDetails The details to identify the app to deploy + * @param algod An algod client instance + */ + constructor(appDetails: AppDetails, private algod: Algodv2) { + this.sender = appDetails.sender + this.appClient = algokit.getAppClient({ + ...appDetails, + app: APP_SPEC + }, algod) + } + + /** + * Checks for decode errors on the AppCallTransactionResult and maps the return value to the specified generic type + * + * @param result The AppCallTransactionResult to be mapped + * @param returnValueFormatter An optional delegate to format the return value if required + * @returns The smart contract response with an updated return value + */ + protected mapReturnValue(result: AppCallTransactionResult, returnValueFormatter?: (value: any) => TReturn): AppCallTransactionResultOfType & TResult { + if(result.return?.decodeError) { + throw result.return.decodeError + } + const returnValue = result.return?.returnValue !== undefined && returnValueFormatter !== undefined + ? returnValueFormatter(result.return.returnValue) + : result.return?.returnValue as TReturn | undefined + return { ...result, return: returnValue } as AppCallTransactionResultOfType & TResult + } + + /** + * Calls the ABI method with the matching signature using an onCompletion code of NO_OP + * + * @param typedCallParams An object containing the method signature, args, and any other relevant parameters + * @param returnValueFormatter An optional delegate which when provided will be used to map non-undefined return values to the target type + * @returns The result of the smart contract call + */ + public async call(typedCallParams: TypedCallParams, returnValueFormatter?: (value: any) => MethodReturn) { + return this.mapReturnValue>(await this.appClient.call(typedCallParams), returnValueFormatter) + } + + /** + * Idempotently deploys the NftMarketplace smart contract. + * + * @param params The arguments for the contract calls and any additional parameters for the call + * @returns The deployment result + */ + public deploy(params: NftMarketplaceDeployArgs & AppClientDeployCoreParams & IncludeSchema = {}): ReturnType { + const createArgs = params.createCall?.(NftMarketplaceCallFactory.create) + const deleteArgs = params.deleteCall?.(NftMarketplaceCallFactory.delete) + return this.appClient.deploy({ + ...params, + deleteArgs, + createArgs, + createOnCompleteAction: createArgs?.onCompleteAction, + }) + } + + /** + * Gets available create methods + */ + public get create() { + const $this = this + return { + /** + * Creates a new instance of the NftMarketplace smart contract using a bare call. + * + * @param args The arguments for the bare call + * @returns The create result + */ + async bare(args: BareCallArgs & AppClientCallCoreParams & AppClientCompilationParams & IncludeSchema & CoreAppCallArgs & (OnCompleteNoOp) = {}) { + return $this.mapReturnValue(await $this.appClient.create(args)) + }, + } + } + + /** + * Gets available delete methods + */ + public get delete() { + const $this = this + return { + /** + * Deletes an existing instance of the NftMarketplace smart contract using the withdraw_and_delete()void ABI method. + * + * @param args The arguments for the smart contract call + * @param params Any additional parameters for the call + * @returns The delete result + */ + async withdrawAndDelete(args: MethodArgs<'withdraw_and_delete()void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return $this.mapReturnValue>(await $this.appClient.delete(NftMarketplaceCallFactory.delete.withdrawAndDelete(args, params))) + }, + } + } + + /** + * Makes a clear_state call to an existing instance of the NftMarketplace smart contract. + * + * @param args The arguments for the bare call + * @returns The clear_state result + */ + public clearState(args: BareCallArgs & AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.appClient.clearState(args) + } + + /** + * Calls the bootstrap(asset,uint64,pay)void ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public bootstrap(args: MethodArgs<'bootstrap(asset,uint64,pay)void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(NftMarketplaceCallFactory.bootstrap(args, params)) + } + + /** + * Calls the buy(pay,uint64)void ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public buy(args: MethodArgs<'buy(pay,uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(NftMarketplaceCallFactory.buy(args, params)) + } + + /** + * Extracts a binary state value out of an AppState dictionary + * + * @param state The state dictionary containing the state value + * @param key The key of the state value + * @returns A BinaryState instance containing the state value, or undefined if the key was not found + */ + private static getBinaryState(state: AppState, key: string): BinaryState | undefined { + const value = state[key] + if (!value) return undefined + if (!('valueRaw' in value)) + throw new Error(`Failed to parse state value for ${key}; received an int when expected a byte array`) + return { + asString(): string { + return value.value + }, + asByteArray(): Uint8Array { + return value.valueRaw + } + } + } + + /** + * Extracts a integer state value out of an AppState dictionary + * + * @param state The state dictionary containing the state value + * @param key The key of the state value + * @returns An IntegerState instance containing the state value, or undefined if the key was not found + */ + private static getIntegerState(state: AppState, key: string): IntegerState | undefined { + const value = state[key] + if (!value) return undefined + if ('valueRaw' in value) + throw new Error(`Failed to parse state value for ${key}; received a byte array when expected a number`) + return { + asBigInt() { + return typeof value.value === 'bigint' ? value.value : BigInt(value.value) + }, + asNumber(): number { + return typeof value.value === 'bigint' ? Number(value.value) : value.value + }, + } + } + + /** + * Returns the smart contract's global state wrapped in a strongly typed accessor with options to format the stored value + */ + public async getGlobalState(): Promise { + const state = await this.appClient.getGlobalState() + return { + get assetId() { + return NftMarketplaceClient.getIntegerState(state, 'asset_id') + }, + get bootstrapped() { + return NftMarketplaceClient.getIntegerState(state, 'bootstrapped') + }, + get unitaryPrice() { + return NftMarketplaceClient.getIntegerState(state, 'unitary_price') + }, + } + } + + public compose(): NftMarketplaceComposer { + const client = this + const atc = new AtomicTransactionComposer() + let promiseChain:Promise = Promise.resolve() + const resultMappers: Array any)> = [] + return { + bootstrap(args: MethodArgs<'bootstrap(asset,uint64,pay)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.bootstrap(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + buy(args: MethodArgs<'buy(pay,uint64)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.buy(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + get delete() { + const $this = this + return { + withdrawAndDelete(args: MethodArgs<'withdraw_and_delete()void'>, params?: AppClientComposeCallCoreParams) { + promiseChain = promiseChain.then(() => client.delete.withdrawAndDelete(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return $this + }, + } + }, + clearState(args?: BareCallArgs & AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.clearState({...args, sendParams: {...args?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + addTransaction(txn: TransactionWithSigner | TransactionToSign | Transaction | Promise, defaultSender?: SendTransactionFrom) { + promiseChain = promiseChain.then(async () => atc.addTransaction(await algokit.getTransactionWithSigner(txn, defaultSender ?? client.sender))) + return this + }, + async atc() { + await promiseChain + return atc + }, + async simulate(options?: SimulateOptions) { + await promiseChain + const result = await atc.simulate(client.algod, new modelsv2.SimulateRequest({ txnGroups: [], ...options })) + return { + ...result, + returns: result.methodResults?.map((val, i) => resultMappers[i] !== undefined ? resultMappers[i]!(val.returnValue) : val.returnValue) + } + }, + async execute(sendParams?: AppClientComposeExecuteParams) { + await promiseChain + const result = await algokit.sendAtomicTransactionComposer({ atc, sendParams }, client.algod) + return { + ...result, + returns: result.returns?.map((val, i) => resultMappers[i] !== undefined ? resultMappers[i]!(val.returnValue) : val.returnValue) + } + } + } as unknown as NftMarketplaceComposer + } +} +export type NftMarketplaceComposer = { + /** + * Calls the bootstrap(asset,uint64,pay)void ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + bootstrap(args: MethodArgs<'bootstrap(asset,uint64,pay)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): NftMarketplaceComposer<[...TReturns, MethodReturn<'bootstrap(asset,uint64,pay)void'>]> + + /** + * Calls the buy(pay,uint64)void ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + buy(args: MethodArgs<'buy(pay,uint64)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): NftMarketplaceComposer<[...TReturns, MethodReturn<'buy(pay,uint64)void'>]> + + /** + * Gets available delete methods + */ + readonly delete: { + /** + * Deletes an existing instance of the NftMarketplace smart contract using the withdraw_and_delete()void ABI method. + * + * @param args The arguments for the smart contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + withdrawAndDelete(args: MethodArgs<'withdraw_and_delete()void'>, params?: AppClientComposeCallCoreParams): NftMarketplaceComposer<[...TReturns, MethodReturn<'withdraw_and_delete()void'>]> + } + + /** + * Makes a clear_state call to an existing instance of the NftMarketplace smart contract. + * + * @param args The arguments for the bare call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + clearState(args?: BareCallArgs & AppClientComposeCallCoreParams & CoreAppCallArgs): NftMarketplaceComposer<[...TReturns, undefined]> + + /** + * Adds a transaction to the composer + * + * @param txn One of: A TransactionWithSigner object (returned as is), a TransactionToSign object (signer is obtained from the signer property), a Transaction object (signer is extracted from the defaultSender parameter), an async SendTransactionResult returned by one of algokit utils helpers (signer is obtained from the defaultSender parameter) + * @param defaultSender The default sender to be used to obtain a signer where the object provided to the transaction parameter does not include a signer. + */ + addTransaction(txn: TransactionWithSigner | TransactionToSign | Transaction | Promise, defaultSender?: SendTransactionFrom): NftMarketplaceComposer + /** + * Returns the underlying AtomicTransactionComposer instance + */ + atc(): Promise + /** + * Simulates the transaction group and returns the result + */ + simulate(options?: SimulateOptions): Promise> + /** + * Executes the transaction group and returns the results + */ + execute(sendParams?: AppClientComposeExecuteParams): Promise> +} +export type SimulateOptions = Omit[0], 'txnGroups'> +export type NftMarketplaceComposerSimulateResult = { + returns: TReturns + methodResults: ABIResult[] + simulateResponse: modelsv2.SimulateResponse +} +export type NftMarketplaceComposerResults = { + returns: TReturns + groupId: string + txIds: string[] + transactions: Transaction[] +} diff --git a/projects/coding-assignment/smart_contracts/nft_marketplace/contract.py b/projects/coding-assignment/smart_contracts/nft_marketplace/contract.py index bc4ddb2..d61b3ea 100644 --- a/projects/coding-assignment/smart_contracts/nft_marketplace/contract.py +++ b/projects/coding-assignment/smart_contracts/nft_marketplace/contract.py @@ -44,9 +44,9 @@ class NftMarketplace(arc4.ARC4Contract): def __init__(self) -> None: "문제 1 시작" - self.asset_id = "여기에 코드 작성" - self.unitary_price = "여기에 코드 작성" - self.bootstrapped = "여기에 코드 작성" + self.asset_id = UInt64(0) + self.unitary_price = UInt64(0) + self.bootstrapped = False "문제 1 끝" """ @@ -91,7 +91,21 @@ def __init__(self) -> None: def bootstrap( self, asset: Asset, unitary_price: UInt64, mbr_pay: gtxn.PaymentTransaction ) -> None: - "여기에 코드 작성" + assert Txn.sender == Global.creator_address + assert self.bootstrapped == False + assert mbr_pay.receiver == Global.current_application_address + assert mbr_pay.amount == (Global.current_application_address.min_balance+Global.asset_opt_in_min_balance) + + self.asset_id = asset.id + self.unitary_price=unitary_price + self.bootstrapped=True + + itxn.AssetTransfer( + xfer_asset=self.asset_id, + asset_receiver=Global.current_application_address, + asset_amount=0, + ).submit() + "문제 2 끝" @@ -131,7 +145,17 @@ def buy( buyer_txn: gtxn.PaymentTransaction, quantity: UInt64, ) -> None: - "여기에 코드 작성" + assert self.bootstrapped==True + assert buyer_txn.sender == Txn.sender + assert buyer_txn.receiver == Global.current_application_address + assert buyer_txn.amount == self.unitary_price*quantity + + itxn.AssetTransfer( + xfer_asset=self.asset_id, + asset_receiver=Txn.sender, + asset_amount=quantity, + ).submit() + "문제 3 끝" @@ -182,5 +206,15 @@ def buy( @arc4.abimethod(allow_actions=["DeleteApplication"]) def withdraw_and_delete(self) -> None: "여기에 코드 작성" + assert Txn.sender == Global.creator_address + itxn.AssetTransfer( + xfer_asset=self.asset_id, + asset_receiver=Global.creator_address, + asset_close_to=Global.creator_address, + ).submit() + itxn.Payment( + receiver=Global.creator_address, + close_remainder_to=Global.creator_address + ).submit() "문제 4 끝"