diff --git a/projects/hackalgo-frontend/src/contracts/Algomint.ts b/projects/hackalgo-frontend/src/contracts/Algomint.ts new file mode 100644 index 0000000..9646c9c --- /dev/null +++ b/projects/hackalgo-frontend/src/contracts/Algomint.ts @@ -0,0 +1,1145 @@ +/* eslint-disable */ +/** + * This file was automatically generated by @algorandfoundation/algokit-client-generator. + * DO NOT MODIFY IT BY HAND. + * requires: @algorandfoundation/algokit-utils: ^7 + */ +import { type AlgorandClient } from '@algorandfoundation/algokit-utils/types/algorand-client' +import { ABIReturn, AppReturn, SendAppTransactionResult } from '@algorandfoundation/algokit-utils/types/app' +import { Arc56Contract, getArc56ReturnValue, getABIStructFromABITuple } from '@algorandfoundation/algokit-utils/types/app-arc56' +import { + AppClient as _AppClient, + AppClientMethodCallParams, + AppClientParams, + AppClientBareCallParams, + CallOnComplete, + AppClientCompilationParams, + ResolveAppClientByCreatorAndName, + ResolveAppClientByNetwork, + CloneAppClientParams, +} from '@algorandfoundation/algokit-utils/types/app-client' +import { AppFactory as _AppFactory, AppFactoryAppClientParams, AppFactoryResolveAppClientByCreatorAndNameParams, AppFactoryDeployParams, AppFactoryParams, CreateSchema } from '@algorandfoundation/algokit-utils/types/app-factory' +import { TransactionComposer, AppCallMethodCall, AppMethodCallTransactionArgument, SimulateOptions, RawSimulateOptions, SkipSignaturesSimulateOptions } from '@algorandfoundation/algokit-utils/types/composer' +import { SendParams, SendSingleTransactionResult, SendAtomicTransactionComposerResults } from '@algorandfoundation/algokit-utils/types/transaction' +import { Address, encodeAddress, modelsv2, OnApplicationComplete, Transaction, TransactionSigner } from 'algosdk' +import SimulateResponse = modelsv2.SimulateResponse + +export const APP_SPEC: Arc56Contract = {"name":"Algomint","structs":{},"methods":[{"name":"mint_future_nft","args":[{"type":"uint64","name":"total_nfts"},{"type":"uint64","name":"total_pct_bps"},{"type":"uint64","name":"duration_years"},{"type":"uint64","name":"start_quarter"},{"type":"uint64","name":"sale_price"},{"type":"pay","name":"mbr_payment"}],"returns":{"type":"void"},"actions":{"create":[],"call":["NoOp"]},"readonly":false,"events":[],"recommendations":{}},{"name":"buy_nft","args":[{"type":"uint64","name":"asset_id"},{"type":"axfer","name":"opt_in"},{"type":"pay","name":"payment"}],"returns":{"type":"void"},"actions":{"create":[],"call":["NoOp"]},"readonly":false,"events":[],"recommendations":{}},{"name":"report_income","args":[{"type":"uint64","name":"quarter"},{"type":"uint64","name":"income_amount"},{"type":"pay","name":"payout_funding"}],"returns":{"type":"void"},"actions":{"create":[],"call":["NoOp"]},"readonly":false,"events":[],"recommendations":{}},{"name":"claim_payout","args":[{"type":"uint64","name":"asset_id"}],"returns":{"type":"void"},"actions":{"create":[],"call":["NoOp"]},"readonly":false,"events":[],"recommendations":{}},{"name":"get_pending_payout","args":[{"type":"uint64","name":"asset_id"},{"type":"address","name":"address"}],"returns":{"type":"uint64"},"actions":{"create":[],"call":["NoOp"]},"readonly":true,"events":[],"recommendations":{}},{"name":"get_terms","args":[],"returns":{"type":"(address,uint64,uint64,uint64,uint64,uint64,uint64)"},"actions":{"create":[],"call":["NoOp"]},"readonly":true,"desc":"Returns: (creator, total_nfts, total_pct_bps, duration_years, start_quarter, sale_price, first_asset_id)","events":[],"recommendations":{}}],"arcs":[22,28],"networks":{},"state":{"schema":{"global":{"ints":11,"bytes":1},"local":{"ints":0,"bytes":0}},"keys":{"global":{"creator":{"keyType":"AVMString","valueType":"address","key":"Y3JlYXRvcg=="},"total_nfts":{"keyType":"AVMString","valueType":"AVMUint64","key":"dG90YWxfbmZ0cw=="},"total_pct_bps":{"keyType":"AVMString","valueType":"AVMUint64","key":"dG90YWxfcGN0X2Jwcw=="},"duration_years":{"keyType":"AVMString","valueType":"AVMUint64","key":"ZHVyYXRpb25feWVhcnM="},"start_quarter":{"keyType":"AVMString","valueType":"AVMUint64","key":"c3RhcnRfcXVhcnRlcg=="},"sale_price":{"keyType":"AVMString","valueType":"AVMUint64","key":"c2FsZV9wcmljZQ=="},"first_asset_id":{"keyType":"AVMString","valueType":"AVMUint64","key":"Zmlyc3RfYXNzZXRfaWQ="},"pct_per_nft_bps":{"keyType":"AVMString","valueType":"AVMUint64","key":"cGN0X3Blcl9uZnRfYnBz"},"last_reported_quarter":{"keyType":"AVMString","valueType":"AVMUint64","key":"bGFzdF9yZXBvcnRlZF9xdWFydGVy"},"last_reported_income":{"keyType":"AVMString","valueType":"AVMUint64","key":"bGFzdF9yZXBvcnRlZF9pbmNvbWU="},"payout_per_nft":{"keyType":"AVMString","valueType":"AVMUint64","key":"cGF5b3V0X3Blcl9uZnQ="},"initialized":{"keyType":"AVMString","valueType":"AVMUint64","key":"aW5pdGlhbGl6ZWQ="}},"local":{},"box":{}},"maps":{"global":{},"local":{},"box":{"last_claimed_quarter":{"keyType":"uint64","valueType":"uint64","prefix":"bGNf"},"minted_assets":{"keyType":"uint64","valueType":"uint64","prefix":"bWFf"}}}},"bareActions":{"create":["NoOp"],"call":[]},"sourceInfo":{"approval":{"sourceInfo":[{"pc":[755,808,1111],"errorMessage":"check self.creator exists"},{"pc":[1124],"errorMessage":"check self.duration_years exists"},{"pc":[1139],"errorMessage":"check self.first_asset_id exists"},{"pc":[373,644,800,888,997,1105],"errorMessage":"check self.initialized exists"},{"pc":[814,913,1029,1085],"errorMessage":"check self.last_reported_quarter exists"},{"pc":[948,1094],"errorMessage":"check self.payout_per_nft exists"},{"pc":[716,1134],"errorMessage":"check self.sale_price exists"},{"pc":[1129],"errorMessage":"check self.start_quarter exists"},{"pc":[452,868,1115],"errorMessage":"check self.total_nfts exists"},{"pc":[448,825,1119],"errorMessage":"check self.total_pct_bps exists"},{"pc":[993],"errorMessage":"invalid number of bytes for arc4.static_array"},{"pc":[321,331,340,349,358,617,776,785,883,979],"errorMessage":"invalid number of bytes for arc4.uint64"},{"pc":[630],"errorMessage":"transaction type is axfer"},{"pc":[369,640,796],"errorMessage":"transaction type is pay"}],"pcOffsetMethod":"none"},"clear":{"sourceInfo":[],"pcOffsetMethod":"none"}},"source":{"approval":"I3ByYWdtYSB2ZXJzaW9uIDExCiNwcmFnbWEgdHlwZXRyYWNrIGZhbHNlCgovLyBhbGdvcHkuYXJjNC5BUkM0Q29udHJhY3QuYXBwcm92YWxfcHJvZ3JhbSgpIC0+IHVpbnQ2NDoKbWFpbjoKICAgIGludGNibG9jayAwIDEgOCAxMDAwMAogICAgYnl0ZWNibG9jayAiaW5pdGlhbGl6ZWQiICJsYXN0X3JlcG9ydGVkX3F1YXJ0ZXIiICJ0b3RhbF9uZnRzIiAidG90YWxfcGN0X2JwcyIgInNhbGVfcHJpY2UiICJwYXlvdXRfcGVyX25mdCIgImNyZWF0b3IiICJtYV8iICJkdXJhdGlvbl95ZWFycyIgInN0YXJ0X3F1YXJ0ZXIiICJmaXJzdF9hc3NldF9pZCIgInBjdF9wZXJfbmZ0X2JwcyIgImxhc3RfcmVwb3J0ZWRfaW5jb21lIiAibGNfIiAweDE1MWY3Yzc1CiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYm56IG1haW5fYWZ0ZXJfaWZfZWxzZUAyCiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6OAogICAgLy8gc2VsZi50b3RhbF9uZnRzID0gR2xvYmFsU3RhdGUoVUludDY0KDApKQogICAgYnl0ZWNfMiAvLyAidG90YWxfbmZ0cyIKICAgIGludGNfMCAvLyAwCiAgICBhcHBfZ2xvYmFsX3B1dAogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjkKICAgIC8vIHNlbGYudG90YWxfcGN0X2JwcyA9IEdsb2JhbFN0YXRlKFVJbnQ2NCgwKSkKICAgIGJ5dGVjXzMgLy8gInRvdGFsX3BjdF9icHMiCiAgICBpbnRjXzAgLy8gMAogICAgYXBwX2dsb2JhbF9wdXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxMAogICAgLy8gc2VsZi5kdXJhdGlvbl95ZWFycyA9IEdsb2JhbFN0YXRlKFVJbnQ2NCgwKSkKICAgIGJ5dGVjIDggLy8gImR1cmF0aW9uX3llYXJzIgogICAgaW50Y18wIC8vIDAKICAgIGFwcF9nbG9iYWxfcHV0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTEKICAgIC8vIHNlbGYuc3RhcnRfcXVhcnRlciA9IEdsb2JhbFN0YXRlKFVJbnQ2NCgwKSkKICAgIGJ5dGVjIDkgLy8gInN0YXJ0X3F1YXJ0ZXIiCiAgICBpbnRjXzAgLy8gMAogICAgYXBwX2dsb2JhbF9wdXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxMgogICAgLy8gc2VsZi5zYWxlX3ByaWNlID0gR2xvYmFsU3RhdGUoVUludDY0KDApKQogICAgYnl0ZWMgNCAvLyAic2FsZV9wcmljZSIKICAgIGludGNfMCAvLyAwCiAgICBhcHBfZ2xvYmFsX3B1dAogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjEzCiAgICAvLyBzZWxmLmZpcnN0X2Fzc2V0X2lkID0gR2xvYmFsU3RhdGUoVUludDY0KDApKQogICAgYnl0ZWMgMTAgLy8gImZpcnN0X2Fzc2V0X2lkIgogICAgaW50Y18wIC8vIDAKICAgIGFwcF9nbG9iYWxfcHV0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTQKICAgIC8vIHNlbGYucGN0X3Blcl9uZnRfYnBzID0gR2xvYmFsU3RhdGUoVUludDY0KDApKQogICAgYnl0ZWMgMTEgLy8gInBjdF9wZXJfbmZ0X2JwcyIKICAgIGludGNfMCAvLyAwCiAgICBhcHBfZ2xvYmFsX3B1dAogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjE1CiAgICAvLyBzZWxmLmxhc3RfcmVwb3J0ZWRfcXVhcnRlciA9IEdsb2JhbFN0YXRlKFVJbnQ2NCgwKSkKICAgIGJ5dGVjXzEgLy8gImxhc3RfcmVwb3J0ZWRfcXVhcnRlciIKICAgIGludGNfMCAvLyAwCiAgICBhcHBfZ2xvYmFsX3B1dAogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjE2CiAgICAvLyBzZWxmLmxhc3RfcmVwb3J0ZWRfaW5jb21lID0gR2xvYmFsU3RhdGUoVUludDY0KDApKQogICAgYnl0ZWMgMTIgLy8gImxhc3RfcmVwb3J0ZWRfaW5jb21lIgogICAgaW50Y18wIC8vIDAKICAgIGFwcF9nbG9iYWxfcHV0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTcKICAgIC8vIHNlbGYucGF5b3V0X3Blcl9uZnQgPSBHbG9iYWxTdGF0ZShVSW50NjQoMCkpCiAgICBieXRlYyA1IC8vICJwYXlvdXRfcGVyX25mdCIKICAgIGludGNfMCAvLyAwCiAgICBhcHBfZ2xvYmFsX3B1dAogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjE4CiAgICAvLyBzZWxmLmluaXRpYWxpemVkID0gR2xvYmFsU3RhdGUoRmFsc2UpCiAgICBieXRlY18wIC8vICJpbml0aWFsaXplZCIKICAgIGludGNfMCAvLyAwCiAgICBhcHBfZ2xvYmFsX3B1dAoKbWFpbl9hZnRlcl9pZl9lbHNlQDI6CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6NAogICAgLy8gY2xhc3MgQWxnb21pbnQoQVJDNENvbnRyYWN0KToKICAgIHR4biBOdW1BcHBBcmdzCiAgICBieiBtYWluX19fYWxnb3B5X2RlZmF1bHRfY3JlYXRlQDE1CiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQKICAgIHB1c2hieXRlc3MgMHhhYzZlMWEwNCAweGRkOTgwZTZkIDB4YmQ4ZGM5N2UgMHg5NDVmMTc3NyAweDU3Mzc3MTc4IDB4YmVmYzE2YzUgLy8gbWV0aG9kICJtaW50X2Z1dHVyZV9uZnQodWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCxwYXkpdm9pZCIsIG1ldGhvZCAiYnV5X25mdCh1aW50NjQsYXhmZXIscGF5KXZvaWQiLCBtZXRob2QgInJlcG9ydF9pbmNvbWUodWludDY0LHVpbnQ2NCxwYXkpdm9pZCIsIG1ldGhvZCAiY2xhaW1fcGF5b3V0KHVpbnQ2NCl2b2lkIiwgbWV0aG9kICJnZXRfcGVuZGluZ19wYXlvdXQodWludDY0LGFkZHJlc3MpdWludDY0IiwgbWV0aG9kICJnZXRfdGVybXMoKShhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KSIKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDAKICAgIG1hdGNoIG1pbnRfZnV0dXJlX25mdCBidXlfbmZ0IHJlcG9ydF9pbmNvbWUgY2xhaW1fcGF5b3V0IGdldF9wZW5kaW5nX3BheW91dCBnZXRfdGVybXMKICAgIGVycgoKbWFpbl9fX2FsZ29weV9kZWZhdWx0X2NyZWF0ZUAxNToKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICAhCiAgICAmJgogICAgcmV0dXJuCgoKLy8gc21hcnRfY29udHJhY3RzLmFsZ29taW50LmNvbnRyYWN0LkFsZ29taW50Lm1pbnRfZnV0dXJlX25mdFtyb3V0aW5nXSgpIC0+IHZvaWQ6Cm1pbnRfZnV0dXJlX25mdDoKICAgIHB1c2hieXRlcyAiIgogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjI1CiAgICAvLyBAYXJjNC5hYmltZXRob2QKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGR1cAogICAgbGVuCiAgICBpbnRjXzIgLy8gOAogICAgPT0KICAgIGFzc2VydCAvLyBpbnZhbGlkIG51bWJlciBvZiBieXRlcyBmb3IgYXJjNC51aW50NjQKICAgIGJ0b2kKICAgIGR1cAogICAgdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgogICAgZHVwCiAgICBsZW4KICAgIGludGNfMiAvLyA4CiAgICA9PQogICAgYXNzZXJ0IC8vIGludmFsaWQgbnVtYmVyIG9mIGJ5dGVzIGZvciBhcmM0LnVpbnQ2NAogICAgYnRvaQogICAgdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMwogICAgZHVwCiAgICBsZW4KICAgIGludGNfMiAvLyA4CiAgICA9PQogICAgYXNzZXJ0IC8vIGludmFsaWQgbnVtYmVyIG9mIGJ5dGVzIGZvciBhcmM0LnVpbnQ2NAogICAgYnRvaQogICAgdHhuYSBBcHBsaWNhdGlvbkFyZ3MgNAogICAgZHVwCiAgICBsZW4KICAgIGludGNfMiAvLyA4CiAgICA9PQogICAgYXNzZXJ0IC8vIGludmFsaWQgbnVtYmVyIG9mIGJ5dGVzIGZvciBhcmM0LnVpbnQ2NAogICAgYnRvaQogICAgdHhuYSBBcHBsaWNhdGlvbkFyZ3MgNQogICAgZHVwCiAgICBsZW4KICAgIGludGNfMiAvLyA4CiAgICA9PQogICAgYXNzZXJ0IC8vIGludmFsaWQgbnVtYmVyIG9mIGJ5dGVzIGZvciBhcmM0LnVpbnQ2NAogICAgYnRvaQogICAgdHhuIEdyb3VwSW5kZXgKICAgIGludGNfMSAvLyAxCiAgICAtCiAgICBkdXAKICAgIGd0eG5zIFR5cGVFbnVtCiAgICBpbnRjXzEgLy8gcGF5CiAgICA9PQogICAgYXNzZXJ0IC8vIHRyYW5zYWN0aW9uIHR5cGUgaXMgcGF5CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MzUKICAgIC8vIGFzc2VydCBub3Qgc2VsZi5pbml0aWFsaXplZC52YWx1ZQogICAgaW50Y18wIC8vIDAKICAgIGJ5dGVjXzAgLy8gImluaXRpYWxpemVkIgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayBzZWxmLmluaXRpYWxpemVkIGV4aXN0cwogICAgIQogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MzYKICAgIC8vIGFzc2VydCB0b3RhbF9uZnRzID4gVUludDY0KDApCiAgICBkaWcgNQogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MzcKICAgIC8vIGFzc2VydCB0b3RhbF9wY3RfYnBzID4gVUludDY0KDApCiAgICBkaWcgNAogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MzgKICAgIC8vIGFzc2VydCB0b3RhbF9wY3RfYnBzIDw9IFVJbnQ2NCgxMF8wMDApCiAgICBkaWcgNAogICAgaW50Y18zIC8vIDEwMDAwCiAgICA8PQogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MzkKICAgIC8vIGFzc2VydCBkdXJhdGlvbl95ZWFycyA+IFVJbnQ2NCgwKQogICAgZGlnIDMKICAgIGFzc2VydAogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjQwCiAgICAvLyBhc3NlcnQgc3RhcnRfcXVhcnRlciA+IFVJbnQ2NCgwKQogICAgZGlnIDIKICAgIGFzc2VydAogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjQxCiAgICAvLyBhc3NlcnQgc2FsZV9wcmljZSA+IFVJbnQ2NCgwKQogICAgZGlnIDEKICAgIGFzc2VydAogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjQzCiAgICAvLyBhc3NlcnQgbWJyX3BheW1lbnQuc2VuZGVyID09IFR4bi5zZW5kZXIKICAgIGR1cAogICAgZ3R4bnMgU2VuZGVyCiAgICB0eG4gU2VuZGVyCiAgICA9PQogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6NDQKICAgIC8vIGFzc2VydCBtYnJfcGF5bWVudC5yZWNlaXZlciA9PSBHbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzCiAgICBkdXAKICAgIGd0eG5zIFJlY2VpdmVyCiAgICBnbG9iYWwgQ3VycmVudEFwcGxpY2F0aW9uQWRkcmVzcwogICAgPT0KICAgIGFzc2VydAogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjQ1LTQ2CiAgICAvLyAjIE5PVEU6IEV4YWN0IE1CUiBkZXBlbmRzIG9uIHByb3RvY29sIHBhcmFtczsgcmVxdWlyZSBhIHNlbnNpYmxlIG1pbmltdW0gZm9yIGRlbW8uCiAgICAvLyBhc3NlcnQgbWJyX3BheW1lbnQuYW1vdW50ID49IFVJbnQ2NCgxXzAwMF8wMDApCiAgICBndHhucyBBbW91bnQKICAgIHB1c2hpbnQgMTAwMDAwMAogICAgPj0KICAgIGFzc2VydAogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjQ4CiAgICAvLyBzZWxmLmNyZWF0b3IudmFsdWUgPSBUeG4uc2VuZGVyCiAgICBieXRlYyA2IC8vICJjcmVhdG9yIgogICAgdHhuIFNlbmRlcgogICAgYXBwX2dsb2JhbF9wdXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weTo0OQogICAgLy8gc2VsZi50b3RhbF9uZnRzLnZhbHVlID0gdG90YWxfbmZ0cwogICAgYnl0ZWNfMiAvLyAidG90YWxfbmZ0cyIKICAgIHVuY292ZXIgNQogICAgYXBwX2dsb2JhbF9wdXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weTo1MAogICAgLy8gc2VsZi50b3RhbF9wY3RfYnBzLnZhbHVlID0gdG90YWxfcGN0X2JwcwogICAgYnl0ZWNfMyAvLyAidG90YWxfcGN0X2JwcyIKICAgIHVuY292ZXIgNAogICAgYXBwX2dsb2JhbF9wdXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weTo1MQogICAgLy8gc2VsZi5kdXJhdGlvbl95ZWFycy52YWx1ZSA9IGR1cmF0aW9uX3llYXJzCiAgICBieXRlYyA4IC8vICJkdXJhdGlvbl95ZWFycyIKICAgIHVuY292ZXIgMwogICAgYXBwX2dsb2JhbF9wdXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weTo1MgogICAgLy8gc2VsZi5zdGFydF9xdWFydGVyLnZhbHVlID0gc3RhcnRfcXVhcnRlcgogICAgYnl0ZWMgOSAvLyAic3RhcnRfcXVhcnRlciIKICAgIHVuY292ZXIgMgogICAgYXBwX2dsb2JhbF9wdXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weTo1MwogICAgLy8gc2VsZi5zYWxlX3ByaWNlLnZhbHVlID0gc2FsZV9wcmljZQogICAgYnl0ZWMgNCAvLyAic2FsZV9wcmljZSIKICAgIHN3YXAKICAgIGFwcF9nbG9iYWxfcHV0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6NTQKICAgIC8vIHNlbGYucGN0X3Blcl9uZnRfYnBzLnZhbHVlID0gc2VsZi50b3RhbF9wY3RfYnBzLnZhbHVlIC8vIHNlbGYudG90YWxfbmZ0cy52YWx1ZQogICAgaW50Y18wIC8vIDAKICAgIGJ5dGVjXzMgLy8gInRvdGFsX3BjdF9icHMiCiAgICBhcHBfZ2xvYmFsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIHNlbGYudG90YWxfcGN0X2JwcyBleGlzdHMKICAgIGludGNfMCAvLyAwCiAgICBieXRlY18yIC8vICJ0b3RhbF9uZnRzIgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayBzZWxmLnRvdGFsX25mdHMgZXhpc3RzCiAgICAvCiAgICBieXRlYyAxMSAvLyAicGN0X3Blcl9uZnRfYnBzIgogICAgc3dhcAogICAgYXBwX2dsb2JhbF9wdXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weTo1NQogICAgLy8gc2VsZi5pbml0aWFsaXplZC52YWx1ZSA9IFRydWUKICAgIGJ5dGVjXzAgLy8gImluaXRpYWxpemVkIgogICAgaW50Y18xIC8vIDEKICAgIGFwcF9nbG9iYWxfcHV0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6NTctNTgKICAgIC8vICMgTWludCBhIGZpeGVkIHNlcmllcyBvZiBBUkMtMTkgc3R5bGUgTkZUcyBmcm9tIHRoZSBhcHAgYWNjb3VudC4KICAgIC8vIGZvciBpZHggaW4gdXJhbmdlKHRvdGFsX25mdHMpOgogICAgaW50Y18wIC8vIDAKCm1pbnRfZnV0dXJlX25mdF9mb3JfaGVhZGVyQDI6CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6NTctNTgKICAgIC8vICMgTWludCBhIGZpeGVkIHNlcmllcyBvZiBBUkMtMTkgc3R5bGUgTkZUcyBmcm9tIHRoZSBhcHAgYWNjb3VudC4KICAgIC8vIGZvciBpZHggaW4gdXJhbmdlKHRvdGFsX25mdHMpOgogICAgZHVwCiAgICBkaWcgMgogICAgPAogICAgYnogbWludF9mdXR1cmVfbmZ0X2FmdGVyX2ZvckA4CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6NTktNzAKICAgIC8vIGNyZWF0ZWQgPSBpdHhuLkFzc2V0Q29uZmlnKAogICAgLy8gICAgIHRvdGFsPTEsCiAgICAvLyAgICAgZGVjaW1hbHM9MCwKICAgIC8vICAgICBkZWZhdWx0X2Zyb3plbj1GYWxzZSwKICAgIC8vICAgICBhc3NldF9uYW1lPWIiRnV0dXJlIEVhcm5pbmcgTkZUIiwKICAgIC8vICAgICB1bml0X25hbWU9YiJGRU5GVCIsCiAgICAvLyAgICAgIyBBUkMtMTkgdGVtcGxhdGUgVVJMIChDSUQgc291cmNlZCBmcm9tIHJlc2VydmUgYWNjb3VudCBieSBjbGllbnRzKS4KICAgIC8vICAgICB1cmw9YiJ0ZW1wbGF0ZS1pcGZzOi8ve2lwZnNjaWQ6MTpyYXc6cmVzZXJ2ZTpzaGEyLTI1Nn0iLAogICAgLy8gICAgIG1hbmFnZXI9R2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcywKICAgIC8vICAgICByZXNlcnZlPUdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2FkZHJlc3MsCiAgICAvLyAgICAgZmVlPTAsCiAgICAvLyApLnN1Ym1pdCgpCiAgICBpdHhuX2JlZ2luCiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6NjcKICAgIC8vIG1hbmFnZXI9R2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcywKICAgIGdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6NjgKICAgIC8vIHJlc2VydmU9R2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcywKICAgIGR1cAogICAgaXR4bl9maWVsZCBDb25maWdBc3NldFJlc2VydmUKICAgIGl0eG5fZmllbGQgQ29uZmlnQXNzZXRNYW5hZ2VyCiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6NjUtNjYKICAgIC8vICMgQVJDLTE5IHRlbXBsYXRlIFVSTCAoQ0lEIHNvdXJjZWQgZnJvbSByZXNlcnZlIGFjY291bnQgYnkgY2xpZW50cykuCiAgICAvLyB1cmw9YiJ0ZW1wbGF0ZS1pcGZzOi8ve2lwZnNjaWQ6MTpyYXc6cmVzZXJ2ZTpzaGEyLTI1Nn0iLAogICAgcHVzaGJ5dGVzIDB4NzQ2NTZkNzA2YzYxNzQ2NTJkNjk3MDY2NzMzYTJmMmY3YjY5NzA2NjczNjM2OTY0M2EzMTNhNzI2MTc3M2E3MjY1NzM2NTcyNzY2NTNhNzM2ODYxMzIyZDMyMzUzNjdkCiAgICBpdHhuX2ZpZWxkIENvbmZpZ0Fzc2V0VVJMCiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6NjQKICAgIC8vIHVuaXRfbmFtZT1iIkZFTkZUIiwKICAgIHB1c2hieXRlcyAweDQ2NDU0ZTQ2NTQKICAgIGl0eG5fZmllbGQgQ29uZmlnQXNzZXRVbml0TmFtZQogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjYzCiAgICAvLyBhc3NldF9uYW1lPWIiRnV0dXJlIEVhcm5pbmcgTkZUIiwKICAgIHB1c2hieXRlcyAweDQ2NzU3NDc1NzI2NTIwNDU2MTcyNmU2OTZlNjcyMDRlNDY1NAogICAgaXR4bl9maWVsZCBDb25maWdBc3NldE5hbWUKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weTo2MgogICAgLy8gZGVmYXVsdF9mcm96ZW49RmFsc2UsCiAgICBpbnRjXzAgLy8gMAogICAgaXR4bl9maWVsZCBDb25maWdBc3NldERlZmF1bHRGcm96ZW4KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weTo2MQogICAgLy8gZGVjaW1hbHM9MCwKICAgIGludGNfMCAvLyAwCiAgICBpdHhuX2ZpZWxkIENvbmZpZ0Fzc2V0RGVjaW1hbHMKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weTo2MAogICAgLy8gdG90YWw9MSwKICAgIGludGNfMSAvLyAxCiAgICBpdHhuX2ZpZWxkIENvbmZpZ0Fzc2V0VG90YWwKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weTo1OQogICAgLy8gY3JlYXRlZCA9IGl0eG4uQXNzZXRDb25maWcoCiAgICBwdXNoaW50IDMgLy8gYWNmZwogICAgaXR4bl9maWVsZCBUeXBlRW51bQogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjY5CiAgICAvLyBmZWU9MCwKICAgIGludGNfMCAvLyAwCiAgICBpdHhuX2ZpZWxkIEZlZQogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjU5LTcwCiAgICAvLyBjcmVhdGVkID0gaXR4bi5Bc3NldENvbmZpZygKICAgIC8vICAgICB0b3RhbD0xLAogICAgLy8gICAgIGRlY2ltYWxzPTAsCiAgICAvLyAgICAgZGVmYXVsdF9mcm96ZW49RmFsc2UsCiAgICAvLyAgICAgYXNzZXRfbmFtZT1iIkZ1dHVyZSBFYXJuaW5nIE5GVCIsCiAgICAvLyAgICAgdW5pdF9uYW1lPWIiRkVORlQiLAogICAgLy8gICAgICMgQVJDLTE5IHRlbXBsYXRlIFVSTCAoQ0lEIHNvdXJjZWQgZnJvbSByZXNlcnZlIGFjY291bnQgYnkgY2xpZW50cykuCiAgICAvLyAgICAgdXJsPWIidGVtcGxhdGUtaXBmczovL3tpcGZzY2lkOjE6cmF3OnJlc2VydmU6c2hhMi0yNTZ9IiwKICAgIC8vICAgICBtYW5hZ2VyPUdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2FkZHJlc3MsCiAgICAvLyAgICAgcmVzZXJ2ZT1HbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzLAogICAgLy8gICAgIGZlZT0wLAogICAgLy8gKS5zdWJtaXQoKQogICAgaXR4bl9zdWJtaXQKICAgIGl0eG4gQ3JlYXRlZEFzc2V0SUQKICAgIGJ1cnkgMwogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjcxCiAgICAvLyBpZiBpZHggPT0gVUludDY0KDApOgogICAgZHVwCiAgICBibnogbWludF9mdXR1cmVfbmZ0X2FmdGVyX2lmX2Vsc2VANgogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjcyCiAgICAvLyBzZWxmLmZpcnN0X2Fzc2V0X2lkLnZhbHVlID0gY3JlYXRlZC5jcmVhdGVkX2Fzc2V0LmlkCiAgICBieXRlYyAxMCAvLyAiZmlyc3RfYXNzZXRfaWQiCiAgICBkaWcgMwogICAgYXBwX2dsb2JhbF9wdXQKCm1pbnRfZnV0dXJlX25mdF9hZnRlcl9pZl9lbHNlQDY6CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6NzMKICAgIC8vIHNlbGYubWludGVkX2Fzc2V0c1tjcmVhdGVkLmNyZWF0ZWRfYXNzZXQuaWRdID0gVUludDY0KDEpCiAgICBkaWcgMgogICAgaXRvYgogICAgYnl0ZWMgNyAvLyAibWFfIgogICAgc3dhcAogICAgY29uY2F0CiAgICBpbnRjXzEgLy8gMQogICAgaXRvYgogICAgYm94X3B1dAogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjU3LTU4CiAgICAvLyAjIE1pbnQgYSBmaXhlZCBzZXJpZXMgb2YgQVJDLTE5IHN0eWxlIE5GVHMgZnJvbSB0aGUgYXBwIGFjY291bnQuCiAgICAvLyBmb3IgaWR4IGluIHVyYW5nZSh0b3RhbF9uZnRzKToKICAgIGR1cAogICAgaW50Y18xIC8vIDEKICAgICsKICAgIGJ1cnkgMQogICAgYiBtaW50X2Z1dHVyZV9uZnRfZm9yX2hlYWRlckAyCgptaW50X2Z1dHVyZV9uZnRfYWZ0ZXJfZm9yQDg6CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MjUKICAgIC8vIEBhcmM0LmFiaW1ldGhvZAogICAgaW50Y18xIC8vIDEKICAgIHJldHVybgoKCi8vIHNtYXJ0X2NvbnRyYWN0cy5hbGdvbWludC5jb250cmFjdC5BbGdvbWludC5idXlfbmZ0W3JvdXRpbmddKCkgLT4gdm9pZDoKYnV5X25mdDoKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weTo3NQogICAgLy8gQGFyYzQuYWJpbWV0aG9kCiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAxCiAgICBkdXAKICAgIGxlbgogICAgaW50Y18yIC8vIDgKICAgID09CiAgICBhc3NlcnQgLy8gaW52YWxpZCBudW1iZXIgb2YgYnl0ZXMgZm9yIGFyYzQudWludDY0CiAgICBidG9pCiAgICB0eG4gR3JvdXBJbmRleAogICAgcHVzaGludCAyCiAgICAtCiAgICBkdXAKICAgIGd0eG5zIFR5cGVFbnVtCiAgICBwdXNoaW50IDQgLy8gYXhmZXIKICAgID09CiAgICBhc3NlcnQgLy8gdHJhbnNhY3Rpb24gdHlwZSBpcyBheGZlcgogICAgdHhuIEdyb3VwSW5kZXgKICAgIGludGNfMSAvLyAxCiAgICAtCiAgICBkdXAKICAgIGd0eG5zIFR5cGVFbnVtCiAgICBpbnRjXzEgLy8gcGF5CiAgICA9PQogICAgYXNzZXJ0IC8vIHRyYW5zYWN0aW9uIHR5cGUgaXMgcGF5CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6ODIKICAgIC8vIGFzc2VydCBzZWxmLmluaXRpYWxpemVkLnZhbHVlCiAgICBpbnRjXzAgLy8gMAogICAgYnl0ZWNfMCAvLyAiaW5pdGlhbGl6ZWQiCiAgICBhcHBfZ2xvYmFsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIHNlbGYuaW5pdGlhbGl6ZWQgZXhpc3RzCiAgICBhc3NlcnQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weTo4MwogICAgLy8gYXNzZXJ0IGFzc2V0X2lkID4gVUludDY0KDApCiAgICBkaWcgMgogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6ODQKICAgIC8vIGFzc2VydCBzZWxmLm1pbnRlZF9hc3NldHMuZ2V0KGFzc2V0X2lkLCBkZWZhdWx0PVVJbnQ2NCgwKSkgPT0gVUludDY0KDEpCiAgICBkaWcgMgogICAgaXRvYgogICAgYnl0ZWMgNyAvLyAibWFfIgogICAgc3dhcAogICAgY29uY2F0CiAgICBib3hfZ2V0CiAgICBzd2FwCiAgICBidG9pCiAgICBpbnRjXzAgLy8gMAogICAgc3dhcAogICAgdW5jb3ZlciAyCiAgICBzZWxlY3QKICAgIGludGNfMSAvLyAxCiAgICA9PQogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6ODgtODkKICAgIC8vICMgRW5zdXJlIGJ1eWVyIGhhcyBvcHRlZC1pbiBpbiB0aGUgc2FtZSBncm91cC4KICAgIC8vIGFzc2VydCBvcHRfaW4uc2VuZGVyID09IFR4bi5zZW5kZXIKICAgIGRpZyAxCiAgICBndHhucyBTZW5kZXIKICAgIHR4biBTZW5kZXIKICAgID09CiAgICBhc3NlcnQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weTo5MAogICAgLy8gYXNzZXJ0IG9wdF9pbi5hc3NldF9yZWNlaXZlciA9PSBUeG4uc2VuZGVyCiAgICBkaWcgMQogICAgZ3R4bnMgQXNzZXRSZWNlaXZlcgogICAgdHhuIFNlbmRlcgogICAgPT0KICAgIGFzc2VydAogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjkxCiAgICAvLyBhc3NlcnQgb3B0X2luLnhmZXJfYXNzZXQuaWQgPT0gYXNzZXQuaWQKICAgIGRpZyAxCiAgICBndHhucyBYZmVyQXNzZXQKICAgIGRpZyAzCiAgICA9PQogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6OTIKICAgIC8vIGFzc2VydCBvcHRfaW4uYXNzZXRfYW1vdW50ID09IFVJbnQ2NCgwKQogICAgc3dhcAogICAgZ3R4bnMgQXNzZXRBbW91bnQKICAgICEKICAgIGFzc2VydAogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5Ojk0CiAgICAvLyBhc3NlcnQgcGF5bWVudC5zZW5kZXIgPT0gVHhuLnNlbmRlcgogICAgZHVwCiAgICBndHhucyBTZW5kZXIKICAgIHR4biBTZW5kZXIKICAgID09CiAgICBhc3NlcnQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weTo5NQogICAgLy8gYXNzZXJ0IHBheW1lbnQucmVjZWl2ZXIgPT0gR2xvYmFsLmN1cnJlbnRfYXBwbGljYXRpb25fYWRkcmVzcwogICAgZHVwCiAgICBndHhucyBSZWNlaXZlcgogICAgZ2xvYmFsIEN1cnJlbnRBcHBsaWNhdGlvbkFkZHJlc3MKICAgID09CiAgICBhc3NlcnQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weTo5NgogICAgLy8gYXNzZXJ0IHBheW1lbnQuYW1vdW50ID09IHNlbGYuc2FsZV9wcmljZS52YWx1ZQogICAgZ3R4bnMgQW1vdW50CiAgICBpbnRjXzAgLy8gMAogICAgYnl0ZWMgNCAvLyAic2FsZV9wcmljZSIKICAgIGFwcF9nbG9iYWxfZ2V0X2V4CiAgICBhc3NlcnQgLy8gY2hlY2sgc2VsZi5zYWxlX3ByaWNlIGV4aXN0cwogICAgZGlnIDEKICAgID09CiAgICBhc3NlcnQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weTo5OAogICAgLy8gYXBwX2JhbGFuY2UsIGFwcF9vcHRlZCA9IG9wLkFzc2V0SG9sZGluZ0dldC5hc3NldF9iYWxhbmNlKEdsb2JhbC5jdXJyZW50X2FwcGxpY2F0aW9uX2FkZHJlc3MsIGFzc2V0KQogICAgZ2xvYmFsIEN1cnJlbnRBcHBsaWNhdGlvbkFkZHJlc3MKICAgIGRpZyAyCiAgICBhc3NldF9ob2xkaW5nX2dldCBBc3NldEJhbGFuY2UKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weTo5OQogICAgLy8gYXNzZXJ0IGFwcF9vcHRlZAogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTAwCiAgICAvLyBhc3NlcnQgYXBwX2JhbGFuY2UgPT0gVUludDY0KDEpCiAgICBpbnRjXzEgLy8gMQogICAgPT0KICAgIGFzc2VydAogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjEwMi0xMDgKICAgIC8vICMgVHJhbnNmZXIgTkZUIHRvIGludmVzdG9yIGFuZCBmb3J3YXJkIHBheW1lbnQgdG8gY3JlYXRvci4KICAgIC8vIGl0eG4uQXNzZXRUcmFuc2ZlcigKICAgIC8vICAgICB4ZmVyX2Fzc2V0PWFzc2V0LAogICAgLy8gICAgIGFzc2V0X3JlY2VpdmVyPVR4bi5zZW5kZXIsCiAgICAvLyAgICAgYXNzZXRfYW1vdW50PVVJbnQ2NCgxKSwKICAgIC8vICAgICBmZWU9MCwKICAgIC8vICkuc3VibWl0KCkKICAgIGl0eG5fYmVnaW4KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxMDUKICAgIC8vIGFzc2V0X3JlY2VpdmVyPVR4bi5zZW5kZXIsCiAgICB0eG4gU2VuZGVyCiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTA2CiAgICAvLyBhc3NldF9hbW91bnQ9VUludDY0KDEpLAogICAgaW50Y18xIC8vIDEKICAgIGl0eG5fZmllbGQgQXNzZXRBbW91bnQKICAgIGl0eG5fZmllbGQgQXNzZXRSZWNlaXZlcgogICAgc3dhcAogICAgaXR4bl9maWVsZCBYZmVyQXNzZXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxMDItMTAzCiAgICAvLyAjIFRyYW5zZmVyIE5GVCB0byBpbnZlc3RvciBhbmQgZm9yd2FyZCBwYXltZW50IHRvIGNyZWF0b3IuCiAgICAvLyBpdHhuLkFzc2V0VHJhbnNmZXIoCiAgICBwdXNoaW50IDQgLy8gYXhmZXIKICAgIGl0eG5fZmllbGQgVHlwZUVudW0KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxMDcKICAgIC8vIGZlZT0wLAogICAgaW50Y18wIC8vIDAKICAgIGl0eG5fZmllbGQgRmVlCiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTAyLTEwOAogICAgLy8gIyBUcmFuc2ZlciBORlQgdG8gaW52ZXN0b3IgYW5kIGZvcndhcmQgcGF5bWVudCB0byBjcmVhdG9yLgogICAgLy8gaXR4bi5Bc3NldFRyYW5zZmVyKAogICAgLy8gICAgIHhmZXJfYXNzZXQ9YXNzZXQsCiAgICAvLyAgICAgYXNzZXRfcmVjZWl2ZXI9VHhuLnNlbmRlciwKICAgIC8vICAgICBhc3NldF9hbW91bnQ9VUludDY0KDEpLAogICAgLy8gICAgIGZlZT0wLAogICAgLy8gKS5zdWJtaXQoKQogICAgaXR4bl9zdWJtaXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxMDktMTEzCiAgICAvLyBpdHhuLlBheW1lbnQoCiAgICAvLyAgICAgcmVjZWl2ZXI9c2VsZi5jcmVhdG9yLnZhbHVlLAogICAgLy8gICAgIGFtb3VudD1wYXltZW50LmFtb3VudCwKICAgIC8vICAgICBmZWU9MCwKICAgIC8vICkuc3VibWl0KCkKICAgIGl0eG5fYmVnaW4KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxMTAKICAgIC8vIHJlY2VpdmVyPXNlbGYuY3JlYXRvci52YWx1ZSwKICAgIGludGNfMCAvLyAwCiAgICBieXRlYyA2IC8vICJjcmVhdG9yIgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayBzZWxmLmNyZWF0b3IgZXhpc3RzCiAgICBpdHhuX2ZpZWxkIFJlY2VpdmVyCiAgICBpdHhuX2ZpZWxkIEFtb3VudAogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjEwOQogICAgLy8gaXR4bi5QYXltZW50KAogICAgaW50Y18xIC8vIHBheQogICAgaXR4bl9maWVsZCBUeXBlRW51bQogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjExMgogICAgLy8gZmVlPTAsCiAgICBpbnRjXzAgLy8gMAogICAgaXR4bl9maWVsZCBGZWUKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxMDktMTEzCiAgICAvLyBpdHhuLlBheW1lbnQoCiAgICAvLyAgICAgcmVjZWl2ZXI9c2VsZi5jcmVhdG9yLnZhbHVlLAogICAgLy8gICAgIGFtb3VudD1wYXltZW50LmFtb3VudCwKICAgIC8vICAgICBmZWU9MCwKICAgIC8vICkuc3VibWl0KCkKICAgIGl0eG5fc3VibWl0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6NzUKICAgIC8vIEBhcmM0LmFiaW1ldGhvZAogICAgaW50Y18xIC8vIDEKICAgIHJldHVybgoKCi8vIHNtYXJ0X2NvbnRyYWN0cy5hbGdvbWludC5jb250cmFjdC5BbGdvbWludC5yZXBvcnRfaW5jb21lW3JvdXRpbmddKCkgLT4gdm9pZDoKcmVwb3J0X2luY29tZToKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxMTUKICAgIC8vIEBhcmM0LmFiaW1ldGhvZAogICAgdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQogICAgZHVwCiAgICBsZW4KICAgIGludGNfMiAvLyA4CiAgICA9PQogICAgYXNzZXJ0IC8vIGludmFsaWQgbnVtYmVyIG9mIGJ5dGVzIGZvciBhcmM0LnVpbnQ2NAogICAgYnRvaQogICAgdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgogICAgZHVwCiAgICBsZW4KICAgIGludGNfMiAvLyA4CiAgICA9PQogICAgYXNzZXJ0IC8vIGludmFsaWQgbnVtYmVyIG9mIGJ5dGVzIGZvciBhcmM0LnVpbnQ2NAogICAgYnRvaQogICAgdHhuIEdyb3VwSW5kZXgKICAgIGludGNfMSAvLyAxCiAgICAtCiAgICBkdXAKICAgIGd0eG5zIFR5cGVFbnVtCiAgICBpbnRjXzEgLy8gcGF5CiAgICA9PQogICAgYXNzZXJ0IC8vIHRyYW5zYWN0aW9uIHR5cGUgaXMgcGF5CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTE5CiAgICAvLyBhc3NlcnQgc2VsZi5pbml0aWFsaXplZC52YWx1ZQogICAgaW50Y18wIC8vIDAKICAgIGJ5dGVjXzAgLy8gImluaXRpYWxpemVkIgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayBzZWxmLmluaXRpYWxpemVkIGV4aXN0cwogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTIwCiAgICAvLyBhc3NlcnQgVHhuLnNlbmRlciA9PSBzZWxmLmNyZWF0b3IudmFsdWUKICAgIHR4biBTZW5kZXIKICAgIGludGNfMCAvLyAwCiAgICBieXRlYyA2IC8vICJjcmVhdG9yIgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayBzZWxmLmNyZWF0b3IgZXhpc3RzCiAgICA9PQogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTIxCiAgICAvLyBhc3NlcnQgcXVhcnRlciA+IHNlbGYubGFzdF9yZXBvcnRlZF9xdWFydGVyLnZhbHVlCiAgICBpbnRjXzAgLy8gMAogICAgYnl0ZWNfMSAvLyAibGFzdF9yZXBvcnRlZF9xdWFydGVyIgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayBzZWxmLmxhc3RfcmVwb3J0ZWRfcXVhcnRlciBleGlzdHMKICAgIGRpZyAzCiAgICA8CiAgICBhc3NlcnQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxMjIKICAgIC8vIGFzc2VydCBpbmNvbWVfYW1vdW50ID4gVUludDY0KDApCiAgICBkaWcgMQogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTI0CiAgICAvLyB0b3RhbF9wYXlvdXQgPSAoaW5jb21lX2Ftb3VudCAqIHNlbGYudG90YWxfcGN0X2Jwcy52YWx1ZSkgLy8gVUludDY0KDEwXzAwMCkKICAgIGludGNfMCAvLyAwCiAgICBieXRlY18zIC8vICJ0b3RhbF9wY3RfYnBzIgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayBzZWxmLnRvdGFsX3BjdF9icHMgZXhpc3RzCiAgICBkaWcgMgogICAgKgogICAgaW50Y18zIC8vIDEwMDAwCiAgICAvCiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTI1CiAgICAvLyBhc3NlcnQgdG90YWxfcGF5b3V0ID4gVUludDY0KDApCiAgICBkdXAKICAgIGFzc2VydAogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjEyNy0xMjgKICAgIC8vICMgUmVxdWlyZSB0aGUgY3JlYXRvciB0byBmdW5kIHRoZSBhcHAgZm9yIHRoaXMgcXVhcnRlcidzIHBheW91dHMuCiAgICAvLyBhc3NlcnQgcGF5b3V0X2Z1bmRpbmcuc2VuZGVyID09IFR4bi5zZW5kZXIKICAgIGRpZyAxCiAgICBndHhucyBTZW5kZXIKICAgIHR4biBTZW5kZXIKICAgID09CiAgICBhc3NlcnQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxMjkKICAgIC8vIGFzc2VydCBwYXlvdXRfZnVuZGluZy5yZWNlaXZlciA9PSBHbG9iYWwuY3VycmVudF9hcHBsaWNhdGlvbl9hZGRyZXNzCiAgICBkaWcgMQogICAgZ3R4bnMgUmVjZWl2ZXIKICAgIGdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCiAgICA9PQogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTMwCiAgICAvLyBhc3NlcnQgcGF5b3V0X2Z1bmRpbmcuYW1vdW50ID09IHRvdGFsX3BheW91dAogICAgc3dhcAogICAgZ3R4bnMgQW1vdW50CiAgICBkaWcgMQogICAgPT0KICAgIGFzc2VydAogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjEzMgogICAgLy8gc2VsZi5sYXN0X3JlcG9ydGVkX3F1YXJ0ZXIudmFsdWUgPSBxdWFydGVyCiAgICBieXRlY18xIC8vICJsYXN0X3JlcG9ydGVkX3F1YXJ0ZXIiCiAgICB1bmNvdmVyIDMKICAgIGFwcF9nbG9iYWxfcHV0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTMzCiAgICAvLyBzZWxmLmxhc3RfcmVwb3J0ZWRfaW5jb21lLnZhbHVlID0gaW5jb21lX2Ftb3VudAogICAgYnl0ZWMgMTIgLy8gImxhc3RfcmVwb3J0ZWRfaW5jb21lIgogICAgdW5jb3ZlciAyCiAgICBhcHBfZ2xvYmFsX3B1dAogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjEzNAogICAgLy8gc2VsZi5wYXlvdXRfcGVyX25mdC52YWx1ZSA9IHRvdGFsX3BheW91dCAvLyBzZWxmLnRvdGFsX25mdHMudmFsdWUKICAgIGludGNfMCAvLyAwCiAgICBieXRlY18yIC8vICJ0b3RhbF9uZnRzIgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayBzZWxmLnRvdGFsX25mdHMgZXhpc3RzCiAgICAvCiAgICBieXRlYyA1IC8vICJwYXlvdXRfcGVyX25mdCIKICAgIHN3YXAKICAgIGFwcF9nbG9iYWxfcHV0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTE1CiAgICAvLyBAYXJjNC5hYmltZXRob2QKICAgIGludGNfMSAvLyAxCiAgICByZXR1cm4KCgovLyBzbWFydF9jb250cmFjdHMuYWxnb21pbnQuY29udHJhY3QuQWxnb21pbnQuY2xhaW1fcGF5b3V0W3JvdXRpbmddKCkgLT4gdm9pZDoKY2xhaW1fcGF5b3V0OgogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjEzNgogICAgLy8gQGFyYzQuYWJpbWV0aG9kCiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAxCiAgICBkdXAKICAgIGxlbgogICAgaW50Y18yIC8vIDgKICAgID09CiAgICBhc3NlcnQgLy8gaW52YWxpZCBudW1iZXIgb2YgYnl0ZXMgZm9yIGFyYzQudWludDY0CiAgICBidG9pCiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTM4CiAgICAvLyBhc3NlcnQgc2VsZi5pbml0aWFsaXplZC52YWx1ZQogICAgaW50Y18wIC8vIDAKICAgIGJ5dGVjXzAgLy8gImluaXRpYWxpemVkIgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayBzZWxmLmluaXRpYWxpemVkIGV4aXN0cwogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTM5CiAgICAvLyBhc3NlcnQgYXNzZXRfaWQgPiBVSW50NjQoMCkKICAgIGR1cAogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTQwCiAgICAvLyBhc3NlcnQgc2VsZi5taW50ZWRfYXNzZXRzLmdldChhc3NldF9pZCwgZGVmYXVsdD1VSW50NjQoMCkpID09IFVJbnQ2NCgxKQogICAgZHVwCiAgICBpdG9iCiAgICBieXRlYyA3IC8vICJtYV8iCiAgICBkaWcgMQogICAgY29uY2F0CiAgICBib3hfZ2V0CiAgICBzd2FwCiAgICBidG9pCiAgICBpbnRjXzAgLy8gMAogICAgc3dhcAogICAgdW5jb3ZlciAyCiAgICBzZWxlY3QKICAgIGludGNfMSAvLyAxCiAgICA9PQogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTQxCiAgICAvLyBhc3NlcnQgc2VsZi5sYXN0X3JlcG9ydGVkX3F1YXJ0ZXIudmFsdWUgPiBVSW50NjQoMCkKICAgIGludGNfMCAvLyAwCiAgICBieXRlY18xIC8vICJsYXN0X3JlcG9ydGVkX3F1YXJ0ZXIiCiAgICBhcHBfZ2xvYmFsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIHNlbGYubGFzdF9yZXBvcnRlZF9xdWFydGVyIGV4aXN0cwogICAgZHVwCiAgICBhc3NlcnQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxNDMKICAgIC8vIGhvbGRlcl9iYWxhbmNlLCBob2xkZXJfb3B0ZWQgPSBvcC5Bc3NldEhvbGRpbmdHZXQuYXNzZXRfYmFsYW5jZShUeG4uc2VuZGVyLCBBc3NldChhc3NldF9pZCkpCiAgICB0eG4gU2VuZGVyCiAgICB1bmNvdmVyIDMKICAgIGFzc2V0X2hvbGRpbmdfZ2V0IEFzc2V0QmFsYW5jZQogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjE0NAogICAgLy8gYXNzZXJ0IGhvbGRlcl9vcHRlZAogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTQ1CiAgICAvLyBhc3NlcnQgaG9sZGVyX2JhbGFuY2UgPT0gVUludDY0KDEpCiAgICBpbnRjXzEgLy8gMQogICAgPT0KICAgIGFzc2VydAogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjE0NwogICAgLy8gY2xhaW1lZCA9IHNlbGYubGFzdF9jbGFpbWVkX3F1YXJ0ZXIuZ2V0KGFzc2V0X2lkLCBkZWZhdWx0PVVJbnQ2NCgwKSkKICAgIGJ5dGVjIDEzIC8vICJsY18iCiAgICB1bmNvdmVyIDIKICAgIGNvbmNhdAogICAgZHVwCiAgICBib3hfZ2V0CiAgICBzd2FwCiAgICBidG9pCiAgICBpbnRjXzAgLy8gMAogICAgc3dhcAogICAgdW5jb3ZlciAyCiAgICBzZWxlY3QKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxNDgKICAgIC8vIGFzc2VydCBjbGFpbWVkIDwgc2VsZi5sYXN0X3JlcG9ydGVkX3F1YXJ0ZXIudmFsdWUKICAgIGRpZyAyCiAgICA8CiAgICBhc3NlcnQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxNDkKICAgIC8vIGFzc2VydCBzZWxmLnBheW91dF9wZXJfbmZ0LnZhbHVlID4gVUludDY0KDApCiAgICBpbnRjXzAgLy8gMAogICAgYnl0ZWMgNSAvLyAicGF5b3V0X3Blcl9uZnQiCiAgICBhcHBfZ2xvYmFsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIHNlbGYucGF5b3V0X3Blcl9uZnQgZXhpc3RzCiAgICBkdXAKICAgIGFzc2VydAogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjE1MS0xNTUKICAgIC8vIGl0eG4uUGF5bWVudCgKICAgIC8vICAgICBhbW91bnQ9c2VsZi5wYXlvdXRfcGVyX25mdC52YWx1ZSwKICAgIC8vICAgICByZWNlaXZlcj1UeG4uc2VuZGVyLAogICAgLy8gICAgIGZlZT0wLAogICAgLy8gKS5zdWJtaXQoKQogICAgaXR4bl9iZWdpbgogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjE1MwogICAgLy8gcmVjZWl2ZXI9VHhuLnNlbmRlciwKICAgIHR4biBTZW5kZXIKICAgIGl0eG5fZmllbGQgUmVjZWl2ZXIKICAgIGl0eG5fZmllbGQgQW1vdW50CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTUxCiAgICAvLyBpdHhuLlBheW1lbnQoCiAgICBpbnRjXzEgLy8gcGF5CiAgICBpdHhuX2ZpZWxkIFR5cGVFbnVtCiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTU0CiAgICAvLyBmZWU9MCwKICAgIGludGNfMCAvLyAwCiAgICBpdHhuX2ZpZWxkIEZlZQogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjE1MS0xNTUKICAgIC8vIGl0eG4uUGF5bWVudCgKICAgIC8vICAgICBhbW91bnQ9c2VsZi5wYXlvdXRfcGVyX25mdC52YWx1ZSwKICAgIC8vICAgICByZWNlaXZlcj1UeG4uc2VuZGVyLAogICAgLy8gICAgIGZlZT0wLAogICAgLy8gKS5zdWJtaXQoKQogICAgaXR4bl9zdWJtaXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxNTcKICAgIC8vIHNlbGYubGFzdF9jbGFpbWVkX3F1YXJ0ZXJbYXNzZXRfaWRdID0gc2VsZi5sYXN0X3JlcG9ydGVkX3F1YXJ0ZXIudmFsdWUKICAgIHN3YXAKICAgIGl0b2IKICAgIGJveF9wdXQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxMzYKICAgIC8vIEBhcmM0LmFiaW1ldGhvZAogICAgaW50Y18xIC8vIDEKICAgIHJldHVybgoKCi8vIHNtYXJ0X2NvbnRyYWN0cy5hbGdvbWludC5jb250cmFjdC5BbGdvbWludC5nZXRfcGVuZGluZ19wYXlvdXRbcm91dGluZ10oKSAtPiB2b2lkOgpnZXRfcGVuZGluZ19wYXlvdXQ6CiAgICBwdXNoYnl0ZXMgIiIKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxNTkKICAgIC8vIEBhcmM0LmFiaW1ldGhvZChyZWFkb25seT1UcnVlKQogICAgdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQogICAgZHVwCiAgICBsZW4KICAgIGludGNfMiAvLyA4CiAgICA9PQogICAgYXNzZXJ0IC8vIGludmFsaWQgbnVtYmVyIG9mIGJ5dGVzIGZvciBhcmM0LnVpbnQ2NAogICAgYnRvaQogICAgZHVwCiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAyCiAgICBkdXAKICAgIGNvdmVyIDIKICAgIGR1cAogICAgbGVuCiAgICBwdXNoaW50IDMyCiAgICA9PQogICAgYXNzZXJ0IC8vIGludmFsaWQgbnVtYmVyIG9mIGJ5dGVzIGZvciBhcmM0LnN0YXRpY19hcnJheTxhcmM0LnVpbnQ4LCAzMj4KICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxNjEKICAgIC8vIGFzc2VydCBzZWxmLmluaXRpYWxpemVkLnZhbHVlCiAgICBpbnRjXzAgLy8gMAogICAgYnl0ZWNfMCAvLyAiaW5pdGlhbGl6ZWQiCiAgICBhcHBfZ2xvYmFsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIHNlbGYuaW5pdGlhbGl6ZWQgZXhpc3RzCiAgICBhc3NlcnQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxNjIKICAgIC8vIGFzc2VydCBhc3NldF9pZCA+IFVJbnQ2NCgwKQogICAgZGlnIDEKICAgIGFzc2VydAogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjE2MwogICAgLy8gYXNzZXJ0IHNlbGYubWludGVkX2Fzc2V0cy5nZXQoYXNzZXRfaWQsIGRlZmF1bHQ9VUludDY0KDApKSA9PSBVSW50NjQoMSkKICAgIHN3YXAKICAgIGl0b2IKICAgIGR1cAogICAgY292ZXIgMgogICAgYnl0ZWMgNyAvLyAibWFfIgogICAgc3dhcAogICAgY29uY2F0CiAgICBib3hfZ2V0CiAgICBzd2FwCiAgICBidG9pCiAgICBpbnRjXzAgLy8gMAogICAgc3dhcAogICAgdW5jb3ZlciAyCiAgICBzZWxlY3QKICAgIGludGNfMSAvLyAxCiAgICA9PQogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTY0CiAgICAvLyBhc3NlcnQgYWRkcmVzcyAhPSBHbG9iYWwuemVyb19hZGRyZXNzCiAgICBnbG9iYWwgWmVyb0FkZHJlc3MKICAgICE9CiAgICBhc3NlcnQKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxNjYKICAgIC8vIGlmIHNlbGYubGFzdF9yZXBvcnRlZF9xdWFydGVyLnZhbHVlID09IFVJbnQ2NCgwKToKICAgIGludGNfMCAvLyAwCiAgICBieXRlY18xIC8vICJsYXN0X3JlcG9ydGVkX3F1YXJ0ZXIiCiAgICBhcHBfZ2xvYmFsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIHNlbGYubGFzdF9yZXBvcnRlZF9xdWFydGVyIGV4aXN0cwogICAgYm56IGdldF9wZW5kaW5nX3BheW91dF9hZnRlcl9pZl9lbHNlQDMKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxNjcKICAgIC8vIHJldHVybiBVSW50NjQoMCkKICAgIGludGNfMCAvLyAwCgpnZXRfcGVuZGluZ19wYXlvdXRfYWZ0ZXJfaW5saW5lZF9zbWFydF9jb250cmFjdHMuYWxnb21pbnQuY29udHJhY3QuQWxnb21pbnQuZ2V0X3BlbmRpbmdfcGF5b3V0QDEwOgogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjE1OQogICAgLy8gQGFyYzQuYWJpbWV0aG9kKHJlYWRvbmx5PVRydWUpCiAgICBpdG9iCiAgICBieXRlYyAxNCAvLyAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50Y18xIC8vIDEKICAgIHJldHVybgoKZ2V0X3BlbmRpbmdfcGF5b3V0X2FmdGVyX2lmX2Vsc2VAMzoKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxNjkKICAgIC8vIGhvbGRlcl9iYWxhbmNlLCBob2xkZXJfb3B0ZWQgPSBvcC5Bc3NldEhvbGRpbmdHZXQuYXNzZXRfYmFsYW5jZShhZGRyZXNzLCBBc3NldChhc3NldF9pZCkpCiAgICBkaWcgMQogICAgZGlnIDMKICAgIGFzc2V0X2hvbGRpbmdfZ2V0IEFzc2V0QmFsYW5jZQogICAgc3dhcAogICAgYnVyeSA1CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTcwCiAgICAvLyBpZiBub3QgaG9sZGVyX29wdGVkOgogICAgYm56IGdldF9wZW5kaW5nX3BheW91dF9hZnRlcl9pZl9lbHNlQDUKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxNzEKICAgIC8vIHJldHVybiBVSW50NjQoMCkKICAgIGludGNfMCAvLyAwCiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTU5CiAgICAvLyBAYXJjNC5hYmltZXRob2QocmVhZG9ubHk9VHJ1ZSkKICAgIGIgZ2V0X3BlbmRpbmdfcGF5b3V0X2FmdGVyX2lubGluZWRfc21hcnRfY29udHJhY3RzLmFsZ29taW50LmNvbnRyYWN0LkFsZ29taW50LmdldF9wZW5kaW5nX3BheW91dEAxMAoKZ2V0X3BlbmRpbmdfcGF5b3V0X2FmdGVyX2lmX2Vsc2VANToKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxNzIKICAgIC8vIGlmIGhvbGRlcl9iYWxhbmNlICE9IFVJbnQ2NCgxKToKICAgIGRpZyAzCiAgICBpbnRjXzEgLy8gMQogICAgIT0KICAgIGJ6IGdldF9wZW5kaW5nX3BheW91dF9hZnRlcl9pZl9lbHNlQDcKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxNzMKICAgIC8vIHJldHVybiBVSW50NjQoMCkKICAgIGludGNfMCAvLyAwCiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTU5CiAgICAvLyBAYXJjNC5hYmltZXRob2QocmVhZG9ubHk9VHJ1ZSkKICAgIGIgZ2V0X3BlbmRpbmdfcGF5b3V0X2FmdGVyX2lubGluZWRfc21hcnRfY29udHJhY3RzLmFsZ29taW50LmNvbnRyYWN0LkFsZ29taW50LmdldF9wZW5kaW5nX3BheW91dEAxMAoKZ2V0X3BlbmRpbmdfcGF5b3V0X2FmdGVyX2lmX2Vsc2VANzoKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxNzUKICAgIC8vIGNsYWltZWQgPSBzZWxmLmxhc3RfY2xhaW1lZF9xdWFydGVyLmdldChhc3NldF9pZCwgZGVmYXVsdD1VSW50NjQoMCkpCiAgICBieXRlYyAxMyAvLyAibGNfIgogICAgZGlnIDEKICAgIGNvbmNhdAogICAgYm94X2dldAogICAgc3dhcAogICAgYnRvaQogICAgaW50Y18wIC8vIDAKICAgIHN3YXAKICAgIHVuY292ZXIgMgogICAgc2VsZWN0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTc2CiAgICAvLyBpZiBjbGFpbWVkIDwgc2VsZi5sYXN0X3JlcG9ydGVkX3F1YXJ0ZXIudmFsdWU6CiAgICBpbnRjXzAgLy8gMAogICAgYnl0ZWNfMSAvLyAibGFzdF9yZXBvcnRlZF9xdWFydGVyIgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayBzZWxmLmxhc3RfcmVwb3J0ZWRfcXVhcnRlciBleGlzdHMKICAgIDwKICAgIGJ6IGdldF9wZW5kaW5nX3BheW91dF9hZnRlcl9pZl9lbHNlQDkKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxNzcKICAgIC8vIHJldHVybiBzZWxmLnBheW91dF9wZXJfbmZ0LnZhbHVlCiAgICBpbnRjXzAgLy8gMAogICAgYnl0ZWMgNSAvLyAicGF5b3V0X3Blcl9uZnQiCiAgICBhcHBfZ2xvYmFsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIHNlbGYucGF5b3V0X3Blcl9uZnQgZXhpc3RzCiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTU5CiAgICAvLyBAYXJjNC5hYmltZXRob2QocmVhZG9ubHk9VHJ1ZSkKICAgIGIgZ2V0X3BlbmRpbmdfcGF5b3V0X2FmdGVyX2lubGluZWRfc21hcnRfY29udHJhY3RzLmFsZ29taW50LmNvbnRyYWN0LkFsZ29taW50LmdldF9wZW5kaW5nX3BheW91dEAxMAoKZ2V0X3BlbmRpbmdfcGF5b3V0X2FmdGVyX2lmX2Vsc2VAOToKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxNzgKICAgIC8vIHJldHVybiBVSW50NjQoMCkKICAgIGludGNfMCAvLyAwCiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTU5CiAgICAvLyBAYXJjNC5hYmltZXRob2QocmVhZG9ubHk9VHJ1ZSkKICAgIGIgZ2V0X3BlbmRpbmdfcGF5b3V0X2FmdGVyX2lubGluZWRfc21hcnRfY29udHJhY3RzLmFsZ29taW50LmNvbnRyYWN0LkFsZ29taW50LmdldF9wZW5kaW5nX3BheW91dEAxMAoKCi8vIHNtYXJ0X2NvbnRyYWN0cy5hbGdvbWludC5jb250cmFjdC5BbGdvbWludC5nZXRfdGVybXNbcm91dGluZ10oKSAtPiB2b2lkOgpnZXRfdGVybXM6CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTg1CiAgICAvLyBhc3NlcnQgc2VsZi5pbml0aWFsaXplZC52YWx1ZQogICAgaW50Y18wIC8vIDAKICAgIGJ5dGVjXzAgLy8gImluaXRpYWxpemVkIgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayBzZWxmLmluaXRpYWxpemVkIGV4aXN0cwogICAgYXNzZXJ0CiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTg3CiAgICAvLyBzZWxmLmNyZWF0b3IudmFsdWUsCiAgICBpbnRjXzAgLy8gMAogICAgYnl0ZWMgNiAvLyAiY3JlYXRvciIKICAgIGFwcF9nbG9iYWxfZ2V0X2V4CiAgICBhc3NlcnQgLy8gY2hlY2sgc2VsZi5jcmVhdG9yIGV4aXN0cwogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjE4OAogICAgLy8gc2VsZi50b3RhbF9uZnRzLnZhbHVlLAogICAgaW50Y18wIC8vIDAKICAgIGJ5dGVjXzIgLy8gInRvdGFsX25mdHMiCiAgICBhcHBfZ2xvYmFsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIHNlbGYudG90YWxfbmZ0cyBleGlzdHMKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxODkKICAgIC8vIHNlbGYudG90YWxfcGN0X2Jwcy52YWx1ZSwKICAgIGludGNfMCAvLyAwCiAgICBieXRlY18zIC8vICJ0b3RhbF9wY3RfYnBzIgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayBzZWxmLnRvdGFsX3BjdF9icHMgZXhpc3RzCiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTkwCiAgICAvLyBzZWxmLmR1cmF0aW9uX3llYXJzLnZhbHVlLAogICAgaW50Y18wIC8vIDAKICAgIGJ5dGVjIDggLy8gImR1cmF0aW9uX3llYXJzIgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayBzZWxmLmR1cmF0aW9uX3llYXJzIGV4aXN0cwogICAgLy8gc21hcnRfY29udHJhY3RzL2FsZ29taW50L2NvbnRyYWN0LnB5OjE5MQogICAgLy8gc2VsZi5zdGFydF9xdWFydGVyLnZhbHVlLAogICAgaW50Y18wIC8vIDAKICAgIGJ5dGVjIDkgLy8gInN0YXJ0X3F1YXJ0ZXIiCiAgICBhcHBfZ2xvYmFsX2dldF9leAogICAgYXNzZXJ0IC8vIGNoZWNrIHNlbGYuc3RhcnRfcXVhcnRlciBleGlzdHMKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxOTIKICAgIC8vIHNlbGYuc2FsZV9wcmljZS52YWx1ZSwKICAgIGludGNfMCAvLyAwCiAgICBieXRlYyA0IC8vICJzYWxlX3ByaWNlIgogICAgYXBwX2dsb2JhbF9nZXRfZXgKICAgIGFzc2VydCAvLyBjaGVjayBzZWxmLnNhbGVfcHJpY2UgZXhpc3RzCiAgICAvLyBzbWFydF9jb250cmFjdHMvYWxnb21pbnQvY29udHJhY3QucHk6MTkzCiAgICAvLyBzZWxmLmZpcnN0X2Fzc2V0X2lkLnZhbHVlLAogICAgaW50Y18wIC8vIDAKICAgIGJ5dGVjIDEwIC8vICJmaXJzdF9hc3NldF9pZCIKICAgIGFwcF9nbG9iYWxfZ2V0X2V4CiAgICBhc3NlcnQgLy8gY2hlY2sgc2VsZi5maXJzdF9hc3NldF9pZCBleGlzdHMKICAgIC8vIHNtYXJ0X2NvbnRyYWN0cy9hbGdvbWludC9jb250cmFjdC5weToxODAKICAgIC8vIEBhcmM0LmFiaW1ldGhvZChyZWFkb25seT1UcnVlKQogICAgdW5jb3ZlciA1CiAgICBpdG9iCiAgICB1bmNvdmVyIDYKICAgIHN3YXAKICAgIGNvbmNhdAogICAgdW5jb3ZlciA1CiAgICBpdG9iCiAgICBjb25jYXQKICAgIHVuY292ZXIgNAogICAgaXRvYgogICAgY29uY2F0CiAgICB1bmNvdmVyIDMKICAgIGl0b2IKICAgIGNvbmNhdAogICAgdW5jb3ZlciAyCiAgICBpdG9iCiAgICBjb25jYXQKICAgIHN3YXAKICAgIGl0b2IKICAgIGNvbmNhdAogICAgYnl0ZWMgMTQgLy8gMHgxNTFmN2M3NQogICAgc3dhcAogICAgY29uY2F0CiAgICBsb2cKICAgIGludGNfMSAvLyAxCiAgICByZXR1cm4K","clear":"I3ByYWdtYSB2ZXJzaW9uIDExCiNwcmFnbWEgdHlwZXRyYWNrIGZhbHNlCgovLyBhbGdvcHkuYXJjNC5BUkM0Q29udHJhY3QuY2xlYXJfc3RhdGVfcHJvZ3JhbSgpIC0+IHVpbnQ2NDoKbWFpbjoKICAgIHB1c2hpbnQgMQogICAgcmV0dXJuCg=="},"byteCode":{"approval":"CyAEAAEIkE4mDwtpbml0aWFsaXplZBVsYXN0X3JlcG9ydGVkX3F1YXJ0ZXIKdG90YWxfbmZ0cw10b3RhbF9wY3RfYnBzCnNhbGVfcHJpY2UOcGF5b3V0X3Blcl9uZnQHY3JlYXRvcgNtYV8OZHVyYXRpb25feWVhcnMNc3RhcnRfcXVhcnRlcg5maXJzdF9hc3NldF9pZA9wY3RfcGVyX25mdF9icHMUbGFzdF9yZXBvcnRlZF9pbmNvbWUDbGNfBBUffHUxGEAAKCoiZysiZycIImcnCSJnJwQiZycKImcnCyJnKSJnJwwiZycFImcoImcxG0EAOTEZFEQxGESCBgSsbhoEBN2YDm0EvY3JfgSUXxd3BFc3cXgEvvwWxTYaAI4GAAkBMwHSAj0CmwMfADEZFDEYFBBDgAA2GgFJFSQSRBdJNhoCSRUkEkQXNhoDSRUkEkQXNhoESRUkEkQXNhoFSRUkEkQXMRYjCUk4ECMSRCIoZUQUREsFREsEREsEJQ5ESwNESwJESwFESTgAMQASREk4BzIKEkQ4CIHAhD0PRCcGMQBnKk8FZytPBGcnCE8DZycJTwJnJwRMZyIrZUQiKmVECicLTGcoI2ciSUsCDEEAi7EyCkmyKrIpgDB0ZW1wbGF0ZS1pcGZzOi8ve2lwZnNjaWQ6MTpyYXc6cmVzZXJ2ZTpzaGEyLTI1Nn2yJ4AFRkVORlSyJYASRnV0dXJlIEVhcm5pbmcgTkZUsiYisiQisiMjsiKBA7IQIrIBs7Q8RQNJQAAFJwpLA2dLAhYnB0xQIxa/SSMIRQFC/24jQzYaAUkVJBJEFzEWgQIJSTgQgQQSRDEWIwlJOBAjEkQiKGVEREsCREsCFicHTFC+TBciTE8CTSMSREsBOAAxABJESwE4FDEAEkRLATgRSwMSREw4EhRESTgAMQASREk4BzIKEkQ4CCInBGVESwESRDIKSwJwAEQjEkSxMQAjshKyFEyyEYEEshAisgGzsSInBmVEsgeyCCOyECKyAbMjQzYaAUkVJBJEFzYaAkkVJBJEFzEWIwlJOBAjEkQiKGVERDEAIicGZUQSRCIpZURLAwxESwFEIitlREsCCyUKSURLATgAMQASREsBOAcyChJETDgISwESRClPA2cnDE8CZyIqZUQKJwVMZyNDNhoBSRUkEkQXIihlRERJREkWJwdLAVC+TBciTE8CTSMSRCIpZURJRDEATwNwAEQjEkQnDU8CUEm+TBciTE8CTUsCDEQiJwVlRElEsTEAsgeyCCOyECKyAbNMFr8jQ4AANhoBSRUkEkQXSTYaAklOAkkVgSASRCIoZURESwFETBZJTgInB0xQvkwXIkxPAk0jEkQyAxNEIillREAACSIWJw5MULAjQ0sBSwNwAExFBUAABCJC/+hLAyMTQQAEIkL/3ScNSwFQvkwXIkxPAk0iKWVEDEEACCInBWVEQv/AIkL/vCIoZUREIicGZUQiKmVEIitlRCInCGVEIicJZUQiJwRlRCInCmVETwUWTwZMUE8FFlBPBBZQTwMWUE8CFlBMFlAnDkxQsCND","clear":"C4EBQw=="},"compilerInfo":{"compiler":"puya","compilerVersion":{"major":5,"minor":8,"patch":0}},"events":[],"templateVariables":{}} as unknown as Arc56Contract + +/** + * A state record containing binary data + */ +export interface BinaryState { + /** + * Gets the state value as a Uint8Array + */ + asByteArray(): Uint8Array | undefined + /** + * Gets the state value as a string + */ + asString(): string | undefined +} + +class BinaryStateValue implements BinaryState { + constructor(private value: Uint8Array | undefined) {} + + asByteArray(): Uint8Array | undefined { + return this.value + } + + asString(): string | undefined { + return this.value !== undefined ? Buffer.from(this.value).toString('utf-8') : undefined + } +} + +/** + * Expands types for IntelliSense so they are more human readable + * See https://stackoverflow.com/a/69288824 + */ +export type Expand = T extends (...args: infer A) => infer R + ? (...args: Expand) => Expand + : T extends infer O + ? { [K in keyof O]: O[K] } + : never + + +/** + * The argument types for the Algomint contract + */ +export type AlgomintArgs = { + /** + * The object representation of the arguments for each method + */ + obj: { + 'mint_future_nft(uint64,uint64,uint64,uint64,uint64,pay)void': { + totalNfts: bigint | number + totalPctBps: bigint | number + durationYears: bigint | number + startQuarter: bigint | number + salePrice: bigint | number + mbrPayment: AppMethodCallTransactionArgument + } + 'buy_nft(uint64,axfer,pay)void': { + assetId: bigint | number + optIn: AppMethodCallTransactionArgument + payment: AppMethodCallTransactionArgument + } + 'report_income(uint64,uint64,pay)void': { + quarter: bigint | number + incomeAmount: bigint | number + payoutFunding: AppMethodCallTransactionArgument + } + 'claim_payout(uint64)void': { + assetId: bigint | number + } + 'get_pending_payout(uint64,address)uint64': { + assetId: bigint | number + address: string + } + 'get_terms()(address,uint64,uint64,uint64,uint64,uint64,uint64)': Record + } + /** + * The tuple representation of the arguments for each method + */ + tuple: { + 'mint_future_nft(uint64,uint64,uint64,uint64,uint64,pay)void': [totalNfts: bigint | number, totalPctBps: bigint | number, durationYears: bigint | number, startQuarter: bigint | number, salePrice: bigint | number, mbrPayment: AppMethodCallTransactionArgument] + 'buy_nft(uint64,axfer,pay)void': [assetId: bigint | number, optIn: AppMethodCallTransactionArgument, payment: AppMethodCallTransactionArgument] + 'report_income(uint64,uint64,pay)void': [quarter: bigint | number, incomeAmount: bigint | number, payoutFunding: AppMethodCallTransactionArgument] + 'claim_payout(uint64)void': [assetId: bigint | number] + 'get_pending_payout(uint64,address)uint64': [assetId: bigint | number, address: string] + 'get_terms()(address,uint64,uint64,uint64,uint64,uint64,uint64)': [] + } +} + +/** + * The return type for each method + */ +export type AlgomintReturns = { + 'mint_future_nft(uint64,uint64,uint64,uint64,uint64,pay)void': void + 'buy_nft(uint64,axfer,pay)void': void + 'report_income(uint64,uint64,pay)void': void + 'claim_payout(uint64)void': void + 'get_pending_payout(uint64,address)uint64': bigint + 'get_terms()(address,uint64,uint64,uint64,uint64,uint64,uint64)': [string, bigint, bigint, bigint, bigint, bigint, bigint] +} + +/** + * Defines the types of available calls and state of the Algomint smart contract. + */ +export type AlgomintTypes = { + /** + * Maps method signatures / names to their argument and return types. + */ + methods: + & Record<'mint_future_nft(uint64,uint64,uint64,uint64,uint64,pay)void' | 'mint_future_nft', { + argsObj: AlgomintArgs['obj']['mint_future_nft(uint64,uint64,uint64,uint64,uint64,pay)void'] + argsTuple: AlgomintArgs['tuple']['mint_future_nft(uint64,uint64,uint64,uint64,uint64,pay)void'] + returns: AlgomintReturns['mint_future_nft(uint64,uint64,uint64,uint64,uint64,pay)void'] + }> + & Record<'buy_nft(uint64,axfer,pay)void' | 'buy_nft', { + argsObj: AlgomintArgs['obj']['buy_nft(uint64,axfer,pay)void'] + argsTuple: AlgomintArgs['tuple']['buy_nft(uint64,axfer,pay)void'] + returns: AlgomintReturns['buy_nft(uint64,axfer,pay)void'] + }> + & Record<'report_income(uint64,uint64,pay)void' | 'report_income', { + argsObj: AlgomintArgs['obj']['report_income(uint64,uint64,pay)void'] + argsTuple: AlgomintArgs['tuple']['report_income(uint64,uint64,pay)void'] + returns: AlgomintReturns['report_income(uint64,uint64,pay)void'] + }> + & Record<'claim_payout(uint64)void' | 'claim_payout', { + argsObj: AlgomintArgs['obj']['claim_payout(uint64)void'] + argsTuple: AlgomintArgs['tuple']['claim_payout(uint64)void'] + returns: AlgomintReturns['claim_payout(uint64)void'] + }> + & Record<'get_pending_payout(uint64,address)uint64' | 'get_pending_payout', { + argsObj: AlgomintArgs['obj']['get_pending_payout(uint64,address)uint64'] + argsTuple: AlgomintArgs['tuple']['get_pending_payout(uint64,address)uint64'] + returns: AlgomintReturns['get_pending_payout(uint64,address)uint64'] + }> + & Record<'get_terms()(address,uint64,uint64,uint64,uint64,uint64,uint64)' | 'get_terms', { + argsObj: AlgomintArgs['obj']['get_terms()(address,uint64,uint64,uint64,uint64,uint64,uint64)'] + argsTuple: AlgomintArgs['tuple']['get_terms()(address,uint64,uint64,uint64,uint64,uint64,uint64)'] + returns: AlgomintReturns['get_terms()(address,uint64,uint64,uint64,uint64,uint64,uint64)'] + }> + /** + * Defines the shape of the state of the application. + */ + state: { + global: { + keys: { + creator: string + totalNfts: bigint + totalPctBps: bigint + durationYears: bigint + startQuarter: bigint + salePrice: bigint + firstAssetId: bigint + pctPerNftBps: bigint + lastReportedQuarter: bigint + lastReportedIncome: bigint + payoutPerNft: bigint + initialized: bigint + } + maps: {} + } + box: { + keys: {} + maps: { + lastClaimedQuarter: Map + mintedAssets: Map + } + } + } +} + +/** + * Defines the possible abi call signatures. + */ +export type AlgomintSignatures = keyof AlgomintTypes['methods'] +/** + * Defines the possible abi call signatures for methods that return a non-void value. + */ +export type AlgomintNonVoidMethodSignatures = keyof AlgomintTypes['methods'] extends infer T ? T extends keyof AlgomintTypes['methods'] ? MethodReturn extends void ? never : T : never : never +/** + * Defines an object containing all relevant parameters for a single call to the contract. + */ +export type CallParams = Expand< + Omit & + { + /** The args for the ABI method call, either as an ordered array or an object */ + args: Expand + } +> +/** + * Maps a method signature from the Algomint smart contract to the method's arguments in either tuple or struct form + */ +export type MethodArgs = AlgomintTypes['methods'][TSignature]['argsObj' | 'argsTuple'] +/** + * Maps a method signature from the Algomint smart contract to the method's return type + */ +export type MethodReturn = AlgomintTypes['methods'][TSignature]['returns'] + +/** + * Defines the shape of the keyed global state of the application. + */ +export type GlobalKeysState = AlgomintTypes['state']['global']['keys'] + +/** + * Defines the shape of the keyed box state of the application. + */ +export type BoxKeysState = AlgomintTypes['state']['box']['keys'] + + +/** + * Defines supported create method params for this smart contract + */ +export type AlgomintCreateCallParams = + | Expand +/** + * Defines arguments required for the deploy method. + */ +export type AlgomintDeployParams = Expand & { + /** + * Create transaction parameters to use if a create needs to be issued as part of deployment; use `method` to define ABI call (if available) or leave out for a bare call (if available) + */ + createParams?: AlgomintCreateCallParams +}> + + +/** + * Exposes methods for constructing `AppClient` params objects for ABI calls to the Algomint smart contract + */ +export abstract class AlgomintParamsFactory { + /** + * Constructs a no op call for the mint_future_nft(uint64,uint64,uint64,uint64,uint64,pay)void ABI method + * + * @param params Parameters for the call + * @returns An `AppClientMethodCallParams` object for the call + */ + static mintFutureNft(params: CallParams & CallOnComplete): AppClientMethodCallParams & CallOnComplete { + return { + ...params, + method: 'mint_future_nft(uint64,uint64,uint64,uint64,uint64,pay)void' as const, + args: Array.isArray(params.args) ? params.args : [params.args.totalNfts, params.args.totalPctBps, params.args.durationYears, params.args.startQuarter, params.args.salePrice, params.args.mbrPayment], + } + } + /** + * Constructs a no op call for the buy_nft(uint64,axfer,pay)void ABI method + * + * @param params Parameters for the call + * @returns An `AppClientMethodCallParams` object for the call + */ + static buyNft(params: CallParams & CallOnComplete): AppClientMethodCallParams & CallOnComplete { + return { + ...params, + method: 'buy_nft(uint64,axfer,pay)void' as const, + args: Array.isArray(params.args) ? params.args : [params.args.assetId, params.args.optIn, params.args.payment], + } + } + /** + * Constructs a no op call for the report_income(uint64,uint64,pay)void ABI method + * + * @param params Parameters for the call + * @returns An `AppClientMethodCallParams` object for the call + */ + static reportIncome(params: CallParams & CallOnComplete): AppClientMethodCallParams & CallOnComplete { + return { + ...params, + method: 'report_income(uint64,uint64,pay)void' as const, + args: Array.isArray(params.args) ? params.args : [params.args.quarter, params.args.incomeAmount, params.args.payoutFunding], + } + } + /** + * Constructs a no op call for the claim_payout(uint64)void ABI method + * + * @param params Parameters for the call + * @returns An `AppClientMethodCallParams` object for the call + */ + static claimPayout(params: CallParams & CallOnComplete): AppClientMethodCallParams & CallOnComplete { + return { + ...params, + method: 'claim_payout(uint64)void' as const, + args: Array.isArray(params.args) ? params.args : [params.args.assetId], + } + } + /** + * Constructs a no op call for the get_pending_payout(uint64,address)uint64 ABI method + * + * @param params Parameters for the call + * @returns An `AppClientMethodCallParams` object for the call + */ + static getPendingPayout(params: CallParams & CallOnComplete): AppClientMethodCallParams & CallOnComplete { + return { + ...params, + method: 'get_pending_payout(uint64,address)uint64' as const, + args: Array.isArray(params.args) ? params.args : [params.args.assetId, params.args.address], + } + } + /** + * Constructs a no op call for the get_terms()(address,uint64,uint64,uint64,uint64,uint64,uint64) ABI method + * + * Returns: (creator, total_nfts, total_pct_bps, duration_years, start_quarter, sale_price, first_asset_id) + * + * @param params Parameters for the call + * @returns An `AppClientMethodCallParams` object for the call + */ + static getTerms(params: CallParams & CallOnComplete): AppClientMethodCallParams & CallOnComplete { + return { + ...params, + method: 'get_terms()(address,uint64,uint64,uint64,uint64,uint64,uint64)' as const, + args: Array.isArray(params.args) ? params.args : [], + } + } +} + +/** + * A factory to create and deploy one or more instance of the Algomint smart contract and to create one or more app clients to interact with those (or other) app instances + */ +export class AlgomintFactory { + /** + * The underlying `AppFactory` for when you want to have more flexibility + */ + public readonly appFactory: _AppFactory + + /** + * Creates a new instance of `AlgomintFactory` + * + * @param params The parameters to initialise the app factory with + */ + constructor(params: Omit) { + this.appFactory = new _AppFactory({ + ...params, + appSpec: APP_SPEC, + }) + } + + /** The name of the app (from the ARC-32 / ARC-56 app spec or override). */ + public get appName() { + return this.appFactory.appName + } + + /** The ARC-56 app spec being used */ + get appSpec() { + return APP_SPEC + } + + /** A reference to the underlying `AlgorandClient` this app factory is using. */ + public get algorand(): AlgorandClient { + return this.appFactory.algorand + } + + /** + * Returns a new `AppClient` client for an app instance of the given ID. + * + * Automatically populates appName, defaultSender and source maps from the factory + * if not specified in the params. + * @param params The parameters to create the app client + * @returns The `AppClient` + */ + public getAppClientById(params: AppFactoryAppClientParams) { + return new AlgomintClient(this.appFactory.getAppClientById(params)) + } + + /** + * Returns a new `AppClient` client, resolving the app by creator address and name + * using AlgoKit app deployment semantics (i.e. looking for the app creation transaction note). + * + * Automatically populates appName, defaultSender and source maps from the factory + * if not specified in the params. + * @param params The parameters to create the app client + * @returns The `AppClient` + */ + public async getAppClientByCreatorAndName( + params: AppFactoryResolveAppClientByCreatorAndNameParams, + ) { + return new AlgomintClient(await this.appFactory.getAppClientByCreatorAndName(params)) + } + + /** + * Idempotently deploys the Algomint smart contract. + * + * @param params The arguments for the contract calls and any additional parameters for the call + * @returns The deployment result + */ + public async deploy(params: AlgomintDeployParams = {}) { + const result = await this.appFactory.deploy({ + ...params, + }) + return { result: result.result, appClient: new AlgomintClient(result.appClient) } + } + + /** + * Get parameters to create transactions (create and deploy related calls) for the current app. A good mental model for this is that these parameters represent a deferred transaction creation. + */ + readonly params = { + /** + * Gets available create methods + */ + create: { + /** + * Creates a new instance of the Algomint smart contract using a bare call. + * + * @param params The params for the bare (raw) call + * @returns The params for a create call + */ + bare: (params?: Expand) => { + return this.appFactory.params.bare.create(params) + }, + }, + + } + + /** + * Create transactions for the current app + */ + readonly createTransaction = { + /** + * Gets available create methods + */ + create: { + /** + * Creates a new instance of the Algomint smart contract using a bare call. + * + * @param params The params for the bare (raw) call + * @returns The transaction for a create call + */ + bare: (params?: Expand) => { + return this.appFactory.createTransaction.bare.create(params) + }, + }, + + } + + /** + * Send calls to the current app + */ + readonly send = { + /** + * Gets available create methods + */ + create: { + /** + * Creates a new instance of the Algomint smart contract using a bare call. + * + * @param params The params for the bare (raw) call + * @returns The create result + */ + bare: async (params?: Expand) => { + const result = await this.appFactory.send.bare.create(params) + return { result: result.result, appClient: new AlgomintClient(result.appClient) } + }, + }, + + } + +} +/** + * A client to make calls to the Algomint smart contract + */ +export class AlgomintClient { + /** + * The underlying `AppClient` for when you want to have more flexibility + */ + public readonly appClient: _AppClient + + /** + * Creates a new instance of `AlgomintClient` + * + * @param appClient An `AppClient` instance which has been created with the Algomint app spec + */ + constructor(appClient: _AppClient) + /** + * Creates a new instance of `AlgomintClient` + * + * @param params The parameters to initialise the app client with + */ + constructor(params: Omit) + constructor(appClientOrParams: _AppClient | Omit) { + this.appClient = appClientOrParams instanceof _AppClient ? appClientOrParams : new _AppClient({ + ...appClientOrParams, + appSpec: APP_SPEC, + }) + } + + /** + * Checks for decode errors on the given return value and maps the return value to the return type for the given method + * @returns The typed return value or undefined if there was no value + */ + decodeReturnValue(method: TSignature, returnValue: ABIReturn | undefined) { + return returnValue !== undefined ? getArc56ReturnValue>(returnValue, this.appClient.getABIMethod(method), APP_SPEC.structs) : undefined + } + + /** + * Returns a new `AlgomintClient` client, resolving the app by creator address and name + * using AlgoKit app deployment semantics (i.e. looking for the app creation transaction note). + * @param params The parameters to create the app client + */ + public static async fromCreatorAndName(params: Omit): Promise { + return new AlgomintClient(await _AppClient.fromCreatorAndName({...params, appSpec: APP_SPEC})) + } + + /** + * Returns an `AlgomintClient` instance for the current network based on + * pre-determined network-specific app IDs specified in the ARC-56 app spec. + * + * If no IDs are in the app spec or the network isn't recognised, an error is thrown. + * @param params The parameters to create the app client + */ + static async fromNetwork( + params: Omit + ): Promise { + return new AlgomintClient(await _AppClient.fromNetwork({...params, appSpec: APP_SPEC})) + } + + /** The ID of the app instance this client is linked to. */ + public get appId() { + return this.appClient.appId + } + + /** The app address of the app instance this client is linked to. */ + public get appAddress() { + return this.appClient.appAddress + } + + /** The name of the app. */ + public get appName() { + return this.appClient.appName + } + + /** The ARC-56 app spec being used */ + public get appSpec() { + return this.appClient.appSpec + } + + /** A reference to the underlying `AlgorandClient` this app client is using. */ + public get algorand(): AlgorandClient { + return this.appClient.algorand + } + + /** + * Get parameters to create transactions for the current app. A good mental model for this is that these parameters represent a deferred transaction creation. + */ + readonly params = { + /** + * Makes a clear_state call to an existing instance of the Algomint smart contract. + * + * @param params The params for the bare (raw) call + * @returns The clearState result + */ + clearState: (params?: Expand) => { + return this.appClient.params.bare.clearState(params) + }, + + /** + * Makes a call to the Algomint smart contract using the `mint_future_nft(uint64,uint64,uint64,uint64,uint64,pay)void` ABI method. + * + * @param params The params for the smart contract call + * @returns The call params + */ + mintFutureNft: (params: CallParams & {onComplete?: OnApplicationComplete.NoOpOC}) => { + return this.appClient.params.call(AlgomintParamsFactory.mintFutureNft(params)) + }, + + /** + * Makes a call to the Algomint smart contract using the `buy_nft(uint64,axfer,pay)void` ABI method. + * + * @param params The params for the smart contract call + * @returns The call params + */ + buyNft: (params: CallParams & {onComplete?: OnApplicationComplete.NoOpOC}) => { + return this.appClient.params.call(AlgomintParamsFactory.buyNft(params)) + }, + + /** + * Makes a call to the Algomint smart contract using the `report_income(uint64,uint64,pay)void` ABI method. + * + * @param params The params for the smart contract call + * @returns The call params + */ + reportIncome: (params: CallParams & {onComplete?: OnApplicationComplete.NoOpOC}) => { + return this.appClient.params.call(AlgomintParamsFactory.reportIncome(params)) + }, + + /** + * Makes a call to the Algomint smart contract using the `claim_payout(uint64)void` ABI method. + * + * @param params The params for the smart contract call + * @returns The call params + */ + claimPayout: (params: CallParams & {onComplete?: OnApplicationComplete.NoOpOC}) => { + return this.appClient.params.call(AlgomintParamsFactory.claimPayout(params)) + }, + + /** + * Makes a call to the Algomint smart contract using the `get_pending_payout(uint64,address)uint64` ABI method. + * + * This method is a readonly method; calling it with onComplete of NoOp will result in a simulated transaction rather than a real transaction. + * + * @param params The params for the smart contract call + * @returns The call params + */ + getPendingPayout: (params: CallParams & {onComplete?: OnApplicationComplete.NoOpOC}) => { + return this.appClient.params.call(AlgomintParamsFactory.getPendingPayout(params)) + }, + + /** + * Makes a call to the Algomint smart contract using the `get_terms()(address,uint64,uint64,uint64,uint64,uint64,uint64)` ABI method. + * + * This method is a readonly method; calling it with onComplete of NoOp will result in a simulated transaction rather than a real transaction. + * + * Returns: (creator, total_nfts, total_pct_bps, duration_years, start_quarter, sale_price, first_asset_id) + * + * @param params The params for the smart contract call + * @returns The call params + */ + getTerms: (params: CallParams & {onComplete?: OnApplicationComplete.NoOpOC} = {args: []}) => { + return this.appClient.params.call(AlgomintParamsFactory.getTerms(params)) + }, + + } + + /** + * Create transactions for the current app + */ + readonly createTransaction = { + /** + * Makes a clear_state call to an existing instance of the Algomint smart contract. + * + * @param params The params for the bare (raw) call + * @returns The clearState result + */ + clearState: (params?: Expand) => { + return this.appClient.createTransaction.bare.clearState(params) + }, + + /** + * Makes a call to the Algomint smart contract using the `mint_future_nft(uint64,uint64,uint64,uint64,uint64,pay)void` ABI method. + * + * @param params The params for the smart contract call + * @returns The call transaction + */ + mintFutureNft: (params: CallParams & {onComplete?: OnApplicationComplete.NoOpOC}) => { + return this.appClient.createTransaction.call(AlgomintParamsFactory.mintFutureNft(params)) + }, + + /** + * Makes a call to the Algomint smart contract using the `buy_nft(uint64,axfer,pay)void` ABI method. + * + * @param params The params for the smart contract call + * @returns The call transaction + */ + buyNft: (params: CallParams & {onComplete?: OnApplicationComplete.NoOpOC}) => { + return this.appClient.createTransaction.call(AlgomintParamsFactory.buyNft(params)) + }, + + /** + * Makes a call to the Algomint smart contract using the `report_income(uint64,uint64,pay)void` ABI method. + * + * @param params The params for the smart contract call + * @returns The call transaction + */ + reportIncome: (params: CallParams & {onComplete?: OnApplicationComplete.NoOpOC}) => { + return this.appClient.createTransaction.call(AlgomintParamsFactory.reportIncome(params)) + }, + + /** + * Makes a call to the Algomint smart contract using the `claim_payout(uint64)void` ABI method. + * + * @param params The params for the smart contract call + * @returns The call transaction + */ + claimPayout: (params: CallParams & {onComplete?: OnApplicationComplete.NoOpOC}) => { + return this.appClient.createTransaction.call(AlgomintParamsFactory.claimPayout(params)) + }, + + /** + * Makes a call to the Algomint smart contract using the `get_pending_payout(uint64,address)uint64` ABI method. + * + * This method is a readonly method; calling it with onComplete of NoOp will result in a simulated transaction rather than a real transaction. + * + * @param params The params for the smart contract call + * @returns The call transaction + */ + getPendingPayout: (params: CallParams & {onComplete?: OnApplicationComplete.NoOpOC}) => { + return this.appClient.createTransaction.call(AlgomintParamsFactory.getPendingPayout(params)) + }, + + /** + * Makes a call to the Algomint smart contract using the `get_terms()(address,uint64,uint64,uint64,uint64,uint64,uint64)` ABI method. + * + * This method is a readonly method; calling it with onComplete of NoOp will result in a simulated transaction rather than a real transaction. + * + * Returns: (creator, total_nfts, total_pct_bps, duration_years, start_quarter, sale_price, first_asset_id) + * + * @param params The params for the smart contract call + * @returns The call transaction + */ + getTerms: (params: CallParams & {onComplete?: OnApplicationComplete.NoOpOC} = {args: []}) => { + return this.appClient.createTransaction.call(AlgomintParamsFactory.getTerms(params)) + }, + + } + + /** + * Send calls to the current app + */ + readonly send = { + /** + * Makes a clear_state call to an existing instance of the Algomint smart contract. + * + * @param params The params for the bare (raw) call + * @returns The clearState result + */ + clearState: (params?: Expand) => { + return this.appClient.send.bare.clearState(params) + }, + + /** + * Makes a call to the Algomint smart contract using the `mint_future_nft(uint64,uint64,uint64,uint64,uint64,pay)void` ABI method. + * + * @param params The params for the smart contract call + * @returns The call result + */ + mintFutureNft: async (params: CallParams & SendParams & {onComplete?: OnApplicationComplete.NoOpOC}) => { + const result = await this.appClient.send.call(AlgomintParamsFactory.mintFutureNft(params)) + return {...result, return: result.return as unknown as (undefined | AlgomintReturns['mint_future_nft(uint64,uint64,uint64,uint64,uint64,pay)void'])} + }, + + /** + * Makes a call to the Algomint smart contract using the `buy_nft(uint64,axfer,pay)void` ABI method. + * + * @param params The params for the smart contract call + * @returns The call result + */ + buyNft: async (params: CallParams & SendParams & {onComplete?: OnApplicationComplete.NoOpOC}) => { + const result = await this.appClient.send.call(AlgomintParamsFactory.buyNft(params)) + return {...result, return: result.return as unknown as (undefined | AlgomintReturns['buy_nft(uint64,axfer,pay)void'])} + }, + + /** + * Makes a call to the Algomint smart contract using the `report_income(uint64,uint64,pay)void` ABI method. + * + * @param params The params for the smart contract call + * @returns The call result + */ + reportIncome: async (params: CallParams & SendParams & {onComplete?: OnApplicationComplete.NoOpOC}) => { + const result = await this.appClient.send.call(AlgomintParamsFactory.reportIncome(params)) + return {...result, return: result.return as unknown as (undefined | AlgomintReturns['report_income(uint64,uint64,pay)void'])} + }, + + /** + * Makes a call to the Algomint smart contract using the `claim_payout(uint64)void` ABI method. + * + * @param params The params for the smart contract call + * @returns The call result + */ + claimPayout: async (params: CallParams & SendParams & {onComplete?: OnApplicationComplete.NoOpOC}) => { + const result = await this.appClient.send.call(AlgomintParamsFactory.claimPayout(params)) + return {...result, return: result.return as unknown as (undefined | AlgomintReturns['claim_payout(uint64)void'])} + }, + + /** + * Makes a call to the Algomint smart contract using the `get_pending_payout(uint64,address)uint64` ABI method. + * + * This method is a readonly method; calling it with onComplete of NoOp will result in a simulated transaction rather than a real transaction. + * + * @param params The params for the smart contract call + * @returns The call result + */ + getPendingPayout: async (params: CallParams & SendParams & {onComplete?: OnApplicationComplete.NoOpOC}) => { + const result = await this.appClient.send.call(AlgomintParamsFactory.getPendingPayout(params)) + return {...result, return: result.return as unknown as (undefined | AlgomintReturns['get_pending_payout(uint64,address)uint64'])} + }, + + /** + * Makes a call to the Algomint smart contract using the `get_terms()(address,uint64,uint64,uint64,uint64,uint64,uint64)` ABI method. + * + * This method is a readonly method; calling it with onComplete of NoOp will result in a simulated transaction rather than a real transaction. + * + * Returns: (creator, total_nfts, total_pct_bps, duration_years, start_quarter, sale_price, first_asset_id) + * + * @param params The params for the smart contract call + * @returns The call result + */ + getTerms: async (params: CallParams & SendParams & {onComplete?: OnApplicationComplete.NoOpOC} = {args: []}) => { + const result = await this.appClient.send.call(AlgomintParamsFactory.getTerms(params)) + return {...result, return: result.return as unknown as (undefined | AlgomintReturns['get_terms()(address,uint64,uint64,uint64,uint64,uint64,uint64)'])} + }, + + } + + /** + * Clone this app client with different params + * + * @param params The params to use for the the cloned app client. Omit a param to keep the original value. Set a param to override the original value. Setting to undefined will clear the original value. + * @returns A new app client with the altered params + */ + public clone(params: CloneAppClientParams) { + return new AlgomintClient(this.appClient.clone(params)) + } + + /** + * Makes a readonly (simulated) call to the Algomint smart contract using the `get_pending_payout(uint64,address)uint64` ABI method. + * + * This method is a readonly method; calling it with onComplete of NoOp will result in a simulated transaction rather than a real transaction. + * + * @param params The params for the smart contract call + * @returns The call result + */ + async getPendingPayout(params: CallParams) { + const result = await this.appClient.send.call(AlgomintParamsFactory.getPendingPayout(params)) + return result.return as unknown as AlgomintReturns['get_pending_payout(uint64,address)uint64'] + } + + /** + * Makes a readonly (simulated) call to the Algomint smart contract using the `get_terms()(address,uint64,uint64,uint64,uint64,uint64,uint64)` ABI method. + * + * This method is a readonly method; calling it with onComplete of NoOp will result in a simulated transaction rather than a real transaction. + * + * Returns: (creator, total_nfts, total_pct_bps, duration_years, start_quarter, sale_price, first_asset_id) + * + * @param params The params for the smart contract call + * @returns The call result + */ + async getTerms(params: CallParams = {args: []}) { + const result = await this.appClient.send.call(AlgomintParamsFactory.getTerms(params)) + return result.return as unknown as AlgomintReturns['get_terms()(address,uint64,uint64,uint64,uint64,uint64,uint64)'] + } + + /** + * Methods to access state for the current Algomint app + */ + state = { + /** + * Methods to access global state for the current Algomint app + */ + global: { + /** + * Get all current keyed values from global state + */ + getAll: async (): Promise>> => { + const result = await this.appClient.state.global.getAll() + return { + creator: result.creator, + totalNfts: result.total_nfts, + totalPctBps: result.total_pct_bps, + durationYears: result.duration_years, + startQuarter: result.start_quarter, + salePrice: result.sale_price, + firstAssetId: result.first_asset_id, + pctPerNftBps: result.pct_per_nft_bps, + lastReportedQuarter: result.last_reported_quarter, + lastReportedIncome: result.last_reported_income, + payoutPerNft: result.payout_per_nft, + initialized: result.initialized, + } + }, + /** + * Get the current value of the creator key in global state + */ + creator: async (): Promise => { return (await this.appClient.state.global.getValue("creator")) as string | undefined }, + /** + * Get the current value of the total_nfts key in global state + */ + totalNfts: async (): Promise => { return (await this.appClient.state.global.getValue("total_nfts")) as bigint | undefined }, + /** + * Get the current value of the total_pct_bps key in global state + */ + totalPctBps: async (): Promise => { return (await this.appClient.state.global.getValue("total_pct_bps")) as bigint | undefined }, + /** + * Get the current value of the duration_years key in global state + */ + durationYears: async (): Promise => { return (await this.appClient.state.global.getValue("duration_years")) as bigint | undefined }, + /** + * Get the current value of the start_quarter key in global state + */ + startQuarter: async (): Promise => { return (await this.appClient.state.global.getValue("start_quarter")) as bigint | undefined }, + /** + * Get the current value of the sale_price key in global state + */ + salePrice: async (): Promise => { return (await this.appClient.state.global.getValue("sale_price")) as bigint | undefined }, + /** + * Get the current value of the first_asset_id key in global state + */ + firstAssetId: async (): Promise => { return (await this.appClient.state.global.getValue("first_asset_id")) as bigint | undefined }, + /** + * Get the current value of the pct_per_nft_bps key in global state + */ + pctPerNftBps: async (): Promise => { return (await this.appClient.state.global.getValue("pct_per_nft_bps")) as bigint | undefined }, + /** + * Get the current value of the last_reported_quarter key in global state + */ + lastReportedQuarter: async (): Promise => { return (await this.appClient.state.global.getValue("last_reported_quarter")) as bigint | undefined }, + /** + * Get the current value of the last_reported_income key in global state + */ + lastReportedIncome: async (): Promise => { return (await this.appClient.state.global.getValue("last_reported_income")) as bigint | undefined }, + /** + * Get the current value of the payout_per_nft key in global state + */ + payoutPerNft: async (): Promise => { return (await this.appClient.state.global.getValue("payout_per_nft")) as bigint | undefined }, + /** + * Get the current value of the initialized key in global state + */ + initialized: async (): Promise => { return (await this.appClient.state.global.getValue("initialized")) as bigint | undefined }, + }, + /** + * Methods to access box state for the current Algomint app + */ + box: { + /** + * Get all current keyed values from box state + */ + getAll: async (): Promise>> => { + const result = await this.appClient.state.box.getAll() + return { + } + }, + /** + * Get values from the last_claimed_quarter map in box state + */ + lastClaimedQuarter: { + /** + * Get all current values of the last_claimed_quarter map in box state + */ + getMap: async (): Promise> => { return (await this.appClient.state.box.getMap("last_claimed_quarter")) as Map }, + /** + * Get a current value of the last_claimed_quarter map by key from box state + */ + value: async (key: bigint | number): Promise => { return await this.appClient.state.box.getMapValue("last_claimed_quarter", key) as bigint | undefined }, + }, + /** + * Get values from the minted_assets map in box state + */ + mintedAssets: { + /** + * Get all current values of the minted_assets map in box state + */ + getMap: async (): Promise> => { return (await this.appClient.state.box.getMap("minted_assets")) as Map }, + /** + * Get a current value of the minted_assets map by key from box state + */ + value: async (key: bigint | number): Promise => { return await this.appClient.state.box.getMapValue("minted_assets", key) as bigint | undefined }, + }, + }, + } + + public newGroup(): AlgomintComposer { + const client = this + const composer = this.algorand.newGroup() + let promiseChain:Promise = Promise.resolve() + const resultMappers: Array any)> = [] + return { + /** + * Add a mint_future_nft(uint64,uint64,uint64,uint64,uint64,pay)void method call against the Algomint contract + */ + mintFutureNft(params: CallParams & {onComplete?: OnApplicationComplete.NoOpOC}) { + promiseChain = promiseChain.then(async () => composer.addAppCallMethodCall(await client.params.mintFutureNft(params))) + resultMappers.push(undefined) + return this + }, + /** + * Add a buy_nft(uint64,axfer,pay)void method call against the Algomint contract + */ + buyNft(params: CallParams & {onComplete?: OnApplicationComplete.NoOpOC}) { + promiseChain = promiseChain.then(async () => composer.addAppCallMethodCall(await client.params.buyNft(params))) + resultMappers.push(undefined) + return this + }, + /** + * Add a report_income(uint64,uint64,pay)void method call against the Algomint contract + */ + reportIncome(params: CallParams & {onComplete?: OnApplicationComplete.NoOpOC}) { + promiseChain = promiseChain.then(async () => composer.addAppCallMethodCall(await client.params.reportIncome(params))) + resultMappers.push(undefined) + return this + }, + /** + * Add a claim_payout(uint64)void method call against the Algomint contract + */ + claimPayout(params: CallParams & {onComplete?: OnApplicationComplete.NoOpOC}) { + promiseChain = promiseChain.then(async () => composer.addAppCallMethodCall(await client.params.claimPayout(params))) + resultMappers.push(undefined) + return this + }, + /** + * Add a get_pending_payout(uint64,address)uint64 method call against the Algomint contract + */ + getPendingPayout(params: CallParams & {onComplete?: OnApplicationComplete.NoOpOC}) { + promiseChain = promiseChain.then(async () => composer.addAppCallMethodCall(await client.params.getPendingPayout(params))) + resultMappers.push((v) => client.decodeReturnValue('get_pending_payout(uint64,address)uint64', v)) + return this + }, + /** + * Add a get_terms()(address,uint64,uint64,uint64,uint64,uint64,uint64) method call against the Algomint contract + */ + getTerms(params: CallParams & {onComplete?: OnApplicationComplete.NoOpOC}) { + promiseChain = promiseChain.then(async () => composer.addAppCallMethodCall(await client.params.getTerms(params))) + resultMappers.push((v) => client.decodeReturnValue('get_terms()(address,uint64,uint64,uint64,uint64,uint64,uint64)', v)) + return this + }, + /** + * Add a clear state call to the Algomint contract + */ + clearState(params: AppClientBareCallParams) { + promiseChain = promiseChain.then(() => composer.addAppCall(client.params.clearState(params))) + return this + }, + addTransaction(txn: Transaction, signer?: TransactionSigner) { + promiseChain = promiseChain.then(() => composer.addTransaction(txn, signer)) + return this + }, + async composer() { + await promiseChain + return composer + }, + async simulate(options?: SimulateOptions) { + await promiseChain + const result = await (!options ? composer.simulate() : composer.simulate(options)) + return { + ...result, + returns: result.returns?.map((val, i) => resultMappers[i] !== undefined ? resultMappers[i]!(val) : val.returnValue) + } + }, + async send(params?: SendParams) { + await promiseChain + const result = await composer.send(params) + return { + ...result, + returns: result.returns?.map((val, i) => resultMappers[i] !== undefined ? resultMappers[i]!(val) : val.returnValue) + } + } + } as unknown as AlgomintComposer + } +} +export type AlgomintComposer = { + /** + * Calls the mint_future_nft(uint64,uint64,uint64,uint64,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 + */ + mintFutureNft(params?: CallParams): AlgomintComposer<[...TReturns, AlgomintReturns['mint_future_nft(uint64,uint64,uint64,uint64,uint64,pay)void'] | undefined]> + + /** + * Calls the buy_nft(uint64,axfer,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 + */ + buyNft(params?: CallParams): AlgomintComposer<[...TReturns, AlgomintReturns['buy_nft(uint64,axfer,pay)void'] | undefined]> + + /** + * Calls the report_income(uint64,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 + */ + reportIncome(params?: CallParams): AlgomintComposer<[...TReturns, AlgomintReturns['report_income(uint64,uint64,pay)void'] | undefined]> + + /** + * Calls the claim_payout(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 + */ + claimPayout(params?: CallParams): AlgomintComposer<[...TReturns, AlgomintReturns['claim_payout(uint64)void'] | undefined]> + + /** + * Calls the get_pending_payout(uint64,address)uint64 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 + */ + getPendingPayout(params?: CallParams): AlgomintComposer<[...TReturns, AlgomintReturns['get_pending_payout(uint64,address)uint64'] | undefined]> + + /** + * Calls the get_terms()(address,uint64,uint64,uint64,uint64,uint64,uint64) ABI method. + * + * Returns: (creator, total_nfts, total_pct_bps, duration_years, start_quarter, sale_price, first_asset_id) + * + * @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 + */ + getTerms(params?: CallParams): AlgomintComposer<[...TReturns, AlgomintReturns['get_terms()(address,uint64,uint64,uint64,uint64,uint64,uint64)'] | undefined]> + + /** + * Makes a clear_state call to an existing instance of the Algomint 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(params?: AppClientBareCallParams): AlgomintComposer<[...TReturns, undefined]> + + /** + * Adds a transaction to the composer + * + * @param txn A transaction to add to the transaction group + * @param signer The optional signer to use when signing this transaction. + */ + addTransaction(txn: Transaction, signer?: TransactionSigner): AlgomintComposer + /** + * Returns the underlying AtomicTransactionComposer instance + */ + composer(): Promise + /** + * Simulates the transaction group and returns the result + */ + simulate(): Promise & { simulateResponse: SimulateResponse }> + simulate(options: SkipSignaturesSimulateOptions): Promise & { simulateResponse: SimulateResponse }> + simulate(options: RawSimulateOptions): Promise & { simulateResponse: SimulateResponse }> + /** + * Sends the transaction group to the network and returns the results + */ + send(params?: SendParams): Promise> +} +export type AlgomintComposerResults = Expand + diff --git a/projects/hackalgo-frontend/src/hooks/useAlgoMint.ts b/projects/hackalgo-frontend/src/hooks/useAlgoMint.ts index bb052a6..8fb3bd0 100644 --- a/projects/hackalgo-frontend/src/hooks/useAlgoMint.ts +++ b/projects/hackalgo-frontend/src/hooks/useAlgoMint.ts @@ -1,10 +1,17 @@ -import { useCallback, useMemo, useState } from 'react' -import assetIdsJson from '../assets/asset_ids.json' +import { AlgorandClient, algo } from '@algorandfoundation/algokit-utils' +import { useWallet } from '@txnlab/use-wallet-react' +import algosdk from 'algosdk' +import { useCallback, useEffect, useMemo, useState } from 'react' +import { AlgomintClient, AlgomintFactory } from '../contracts/Algomint' +import { getAlgodConfigFromViteEnvironment, getIndexerConfigFromViteEnvironment } from '../utils/network/getAlgoClientConfigs' type AlgoMintTerms = { nft_count: number total_pct_bps: number duration_years: number + start_quarter: number + sale_price_micro_algo: number + first_asset_id: number } export type AlgoMintNft = { @@ -13,10 +20,7 @@ export type AlgoMintNft = { } type PersistedState = { - terms: AlgoMintTerms | null - creatorAddress: string | null - nfts: AlgoMintNft[] - pendingPayoutByAssetId: Record + appId: string | null } const STORAGE_KEY = 'algomint:mock:state:v1' @@ -41,136 +45,282 @@ function saveState(state: PersistedState) { function defaultState(): PersistedState { return { - terms: null, - creatorAddress: null, - nfts: [], - pendingPayoutByAssetId: {}, + appId: null, } } -function delay(ms: number) { - return new Promise((resolve) => setTimeout(resolve, ms)) -} - export function useAlgoMint() { + const { transactionSigner, activeAddress } = useWallet() const [state, setState] = useState(() => loadState()) + const [termsValue, setTermsValue] = useState(null) + const [creatorAddressValue, setCreatorAddressValue] = useState(null) const persist = useCallback((next: PersistedState) => { setState(next) saveState(next) }, []) - const terms = state.terms - const creatorAddress = state.creatorAddress + // Important: Memoize configs to avoid recreating AlgorandClient every render + // (which can cause effects to re-run and lock the UI in a re-render loop). + const algodConfig = useMemo(() => getAlgodConfigFromViteEnvironment(), []) + const indexerConfig = useMemo(() => getIndexerConfigFromViteEnvironment(), []) + const algorand = useMemo(() => AlgorandClient.fromConfig({ algodConfig, indexerConfig }), [algodConfig, indexerConfig]) + + const getClient = useCallback(async (): Promise => { + if (!transactionSigner || !activeAddress) { + throw new Error('Wallet not connected') + } + + if (state.appId) { + return new AlgomintClient({ + algorand, + appId: BigInt(state.appId), + defaultSender: activeAddress, + defaultSigner: transactionSigner, + }) + } + + // Hackathon convenience: deploy the app from the UI on first use. + const factory = new AlgomintFactory({ + algorand, + defaultSender: activeAddress, + defaultSigner: transactionSigner, + }) + + const deployed = await factory.send.create.bare({}) + const appId = deployed.appClient.appId.toString() + persist({ appId }) + + return deployed.appClient.clone({ defaultSender: activeAddress, defaultSigner: transactionSigner }) + }, [activeAddress, algorand, persist, state.appId, transactionSigner]) + + const fetchTerms = useCallback(async (): Promise => { + if (!state.appId) return null + const client = await getClient() + const [creator, totalNfts, totalPctBps, durationYears, startQuarter, salePrice, firstAssetId] = + await client.getTerms() + return { + nft_count: Number(totalNfts), + total_pct_bps: Number(totalPctBps), + duration_years: Number(durationYears), + start_quarter: Number(startQuarter), + sale_price_micro_algo: Number(salePrice), + first_asset_id: Number(firstAssetId), + } + }, [getClient, state.appId]) + + const refreshTerms = useCallback(async () => { + if (!state.appId || !transactionSigner || !activeAddress) { + setTermsValue(null) + setCreatorAddressValue(null) + return + } + const client = await getClient() + const [creator, totalNfts, totalPctBps, durationYears, startQuarter, salePrice, firstAssetId] = + await client.getTerms() + setCreatorAddressValue(creator) + setTermsValue({ + nft_count: Number(totalNfts), + total_pct_bps: Number(totalPctBps), + duration_years: Number(durationYears), + start_quarter: Number(startQuarter), + sale_price_micro_algo: Number(salePrice), + first_asset_id: Number(firstAssetId), + }) + }, [activeAddress, getClient, state.appId, transactionSigner]) + + useEffect(() => { + void refreshTerms() + }, [refreshTerms]) const listNfts = useCallback(async (): Promise => { - await delay(400) - if (state.nfts.length > 0) return state.nfts + if (!state.appId) return [] + const t = termsValue ?? (await fetchTerms()) + if (!t) return [] - const fallback = (assetIdsJson as { assetIds: number[] }).assetIds.map((assetId) => ({ - assetId, - owner: null, - })) - return fallback - }, [state.nfts]) + const client = await getClient() + const appAddr = client.appAddress - // ABI-shaped method names/args (mocked for now) - const mint_future_nft = useCallback( - async (args: { creator: string; nft_count: number; total_pct_bps: number; duration_years: number; mbr_payment?: number }) => { - await delay(900) + const assetIds = Array.from({ length: t.nft_count }).map((_, i) => t.first_asset_id + i) + const algod = algorand.client.algod + + const rows = await Promise.all( + assetIds.map(async (assetId) => { + // Avoid Indexer for responsiveness. We only detect: + // - For sale: app holds the NFT + // - Owned by you: connected wallet holds the NFT + // - Otherwise: owner unknown (treated as not-for-sale) + const appInfo = await algod.accountAssetInformation(appAddr, assetId).do().catch(() => null) + const appHolds = (appInfo?.assetHolding?.amount ?? 0n) === 1n + if (appHolds) return { assetId, owner: null } + + if (activeAddress) { + const youInfo = await algod.accountAssetInformation(activeAddress, assetId).do().catch(() => null) + const youHold = (youInfo?.assetHolding?.amount ?? 0n) === 1n + if (youHold) return { assetId, owner: activeAddress } + } + + return { assetId, owner: 'unknown' } + }), + ) + return rows + }, [activeAddress, algorand.client.algod, fetchTerms, getClient, state.appId, termsValue]) + + const mint_future_nft = useCallback( + async (args: { + creator: string + nft_count: number + total_pct_bps: number + duration_years: number + start_quarter: number + sale_price_micro_algo: number + mbr_payment_micro_algo?: number + }) => { if (args.nft_count <= 0) throw new Error('NFT count must be > 0') if (args.total_pct_bps <= 0 || args.total_pct_bps > 10_000) throw new Error('Total % bps must be between 1 and 10000') if (args.duration_years <= 0) throw new Error('Duration years must be > 0') + if (args.start_quarter <= 0) throw new Error('Start quarter must be > 0') + if (args.sale_price_micro_algo <= 0) throw new Error('Sale price must be > 0') + + if (!transactionSigner || !activeAddress) throw new Error('Wallet not connected') + + const client = await getClient() + const sp = await algorand.client.algod.getTransactionParams().do() + const mbrAmount = args.mbr_payment_micro_algo ?? algo(1).microAlgo + const mbrPaymentTxn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({ + sender: activeAddress, + receiver: client.appAddress, + amount: mbrAmount, + suggestedParams: sp, + }) + + const group = client.newGroup() + group.addTransaction(mbrPaymentTxn, transactionSigner) + group.mintFutureNft({ + sender: activeAddress, + args: { + totalNfts: args.nft_count, + totalPctBps: args.total_pct_bps, + durationYears: args.duration_years, + startQuarter: args.start_quarter, + salePrice: args.sale_price_micro_algo, + mbrPayment: mbrPaymentTxn, + }, + }) + await group.send() - // Mock: generate unique-ish asset IDs. - const base = Date.now() % 1_000_000_000 - const nfts: AlgoMintNft[] = Array.from({ length: args.nft_count }).map((_, i) => ({ - assetId: base + i + 1, - owner: null, - })) - - const next: PersistedState = { - ...state, - creatorAddress: args.creator, - terms: { nft_count: args.nft_count, total_pct_bps: args.total_pct_bps, duration_years: args.duration_years }, - nfts, - pendingPayoutByAssetId: {}, - } - persist(next) - - return nfts.map((n) => n.assetId) + await refreshTerms() + const nextTerms = termsValue ?? (await fetchTerms()) + if (!nextTerms) return [] + return Array.from({ length: nextTerms.nft_count }).map((_, i) => nextTerms.first_asset_id + i) }, - [persist, state], + [activeAddress, algorand.client.algod, fetchTerms, getClient, refreshTerms, termsValue, transactionSigner], ) const buy_nft = useCallback( async (args: { buyer: string; asset_id: number; purchase_payment?: number }) => { - await delay(700) - const nextNfts = state.nfts.map((n) => (n.assetId === args.asset_id ? { ...n, owner: args.buyer } : n)) - const next = { ...state, nfts: nextNfts } - persist(next) + if (!transactionSigner || !activeAddress) throw new Error('Wallet not connected') + const client = await getClient() + const t = termsValue ?? (await fetchTerms()) + if (!t) throw new Error('Nothing minted yet') + + const sp = await algorand.client.algod.getTransactionParams().do() + const assetId = args.asset_id + + const optInTxn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({ + sender: activeAddress, + receiver: activeAddress, + assetIndex: assetId, + amount: 0, + suggestedParams: sp, + }) + + const payTxn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({ + sender: activeAddress, + receiver: client.appAddress, + amount: Number(t.sale_price_micro_algo), + suggestedParams: sp, + }) + + const group = client.newGroup() + group.addTransaction(optInTxn, transactionSigner) + group.addTransaction(payTxn, transactionSigner) + group.buyNft({ + sender: activeAddress, + args: { assetId, optIn: optInTxn, payment: payTxn }, + }) + await group.send() + await refreshTerms() }, - [persist, state], + [activeAddress, algorand.client.algod, fetchTerms, getClient, refreshTerms, termsValue, transactionSigner], ) const get_pending_payout = useCallback( async (args: { asset_id: number; address: string }) => { - await delay(250) - const nft = state.nfts.find((n) => n.assetId === args.asset_id) ?? null - if (!nft || nft.owner !== args.address) return 0 - return state.pendingPayoutByAssetId[args.asset_id] ?? 0 + if (!state.appId) return 0 + const client = await getClient() + const pending = await client.getPendingPayout({ args: { assetId: args.asset_id, address: args.address } }) + return Number(pending) }, - [state.nfts, state.pendingPayoutByAssetId], + [getClient, state.appId], ) const claim_payout = useCallback( async (args: { address: string; asset_id: number }) => { - await delay(600) - const nft = state.nfts.find((n) => n.assetId === args.asset_id) ?? null - if (!nft || nft.owner !== args.address) throw new Error('You do not own this NFT') - - const nextPending = { ...state.pendingPayoutByAssetId } - nextPending[args.asset_id] = 0 - persist({ ...state, pendingPayoutByAssetId: nextPending }) + if (!transactionSigner || !activeAddress) throw new Error('Wallet not connected') + const client = await getClient() + await client.send.claimPayout({ + sender: activeAddress, + args: { assetId: args.asset_id }, + }) }, - [persist, state], + [activeAddress, getClient, transactionSigner], ) const report_income = useCallback( async (args: { creator: string; quarter: number; income_amount: number }) => { - await delay(800) - if (!state.terms || !state.creatorAddress) throw new Error('Nothing minted yet') - if (args.creator !== state.creatorAddress) throw new Error('Only the creator can report income') + if (!transactionSigner || !activeAddress) throw new Error('Wallet not connected') + const client = await getClient() + const t = termsValue ?? (await fetchTerms()) + if (!t) throw new Error('Nothing minted yet') + if (!creatorAddressValue || creatorAddressValue !== activeAddress) throw new Error('Only the creator can report income') if (args.income_amount <= 0) throw new Error('Income must be > 0') if (args.quarter <= 0) throw new Error('Quarter must be > 0') - const { nft_count, total_pct_bps } = state.terms - const totalPayout = (args.income_amount * total_pct_bps) / 10_000 - const perNft = totalPayout / nft_count + const totalPayout = Math.floor((args.income_amount * t.total_pct_bps) / 10_000) + const perNft = Math.floor(totalPayout / t.nft_count) + + const sp = await algorand.client.algod.getTransactionParams().do() + const fundTxn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({ + sender: activeAddress, + receiver: client.appAddress, + amount: totalPayout, + suggestedParams: sp, + }) - const nextPending = { ...state.pendingPayoutByAssetId } - for (const nft of state.nfts) { - if (!nft.owner) continue - nextPending[nft.assetId] = (nextPending[nft.assetId] ?? 0) + perNft - } + const group = client.newGroup() + group.addTransaction(fundTxn, transactionSigner) + group.reportIncome({ + sender: activeAddress, + args: { quarter: args.quarter, incomeAmount: args.income_amount, payoutFunding: fundTxn }, + }) + await group.send() + await refreshTerms() - persist({ ...state, pendingPayoutByAssetId: nextPending }) return { totalPayout, perNft } }, - [persist, state], + [activeAddress, algorand.client.algod, creatorAddressValue, fetchTerms, getClient, refreshTerms, termsValue, transactionSigner], ) const resetMock = useCallback(async () => { - await delay(250) - const next = defaultState() - persist(next) + persist(defaultState()) }, [persist]) const api = useMemo( () => ({ - terms, - creatorAddress, + terms: termsValue, + creatorAddress: creatorAddressValue, listNfts, mint_future_nft, buy_nft, @@ -179,7 +329,17 @@ export function useAlgoMint() { report_income, resetMock, }), - [terms, creatorAddress, listNfts, mint_future_nft, buy_nft, get_pending_payout, claim_payout, report_income, resetMock], + [ + creatorAddressValue, + listNfts, + mint_future_nft, + buy_nft, + get_pending_payout, + claim_payout, + report_income, + resetMock, + termsValue, + ], ) return api diff --git a/projects/hackalgo-frontend/src/pages/CreatorPage.tsx b/projects/hackalgo-frontend/src/pages/CreatorPage.tsx index bc5b272..f0e4801 100644 --- a/projects/hackalgo-frontend/src/pages/CreatorPage.tsx +++ b/projects/hackalgo-frontend/src/pages/CreatorPage.tsx @@ -13,6 +13,7 @@ export default function CreatorPage(props: { onRequestWalletConnect: () => void const [durationYears, setDurationYears] = useState(3) const [incomeAmount, setIncomeAmount] = useState(10_000) const [quarter, setQuarter] = useState(20261) + const [salePriceMicroAlgo, setSalePriceMicroAlgo] = useState(1_000_000) const canReportIncome = useMemo( () => !!activeAddress && algoMint.creatorAddress === activeAddress && !!algoMint.terms, @@ -25,7 +26,7 @@ export default function CreatorPage(props: { onRequestWalletConnect: () => void

Mint your future earnings NFTs

-

Hackathon demo: uses mocked calls (fast to swap to ABI later).

+

Hackathon demo: mints real NFTs + distributes real payouts on-chain.

@@ -99,8 +113,10 @@ export default function CreatorPage(props: { onRequestWalletConnect: () => void nft_count: nftCount, total_pct_bps: totalPctBps, duration_years: durationYears, + start_quarter: quarter, + sale_price_micro_algo: salePriceMicroAlgo, }) - enqueueSnackbar(`Minted ${assetIds.length} NFTs (mock)`, { variant: 'success' }) + enqueueSnackbar(`Minted ${assetIds.length} NFTs`, { variant: 'success' }) } catch (e) { enqueueSnackbar((e as Error).message, { variant: 'error' }) } @@ -113,7 +129,7 @@ export default function CreatorPage(props: { onRequestWalletConnect: () => void {algoMint.terms ? ( <> Minted: {algoMint.terms.nft_count} NFTs, {(algoMint.terms.total_pct_bps / 100).toFixed(2)}% for{' '} - {algoMint.terms.duration_years} years + {algoMint.terms.duration_years} years, price {algoMint.terms.sale_price_micro_algo} µALGO ) : ( <>No mint yet diff --git a/projects/hackalgo-frontend/src/pages/GalleryPage.tsx b/projects/hackalgo-frontend/src/pages/GalleryPage.tsx index 17ea1c1..f917dd5 100644 --- a/projects/hackalgo-frontend/src/pages/GalleryPage.tsx +++ b/projects/hackalgo-frontend/src/pages/GalleryPage.tsx @@ -24,6 +24,9 @@ export default function GalleryPage(props: { onRequestWalletConnect: () => void })), ) setRows(withPending) + } catch (e) { + enqueueSnackbar((e as Error).message ?? 'Failed to load gallery', { variant: 'error' }) + setRows([]) } finally { setLoading(false) } @@ -44,7 +47,7 @@ export default function GalleryPage(props: { onRequestWalletConnect: () => void

Gallery

-

Buy + claim payouts (mock).

+

Buy NFTs and claim payouts on-chain.