diff --git a/projects/coding-assignment/smart_contracts/artifacts/digital_marketplace/DigitalMarketplace.approval.teal b/projects/coding-assignment/smart_contracts/artifacts/digital_marketplace/DigitalMarketplace.approval.teal new file mode 100644 index 0000000..d0adaff --- /dev/null +++ b/projects/coding-assignment/smart_contracts/artifacts/digital_marketplace/DigitalMarketplace.approval.teal @@ -0,0 +1,461 @@ +#pragma version 10 + +smart_contracts.digital_marketplace.contract.DigitalMarketplace.approval_program: + txn ApplicationID + bnz main_entrypoint@2 + callsub __init__ + +main_entrypoint@2: + // smart_contracts/digital_marketplace/contract.py:20 + // class DigitalMarketplace(arc4.ARC4Contract): + txn NumAppArgs + bz main_bare_routing@10 + method "set_price(uint64)void" + method "bootstrap(asset,uint64,pay)void" + method "buy(pay,uint64)void" + method "withdraw_and_delete()void" + txna ApplicationArgs 0 + match main_set_price_route@4 main_bootstrap_route@5 main_buy_route@6 main_withdraw_and_delete_route@7 + err // reject transaction + +main_set_price_route@4: + // smart_contracts/digital_marketplace/contract.py:64 + // @arc4.abimethod + txn OnCompletion + ! + assert // OnCompletion is NoOp + txn ApplicationID + assert // is not creating + // smart_contracts/digital_marketplace/contract.py:20 + // class DigitalMarketplace(arc4.ARC4Contract): + txna ApplicationArgs 1 + btoi + // smart_contracts/digital_marketplace/contract.py:64 + // @arc4.abimethod + callsub set_price + int 1 + return + +main_bootstrap_route@5: + // smart_contracts/digital_marketplace/contract.py:100 + // @arc4.abimethod + txn OnCompletion + ! + assert // OnCompletion is NoOp + txn ApplicationID + assert // is not creating + // smart_contracts/digital_marketplace/contract.py:20 + // class DigitalMarketplace(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/digital_marketplace/contract.py:100 + // @arc4.abimethod + callsub bootstrap + int 1 + return + +main_buy_route@6: + // smart_contracts/digital_marketplace/contract.py:150 + // @arc4.abimethod + txn OnCompletion + ! + assert // OnCompletion is NoOp + txn ApplicationID + assert // is not creating + // smart_contracts/digital_marketplace/contract.py:20 + // class DigitalMarketplace(arc4.ARC4Contract): + txn GroupIndex + int 1 + - + dup + gtxns TypeEnum + int pay + == + assert // transaction type is pay + txna ApplicationArgs 1 + btoi + // smart_contracts/digital_marketplace/contract.py:150 + // @arc4.abimethod + callsub buy + int 1 + return + +main_withdraw_and_delete_route@7: + // smart_contracts/digital_marketplace/contract.py:200-201 + // # 문제 5 시작 + // @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@10: + // smart_contracts/digital_marketplace/contract.py:20 + // class DigitalMarketplace(arc4.ARC4Contract): + txn OnCompletion + ! + assert // reject transaction + txn ApplicationID + ! + assert // is creating + int 1 + return + + +// smart_contracts.digital_marketplace.contract.DigitalMarketplace.set_price(unitary_price: uint64) -> void: +set_price: + // smart_contracts/digital_marketplace/contract.py:64-65 + // @arc4.abimethod + // def set_price(self, unitary_price: UInt64) -> None: + proto 1 0 + // smart_contracts/digital_marketplace/contract.py:66-67 + // # 문제 2 시작 + // assert Txn.sender == Global.creator_address, "Only creator can opt in to ASA" + txn Sender + global CreatorAddress + == + assert // Only creator can opt in to ASA + // smart_contracts/digital_marketplace/contract.py:68 + // assert self.bootstrapped.value == True, "App Must be bootstrapped" + int 0 + byte "bootstrapped" + app_global_get_ex + assert // check bootstrapped exists + int 1 + == + assert // App Must be bootstrapped + // smart_contracts/digital_marketplace/contract.py:69 + // self.unitary_price.value = unitary_price + byte "unitary_price" + frame_dig -1 + app_global_put + retsub + + +// smart_contracts.digital_marketplace.contract.DigitalMarketplace.bootstrap(asset: uint64, unitary_price: uint64, mbr_pay: uint64) -> void: +bootstrap: + // smart_contracts/digital_marketplace/contract.py:100-103 + // @arc4.abimethod + // def bootstrap( + // self, asset: Asset, unitary_price: UInt64, mbr_pay: gtxn.PaymentTransaction + // ) -> None: + proto 3 0 + // smart_contracts/digital_marketplace/contract.py:104-105 + // # 문제 3 시작 + // assert Txn.sender == Global.creator_address, "Only creator can opt in to ASA" + txn Sender + global CreatorAddress + == + assert // Only creator can opt in to ASA + // smart_contracts/digital_marketplace/contract.py:106 + // assert self.bootstrapped.value == False, "App is already bootstrapped." + int 0 + byte "bootstrapped" + app_global_get_ex + assert // check bootstrapped exists + ! + assert // App is already bootstrapped. + // smart_contracts/digital_marketplace/contract.py:107 + // assert mbr_pay.receiver == Global.current_application_address, "receiver must be the contract address" + frame_dig -1 + gtxns Receiver + global CurrentApplicationAddress + == + assert // receiver must be the contract address + // smart_contracts/digital_marketplace/contract.py:108 + // assert mbr_pay.amount == (Global.min_balance + Global.asset_opt_in_min_balance), "Incorrect funding amount." + frame_dig -1 + gtxns Amount + global MinBalance + global AssetOptInMinBalance + + + == + assert // Incorrect funding amount. + // smart_contracts/digital_marketplace/contract.py:110 + // self.asset_id.value = (asset.id) + byte "asset_id" + frame_dig -3 + app_global_put + // smart_contracts/digital_marketplace/contract.py:111 + // self.unitary_price.value = (unitary_price) + byte "unitary_price" + frame_dig -2 + app_global_put + // smart_contracts/digital_marketplace/contract.py:112 + // self.bootstrapped.value = (True) + byte "bootstrapped" + int 1 + app_global_put + // smart_contracts/digital_marketplace/contract.py:114-120 + // itxn.AssetTransfer( + // xfer_asset = self.asset_id.value, + // asset_receiver= Txn.sender, + // asset_sender= Global.current_application_address, + // asset_amount= UInt64(0), + // fee=0 + // ).submit() + itxn_begin + // smart_contracts/digital_marketplace/contract.py:115 + // xfer_asset = self.asset_id.value, + int 0 + byte "asset_id" + app_global_get_ex + assert // check asset_id exists + // smart_contracts/digital_marketplace/contract.py:116 + // asset_receiver= Txn.sender, + txn Sender + // smart_contracts/digital_marketplace/contract.py:117 + // asset_sender= Global.current_application_address, + global CurrentApplicationAddress + // smart_contracts/digital_marketplace/contract.py:118 + // asset_amount= UInt64(0), + int 0 + itxn_field AssetAmount + itxn_field AssetSender + itxn_field AssetReceiver + itxn_field XferAsset + // smart_contracts/digital_marketplace/contract.py:114 + // itxn.AssetTransfer( + int axfer + itxn_field TypeEnum + // smart_contracts/digital_marketplace/contract.py:119 + // fee=0 + int 0 + itxn_field Fee + // smart_contracts/digital_marketplace/contract.py:114-120 + // itxn.AssetTransfer( + // xfer_asset = self.asset_id.value, + // asset_receiver= Txn.sender, + // asset_sender= Global.current_application_address, + // asset_amount= UInt64(0), + // fee=0 + // ).submit() + itxn_submit + retsub + + +// smart_contracts.digital_marketplace.contract.DigitalMarketplace.buy(buyer_txn: uint64, quantity: uint64) -> void: +buy: + // smart_contracts/digital_marketplace/contract.py:150-155 + // @arc4.abimethod + // def buy( + // self, + // buyer_txn: gtxn.PaymentTransaction, + // quantity: UInt64, + // ) -> None: + proto 2 0 + // smart_contracts/digital_marketplace/contract.py:156-157 + // # 문제 4 시작 + // assert self.unitary_price.value != UInt64(0), "Unitary price is not set." + int 0 + byte "unitary_price" + app_global_get_ex + assert // check unitary_price exists + assert // Unitary price is not set. + // smart_contracts/digital_marketplace/contract.py:158 + // assert buyer_txn.sender == Txn.sender, "Payment transaction sender must be the caller." + frame_dig -2 + gtxns Sender + txn Sender + == + assert // Payment transaction sender must be the caller. + // smart_contracts/digital_marketplace/contract.py:159 + // assert buyer_txn.receiver == Global.current_application_address, "Receiver must be this app." + frame_dig -2 + gtxns Receiver + global CurrentApplicationAddress + == + assert // Receiver must be this app. + // smart_contracts/digital_marketplace/contract.py:160 + // assert buyer_txn.amount == self.unitary_price.value * quantity, "Incorrect payment amount." + frame_dig -2 + gtxns Amount + int 0 + byte "unitary_price" + app_global_get_ex + assert // check unitary_price exists + frame_dig -1 + * + == + assert // Incorrect payment amount. + // smart_contracts/digital_marketplace/contract.py:162-168 + // itxn.AssetTransfer( + // xfer_asset = self.asset_id.value, + // asset_receiver= Txn.sender, + // asset_sender= Global.current_application_address, + // asset_amount= quantity, + // fee=0 + // ).submit() + itxn_begin + // smart_contracts/digital_marketplace/contract.py:163 + // xfer_asset = self.asset_id.value, + int 0 + byte "asset_id" + app_global_get_ex + assert // check asset_id exists + // smart_contracts/digital_marketplace/contract.py:164 + // asset_receiver= Txn.sender, + txn Sender + // smart_contracts/digital_marketplace/contract.py:165 + // asset_sender= Global.current_application_address, + global CurrentApplicationAddress + frame_dig -1 + itxn_field AssetAmount + itxn_field AssetSender + itxn_field AssetReceiver + itxn_field XferAsset + // smart_contracts/digital_marketplace/contract.py:162 + // itxn.AssetTransfer( + int axfer + itxn_field TypeEnum + // smart_contracts/digital_marketplace/contract.py:167 + // fee=0 + int 0 + itxn_field Fee + // smart_contracts/digital_marketplace/contract.py:162-168 + // itxn.AssetTransfer( + // xfer_asset = self.asset_id.value, + // asset_receiver= Txn.sender, + // asset_sender= Global.current_application_address, + // asset_amount= quantity, + // fee=0 + // ).submit() + itxn_submit + retsub + + +// smart_contracts.digital_marketplace.contract.DigitalMarketplace.withdraw_and_delete() -> void: +withdraw_and_delete: + // smart_contracts/digital_marketplace/contract.py:200-202 + // # 문제 5 시작 + // @arc4.abimethod(allow_actions=["DeleteApplication"]) + // def withdraw_and_delete(self) -> None: + proto 0 0 + // smart_contracts/digital_marketplace/contract.py:203 + // assert Txn.sender == Global.creator_address, "Only creator can opt in to ASA" + txn Sender + global CreatorAddress + == + assert // Only creator can opt in to ASA + // smart_contracts/digital_marketplace/contract.py:205-211 + // itxn.AssetTransfer( + // xfer_asset = self.asset_id.value, + // asset_receiver = Global.creator_address, + // asset_sender = Global.current_application_address, + // asset_close_to = Global.creator_address, + // fee=0 + // ).submit() + itxn_begin + // smart_contracts/digital_marketplace/contract.py:206 + // xfer_asset = self.asset_id.value, + int 0 + byte "asset_id" + app_global_get_ex + assert // check asset_id exists + // smart_contracts/digital_marketplace/contract.py:207 + // asset_receiver = Global.creator_address, + global CreatorAddress + // smart_contracts/digital_marketplace/contract.py:208 + // asset_sender = Global.current_application_address, + global CurrentApplicationAddress + // smart_contracts/digital_marketplace/contract.py:209 + // asset_close_to = Global.creator_address, + global CreatorAddress + itxn_field AssetCloseTo + itxn_field AssetSender + itxn_field AssetReceiver + itxn_field XferAsset + // smart_contracts/digital_marketplace/contract.py:205 + // itxn.AssetTransfer( + int axfer + itxn_field TypeEnum + // smart_contracts/digital_marketplace/contract.py:210 + // fee=0 + int 0 + itxn_field Fee + // smart_contracts/digital_marketplace/contract.py:205-211 + // itxn.AssetTransfer( + // xfer_asset = self.asset_id.value, + // asset_receiver = Global.creator_address, + // asset_sender = Global.current_application_address, + // asset_close_to = Global.creator_address, + // fee=0 + // ).submit() + itxn_submit + // smart_contracts/digital_marketplace/contract.py:213-218 + // itxn.Payment( + // receiver = Global.creator_address, + // sender = Global.current_application_address, + // close_remainder_to = Global.creator_address, + // fee=0 + // ).submit() + itxn_begin + // smart_contracts/digital_marketplace/contract.py:214 + // receiver = Global.creator_address, + global CreatorAddress + // smart_contracts/digital_marketplace/contract.py:215 + // sender = Global.current_application_address, + global CurrentApplicationAddress + // smart_contracts/digital_marketplace/contract.py:216 + // close_remainder_to = Global.creator_address, + global CreatorAddress + itxn_field CloseRemainderTo + itxn_field Sender + itxn_field Receiver + // smart_contracts/digital_marketplace/contract.py:213 + // itxn.Payment( + int pay + itxn_field TypeEnum + // smart_contracts/digital_marketplace/contract.py:217 + // fee=0 + int 0 + itxn_field Fee + // smart_contracts/digital_marketplace/contract.py:213-218 + // itxn.Payment( + // receiver = Global.creator_address, + // sender = Global.current_application_address, + // close_remainder_to = Global.creator_address, + // fee=0 + // ).submit() + itxn_submit + retsub + + +// smart_contracts.digital_marketplace.contract.DigitalMarketplace.__init__() -> void: +__init__: + // smart_contracts/digital_marketplace/contract.py:40 + // def __init__(self) -> None: + proto 0 0 + // smart_contracts/digital_marketplace/contract.py:41-42 + // # 문제 1 시작 + // self.asset_id = GlobalState(UInt64(0)) + byte "asset_id" + int 0 + app_global_put + // smart_contracts/digital_marketplace/contract.py:43 + // self.unitary_price = GlobalState(UInt64(0)) + byte "unitary_price" + int 0 + app_global_put + // smart_contracts/digital_marketplace/contract.py:44 + // self.bootstrapped = GlobalState(bool(False)) + byte "bootstrapped" + int 0 + app_global_put + retsub diff --git a/projects/coding-assignment/smart_contracts/artifacts/digital_marketplace/DigitalMarketplace.arc32.json b/projects/coding-assignment/smart_contracts/artifacts/digital_marketplace/DigitalMarketplace.arc32.json new file mode 100644 index 0000000..f9c1b79 --- /dev/null +++ b/projects/coding-assignment/smart_contracts/artifacts/digital_marketplace/DigitalMarketplace.arc32.json @@ -0,0 +1,126 @@ +{ + "hints": { + "set_price(uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "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": "I3ByYWdtYSB2ZXJzaW9uIDEwCgpzbWFydF9jb250cmFjdHMuZGlnaXRhbF9tYXJrZXRwbGFjZS5jb250cmFjdC5EaWdpdGFsTWFya2V0cGxhY2UuYXBwcm92YWxfcHJvZ3JhbToKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBibnogbWFpbl9lbnRyeXBvaW50QDIKICAgIGNhbGxzdWIgX19pbml0X18KCm1haW5fZW50cnlwb2ludEAyOgogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjAKICAgIC8vIGNsYXNzIERpZ2l0YWxNYXJrZXRwbGFjZShhcmM0LkFSQzRDb250cmFjdCk6CiAgICB0eG4gTnVtQXBwQXJncwogICAgYnogbWFpbl9iYXJlX3JvdXRpbmdAMTAKICAgIG1ldGhvZCAic2V0X3ByaWNlKHVpbnQ2NCl2b2lkIgogICAgbWV0aG9kICJib290c3RyYXAoYXNzZXQsdWludDY0LHBheSl2b2lkIgogICAgbWV0aG9kICJidXkocGF5LHVpbnQ2NCl2b2lkIgogICAgbWV0aG9kICJ3aXRoZHJhd19hbmRfZGVsZXRlKCl2b2lkIgogICAgdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAogICAgbWF0Y2ggbWFpbl9zZXRfcHJpY2Vfcm91dGVANCBtYWluX2Jvb3RzdHJhcF9yb3V0ZUA1IG1haW5fYnV5X3JvdXRlQDYgbWFpbl93aXRoZHJhd19hbmRfZGVsZXRlX3JvdXRlQDcKICAgIGVyciAvLyByZWplY3QgdHJhbnNhY3Rpb24KCm1haW5fc2V0X3ByaWNlX3JvdXRlQDQ6CiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weTo2NAogICAgLy8gQGFyYzQuYWJpbWV0aG9kCiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gT25Db21wbGV0aW9uIGlzIE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gaXMgbm90IGNyZWF0aW5nCiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMAogICAgLy8gY2xhc3MgRGlnaXRhbE1hcmtldHBsYWNlKGFyYzQuQVJDNENvbnRyYWN0KToKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjY0CiAgICAvLyBAYXJjNC5hYmltZXRob2QKICAgIGNhbGxzdWIgc2V0X3ByaWNlCiAgICBpbnQgMQogICAgcmV0dXJuCgptYWluX2Jvb3RzdHJhcF9yb3V0ZUA1OgogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTAwCiAgICAvLyBAYXJjNC5hYmltZXRob2QKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgTm9PcAogICAgdHhuIEFwcGxpY2F0aW9uSUQKICAgIGFzc2VydCAvLyBpcyBub3QgY3JlYXRpbmcKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIwCiAgICAvLyBjbGFzcyBEaWdpdGFsTWFya2V0cGxhY2UoYXJjNC5BUkM0Q29udHJhY3QpOgogICAgdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQogICAgYnRvaQogICAgdHhuYXMgQXNzZXRzCiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAyCiAgICBidG9pCiAgICB0eG4gR3JvdXBJbmRleAogICAgaW50IDEKICAgIC0KICAgIGR1cAogICAgZ3R4bnMgVHlwZUVudW0KICAgIGludCBwYXkKICAgID09CiAgICBhc3NlcnQgLy8gdHJhbnNhY3Rpb24gdHlwZSBpcyBwYXkKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjEwMAogICAgLy8gQGFyYzQuYWJpbWV0aG9kCiAgICBjYWxsc3ViIGJvb3RzdHJhcAogICAgaW50IDEKICAgIHJldHVybgoKbWFpbl9idXlfcm91dGVANjoKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjE1MAogICAgLy8gQGFyYzQuYWJpbWV0aG9kCiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gT25Db21wbGV0aW9uIGlzIE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gaXMgbm90IGNyZWF0aW5nCiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMAogICAgLy8gY2xhc3MgRGlnaXRhbE1hcmtldHBsYWNlKGFyYzQuQVJDNENvbnRyYWN0KToKICAgIHR4biBHcm91cEluZGV4CiAgICBpbnQgMQogICAgLQogICAgZHVwCiAgICBndHhucyBUeXBlRW51bQogICAgaW50IHBheQogICAgPT0KICAgIGFzc2VydCAvLyB0cmFuc2FjdGlvbiB0eXBlIGlzIHBheQogICAgdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQogICAgYnRvaQogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTUwCiAgICAvLyBAYXJjNC5hYmltZXRob2QKICAgIGNhbGxzdWIgYnV5CiAgICBpbnQgMQogICAgcmV0dXJuCgptYWluX3dpdGhkcmF3X2FuZF9kZWxldGVfcm91dGVANzoKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIwMC0yMDEKICAgIC8vICMg66y47KCcIDUg7Iuc7J6RCiAgICAvLyBAYXJjNC5hYmltZXRob2QoYWxsb3dfYWN0aW9ucz1bIkRlbGV0ZUFwcGxpY2F0aW9uIl0pCiAgICB0eG4gT25Db21wbGV0aW9uCiAgICBpbnQgRGVsZXRlQXBwbGljYXRpb24KICAgID09CiAgICBhc3NlcnQgLy8gT25Db21wbGV0aW9uIGlzIERlbGV0ZUFwcGxpY2F0aW9uCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGlzIG5vdCBjcmVhdGluZwogICAgY2FsbHN1YiB3aXRoZHJhd19hbmRfZGVsZXRlCiAgICBpbnQgMQogICAgcmV0dXJuCgptYWluX2JhcmVfcm91dGluZ0AxMDoKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIwCiAgICAvLyBjbGFzcyBEaWdpdGFsTWFya2V0cGxhY2UoYXJjNC5BUkM0Q29udHJhY3QpOgogICAgdHhuIE9uQ29tcGxldGlvbgogICAgIQogICAgYXNzZXJ0IC8vIHJlamVjdCB0cmFuc2FjdGlvbgogICAgdHhuIEFwcGxpY2F0aW9uSUQKICAgICEKICAgIGFzc2VydCAvLyBpcyBjcmVhdGluZwogICAgaW50IDEKICAgIHJldHVybgoKCi8vIHNtYXJ0X2NvbnRyYWN0cy5kaWdpdGFsX21hcmtldHBsYWNlLmNvbnRyYWN0LkRpZ2l0YWxNYXJrZXRwbGFjZS5zZXRfcHJpY2UodW5pdGFyeV9wcmljZTogdWludDY0KSAtPiB2b2lkOgpzZXRfcHJpY2U6CiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weTo2NC02NQogICAgLy8gQGFyYzQuYWJpbWV0aG9kCiAgICAvLyBkZWYgc2V0X3ByaWNlKHNlbGYsIHVuaXRhcnlfcHJpY2U6IFVJbnQ2NCkgLT4gTm9uZToKICAgIHByb3RvIDEgMAogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6NjYtNjcKICAgIC8vICAjIOusuOygnCAyIOyLnOyekQogICAgLy8gYXNzZXJ0IFR4bi5zZW5kZXIgPT0gR2xvYmFsLmNyZWF0b3JfYWRkcmVzcywgIk9ubHkgY3JlYXRvciBjYW4gb3B0IGluIHRvIEFTQSIKICAgIHR4biBTZW5kZXIKICAgIGdsb2JhbCBDcmVhdG9yQWRkcmVzcwogICAgPT0KICAgIGFzc2VydCAvLyBPbmx5IGNyZWF0b3IgY2FuIG9wdCBpbiB0byBBU0EKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjY4CiAgICAvLyBhc3NlcnQgc2VsZi5ib290c3RyYXBwZWQudmFsdWUgPT0gVHJ1ZSwgIkFwcCBNdXN0IGJlIGJvb3RzdHJhcHBlZCIKICAgIGludCAwCiAgICBieXRlICJib290c3RyYXBwZWQiCiAgICBhcHBfZ2xvYmFsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIGJvb3RzdHJhcHBlZCBleGlzdHMKICAgIGludCAxCiAgICA9PQogICAgYXNzZXJ0IC8vIEFwcCBNdXN0IGJlIGJvb3RzdHJhcHBlZAogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6NjkKICAgIC8vIHNlbGYudW5pdGFyeV9wcmljZS52YWx1ZSA9IHVuaXRhcnlfcHJpY2UKICAgIGJ5dGUgInVuaXRhcnlfcHJpY2UiCiAgICBmcmFtZV9kaWcgLTEKICAgIGFwcF9nbG9iYWxfcHV0CiAgICByZXRzdWIKCgovLyBzbWFydF9jb250cmFjdHMuZGlnaXRhbF9tYXJrZXRwbGFjZS5jb250cmFjdC5EaWdpdGFsTWFya2V0cGxhY2UuYm9vdHN0cmFwKGFzc2V0OiB1aW50NjQsIHVuaXRhcnlfcHJpY2U6IHVpbnQ2NCwgbWJyX3BheTogdWludDY0KSAtPiB2b2lkOgpib290c3RyYXA6CiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxMDAtMTAzCiAgICAvLyBAYXJjNC5hYmltZXRob2QKICAgIC8vIGRlZiBib290c3RyYXAoCiAgICAvLyAgICAgc2VsZiwgYXNzZXQ6IEFzc2V0LCB1bml0YXJ5X3ByaWNlOiBVSW50NjQsIG1icl9wYXk6IGd0eG4uUGF5bWVudFRyYW5zYWN0aW9uCiAgICAvLyApIC0+IE5vbmU6CiAgICBwcm90byAzIDAKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjEwNC0xMDUKICAgIC8vICMg66y47KCcIDMg7Iuc7J6RCiAgICAvLyBhc3NlcnQgVHhuLnNlbmRlciA9PSBHbG9iYWwuY3JlYXRvcl9hZGRyZXNzLCAiT25seSBjcmVhdG9yIGNhbiBvcHQgaW4gdG8gQVNBIgogICAgdHhuIFNlbmRlcgogICAgZ2xvYmFsIENyZWF0b3JBZGRyZXNzCiAgICA9PQogICAgYXNzZXJ0IC8vIE9ubHkgY3JlYXRvciBjYW4gb3B0IGluIHRvIEFTQQogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTA2CiAgICAvLyBhc3NlcnQgc2VsZi5ib290c3RyYXBwZWQudmFsdWUgPT0gRmFsc2UsICAiQXBwIGlzIGFscmVhZHkgYm9vdHN0cmFwcGVkLiIKICAgIGludCAwCiAgICBieXRlICJib290c3RyYXBwZWQiCiAgICBhcHBfZ2xvYmFsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIGJvb3RzdHJhcHBlZCBleGlzdHMKICAgICEKICAgIGFzc2VydCAvLyBBcHAgaXMgYWxyZWFkeSBib290c3RyYXBwZWQuCiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxMDcKICAgIC8vIGFzc2VydCBtYnJfcGF5LnJlY2VpdmVyID09IEdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2FkZHJlc3MsICJyZWNlaXZlciBtdXN0IGJlIHRoZSBjb250cmFjdCBhZGRyZXNzIgogICAgZnJhbWVfZGlnIC0xCiAgICBndHhucyBSZWNlaXZlcgogICAgZ2xvYmFsIEN1cnJlbnRBcHBsaWNhdGlvbkFkZHJlc3MKICAgID09CiAgICBhc3NlcnQgLy8gcmVjZWl2ZXIgbXVzdCBiZSB0aGUgY29udHJhY3QgYWRkcmVzcwogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTA4CiAgICAvLyBhc3NlcnQgbWJyX3BheS5hbW91bnQgPT0gKEdsb2JhbC5taW5fYmFsYW5jZSArIEdsb2JhbC5hc3NldF9vcHRfaW5fbWluX2JhbGFuY2UpLCAiSW5jb3JyZWN0IGZ1bmRpbmcgYW1vdW50LiIKICAgIGZyYW1lX2RpZyAtMQogICAgZ3R4bnMgQW1vdW50CiAgICBnbG9iYWwgTWluQmFsYW5jZQogICAgZ2xvYmFsIEFzc2V0T3B0SW5NaW5CYWxhbmNlCiAgICArCiAgICA9PQogICAgYXNzZXJ0IC8vIEluY29ycmVjdCBmdW5kaW5nIGFtb3VudC4KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjExMAogICAgLy8gc2VsZi5hc3NldF9pZC52YWx1ZSA9IChhc3NldC5pZCkKICAgIGJ5dGUgImFzc2V0X2lkIgogICAgZnJhbWVfZGlnIC0zCiAgICBhcHBfZ2xvYmFsX3B1dAogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTExCiAgICAvLyBzZWxmLnVuaXRhcnlfcHJpY2UudmFsdWUgPSAodW5pdGFyeV9wcmljZSkKICAgIGJ5dGUgInVuaXRhcnlfcHJpY2UiCiAgICBmcmFtZV9kaWcgLTIKICAgIGFwcF9nbG9iYWxfcHV0CiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxMTIKICAgIC8vIHNlbGYuYm9vdHN0cmFwcGVkLnZhbHVlID0gKFRydWUpCiAgICBieXRlICJib290c3RyYXBwZWQiCiAgICBpbnQgMQogICAgYXBwX2dsb2JhbF9wdXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjExNC0xMjAKICAgIC8vIGl0eG4uQXNzZXRUcmFuc2ZlcigKICAgIC8vICAgICB4ZmVyX2Fzc2V0ID0gc2VsZi5hc3NldF9pZC52YWx1ZSwKICAgIC8vICAgICBhc3NldF9yZWNlaXZlcj0gVHhuLnNlbmRlciwKICAgIC8vICAgICBhc3NldF9zZW5kZXI9IEdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2FkZHJlc3MsCiAgICAvLyAgICAgYXNzZXRfYW1vdW50PSBVSW50NjQoMCksCiAgICAvLyAgICAgZmVlPTAKICAgIC8vICkuc3VibWl0KCkKICAgIGl0eG5fYmVnaW4KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjExNQogICAgLy8geGZlcl9hc3NldCA9IHNlbGYuYXNzZXRfaWQudmFsdWUsCiAgICBpbnQgMAogICAgYnl0ZSAiYXNzZXRfaWQiCiAgICBhcHBfZ2xvYmFsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIGFzc2V0X2lkIGV4aXN0cwogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTE2CiAgICAvLyBhc3NldF9yZWNlaXZlcj0gVHhuLnNlbmRlciwKICAgIHR4biBTZW5kZXIKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjExNwogICAgLy8gYXNzZXRfc2VuZGVyPSBHbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzLAogICAgZ2xvYmFsIEN1cnJlbnRBcHBsaWNhdGlvbkFkZHJlc3MKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjExOAogICAgLy8gYXNzZXRfYW1vdW50PSBVSW50NjQoMCksCiAgICBpbnQgMAogICAgaXR4bl9maWVsZCBBc3NldEFtb3VudAogICAgaXR4bl9maWVsZCBBc3NldFNlbmRlcgogICAgaXR4bl9maWVsZCBBc3NldFJlY2VpdmVyCiAgICBpdHhuX2ZpZWxkIFhmZXJBc3NldAogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTE0CiAgICAvLyBpdHhuLkFzc2V0VHJhbnNmZXIoCiAgICBpbnQgYXhmZXIKICAgIGl0eG5fZmllbGQgVHlwZUVudW0KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjExOQogICAgLy8gZmVlPTAKICAgIGludCAwCiAgICBpdHhuX2ZpZWxkIEZlZQogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTE0LTEyMAogICAgLy8gaXR4bi5Bc3NldFRyYW5zZmVyKAogICAgLy8gICAgIHhmZXJfYXNzZXQgPSBzZWxmLmFzc2V0X2lkLnZhbHVlLAogICAgLy8gICAgIGFzc2V0X3JlY2VpdmVyPSBUeG4uc2VuZGVyLAogICAgLy8gICAgIGFzc2V0X3NlbmRlcj0gR2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcywKICAgIC8vICAgICBhc3NldF9hbW91bnQ9IFVJbnQ2NCgwKSwKICAgIC8vICAgICBmZWU9MAogICAgLy8gKS5zdWJtaXQoKQogICAgaXR4bl9zdWJtaXQKICAgIHJldHN1YgoKCi8vIHNtYXJ0X2NvbnRyYWN0cy5kaWdpdGFsX21hcmtldHBsYWNlLmNvbnRyYWN0LkRpZ2l0YWxNYXJrZXRwbGFjZS5idXkoYnV5ZXJfdHhuOiB1aW50NjQsIHF1YW50aXR5OiB1aW50NjQpIC0+IHZvaWQ6CmJ1eToKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjE1MC0xNTUKICAgIC8vIEBhcmM0LmFiaW1ldGhvZAogICAgLy8gZGVmIGJ1eSgKICAgIC8vICAgICBzZWxmLAogICAgLy8gICAgIGJ1eWVyX3R4bjogZ3R4bi5QYXltZW50VHJhbnNhY3Rpb24sCiAgICAvLyAgICAgcXVhbnRpdHk6IFVJbnQ2NCwKICAgIC8vICkgLT4gTm9uZToKICAgIHByb3RvIDIgMAogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTU2LTE1NwogICAgLy8gIyDrrLjsoJwgNCDsi5zsnpEKICAgIC8vIGFzc2VydCBzZWxmLnVuaXRhcnlfcHJpY2UudmFsdWUgIT0gVUludDY0KDApLCAiVW5pdGFyeSBwcmljZSBpcyBub3Qgc2V0LiIKICAgIGludCAwCiAgICBieXRlICJ1bml0YXJ5X3ByaWNlIgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayB1bml0YXJ5X3ByaWNlIGV4aXN0cwogICAgYXNzZXJ0IC8vIFVuaXRhcnkgcHJpY2UgaXMgbm90IHNldC4KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjE1OAogICAgLy8gYXNzZXJ0IGJ1eWVyX3R4bi5zZW5kZXIgPT0gVHhuLnNlbmRlciwgIlBheW1lbnQgdHJhbnNhY3Rpb24gc2VuZGVyIG11c3QgYmUgdGhlIGNhbGxlci4iCiAgICBmcmFtZV9kaWcgLTIKICAgIGd0eG5zIFNlbmRlcgogICAgdHhuIFNlbmRlcgogICAgPT0KICAgIGFzc2VydCAvLyBQYXltZW50IHRyYW5zYWN0aW9uIHNlbmRlciBtdXN0IGJlIHRoZSBjYWxsZXIuCiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxNTkKICAgIC8vIGFzc2VydCBidXllcl90eG4ucmVjZWl2ZXIgPT0gR2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcywgIlJlY2VpdmVyIG11c3QgYmUgdGhpcyBhcHAuIgogICAgZnJhbWVfZGlnIC0yCiAgICBndHhucyBSZWNlaXZlcgogICAgZ2xvYmFsIEN1cnJlbnRBcHBsaWNhdGlvbkFkZHJlc3MKICAgID09CiAgICBhc3NlcnQgLy8gUmVjZWl2ZXIgbXVzdCBiZSB0aGlzIGFwcC4KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjE2MAogICAgLy8gYXNzZXJ0IGJ1eWVyX3R4bi5hbW91bnQgPT0gc2VsZi51bml0YXJ5X3ByaWNlLnZhbHVlICogcXVhbnRpdHksICJJbmNvcnJlY3QgcGF5bWVudCBhbW91bnQuIgogICAgZnJhbWVfZGlnIC0yCiAgICBndHhucyBBbW91bnQKICAgIGludCAwCiAgICBieXRlICJ1bml0YXJ5X3ByaWNlIgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayB1bml0YXJ5X3ByaWNlIGV4aXN0cwogICAgZnJhbWVfZGlnIC0xCiAgICAqCiAgICA9PQogICAgYXNzZXJ0IC8vIEluY29ycmVjdCBwYXltZW50IGFtb3VudC4KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjE2Mi0xNjgKICAgIC8vIGl0eG4uQXNzZXRUcmFuc2ZlcigKICAgIC8vICAgICB4ZmVyX2Fzc2V0ID0gc2VsZi5hc3NldF9pZC52YWx1ZSwKICAgIC8vICAgICBhc3NldF9yZWNlaXZlcj0gVHhuLnNlbmRlciwKICAgIC8vICAgICBhc3NldF9zZW5kZXI9IEdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2FkZHJlc3MsCiAgICAvLyAgICAgYXNzZXRfYW1vdW50PSBxdWFudGl0eSwKICAgIC8vICAgICBmZWU9MAogICAgLy8gKS5zdWJtaXQoKQogICAgaXR4bl9iZWdpbgogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTYzCiAgICAvLyB4ZmVyX2Fzc2V0ID0gc2VsZi5hc3NldF9pZC52YWx1ZSwKICAgIGludCAwCiAgICBieXRlICJhc3NldF9pZCIKICAgIGFwcF9nbG9iYWxfZ2V0X2V4CiAgICBhc3NlcnQgLy8gY2hlY2sgYXNzZXRfaWQgZXhpc3RzCiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxNjQKICAgIC8vIGFzc2V0X3JlY2VpdmVyPSBUeG4uc2VuZGVyLAogICAgdHhuIFNlbmRlcgogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTY1CiAgICAvLyBhc3NldF9zZW5kZXI9IEdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2FkZHJlc3MsCiAgICBnbG9iYWwgQ3VycmVudEFwcGxpY2F0aW9uQWRkcmVzcwogICAgZnJhbWVfZGlnIC0xCiAgICBpdHhuX2ZpZWxkIEFzc2V0QW1vdW50CiAgICBpdHhuX2ZpZWxkIEFzc2V0U2VuZGVyCiAgICBpdHhuX2ZpZWxkIEFzc2V0UmVjZWl2ZXIKICAgIGl0eG5fZmllbGQgWGZlckFzc2V0CiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxNjIKICAgIC8vIGl0eG4uQXNzZXRUcmFuc2ZlcigKICAgIGludCBheGZlcgogICAgaXR4bl9maWVsZCBUeXBlRW51bQogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTY3CiAgICAvLyBmZWU9MAogICAgaW50IDAKICAgIGl0eG5fZmllbGQgRmVlCiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxNjItMTY4CiAgICAvLyBpdHhuLkFzc2V0VHJhbnNmZXIoCiAgICAvLyAgICAgeGZlcl9hc3NldCA9IHNlbGYuYXNzZXRfaWQudmFsdWUsCiAgICAvLyAgICAgYXNzZXRfcmVjZWl2ZXI9IFR4bi5zZW5kZXIsCiAgICAvLyAgICAgYXNzZXRfc2VuZGVyPSBHbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzLAogICAgLy8gICAgIGFzc2V0X2Ftb3VudD0gcXVhbnRpdHksCiAgICAvLyAgICAgZmVlPTAKICAgIC8vICkuc3VibWl0KCkKICAgIGl0eG5fc3VibWl0CiAgICByZXRzdWIKCgovLyBzbWFydF9jb250cmFjdHMuZGlnaXRhbF9tYXJrZXRwbGFjZS5jb250cmFjdC5EaWdpdGFsTWFya2V0cGxhY2Uud2l0aGRyYXdfYW5kX2RlbGV0ZSgpIC0+IHZvaWQ6CndpdGhkcmF3X2FuZF9kZWxldGU6CiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMDAtMjAyCiAgICAvLyAjIOusuOygnCA1IOyLnOyekQogICAgLy8gQGFyYzQuYWJpbWV0aG9kKGFsbG93X2FjdGlvbnM9WyJEZWxldGVBcHBsaWNhdGlvbiJdKQogICAgLy8gZGVmIHdpdGhkcmF3X2FuZF9kZWxldGUoc2VsZikgLT4gTm9uZToKICAgIHByb3RvIDAgMAogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjAzCiAgICAvLyBhc3NlcnQgVHhuLnNlbmRlciA9PSBHbG9iYWwuY3JlYXRvcl9hZGRyZXNzLCAiT25seSBjcmVhdG9yIGNhbiBvcHQgaW4gdG8gQVNBIgogICAgdHhuIFNlbmRlcgogICAgZ2xvYmFsIENyZWF0b3JBZGRyZXNzCiAgICA9PQogICAgYXNzZXJ0IC8vIE9ubHkgY3JlYXRvciBjYW4gb3B0IGluIHRvIEFTQQogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjA1LTIxMQogICAgLy8gaXR4bi5Bc3NldFRyYW5zZmVyKAogICAgLy8gICAgIHhmZXJfYXNzZXQgPSBzZWxmLmFzc2V0X2lkLnZhbHVlLAogICAgLy8gICAgIGFzc2V0X3JlY2VpdmVyID0gR2xvYmFsLmNyZWF0b3JfYWRkcmVzcywKICAgIC8vICAgICBhc3NldF9zZW5kZXIgPSBHbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzLAogICAgLy8gICAgIGFzc2V0X2Nsb3NlX3RvID0gR2xvYmFsLmNyZWF0b3JfYWRkcmVzcywKICAgIC8vICAgICBmZWU9MAogICAgLy8gKS5zdWJtaXQoKQogICAgaXR4bl9iZWdpbgogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjA2CiAgICAvLyB4ZmVyX2Fzc2V0ID0gc2VsZi5hc3NldF9pZC52YWx1ZSwKICAgIGludCAwCiAgICBieXRlICJhc3NldF9pZCIKICAgIGFwcF9nbG9iYWxfZ2V0X2V4CiAgICBhc3NlcnQgLy8gY2hlY2sgYXNzZXRfaWQgZXhpc3RzCiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMDcKICAgIC8vIGFzc2V0X3JlY2VpdmVyID0gR2xvYmFsLmNyZWF0b3JfYWRkcmVzcywKICAgIGdsb2JhbCBDcmVhdG9yQWRkcmVzcwogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjA4CiAgICAvLyBhc3NldF9zZW5kZXIgPSBHbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzLAogICAgZ2xvYmFsIEN1cnJlbnRBcHBsaWNhdGlvbkFkZHJlc3MKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIwOQogICAgLy8gYXNzZXRfY2xvc2VfdG8gPSBHbG9iYWwuY3JlYXRvcl9hZGRyZXNzLAogICAgZ2xvYmFsIENyZWF0b3JBZGRyZXNzCiAgICBpdHhuX2ZpZWxkIEFzc2V0Q2xvc2VUbwogICAgaXR4bl9maWVsZCBBc3NldFNlbmRlcgogICAgaXR4bl9maWVsZCBBc3NldFJlY2VpdmVyCiAgICBpdHhuX2ZpZWxkIFhmZXJBc3NldAogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjA1CiAgICAvLyBpdHhuLkFzc2V0VHJhbnNmZXIoCiAgICBpbnQgYXhmZXIKICAgIGl0eG5fZmllbGQgVHlwZUVudW0KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIxMAogICAgLy8gZmVlPTAKICAgIGludCAwCiAgICBpdHhuX2ZpZWxkIEZlZQogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjA1LTIxMQogICAgLy8gaXR4bi5Bc3NldFRyYW5zZmVyKAogICAgLy8gICAgIHhmZXJfYXNzZXQgPSBzZWxmLmFzc2V0X2lkLnZhbHVlLAogICAgLy8gICAgIGFzc2V0X3JlY2VpdmVyID0gR2xvYmFsLmNyZWF0b3JfYWRkcmVzcywKICAgIC8vICAgICBhc3NldF9zZW5kZXIgPSBHbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzLAogICAgLy8gICAgIGFzc2V0X2Nsb3NlX3RvID0gR2xvYmFsLmNyZWF0b3JfYWRkcmVzcywKICAgIC8vICAgICBmZWU9MAogICAgLy8gKS5zdWJtaXQoKQogICAgaXR4bl9zdWJtaXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIxMy0yMTgKICAgIC8vIGl0eG4uUGF5bWVudCgKICAgIC8vICAgICByZWNlaXZlciA9IEdsb2JhbC5jcmVhdG9yX2FkZHJlc3MsCiAgICAvLyAgICAgc2VuZGVyID0gR2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcywKICAgIC8vICAgICBjbG9zZV9yZW1haW5kZXJfdG8gPSBHbG9iYWwuY3JlYXRvcl9hZGRyZXNzLAogICAgLy8gICAgIGZlZT0wCiAgICAvLyApLnN1Ym1pdCgpCiAgICBpdHhuX2JlZ2luCiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMTQKICAgIC8vIHJlY2VpdmVyID0gR2xvYmFsLmNyZWF0b3JfYWRkcmVzcywKICAgIGdsb2JhbCBDcmVhdG9yQWRkcmVzcwogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjE1CiAgICAvLyBzZW5kZXIgPSBHbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzLAogICAgZ2xvYmFsIEN1cnJlbnRBcHBsaWNhdGlvbkFkZHJlc3MKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIxNgogICAgLy8gY2xvc2VfcmVtYWluZGVyX3RvID0gR2xvYmFsLmNyZWF0b3JfYWRkcmVzcywKICAgIGdsb2JhbCBDcmVhdG9yQWRkcmVzcwogICAgaXR4bl9maWVsZCBDbG9zZVJlbWFpbmRlclRvCiAgICBpdHhuX2ZpZWxkIFNlbmRlcgogICAgaXR4bl9maWVsZCBSZWNlaXZlcgogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjEzCiAgICAvLyBpdHhuLlBheW1lbnQoCiAgICBpbnQgcGF5CiAgICBpdHhuX2ZpZWxkIFR5cGVFbnVtCiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMTcKICAgIC8vIGZlZT0wCiAgICBpbnQgMAogICAgaXR4bl9maWVsZCBGZWUKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIxMy0yMTgKICAgIC8vIGl0eG4uUGF5bWVudCgKICAgIC8vICAgICByZWNlaXZlciA9IEdsb2JhbC5jcmVhdG9yX2FkZHJlc3MsCiAgICAvLyAgICAgc2VuZGVyID0gR2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcywKICAgIC8vICAgICBjbG9zZV9yZW1haW5kZXJfdG8gPSBHbG9iYWwuY3JlYXRvcl9hZGRyZXNzLAogICAgLy8gICAgIGZlZT0wCiAgICAvLyApLnN1Ym1pdCgpCiAgICBpdHhuX3N1Ym1pdAogICAgcmV0c3ViCgoKLy8gc21hcnRfY29udHJhY3RzLmRpZ2l0YWxfbWFya2V0cGxhY2UuY29udHJhY3QuRGlnaXRhbE1hcmtldHBsYWNlLl9faW5pdF9fKCkgLT4gdm9pZDoKX19pbml0X186CiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weTo0MAogICAgLy8gZGVmIF9faW5pdF9fKHNlbGYpIC0+IE5vbmU6CiAgICBwcm90byAwIDAKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjQxLTQyCiAgICAvLyAjIOusuOygnCAxIOyLnOyekQogICAgLy8gc2VsZi5hc3NldF9pZCA9IEdsb2JhbFN0YXRlKFVJbnQ2NCgwKSkKICAgIGJ5dGUgImFzc2V0X2lkIgogICAgaW50IDAKICAgIGFwcF9nbG9iYWxfcHV0CiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weTo0MwogICAgLy8gc2VsZi51bml0YXJ5X3ByaWNlID0gR2xvYmFsU3RhdGUoVUludDY0KDApKQogICAgYnl0ZSAidW5pdGFyeV9wcmljZSIKICAgIGludCAwCiAgICBhcHBfZ2xvYmFsX3B1dAogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6NDQKICAgIC8vIHNlbGYuYm9vdHN0cmFwcGVkID0gR2xvYmFsU3RhdGUoYm9vbChGYWxzZSkpCiAgICBieXRlICJib290c3RyYXBwZWQiCiAgICBpbnQgMAogICAgYXBwX2dsb2JhbF9wdXQKICAgIHJldHN1Ygo=", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDEwCgpzbWFydF9jb250cmFjdHMuZGlnaXRhbF9tYXJrZXRwbGFjZS5jb250cmFjdC5EaWdpdGFsTWFya2V0cGxhY2UuY2xlYXJfc3RhdGVfcHJvZ3JhbToKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIwCiAgICAvLyBjbGFzcyBEaWdpdGFsTWFya2V0cGxhY2UoYXJjNC5BUkM0Q29udHJhY3QpOgogICAgaW50IDEKICAgIHJldHVybgo=" + }, + "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": "DigitalMarketplace", + "desc": "\n \ubb38\uc81c 1\n DigitalMarketplace \uc571\uc774 \uae30\ub85d \ubc0f \uc720\uc9c0\ud560 \uc0c1\ud0dc\ub97c \uc815\uc758\ud558\uc138\uc694.\n\n DigitalMarketplace \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)\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)\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). 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, False\ub85c \ud45c\ud5cc\ud558\uba74 \ub418\uace0,\n 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 \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 \ud78c\ud2b8 1 - \uae00\ub85c\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": "set_price", + "args": [ + { + "type": "uint64", + "name": "unitary_price" + } + ], + "returns": { + "type": "void" + } + }, + { + "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" + } + } + ], + "networks": {} + }, + "bare_call_config": { + "no_op": "CREATE" + } +} \ No newline at end of file diff --git a/projects/coding-assignment/smart_contracts/artifacts/digital_marketplace/DigitalMarketplace.clear.teal b/projects/coding-assignment/smart_contracts/artifacts/digital_marketplace/DigitalMarketplace.clear.teal new file mode 100644 index 0000000..dc01f70 --- /dev/null +++ b/projects/coding-assignment/smart_contracts/artifacts/digital_marketplace/DigitalMarketplace.clear.teal @@ -0,0 +1,7 @@ +#pragma version 10 + +smart_contracts.digital_marketplace.contract.DigitalMarketplace.clear_state_program: + // smart_contracts/digital_marketplace/contract.py:20 + // class DigitalMarketplace(arc4.ARC4Contract): + int 1 + return diff --git a/projects/coding-assignment/smart_contracts/artifacts/digital_marketplace/client.ts b/projects/coding-assignment/smart_contracts/artifacts/digital_marketplace/client.ts new file mode 100644 index 0000000..6b1c860 --- /dev/null +++ b/projects/coding-assignment/smart_contracts/artifacts/digital_marketplace/client.ts @@ -0,0 +1,774 @@ +/* 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": { + "set_price(uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "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": "I3ByYWdtYSB2ZXJzaW9uIDEwCgpzbWFydF9jb250cmFjdHMuZGlnaXRhbF9tYXJrZXRwbGFjZS5jb250cmFjdC5EaWdpdGFsTWFya2V0cGxhY2UuYXBwcm92YWxfcHJvZ3JhbToKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBibnogbWFpbl9lbnRyeXBvaW50QDIKICAgIGNhbGxzdWIgX19pbml0X18KCm1haW5fZW50cnlwb2ludEAyOgogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjAKICAgIC8vIGNsYXNzIERpZ2l0YWxNYXJrZXRwbGFjZShhcmM0LkFSQzRDb250cmFjdCk6CiAgICB0eG4gTnVtQXBwQXJncwogICAgYnogbWFpbl9iYXJlX3JvdXRpbmdAMTAKICAgIG1ldGhvZCAic2V0X3ByaWNlKHVpbnQ2NCl2b2lkIgogICAgbWV0aG9kICJib290c3RyYXAoYXNzZXQsdWludDY0LHBheSl2b2lkIgogICAgbWV0aG9kICJidXkocGF5LHVpbnQ2NCl2b2lkIgogICAgbWV0aG9kICJ3aXRoZHJhd19hbmRfZGVsZXRlKCl2b2lkIgogICAgdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAogICAgbWF0Y2ggbWFpbl9zZXRfcHJpY2Vfcm91dGVANCBtYWluX2Jvb3RzdHJhcF9yb3V0ZUA1IG1haW5fYnV5X3JvdXRlQDYgbWFpbl93aXRoZHJhd19hbmRfZGVsZXRlX3JvdXRlQDcKICAgIGVyciAvLyByZWplY3QgdHJhbnNhY3Rpb24KCm1haW5fc2V0X3ByaWNlX3JvdXRlQDQ6CiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weTo2NAogICAgLy8gQGFyYzQuYWJpbWV0aG9kCiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gT25Db21wbGV0aW9uIGlzIE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gaXMgbm90IGNyZWF0aW5nCiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMAogICAgLy8gY2xhc3MgRGlnaXRhbE1hcmtldHBsYWNlKGFyYzQuQVJDNENvbnRyYWN0KToKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjY0CiAgICAvLyBAYXJjNC5hYmltZXRob2QKICAgIGNhbGxzdWIgc2V0X3ByaWNlCiAgICBpbnQgMQogICAgcmV0dXJuCgptYWluX2Jvb3RzdHJhcF9yb3V0ZUA1OgogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTAwCiAgICAvLyBAYXJjNC5hYmltZXRob2QKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgTm9PcAogICAgdHhuIEFwcGxpY2F0aW9uSUQKICAgIGFzc2VydCAvLyBpcyBub3QgY3JlYXRpbmcKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIwCiAgICAvLyBjbGFzcyBEaWdpdGFsTWFya2V0cGxhY2UoYXJjNC5BUkM0Q29udHJhY3QpOgogICAgdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQogICAgYnRvaQogICAgdHhuYXMgQXNzZXRzCiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAyCiAgICBidG9pCiAgICB0eG4gR3JvdXBJbmRleAogICAgaW50IDEKICAgIC0KICAgIGR1cAogICAgZ3R4bnMgVHlwZUVudW0KICAgIGludCBwYXkKICAgID09CiAgICBhc3NlcnQgLy8gdHJhbnNhY3Rpb24gdHlwZSBpcyBwYXkKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjEwMAogICAgLy8gQGFyYzQuYWJpbWV0aG9kCiAgICBjYWxsc3ViIGJvb3RzdHJhcAogICAgaW50IDEKICAgIHJldHVybgoKbWFpbl9idXlfcm91dGVANjoKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjE1MAogICAgLy8gQGFyYzQuYWJpbWV0aG9kCiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gT25Db21wbGV0aW9uIGlzIE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gaXMgbm90IGNyZWF0aW5nCiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMAogICAgLy8gY2xhc3MgRGlnaXRhbE1hcmtldHBsYWNlKGFyYzQuQVJDNENvbnRyYWN0KToKICAgIHR4biBHcm91cEluZGV4CiAgICBpbnQgMQogICAgLQogICAgZHVwCiAgICBndHhucyBUeXBlRW51bQogICAgaW50IHBheQogICAgPT0KICAgIGFzc2VydCAvLyB0cmFuc2FjdGlvbiB0eXBlIGlzIHBheQogICAgdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQogICAgYnRvaQogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTUwCiAgICAvLyBAYXJjNC5hYmltZXRob2QKICAgIGNhbGxzdWIgYnV5CiAgICBpbnQgMQogICAgcmV0dXJuCgptYWluX3dpdGhkcmF3X2FuZF9kZWxldGVfcm91dGVANzoKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIwMC0yMDEKICAgIC8vICMg66y47KCcIDUg7Iuc7J6RCiAgICAvLyBAYXJjNC5hYmltZXRob2QoYWxsb3dfYWN0aW9ucz1bIkRlbGV0ZUFwcGxpY2F0aW9uIl0pCiAgICB0eG4gT25Db21wbGV0aW9uCiAgICBpbnQgRGVsZXRlQXBwbGljYXRpb24KICAgID09CiAgICBhc3NlcnQgLy8gT25Db21wbGV0aW9uIGlzIERlbGV0ZUFwcGxpY2F0aW9uCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGlzIG5vdCBjcmVhdGluZwogICAgY2FsbHN1YiB3aXRoZHJhd19hbmRfZGVsZXRlCiAgICBpbnQgMQogICAgcmV0dXJuCgptYWluX2JhcmVfcm91dGluZ0AxMDoKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIwCiAgICAvLyBjbGFzcyBEaWdpdGFsTWFya2V0cGxhY2UoYXJjNC5BUkM0Q29udHJhY3QpOgogICAgdHhuIE9uQ29tcGxldGlvbgogICAgIQogICAgYXNzZXJ0IC8vIHJlamVjdCB0cmFuc2FjdGlvbgogICAgdHhuIEFwcGxpY2F0aW9uSUQKICAgICEKICAgIGFzc2VydCAvLyBpcyBjcmVhdGluZwogICAgaW50IDEKICAgIHJldHVybgoKCi8vIHNtYXJ0X2NvbnRyYWN0cy5kaWdpdGFsX21hcmtldHBsYWNlLmNvbnRyYWN0LkRpZ2l0YWxNYXJrZXRwbGFjZS5zZXRfcHJpY2UodW5pdGFyeV9wcmljZTogdWludDY0KSAtPiB2b2lkOgpzZXRfcHJpY2U6CiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weTo2NC02NQogICAgLy8gQGFyYzQuYWJpbWV0aG9kCiAgICAvLyBkZWYgc2V0X3ByaWNlKHNlbGYsIHVuaXRhcnlfcHJpY2U6IFVJbnQ2NCkgLT4gTm9uZToKICAgIHByb3RvIDEgMAogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6NjYtNjcKICAgIC8vICAjIOusuOygnCAyIOyLnOyekQogICAgLy8gYXNzZXJ0IFR4bi5zZW5kZXIgPT0gR2xvYmFsLmNyZWF0b3JfYWRkcmVzcywgIk9ubHkgY3JlYXRvciBjYW4gb3B0IGluIHRvIEFTQSIKICAgIHR4biBTZW5kZXIKICAgIGdsb2JhbCBDcmVhdG9yQWRkcmVzcwogICAgPT0KICAgIGFzc2VydCAvLyBPbmx5IGNyZWF0b3IgY2FuIG9wdCBpbiB0byBBU0EKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjY4CiAgICAvLyBhc3NlcnQgc2VsZi5ib290c3RyYXBwZWQudmFsdWUgPT0gVHJ1ZSwgIkFwcCBNdXN0IGJlIGJvb3RzdHJhcHBlZCIKICAgIGludCAwCiAgICBieXRlICJib290c3RyYXBwZWQiCiAgICBhcHBfZ2xvYmFsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIGJvb3RzdHJhcHBlZCBleGlzdHMKICAgIGludCAxCiAgICA9PQogICAgYXNzZXJ0IC8vIEFwcCBNdXN0IGJlIGJvb3RzdHJhcHBlZAogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6NjkKICAgIC8vIHNlbGYudW5pdGFyeV9wcmljZS52YWx1ZSA9IHVuaXRhcnlfcHJpY2UKICAgIGJ5dGUgInVuaXRhcnlfcHJpY2UiCiAgICBmcmFtZV9kaWcgLTEKICAgIGFwcF9nbG9iYWxfcHV0CiAgICByZXRzdWIKCgovLyBzbWFydF9jb250cmFjdHMuZGlnaXRhbF9tYXJrZXRwbGFjZS5jb250cmFjdC5EaWdpdGFsTWFya2V0cGxhY2UuYm9vdHN0cmFwKGFzc2V0OiB1aW50NjQsIHVuaXRhcnlfcHJpY2U6IHVpbnQ2NCwgbWJyX3BheTogdWludDY0KSAtPiB2b2lkOgpib290c3RyYXA6CiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxMDAtMTAzCiAgICAvLyBAYXJjNC5hYmltZXRob2QKICAgIC8vIGRlZiBib290c3RyYXAoCiAgICAvLyAgICAgc2VsZiwgYXNzZXQ6IEFzc2V0LCB1bml0YXJ5X3ByaWNlOiBVSW50NjQsIG1icl9wYXk6IGd0eG4uUGF5bWVudFRyYW5zYWN0aW9uCiAgICAvLyApIC0+IE5vbmU6CiAgICBwcm90byAzIDAKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjEwNC0xMDUKICAgIC8vICMg66y47KCcIDMg7Iuc7J6RCiAgICAvLyBhc3NlcnQgVHhuLnNlbmRlciA9PSBHbG9iYWwuY3JlYXRvcl9hZGRyZXNzLCAiT25seSBjcmVhdG9yIGNhbiBvcHQgaW4gdG8gQVNBIgogICAgdHhuIFNlbmRlcgogICAgZ2xvYmFsIENyZWF0b3JBZGRyZXNzCiAgICA9PQogICAgYXNzZXJ0IC8vIE9ubHkgY3JlYXRvciBjYW4gb3B0IGluIHRvIEFTQQogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTA2CiAgICAvLyBhc3NlcnQgc2VsZi5ib290c3RyYXBwZWQudmFsdWUgPT0gRmFsc2UsICAiQXBwIGlzIGFscmVhZHkgYm9vdHN0cmFwcGVkLiIKICAgIGludCAwCiAgICBieXRlICJib290c3RyYXBwZWQiCiAgICBhcHBfZ2xvYmFsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIGJvb3RzdHJhcHBlZCBleGlzdHMKICAgICEKICAgIGFzc2VydCAvLyBBcHAgaXMgYWxyZWFkeSBib290c3RyYXBwZWQuCiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxMDcKICAgIC8vIGFzc2VydCBtYnJfcGF5LnJlY2VpdmVyID09IEdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2FkZHJlc3MsICJyZWNlaXZlciBtdXN0IGJlIHRoZSBjb250cmFjdCBhZGRyZXNzIgogICAgZnJhbWVfZGlnIC0xCiAgICBndHhucyBSZWNlaXZlcgogICAgZ2xvYmFsIEN1cnJlbnRBcHBsaWNhdGlvbkFkZHJlc3MKICAgID09CiAgICBhc3NlcnQgLy8gcmVjZWl2ZXIgbXVzdCBiZSB0aGUgY29udHJhY3QgYWRkcmVzcwogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTA4CiAgICAvLyBhc3NlcnQgbWJyX3BheS5hbW91bnQgPT0gKEdsb2JhbC5taW5fYmFsYW5jZSArIEdsb2JhbC5hc3NldF9vcHRfaW5fbWluX2JhbGFuY2UpLCAiSW5jb3JyZWN0IGZ1bmRpbmcgYW1vdW50LiIKICAgIGZyYW1lX2RpZyAtMQogICAgZ3R4bnMgQW1vdW50CiAgICBnbG9iYWwgTWluQmFsYW5jZQogICAgZ2xvYmFsIEFzc2V0T3B0SW5NaW5CYWxhbmNlCiAgICArCiAgICA9PQogICAgYXNzZXJ0IC8vIEluY29ycmVjdCBmdW5kaW5nIGFtb3VudC4KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjExMAogICAgLy8gc2VsZi5hc3NldF9pZC52YWx1ZSA9IChhc3NldC5pZCkKICAgIGJ5dGUgImFzc2V0X2lkIgogICAgZnJhbWVfZGlnIC0zCiAgICBhcHBfZ2xvYmFsX3B1dAogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTExCiAgICAvLyBzZWxmLnVuaXRhcnlfcHJpY2UudmFsdWUgPSAodW5pdGFyeV9wcmljZSkKICAgIGJ5dGUgInVuaXRhcnlfcHJpY2UiCiAgICBmcmFtZV9kaWcgLTIKICAgIGFwcF9nbG9iYWxfcHV0CiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxMTIKICAgIC8vIHNlbGYuYm9vdHN0cmFwcGVkLnZhbHVlID0gKFRydWUpCiAgICBieXRlICJib290c3RyYXBwZWQiCiAgICBpbnQgMQogICAgYXBwX2dsb2JhbF9wdXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjExNC0xMjAKICAgIC8vIGl0eG4uQXNzZXRUcmFuc2ZlcigKICAgIC8vICAgICB4ZmVyX2Fzc2V0ID0gc2VsZi5hc3NldF9pZC52YWx1ZSwKICAgIC8vICAgICBhc3NldF9yZWNlaXZlcj0gVHhuLnNlbmRlciwKICAgIC8vICAgICBhc3NldF9zZW5kZXI9IEdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2FkZHJlc3MsCiAgICAvLyAgICAgYXNzZXRfYW1vdW50PSBVSW50NjQoMCksCiAgICAvLyAgICAgZmVlPTAKICAgIC8vICkuc3VibWl0KCkKICAgIGl0eG5fYmVnaW4KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjExNQogICAgLy8geGZlcl9hc3NldCA9IHNlbGYuYXNzZXRfaWQudmFsdWUsCiAgICBpbnQgMAogICAgYnl0ZSAiYXNzZXRfaWQiCiAgICBhcHBfZ2xvYmFsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIGFzc2V0X2lkIGV4aXN0cwogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTE2CiAgICAvLyBhc3NldF9yZWNlaXZlcj0gVHhuLnNlbmRlciwKICAgIHR4biBTZW5kZXIKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjExNwogICAgLy8gYXNzZXRfc2VuZGVyPSBHbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzLAogICAgZ2xvYmFsIEN1cnJlbnRBcHBsaWNhdGlvbkFkZHJlc3MKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjExOAogICAgLy8gYXNzZXRfYW1vdW50PSBVSW50NjQoMCksCiAgICBpbnQgMAogICAgaXR4bl9maWVsZCBBc3NldEFtb3VudAogICAgaXR4bl9maWVsZCBBc3NldFNlbmRlcgogICAgaXR4bl9maWVsZCBBc3NldFJlY2VpdmVyCiAgICBpdHhuX2ZpZWxkIFhmZXJBc3NldAogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTE0CiAgICAvLyBpdHhuLkFzc2V0VHJhbnNmZXIoCiAgICBpbnQgYXhmZXIKICAgIGl0eG5fZmllbGQgVHlwZUVudW0KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjExOQogICAgLy8gZmVlPTAKICAgIGludCAwCiAgICBpdHhuX2ZpZWxkIEZlZQogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTE0LTEyMAogICAgLy8gaXR4bi5Bc3NldFRyYW5zZmVyKAogICAgLy8gICAgIHhmZXJfYXNzZXQgPSBzZWxmLmFzc2V0X2lkLnZhbHVlLAogICAgLy8gICAgIGFzc2V0X3JlY2VpdmVyPSBUeG4uc2VuZGVyLAogICAgLy8gICAgIGFzc2V0X3NlbmRlcj0gR2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcywKICAgIC8vICAgICBhc3NldF9hbW91bnQ9IFVJbnQ2NCgwKSwKICAgIC8vICAgICBmZWU9MAogICAgLy8gKS5zdWJtaXQoKQogICAgaXR4bl9zdWJtaXQKICAgIHJldHN1YgoKCi8vIHNtYXJ0X2NvbnRyYWN0cy5kaWdpdGFsX21hcmtldHBsYWNlLmNvbnRyYWN0LkRpZ2l0YWxNYXJrZXRwbGFjZS5idXkoYnV5ZXJfdHhuOiB1aW50NjQsIHF1YW50aXR5OiB1aW50NjQpIC0+IHZvaWQ6CmJ1eToKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjE1MC0xNTUKICAgIC8vIEBhcmM0LmFiaW1ldGhvZAogICAgLy8gZGVmIGJ1eSgKICAgIC8vICAgICBzZWxmLAogICAgLy8gICAgIGJ1eWVyX3R4bjogZ3R4bi5QYXltZW50VHJhbnNhY3Rpb24sCiAgICAvLyAgICAgcXVhbnRpdHk6IFVJbnQ2NCwKICAgIC8vICkgLT4gTm9uZToKICAgIHByb3RvIDIgMAogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTU2LTE1NwogICAgLy8gIyDrrLjsoJwgNCDsi5zsnpEKICAgIC8vIGFzc2VydCBzZWxmLnVuaXRhcnlfcHJpY2UudmFsdWUgIT0gVUludDY0KDApLCAiVW5pdGFyeSBwcmljZSBpcyBub3Qgc2V0LiIKICAgIGludCAwCiAgICBieXRlICJ1bml0YXJ5X3ByaWNlIgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayB1bml0YXJ5X3ByaWNlIGV4aXN0cwogICAgYXNzZXJ0IC8vIFVuaXRhcnkgcHJpY2UgaXMgbm90IHNldC4KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjE1OAogICAgLy8gYXNzZXJ0IGJ1eWVyX3R4bi5zZW5kZXIgPT0gVHhuLnNlbmRlciwgIlBheW1lbnQgdHJhbnNhY3Rpb24gc2VuZGVyIG11c3QgYmUgdGhlIGNhbGxlci4iCiAgICBmcmFtZV9kaWcgLTIKICAgIGd0eG5zIFNlbmRlcgogICAgdHhuIFNlbmRlcgogICAgPT0KICAgIGFzc2VydCAvLyBQYXltZW50IHRyYW5zYWN0aW9uIHNlbmRlciBtdXN0IGJlIHRoZSBjYWxsZXIuCiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxNTkKICAgIC8vIGFzc2VydCBidXllcl90eG4ucmVjZWl2ZXIgPT0gR2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcywgIlJlY2VpdmVyIG11c3QgYmUgdGhpcyBhcHAuIgogICAgZnJhbWVfZGlnIC0yCiAgICBndHhucyBSZWNlaXZlcgogICAgZ2xvYmFsIEN1cnJlbnRBcHBsaWNhdGlvbkFkZHJlc3MKICAgID09CiAgICBhc3NlcnQgLy8gUmVjZWl2ZXIgbXVzdCBiZSB0aGlzIGFwcC4KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjE2MAogICAgLy8gYXNzZXJ0IGJ1eWVyX3R4bi5hbW91bnQgPT0gc2VsZi51bml0YXJ5X3ByaWNlLnZhbHVlICogcXVhbnRpdHksICJJbmNvcnJlY3QgcGF5bWVudCBhbW91bnQuIgogICAgZnJhbWVfZGlnIC0yCiAgICBndHhucyBBbW91bnQKICAgIGludCAwCiAgICBieXRlICJ1bml0YXJ5X3ByaWNlIgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayB1bml0YXJ5X3ByaWNlIGV4aXN0cwogICAgZnJhbWVfZGlnIC0xCiAgICAqCiAgICA9PQogICAgYXNzZXJ0IC8vIEluY29ycmVjdCBwYXltZW50IGFtb3VudC4KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjE2Mi0xNjgKICAgIC8vIGl0eG4uQXNzZXRUcmFuc2ZlcigKICAgIC8vICAgICB4ZmVyX2Fzc2V0ID0gc2VsZi5hc3NldF9pZC52YWx1ZSwKICAgIC8vICAgICBhc3NldF9yZWNlaXZlcj0gVHhuLnNlbmRlciwKICAgIC8vICAgICBhc3NldF9zZW5kZXI9IEdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2FkZHJlc3MsCiAgICAvLyAgICAgYXNzZXRfYW1vdW50PSBxdWFudGl0eSwKICAgIC8vICAgICBmZWU9MAogICAgLy8gKS5zdWJtaXQoKQogICAgaXR4bl9iZWdpbgogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTYzCiAgICAvLyB4ZmVyX2Fzc2V0ID0gc2VsZi5hc3NldF9pZC52YWx1ZSwKICAgIGludCAwCiAgICBieXRlICJhc3NldF9pZCIKICAgIGFwcF9nbG9iYWxfZ2V0X2V4CiAgICBhc3NlcnQgLy8gY2hlY2sgYXNzZXRfaWQgZXhpc3RzCiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxNjQKICAgIC8vIGFzc2V0X3JlY2VpdmVyPSBUeG4uc2VuZGVyLAogICAgdHhuIFNlbmRlcgogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTY1CiAgICAvLyBhc3NldF9zZW5kZXI9IEdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2FkZHJlc3MsCiAgICBnbG9iYWwgQ3VycmVudEFwcGxpY2F0aW9uQWRkcmVzcwogICAgZnJhbWVfZGlnIC0xCiAgICBpdHhuX2ZpZWxkIEFzc2V0QW1vdW50CiAgICBpdHhuX2ZpZWxkIEFzc2V0U2VuZGVyCiAgICBpdHhuX2ZpZWxkIEFzc2V0UmVjZWl2ZXIKICAgIGl0eG5fZmllbGQgWGZlckFzc2V0CiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxNjIKICAgIC8vIGl0eG4uQXNzZXRUcmFuc2ZlcigKICAgIGludCBheGZlcgogICAgaXR4bl9maWVsZCBUeXBlRW51bQogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MTY3CiAgICAvLyBmZWU9MAogICAgaW50IDAKICAgIGl0eG5fZmllbGQgRmVlCiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToxNjItMTY4CiAgICAvLyBpdHhuLkFzc2V0VHJhbnNmZXIoCiAgICAvLyAgICAgeGZlcl9hc3NldCA9IHNlbGYuYXNzZXRfaWQudmFsdWUsCiAgICAvLyAgICAgYXNzZXRfcmVjZWl2ZXI9IFR4bi5zZW5kZXIsCiAgICAvLyAgICAgYXNzZXRfc2VuZGVyPSBHbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzLAogICAgLy8gICAgIGFzc2V0X2Ftb3VudD0gcXVhbnRpdHksCiAgICAvLyAgICAgZmVlPTAKICAgIC8vICkuc3VibWl0KCkKICAgIGl0eG5fc3VibWl0CiAgICByZXRzdWIKCgovLyBzbWFydF9jb250cmFjdHMuZGlnaXRhbF9tYXJrZXRwbGFjZS5jb250cmFjdC5EaWdpdGFsTWFya2V0cGxhY2Uud2l0aGRyYXdfYW5kX2RlbGV0ZSgpIC0+IHZvaWQ6CndpdGhkcmF3X2FuZF9kZWxldGU6CiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMDAtMjAyCiAgICAvLyAjIOusuOygnCA1IOyLnOyekQogICAgLy8gQGFyYzQuYWJpbWV0aG9kKGFsbG93X2FjdGlvbnM9WyJEZWxldGVBcHBsaWNhdGlvbiJdKQogICAgLy8gZGVmIHdpdGhkcmF3X2FuZF9kZWxldGUoc2VsZikgLT4gTm9uZToKICAgIHByb3RvIDAgMAogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjAzCiAgICAvLyBhc3NlcnQgVHhuLnNlbmRlciA9PSBHbG9iYWwuY3JlYXRvcl9hZGRyZXNzLCAiT25seSBjcmVhdG9yIGNhbiBvcHQgaW4gdG8gQVNBIgogICAgdHhuIFNlbmRlcgogICAgZ2xvYmFsIENyZWF0b3JBZGRyZXNzCiAgICA9PQogICAgYXNzZXJ0IC8vIE9ubHkgY3JlYXRvciBjYW4gb3B0IGluIHRvIEFTQQogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjA1LTIxMQogICAgLy8gaXR4bi5Bc3NldFRyYW5zZmVyKAogICAgLy8gICAgIHhmZXJfYXNzZXQgPSBzZWxmLmFzc2V0X2lkLnZhbHVlLAogICAgLy8gICAgIGFzc2V0X3JlY2VpdmVyID0gR2xvYmFsLmNyZWF0b3JfYWRkcmVzcywKICAgIC8vICAgICBhc3NldF9zZW5kZXIgPSBHbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzLAogICAgLy8gICAgIGFzc2V0X2Nsb3NlX3RvID0gR2xvYmFsLmNyZWF0b3JfYWRkcmVzcywKICAgIC8vICAgICBmZWU9MAogICAgLy8gKS5zdWJtaXQoKQogICAgaXR4bl9iZWdpbgogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjA2CiAgICAvLyB4ZmVyX2Fzc2V0ID0gc2VsZi5hc3NldF9pZC52YWx1ZSwKICAgIGludCAwCiAgICBieXRlICJhc3NldF9pZCIKICAgIGFwcF9nbG9iYWxfZ2V0X2V4CiAgICBhc3NlcnQgLy8gY2hlY2sgYXNzZXRfaWQgZXhpc3RzCiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMDcKICAgIC8vIGFzc2V0X3JlY2VpdmVyID0gR2xvYmFsLmNyZWF0b3JfYWRkcmVzcywKICAgIGdsb2JhbCBDcmVhdG9yQWRkcmVzcwogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjA4CiAgICAvLyBhc3NldF9zZW5kZXIgPSBHbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzLAogICAgZ2xvYmFsIEN1cnJlbnRBcHBsaWNhdGlvbkFkZHJlc3MKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIwOQogICAgLy8gYXNzZXRfY2xvc2VfdG8gPSBHbG9iYWwuY3JlYXRvcl9hZGRyZXNzLAogICAgZ2xvYmFsIENyZWF0b3JBZGRyZXNzCiAgICBpdHhuX2ZpZWxkIEFzc2V0Q2xvc2VUbwogICAgaXR4bl9maWVsZCBBc3NldFNlbmRlcgogICAgaXR4bl9maWVsZCBBc3NldFJlY2VpdmVyCiAgICBpdHhuX2ZpZWxkIFhmZXJBc3NldAogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjA1CiAgICAvLyBpdHhuLkFzc2V0VHJhbnNmZXIoCiAgICBpbnQgYXhmZXIKICAgIGl0eG5fZmllbGQgVHlwZUVudW0KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIxMAogICAgLy8gZmVlPTAKICAgIGludCAwCiAgICBpdHhuX2ZpZWxkIEZlZQogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjA1LTIxMQogICAgLy8gaXR4bi5Bc3NldFRyYW5zZmVyKAogICAgLy8gICAgIHhmZXJfYXNzZXQgPSBzZWxmLmFzc2V0X2lkLnZhbHVlLAogICAgLy8gICAgIGFzc2V0X3JlY2VpdmVyID0gR2xvYmFsLmNyZWF0b3JfYWRkcmVzcywKICAgIC8vICAgICBhc3NldF9zZW5kZXIgPSBHbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzLAogICAgLy8gICAgIGFzc2V0X2Nsb3NlX3RvID0gR2xvYmFsLmNyZWF0b3JfYWRkcmVzcywKICAgIC8vICAgICBmZWU9MAogICAgLy8gKS5zdWJtaXQoKQogICAgaXR4bl9zdWJtaXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIxMy0yMTgKICAgIC8vIGl0eG4uUGF5bWVudCgKICAgIC8vICAgICByZWNlaXZlciA9IEdsb2JhbC5jcmVhdG9yX2FkZHJlc3MsCiAgICAvLyAgICAgc2VuZGVyID0gR2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcywKICAgIC8vICAgICBjbG9zZV9yZW1haW5kZXJfdG8gPSBHbG9iYWwuY3JlYXRvcl9hZGRyZXNzLAogICAgLy8gICAgIGZlZT0wCiAgICAvLyApLnN1Ym1pdCgpCiAgICBpdHhuX2JlZ2luCiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMTQKICAgIC8vIHJlY2VpdmVyID0gR2xvYmFsLmNyZWF0b3JfYWRkcmVzcywKICAgIGdsb2JhbCBDcmVhdG9yQWRkcmVzcwogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjE1CiAgICAvLyBzZW5kZXIgPSBHbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzLAogICAgZ2xvYmFsIEN1cnJlbnRBcHBsaWNhdGlvbkFkZHJlc3MKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIxNgogICAgLy8gY2xvc2VfcmVtYWluZGVyX3RvID0gR2xvYmFsLmNyZWF0b3JfYWRkcmVzcywKICAgIGdsb2JhbCBDcmVhdG9yQWRkcmVzcwogICAgaXR4bl9maWVsZCBDbG9zZVJlbWFpbmRlclRvCiAgICBpdHhuX2ZpZWxkIFNlbmRlcgogICAgaXR4bl9maWVsZCBSZWNlaXZlcgogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6MjEzCiAgICAvLyBpdHhuLlBheW1lbnQoCiAgICBpbnQgcGF5CiAgICBpdHhuX2ZpZWxkIFR5cGVFbnVtCiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weToyMTcKICAgIC8vIGZlZT0wCiAgICBpbnQgMAogICAgaXR4bl9maWVsZCBGZWUKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIxMy0yMTgKICAgIC8vIGl0eG4uUGF5bWVudCgKICAgIC8vICAgICByZWNlaXZlciA9IEdsb2JhbC5jcmVhdG9yX2FkZHJlc3MsCiAgICAvLyAgICAgc2VuZGVyID0gR2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcywKICAgIC8vICAgICBjbG9zZV9yZW1haW5kZXJfdG8gPSBHbG9iYWwuY3JlYXRvcl9hZGRyZXNzLAogICAgLy8gICAgIGZlZT0wCiAgICAvLyApLnN1Ym1pdCgpCiAgICBpdHhuX3N1Ym1pdAogICAgcmV0c3ViCgoKLy8gc21hcnRfY29udHJhY3RzLmRpZ2l0YWxfbWFya2V0cGxhY2UuY29udHJhY3QuRGlnaXRhbE1hcmtldHBsYWNlLl9faW5pdF9fKCkgLT4gdm9pZDoKX19pbml0X186CiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weTo0MAogICAgLy8gZGVmIF9faW5pdF9fKHNlbGYpIC0+IE5vbmU6CiAgICBwcm90byAwIDAKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjQxLTQyCiAgICAvLyAjIOusuOygnCAxIOyLnOyekQogICAgLy8gc2VsZi5hc3NldF9pZCA9IEdsb2JhbFN0YXRlKFVJbnQ2NCgwKSkKICAgIGJ5dGUgImFzc2V0X2lkIgogICAgaW50IDAKICAgIGFwcF9nbG9iYWxfcHV0CiAgICAvLyBzbWFydF9jb250cmFjdHMvZGlnaXRhbF9tYXJrZXRwbGFjZS9jb250cmFjdC5weTo0MwogICAgLy8gc2VsZi51bml0YXJ5X3ByaWNlID0gR2xvYmFsU3RhdGUoVUludDY0KDApKQogICAgYnl0ZSAidW5pdGFyeV9wcmljZSIKICAgIGludCAwCiAgICBhcHBfZ2xvYmFsX3B1dAogICAgLy8gc21hcnRfY29udHJhY3RzL2RpZ2l0YWxfbWFya2V0cGxhY2UvY29udHJhY3QucHk6NDQKICAgIC8vIHNlbGYuYm9vdHN0cmFwcGVkID0gR2xvYmFsU3RhdGUoYm9vbChGYWxzZSkpCiAgICBieXRlICJib290c3RyYXBwZWQiCiAgICBpbnQgMAogICAgYXBwX2dsb2JhbF9wdXQKICAgIHJldHN1Ygo=", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDEwCgpzbWFydF9jb250cmFjdHMuZGlnaXRhbF9tYXJrZXRwbGFjZS5jb250cmFjdC5EaWdpdGFsTWFya2V0cGxhY2UuY2xlYXJfc3RhdGVfcHJvZ3JhbToKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9kaWdpdGFsX21hcmtldHBsYWNlL2NvbnRyYWN0LnB5OjIwCiAgICAvLyBjbGFzcyBEaWdpdGFsTWFya2V0cGxhY2UoYXJjNC5BUkM0Q29udHJhY3QpOgogICAgaW50IDEKICAgIHJldHVybgo=" + }, + "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": "DigitalMarketplace", + "desc": "\n 문제 1\n DigitalMarketplace 앱이 기록 및 유지할 상태를 정의하세요.\n\n DigitalMarketplace 앱은 세개의 상태를 가지고 있습니다.\n 1. asset_id: 판매할 에셋(ASA)의 아이디; UInt64타입을 가진 글로벌 상태(Global State)\n 2. unitary_price: 판매할 에셋(ASA)의 가격. UInt64타입을 가진 글로벌 상태(Global State)\n 3. bootstrapped: 앱에서 에셋을 판매할 준비가 되었는지 체크하는 bool 타입의 글로벌 상태(Global State). bootstrap 메서드가 실행되면 True로 변경됩니다.\n\n 재밌는 팩트!\n AVM은 Bytes 타입과 UInt64 타입만 지원합니다. 그래서 다른 타입을 사용하고 싶으면 보통 arc4타입을 사용합니다. 하지만\n Algorand Python에서는 bool, string 타입은 파이썬 코드와 동일하게 사용할 수 있습니다. 예를 들어 bool 타입은 True, False로 표헌하면 되고,\n string 타입은 \"Hello, World!\"와 같이 표현하면 됩니다. Algorand Python에서 데이터 타입을 사용하는 방법은 아래 링크를 참고해주세요.\n - arc4 타입: https://algorandfoundation.github.io/puya/lg-types.html#types\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": "set_price", + "args": [ + { + "type": "uint64", + "name": "unitary_price" + } + ], + "returns": { + "type": "void" + } + }, + { + "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" + } + } + ], + "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 DigitalMarketplace smart contract. + */ +export type DigitalMarketplace = { + /** + * Maps method signatures / names to their argument and return types. + */ + methods: + & Record<'set_price(uint64)void' | 'set_price', { + argsObj: { + unitaryPrice: bigint | number + } + argsTuple: [unitaryPrice: bigint | number] + returns: void + }> + & 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 DigitalMarketplaceSig = keyof DigitalMarketplace['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 DigitalMarketplace smart contract to the method's arguments in either tuple of struct form + */ +export type MethodArgs = DigitalMarketplace['methods'][TSignature]['argsObj' | 'argsTuple'] +/** + * Maps a method signature from the DigitalMarketplace smart contract to the method's return type + */ +export type MethodReturn = DigitalMarketplace['methods'][TSignature]['returns'] + +/** + * A factory for available 'create' calls + */ +export type DigitalMarketplaceCreateCalls = (typeof DigitalMarketplaceCallFactory)['create'] +/** + * Defines supported create methods for this smart contract + */ +export type DigitalMarketplaceCreateCallParams = + | (TypedCallParams & (OnCompleteNoOp)) +/** + * A factory for available 'delete' calls + */ +export type DigitalMarketplaceDeleteCalls = (typeof DigitalMarketplaceCallFactory)['delete'] +/** + * Defines supported delete methods for this smart contract + */ +export type DigitalMarketplaceDeleteCallParams = + | TypedCallParams<'withdraw_and_delete()void'> +/** + * Defines arguments required for the deploy method. + */ +export type DigitalMarketplaceDeployArgs = { + deployTimeParams?: TealTemplateParams + /** + * A delegate which takes a create call factory and returns the create call params for this smart contract + */ + createCall?: (callFactory: DigitalMarketplaceCreateCalls) => DigitalMarketplaceCreateCallParams + /** + * A delegate which takes a delete call factory and returns the delete call params for this smart contract + */ + deleteCall?: (callFactory: DigitalMarketplaceDeleteCalls) => DigitalMarketplaceDeleteCallParams +} + + +/** + * Exposes methods for constructing all available smart contract calls + */ +export abstract class DigitalMarketplaceCallFactory { + /** + * Gets available create call factories + */ + static get create() { + return { + /** + * Constructs a create call for the DigitalMarketplace 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 DigitalMarketplace 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 set_price(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 setPrice(args: MethodArgs<'set_price(uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'set_price(uint64)void' as const, + methodArgs: Array.isArray(args) ? args : [args.unitaryPrice], + ...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 DigitalMarketplace smart contract + */ +export class DigitalMarketplaceClient { + /** + * 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 `DigitalMarketplaceClient` + * + * @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 DigitalMarketplace smart contract. + * + * @param params The arguments for the contract calls and any additional parameters for the call + * @returns The deployment result + */ + public deploy(params: DigitalMarketplaceDeployArgs & AppClientDeployCoreParams & IncludeSchema = {}): ReturnType { + const createArgs = params.createCall?.(DigitalMarketplaceCallFactory.create) + const deleteArgs = params.deleteCall?.(DigitalMarketplaceCallFactory.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 DigitalMarketplace 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 DigitalMarketplace 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(DigitalMarketplaceCallFactory.delete.withdrawAndDelete(args, params))) + }, + } + } + + /** + * Makes a clear_state call to an existing instance of the DigitalMarketplace 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 set_price(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 setPrice(args: MethodArgs<'set_price(uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(DigitalMarketplaceCallFactory.setPrice(args, params)) + } + + /** + * 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(DigitalMarketplaceCallFactory.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(DigitalMarketplaceCallFactory.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 DigitalMarketplaceClient.getIntegerState(state, 'asset_id') + }, + get bootstrapped() { + return DigitalMarketplaceClient.getIntegerState(state, 'bootstrapped') + }, + get unitaryPrice() { + return DigitalMarketplaceClient.getIntegerState(state, 'unitary_price') + }, + } + } + + public compose(): DigitalMarketplaceComposer { + const client = this + const atc = new AtomicTransactionComposer() + let promiseChain:Promise = Promise.resolve() + const resultMappers: Array any)> = [] + return { + setPrice(args: MethodArgs<'set_price(uint64)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.setPrice(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + 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 DigitalMarketplaceComposer + } +} +export type DigitalMarketplaceComposer = { + /** + * Calls the set_price(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 + */ + setPrice(args: MethodArgs<'set_price(uint64)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): DigitalMarketplaceComposer<[...TReturns, MethodReturn<'set_price(uint64)void'>]> + + /** + * 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): DigitalMarketplaceComposer<[...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): DigitalMarketplaceComposer<[...TReturns, MethodReturn<'buy(pay,uint64)void'>]> + + /** + * Gets available delete methods + */ + readonly delete: { + /** + * Deletes an existing instance of the DigitalMarketplace 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): DigitalMarketplaceComposer<[...TReturns, MethodReturn<'withdraw_and_delete()void'>]> + } + + /** + * Makes a clear_state call to an existing instance of the DigitalMarketplace 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): DigitalMarketplaceComposer<[...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): DigitalMarketplaceComposer + /** + * 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 DigitalMarketplaceComposerSimulateResult = { + returns: TReturns + methodResults: ABIResult[] + simulateResponse: modelsv2.SimulateResponse +} +export type DigitalMarketplaceComposerResults = { + returns: TReturns + groupId: string + txIds: string[] + transactions: Transaction[] +} diff --git a/projects/coding-assignment/smart_contracts/digital_marketplace/contract.py b/projects/coding-assignment/smart_contracts/digital_marketplace/contract.py index 5dad29e..3e411b0 100644 --- a/projects/coding-assignment/smart_contracts/digital_marketplace/contract.py +++ b/projects/coding-assignment/smart_contracts/digital_marketplace/contract.py @@ -39,7 +39,9 @@ class DigitalMarketplace(arc4.ARC4Contract): def __init__(self) -> None: # 문제 1 시작 - "*** 여기에 코드 작성 ***" + self.asset_id = GlobalState(UInt64(0)) + self.unitary_price = GlobalState(UInt64(0)) + self.bootstrapped = GlobalState(bool(False)) # 문제 1 끝 """ @@ -62,7 +64,9 @@ def __init__(self) -> None: @arc4.abimethod def set_price(self, unitary_price: UInt64) -> None: # 문제 2 시작 - "*** 여기에 코드 작성 ***" + assert Txn.sender == Global.creator_address, "Only creator can opt in to ASA" + assert self.bootstrapped.value == True, "App Must be bootstrapped" + self.unitary_price.value = unitary_price # 문제 2 끝 """ @@ -98,9 +102,26 @@ def bootstrap( self, asset: Asset, unitary_price: UInt64, mbr_pay: gtxn.PaymentTransaction ) -> None: # 문제 3 시작 - "*** 여기에 코드 작성 ***" + assert Txn.sender == Global.creator_address, "Only creator can opt in to ASA" + assert self.bootstrapped.value == False, "App is already bootstrapped." + assert mbr_pay.receiver == Global.current_application_address, "receiver must be the contract address" + assert mbr_pay.amount == (Global.min_balance + Global.asset_opt_in_min_balance), "Incorrect funding amount." + + self.asset_id.value = (asset.id) + self.unitary_price.value = (unitary_price) + self.bootstrapped.value = (True) + + itxn.AssetTransfer( + xfer_asset = self.asset_id.value, + asset_receiver= Txn.sender, + asset_sender= Global.current_application_address, + asset_amount= UInt64(0), + fee=0 + ).submit() + # 문제 3 끝 + """ 문제 4 buy 메서드를 구현하세요. @@ -133,7 +154,19 @@ def buy( quantity: UInt64, ) -> None: # 문제 4 시작 - "*** 여기에 코드 작성 ***" + assert self.unitary_price.value != UInt64(0), "Unitary price is not set." + assert buyer_txn.sender == Txn.sender, "Payment transaction sender must be the caller." + assert buyer_txn.receiver == Global.current_application_address, "Receiver must be this app." + assert buyer_txn.amount == self.unitary_price.value * quantity, "Incorrect payment amount." + + itxn.AssetTransfer( + xfer_asset = self.asset_id.value, + asset_receiver= Txn.sender, + asset_sender= Global.current_application_address, + asset_amount= quantity, + fee=0 + ).submit() + # 문제 4 끝 """ @@ -165,5 +198,23 @@ def buy( 이번 문제는 함수 정의까지 다 구현해주세요! 함수 이름은 withdraw_and_delete로 해주세요. """ # 문제 5 시작 - "*** 여기에 코드 작성 ***" + @arc4.abimethod(allow_actions=["DeleteApplication"]) + def withdraw_and_delete(self) -> None: + assert Txn.sender == Global.creator_address, "Only creator can opt in to ASA" + + itxn.AssetTransfer( + xfer_asset = self.asset_id.value, + asset_receiver = Global.creator_address, + asset_sender = Global.current_application_address, + asset_close_to = Global.creator_address, + fee=0 + ).submit() + + itxn.Payment( + receiver = Global.creator_address, + sender = Global.current_application_address, + close_remainder_to = Global.creator_address, + fee=0 + ).submit() + # 문제 5 끝