diff --git a/intermediate-en/session_3/dao/.copier-answers.yml b/intermediate-en/session_3/dao/.copier-answers.yml index 41eaaa8..2d3cfcb 100644 --- a/intermediate-en/session_3/dao/.copier-answers.yml +++ b/intermediate-en/session_3/dao/.copier-answers.yml @@ -1,6 +1,6 @@ # Changes here will be overwritten by Copier; NEVER EDIT MANUALLY -_commit: 0.2.1-22-gd5c2296 -_src_path: https://github.com/algorandfoundation/algokit-fullstack-template +_commit: 0.3.0 +_src_path: gh:algorandfoundation/algokit-fullstack-template author_email: your@email.tld author_name: Your-Name cloud_provider: none diff --git a/intermediate-en/session_3/dao/README.md b/intermediate-en/session_3/dao/README.md index b971040..8dfae7d 100644 --- a/intermediate-en/session_3/dao/README.md +++ b/intermediate-en/session_3/dao/README.md @@ -30,7 +30,7 @@ This project uses [GitHub Actions](https://docs.github.com/en/actions/learn-gith For pushes to `main` branch, after the above checks pass, the following deployment actions are performed: - The smart contract(s) are deployed to TestNet using [AlgoNode](https://algonode.io). - - The frontend application is deployed to a provider of your choice (Netflify, Vercel, etc.). See [frontend README](frontend/README.md) for more information. + - The frontend application is deployed to a provider of your choice (Netlify, Vercel, etc.). See [frontend README](frontend/README.md) for more information. > Please note deployment of smart contracts is done via `algokit deploy` command which can be invoked both via CI as seen on this project, or locally. For more information on how to use `algokit deploy` please see [AlgoKit documentation](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/features/deploy.md). diff --git a/intermediate-en/session_3/dao/backend/.copier-answers.yml b/intermediate-en/session_3/dao/backend/.copier-answers.yml index 7caf55a..d9f1cb4 100644 --- a/intermediate-en/session_3/dao/backend/.copier-answers.yml +++ b/intermediate-en/session_3/dao/backend/.copier-answers.yml @@ -1,6 +1,6 @@ # Changes here will be overwritten by Copier; NEVER EDIT MANUALLY -_commit: 1.6.0-38-gd30492e -_src_path: https://github.com/algorandfoundation/algokit-beaker-default-template +_commit: 1.7.0 +_src_path: gh:algorandfoundation/algokit-beaker-default-template algod_port: 4001 algod_server: http://localhost algod_token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa diff --git a/intermediate-en/session_3/dao/backend/smart_contracts/artifacts/dao/application.json b/intermediate-en/session_3/dao/backend/smart_contracts/artifacts/dao/application.json index f7dd944..9a1c862 100644 --- a/intermediate-en/session_3/dao/backend/smart_contracts/artifacts/dao/application.json +++ b/intermediate-en/session_3/dao/backend/smart_contracts/artifacts/dao/application.json @@ -1,10 +1,5 @@ { "hints": { - "create()void": { - "call_config": { - "no_op": "CREATE" - } - }, "add_proposal((string,string,string,byte[32]))void": { "structs": { "proposal": { @@ -15,15 +10,15 @@ "string" ], [ - "unit_name", + "url", "string" ], [ - "url", + "unit_name", "string" ], [ - "hash", + "metadata_hash", "byte[32]" ] ] @@ -33,7 +28,7 @@ "no_op": "CALL" } }, - "vote(address)void": { + "vote(uint64)void": { "call_config": { "no_op": "CALL" } @@ -45,13 +40,13 @@ } }, "source": { - "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKaW50Y2Jsb2NrIDAgMSA0IDIKYnl0ZWNibG9jayAweDc3Njk2ZTZlNjk2ZTY3NWY3MDcyNmY3MDZmNzM2MTZjIDB4CnR4bmEgQXBwbGljYXRpb25BcmdzIDAKcHVzaGJ5dGVzIDB4NGM1YzYxYmEgLy8gImNyZWF0ZSgpdm9pZCIKPT0KYm56IG1haW5fbDgKdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMApwdXNoYnl0ZXMgMHhlZmE4YjQ0YiAvLyAiYWRkX3Byb3Bvc2FsKChzdHJpbmcsc3RyaW5nLHN0cmluZyxieXRlWzMyXSkpdm9pZCIKPT0KYm56IG1haW5fbDcKdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMApwdXNoYnl0ZXMgMHg2MjhjZTMyZCAvLyAidm90ZShhZGRyZXNzKXZvaWQiCj09CmJueiBtYWluX2w2CnR4bmEgQXBwbGljYXRpb25BcmdzIDAKcHVzaGJ5dGVzIDB4NTU4OGRjYjQgLy8gIm1pbnQoKXZvaWQiCj09CmJueiBtYWluX2w1CmVycgptYWluX2w1Ogp0eG4gT25Db21wbGV0aW9uCmludGNfMCAvLyBOb09wCj09CnR4biBBcHBsaWNhdGlvbklECmludGNfMCAvLyAwCiE9CiYmCmFzc2VydApjYWxsc3ViIG1pbnRjYXN0ZXJfNwppbnRjXzEgLy8gMQpyZXR1cm4KbWFpbl9sNjoKdHhuIE9uQ29tcGxldGlvbgppbnRjXzAgLy8gTm9PcAo9PQp0eG4gQXBwbGljYXRpb25JRAppbnRjXzAgLy8gMAohPQomJgphc3NlcnQKY2FsbHN1YiB2b3RlY2FzdGVyXzYKaW50Y18xIC8vIDEKcmV0dXJuCm1haW5fbDc6CnR4biBPbkNvbXBsZXRpb24KaW50Y18wIC8vIE5vT3AKPT0KdHhuIEFwcGxpY2F0aW9uSUQKaW50Y18wIC8vIDAKIT0KJiYKYXNzZXJ0CmNhbGxzdWIgYWRkcHJvcG9zYWxjYXN0ZXJfNQppbnRjXzEgLy8gMQpyZXR1cm4KbWFpbl9sODoKdHhuIE9uQ29tcGxldGlvbgppbnRjXzAgLy8gTm9PcAo9PQp0eG4gQXBwbGljYXRpb25JRAppbnRjXzAgLy8gMAo9PQomJgphc3NlcnQKY2FsbHN1YiBjcmVhdGVjYXN0ZXJfNAppbnRjXzEgLy8gMQpyZXR1cm4KCi8vIGNyZWF0ZQpjcmVhdGVfMDoKcHJvdG8gMCAwCnB1c2hieXRlcyAweDYzNzU3MjcyNjU2ZTc0NWY3MDcyNmY3MDZmNzM2MTZjNWY2OTY0IC8vICJjdXJyZW50X3Byb3Bvc2FsX2lkIgppbnRjXzAgLy8gMAphcHBfZ2xvYmFsX3B1dApieXRlY18wIC8vICJ3aW5uaW5nX3Byb3Bvc2FsIgpieXRlY18xIC8vICIiCmFwcF9nbG9iYWxfcHV0CnJldHN1YgoKLy8gYWRkX3Byb3Bvc2FsCmFkZHByb3Bvc2FsXzE6CnByb3RvIDEgMAppbnRjXzAgLy8gMAppbnRjXzAgLy8gMApmcmFtZV9idXJ5IDAKdHhuIFNlbmRlcgpib3hfZGVsCnBvcAp0eG4gU2VuZGVyCmZyYW1lX2RpZyAtMQpib3hfcHV0CnR4biBTZW5kZXIKYm94X2RlbApwb3AKdHhuIFNlbmRlcgpmcmFtZV9kaWcgMAppdG9iCmJveF9wdXQKcmV0c3ViCgovLyB2b3RlCnZvdGVfMjoKcHJvdG8gMSAwCmludGNfMCAvLyAwCmZyYW1lX2RpZyAtMQpib3hfZ2V0CnN0b3JlIDEKc3RvcmUgMApsb2FkIDEKYXNzZXJ0CmxvYWQgMApidG9pCmludGNfMSAvLyAxCisKYnl0ZWNfMCAvLyAid2lubmluZ19wcm9wb3NhbCIKYXBwX2dsb2JhbF9nZXQKYm94X2dldApzdG9yZSAzCnN0b3JlIDIKbG9hZCAzCmFzc2VydApsb2FkIDIKYnRvaQo+CmJ6IHZvdGVfMl9sMgpieXRlY18wIC8vICJ3aW5uaW5nX3Byb3Bvc2FsIgpmcmFtZV9kaWcgLTEKYXBwX2dsb2JhbF9wdXQKdm90ZV8yX2wyOgpmcmFtZV9kaWcgLTEKYm94X2dldApzdG9yZSAxCnN0b3JlIDAKbG9hZCAxCmFzc2VydApsb2FkIDAKYnRvaQppbnRjXzEgLy8gMQorCmZyYW1lX2J1cnkgMApmcmFtZV9kaWcgLTEKYm94X2RlbApwb3AKZnJhbWVfZGlnIC0xCmZyYW1lX2RpZyAwCml0b2IKYm94X3B1dApyZXRzdWIKCi8vIG1pbnQKbWludF8zOgpwcm90byAwIDAKaW50Y18wIC8vIDAKYnl0ZWNfMSAvLyAiIgpkdXBuIDQKZnJhbWVfZGlnIDEKZnJhbWVfZGlnIDEKaW50Y18yIC8vIDQKZXh0cmFjdF91aW50MTYKZGlnIDEKbGVuCnN1YnN0cmluZzMKZnJhbWVfYnVyeSAyCmZyYW1lX2RpZyAxCmV4dHJhY3QgNiAzMgpmcmFtZV9idXJ5IDMKZnJhbWVfZGlnIDEKZnJhbWVfZGlnIDEKaW50Y18wIC8vIDAKZXh0cmFjdF91aW50MTYKZnJhbWVfZGlnIDEKaW50Y18zIC8vIDIKZXh0cmFjdF91aW50MTYKc3Vic3RyaW5nMwpmcmFtZV9idXJ5IDQKZnJhbWVfZGlnIDEKZnJhbWVfZGlnIDEKaW50Y18zIC8vIDIKZXh0cmFjdF91aW50MTYKZnJhbWVfZGlnIDEKaW50Y18yIC8vIDQKZXh0cmFjdF91aW50MTYKc3Vic3RyaW5nMwpmcmFtZV9idXJ5IDUKYnl0ZWNfMCAvLyAid2lubmluZ19wcm9wb3NhbCIKYXBwX2dsb2JhbF9nZXQKZnJhbWVfYnVyeSAwCmZyYW1lX2RpZyAwCml0b2IKYm94X2dldApzdG9yZSA1CnN0b3JlIDQKbG9hZCA1CmFzc2VydApsb2FkIDQKZnJhbWVfYnVyeSAxCml0eG5fYmVnaW4KcHVzaGludCAzIC8vIGFjZmcKaXR4bl9maWVsZCBUeXBlRW51bQppbnRjXzEgLy8gMQppdHhuX2ZpZWxkIENvbmZpZ0Fzc2V0VG90YWwKZnJhbWVfZGlnIDIKZXh0cmFjdCAyIDAKaXR4bl9maWVsZCBDb25maWdBc3NldFVSTApmcmFtZV9kaWcgMwppdHhuX2ZpZWxkIENvbmZpZ0Fzc2V0TWV0YWRhdGFIYXNoCmZyYW1lX2RpZyA0CmV4dHJhY3QgMiAwCml0eG5fZmllbGQgQ29uZmlnQXNzZXROYW1lCmZyYW1lX2RpZyA1CmV4dHJhY3QgMiAwCml0eG5fZmllbGQgQ29uZmlnQXNzZXRVbml0TmFtZQppdHhuX3N1Ym1pdApyZXRzdWIKCi8vIGNyZWF0ZV9jYXN0ZXIKY3JlYXRlY2FzdGVyXzQ6CnByb3RvIDAgMApjYWxsc3ViIGNyZWF0ZV8wCnJldHN1YgoKLy8gYWRkX3Byb3Bvc2FsX2Nhc3RlcgphZGRwcm9wb3NhbGNhc3Rlcl81Ogpwcm90byAwIDAKYnl0ZWNfMSAvLyAiIgp0eG5hIEFwcGxpY2F0aW9uQXJncyAxCmZyYW1lX2J1cnkgMApmcmFtZV9kaWcgMApjYWxsc3ViIGFkZHByb3Bvc2FsXzEKcmV0c3ViCgovLyB2b3RlX2Nhc3Rlcgp2b3RlY2FzdGVyXzY6CnByb3RvIDAgMApieXRlY18xIC8vICIiCnR4bmEgQXBwbGljYXRpb25BcmdzIDEKZnJhbWVfYnVyeSAwCmZyYW1lX2RpZyAwCmNhbGxzdWIgdm90ZV8yCnJldHN1YgoKLy8gbWludF9jYXN0ZXIKbWludGNhc3Rlcl83Ogpwcm90byAwIDAKY2FsbHN1YiBtaW50XzMKcmV0c3Vi", + "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKaW50Y2Jsb2NrIDAgMSAyIDQKYnl0ZWNibG9jayAweDc2MmQgMHg2Mzc1NzI3MjY1NmU3NDVmNzA3MjZmNzA2ZjczNjE2YzVmNjk2NCAweDc3Njk2ZTZlNjk2ZTY3NWY3MDcyNmY3MDZmNzM2MTZjIDB4NzAyZCAweAp0eG4gTnVtQXBwQXJncwppbnRjXzAgLy8gMAo9PQpibnogbWFpbl9sOAp0eG5hIEFwcGxpY2F0aW9uQXJncyAwCnB1c2hieXRlcyAweGVmYThiNDRiIC8vICJhZGRfcHJvcG9zYWwoKHN0cmluZyxzdHJpbmcsc3RyaW5nLGJ5dGVbMzJdKSl2b2lkIgo9PQpibnogbWFpbl9sNwp0eG5hIEFwcGxpY2F0aW9uQXJncyAwCnB1c2hieXRlcyAweDMxZDVjMzAwIC8vICJ2b3RlKHVpbnQ2NCl2b2lkIgo9PQpibnogbWFpbl9sNgp0eG5hIEFwcGxpY2F0aW9uQXJncyAwCnB1c2hieXRlcyAweDU1ODhkY2I0IC8vICJtaW50KCl2b2lkIgo9PQpibnogbWFpbl9sNQplcnIKbWFpbl9sNToKdHhuIE9uQ29tcGxldGlvbgppbnRjXzAgLy8gTm9PcAo9PQp0eG4gQXBwbGljYXRpb25JRAppbnRjXzAgLy8gMAohPQomJgphc3NlcnQKY2FsbHN1YiBtaW50Y2FzdGVyXzYKaW50Y18xIC8vIDEKcmV0dXJuCm1haW5fbDY6CnR4biBPbkNvbXBsZXRpb24KaW50Y18wIC8vIE5vT3AKPT0KdHhuIEFwcGxpY2F0aW9uSUQKaW50Y18wIC8vIDAKIT0KJiYKYXNzZXJ0CmNhbGxzdWIgdm90ZWNhc3Rlcl81CmludGNfMSAvLyAxCnJldHVybgptYWluX2w3Ogp0eG4gT25Db21wbGV0aW9uCmludGNfMCAvLyBOb09wCj09CnR4biBBcHBsaWNhdGlvbklECmludGNfMCAvLyAwCiE9CiYmCmFzc2VydApjYWxsc3ViIGFkZHByb3Bvc2FsY2FzdGVyXzQKaW50Y18xIC8vIDEKcmV0dXJuCm1haW5fbDg6CnR4biBPbkNvbXBsZXRpb24KaW50Y18wIC8vIE5vT3AKPT0KYm56IG1haW5fbDEwCmVycgptYWluX2wxMDoKdHhuIEFwcGxpY2F0aW9uSUQKaW50Y18wIC8vIDAKPT0KYXNzZXJ0CmNhbGxzdWIgY3JlYXRlXzAKaW50Y18xIC8vIDEKcmV0dXJuCgovLyBjcmVhdGUKY3JlYXRlXzA6CnByb3RvIDAgMApieXRlY18xIC8vICJjdXJyZW50X3Byb3Bvc2FsX2lkIgppbnRjXzAgLy8gMAphcHBfZ2xvYmFsX3B1dApieXRlY18yIC8vICJ3aW5uaW5nX3Byb3Bvc2FsIgppbnRjXzAgLy8gMAphcHBfZ2xvYmFsX3B1dApyZXRzdWIKCi8vIGFkZF9wcm9wb3NhbAphZGRwcm9wb3NhbF8xOgpwcm90byAxIDAKaW50Y18wIC8vIDAKZHVwCmJ5dGVjXzEgLy8gImN1cnJlbnRfcHJvcG9zYWxfaWQiCmFwcF9nbG9iYWxfZ2V0CmZyYW1lX2J1cnkgMAppbnRjXzAgLy8gMApmcmFtZV9idXJ5IDEKYnl0ZWNfMyAvLyAicC0iCmZyYW1lX2RpZyAwCml0b2IKY29uY2F0CmJveF9kZWwKcG9wCmJ5dGVjXzMgLy8gInAtIgpmcmFtZV9kaWcgMAppdG9iCmNvbmNhdApmcmFtZV9kaWcgLTEKYm94X3B1dApieXRlY18wIC8vICJ2LSIKZnJhbWVfZGlnIDAKaXRvYgpjb25jYXQKYm94X2RlbApwb3AKYnl0ZWNfMCAvLyAidi0iCmZyYW1lX2RpZyAwCml0b2IKY29uY2F0CmZyYW1lX2RpZyAxCml0b2IKYm94X3B1dApieXRlY18xIC8vICJjdXJyZW50X3Byb3Bvc2FsX2lkIgpieXRlY18xIC8vICJjdXJyZW50X3Byb3Bvc2FsX2lkIgphcHBfZ2xvYmFsX2dldAppbnRjXzEgLy8gMQorCmFwcF9nbG9iYWxfcHV0CnJldHN1YgoKLy8gdm90ZQp2b3RlXzI6CnByb3RvIDEgMAppbnRjXzAgLy8gMApkdXAKYnl0ZWNfMiAvLyAid2lubmluZ19wcm9wb3NhbCIKYXBwX2dsb2JhbF9nZXQKZnJhbWVfYnVyeSAxCmJ5dGVjXzAgLy8gInYtIgpmcmFtZV9kaWcgLTEKaXRvYgpjb25jYXQKYm94X2dldApzdG9yZSAxCnN0b3JlIDAKbG9hZCAxCmFzc2VydApsb2FkIDAKYnRvaQppbnRjXzEgLy8gMQorCmZyYW1lX2J1cnkgMApieXRlY18wIC8vICJ2LSIKZnJhbWVfZGlnIC0xCml0b2IKY29uY2F0CmJveF9nZXQKc3RvcmUgMQpzdG9yZSAwCmxvYWQgMQphc3NlcnQKbG9hZCAwCmJ0b2kKaW50Y18xIC8vIDEKKwpieXRlY18wIC8vICJ2LSIKZnJhbWVfZGlnIDEKaXRvYgpjb25jYXQKYm94X2dldApzdG9yZSAzCnN0b3JlIDIKbG9hZCAzCmFzc2VydApsb2FkIDIKYnRvaQo+CmJ6IHZvdGVfMl9sMgpieXRlY18yIC8vICJ3aW5uaW5nX3Byb3Bvc2FsIgpmcmFtZV9kaWcgLTEKYXBwX2dsb2JhbF9wdXQKdm90ZV8yX2wyOgpieXRlY18wIC8vICJ2LSIKZnJhbWVfZGlnIC0xCml0b2IKY29uY2F0CmJveF9kZWwKcG9wCmJ5dGVjXzAgLy8gInYtIgpmcmFtZV9kaWcgLTEKaXRvYgpjb25jYXQKZnJhbWVfZGlnIDAKaXRvYgpib3hfcHV0CnJldHN1YgoKLy8gbWludAptaW50XzM6CnByb3RvIDAgMAppbnRjXzAgLy8gMApieXRlYyA0IC8vICIiCmR1cG4gNApieXRlY18yIC8vICJ3aW5uaW5nX3Byb3Bvc2FsIgphcHBfZ2xvYmFsX2dldApmcmFtZV9idXJ5IDAKYnl0ZWNfMyAvLyAicC0iCmZyYW1lX2RpZyAwCml0b2IKY29uY2F0CmJveF9nZXQKc3RvcmUgNQpzdG9yZSA0CmxvYWQgNQphc3NlcnQKbG9hZCA0CmZyYW1lX2J1cnkgMQpmcmFtZV9kaWcgMQpmcmFtZV9kaWcgMQppbnRjXzIgLy8gMgpleHRyYWN0X3VpbnQxNgpmcmFtZV9kaWcgMQppbnRjXzMgLy8gNApleHRyYWN0X3VpbnQxNgpzdWJzdHJpbmczCmZyYW1lX2J1cnkgMgpmcmFtZV9kaWcgMQpmcmFtZV9kaWcgMQppbnRjXzAgLy8gMApleHRyYWN0X3VpbnQxNgpmcmFtZV9kaWcgMQppbnRjXzIgLy8gMgpleHRyYWN0X3VpbnQxNgpzdWJzdHJpbmczCmZyYW1lX2J1cnkgMwpmcmFtZV9kaWcgMQpmcmFtZV9kaWcgMQppbnRjXzMgLy8gNApleHRyYWN0X3VpbnQxNgpkaWcgMQpsZW4Kc3Vic3RyaW5nMwpmcmFtZV9idXJ5IDQKZnJhbWVfZGlnIDEKZXh0cmFjdCA2IDMyCmZyYW1lX2J1cnkgNQppdHhuX2JlZ2luCnB1c2hpbnQgMyAvLyBhY2ZnCml0eG5fZmllbGQgVHlwZUVudW0KaW50Y18xIC8vIDEKaXR4bl9maWVsZCBDb25maWdBc3NldFRvdGFsCmZyYW1lX2RpZyAyCmV4dHJhY3QgMiAwCml0eG5fZmllbGQgQ29uZmlnQXNzZXRVUkwKZnJhbWVfZGlnIDMKZXh0cmFjdCAyIDAKaXR4bl9maWVsZCBDb25maWdBc3NldE5hbWUKZnJhbWVfZGlnIDQKZXh0cmFjdCAyIDAKaXR4bl9maWVsZCBDb25maWdBc3NldFVuaXROYW1lCmZyYW1lX2RpZyA1Cml0eG5fZmllbGQgQ29uZmlnQXNzZXRNZXRhZGF0YUhhc2gKaXR4bl9zdWJtaXQKcmV0c3ViCgovLyBhZGRfcHJvcG9zYWxfY2FzdGVyCmFkZHByb3Bvc2FsY2FzdGVyXzQ6CnByb3RvIDAgMApieXRlYyA0IC8vICIiCnR4bmEgQXBwbGljYXRpb25BcmdzIDEKZnJhbWVfYnVyeSAwCmZyYW1lX2RpZyAwCmNhbGxzdWIgYWRkcHJvcG9zYWxfMQpyZXRzdWIKCi8vIHZvdGVfY2FzdGVyCnZvdGVjYXN0ZXJfNToKcHJvdG8gMCAwCmludGNfMCAvLyAwCnR4bmEgQXBwbGljYXRpb25BcmdzIDEKYnRvaQpmcmFtZV9idXJ5IDAKZnJhbWVfZGlnIDAKY2FsbHN1YiB2b3RlXzIKcmV0c3ViCgovLyBtaW50X2Nhc3RlcgptaW50Y2FzdGVyXzY6CnByb3RvIDAgMApjYWxsc3ViIG1pbnRfMwpyZXRzdWI=", "clear": "I3ByYWdtYSB2ZXJzaW9uIDgKcHVzaGludCAwIC8vIDAKcmV0dXJu" }, "state": { "global": { - "num_byte_slices": 1, - "num_uints": 1 + "num_byte_slices": 0, + "num_uints": 2 }, "local": { "num_byte_slices": 0, @@ -67,7 +62,7 @@ "descr": "" }, "winning_proposal": { - "type": "bytes", + "type": "uint64", "key": "winning_proposal", "descr": "" } @@ -80,15 +75,8 @@ } }, "contract": { - "name": "dao", + "name": "DAO", "methods": [ - { - "name": "create", - "args": [], - "returns": { - "type": "void" - } - }, { "name": "add_proposal", "args": [ @@ -105,8 +93,8 @@ "name": "vote", "args": [ { - "type": "address", - "name": "proposer" + "type": "uint64", + "name": "proposal_id" } ], "returns": { @@ -123,5 +111,7 @@ ], "networks": {} }, - "bare_call_config": {} + "bare_call_config": { + "no_op": "CREATE" + } } \ No newline at end of file diff --git a/intermediate-en/session_3/dao/backend/smart_contracts/artifacts/dao/approval.teal b/intermediate-en/session_3/dao/backend/smart_contracts/artifacts/dao/approval.teal index c2387cf..fa5a2e9 100644 --- a/intermediate-en/session_3/dao/backend/smart_contracts/artifacts/dao/approval.teal +++ b/intermediate-en/session_3/dao/backend/smart_contracts/artifacts/dao/approval.teal @@ -1,8 +1,8 @@ #pragma version 8 -intcblock 0 1 4 2 -bytecblock 0x77696e6e696e675f70726f706f73616c 0x -txna ApplicationArgs 0 -pushbytes 0x4c5c61ba // "create()void" +intcblock 0 1 2 4 +bytecblock 0x762d 0x63757272656e745f70726f706f73616c5f6964 0x77696e6e696e675f70726f706f73616c 0x702d 0x +txn NumAppArgs +intc_0 // 0 == bnz main_l8 txna ApplicationArgs 0 @@ -10,7 +10,7 @@ pushbytes 0xefa8b44b // "add_proposal((string,string,string,byte[32]))void" == bnz main_l7 txna ApplicationArgs 0 -pushbytes 0x628ce32d // "vote(address)void" +pushbytes 0x31d5c300 // "vote(uint64)void" == bnz main_l6 txna ApplicationArgs 0 @@ -27,7 +27,7 @@ intc_0 // 0 != && assert -callsub mintcaster_7 +callsub mintcaster_6 intc_1 // 1 return main_l6: @@ -39,7 +39,7 @@ intc_0 // 0 != && assert -callsub votecaster_6 +callsub votecaster_5 intc_1 // 1 return main_l7: @@ -51,30 +51,32 @@ intc_0 // 0 != && assert -callsub addproposalcaster_5 +callsub addproposalcaster_4 intc_1 // 1 return main_l8: txn OnCompletion intc_0 // NoOp == +bnz main_l10 +err +main_l10: txn ApplicationID intc_0 // 0 == -&& assert -callsub createcaster_4 +callsub create_0 intc_1 // 1 return // create create_0: proto 0 0 -pushbytes 0x63757272656e745f70726f706f73616c5f6964 // "current_proposal_id" +bytec_1 // "current_proposal_id" intc_0 // 0 app_global_put -bytec_0 // "winning_proposal" -bytec_1 // "" +bytec_2 // "winning_proposal" +intc_0 // 0 app_global_put retsub @@ -82,28 +84,57 @@ retsub addproposal_1: proto 1 0 intc_0 // 0 -intc_0 // 0 +dup +bytec_1 // "current_proposal_id" +app_global_get frame_bury 0 -txn Sender +intc_0 // 0 +frame_bury 1 +bytec_3 // "p-" +frame_dig 0 +itob +concat box_del pop -txn Sender +bytec_3 // "p-" +frame_dig 0 +itob +concat frame_dig -1 box_put -txn Sender +bytec_0 // "v-" +frame_dig 0 +itob +concat box_del pop -txn Sender +bytec_0 // "v-" frame_dig 0 itob +concat +frame_dig 1 +itob box_put +bytec_1 // "current_proposal_id" +bytec_1 // "current_proposal_id" +app_global_get +intc_1 // 1 ++ +app_global_put retsub // vote vote_2: proto 1 0 intc_0 // 0 +dup +bytec_2 // "winning_proposal" +app_global_get +frame_bury 1 +bytec_0 // "v-" frame_dig -1 +itob +concat box_get store 1 store 0 @@ -113,8 +144,24 @@ load 0 btoi intc_1 // 1 + -bytec_0 // "winning_proposal" -app_global_get +frame_bury 0 +bytec_0 // "v-" +frame_dig -1 +itob +concat +box_get +store 1 +store 0 +load 1 +assert +load 0 +btoi +intc_1 // 1 ++ +bytec_0 // "v-" +frame_dig 1 +itob +concat box_get store 3 store 2 @@ -124,25 +171,20 @@ load 2 btoi > bz vote_2_l2 -bytec_0 // "winning_proposal" +bytec_2 // "winning_proposal" frame_dig -1 app_global_put vote_2_l2: +bytec_0 // "v-" frame_dig -1 -box_get -store 1 -store 0 -load 1 -assert -load 0 -btoi -intc_1 // 1 -+ -frame_bury 0 -frame_dig -1 +itob +concat box_del pop +bytec_0 // "v-" frame_dig -1 +itob +concat frame_dig 0 itob box_put @@ -152,49 +194,51 @@ retsub mint_3: proto 0 0 intc_0 // 0 -bytec_1 // "" +bytec 4 // "" dupn 4 +bytec_2 // "winning_proposal" +app_global_get +frame_bury 0 +bytec_3 // "p-" +frame_dig 0 +itob +concat +box_get +store 5 +store 4 +load 5 +assert +load 4 +frame_bury 1 frame_dig 1 frame_dig 1 -intc_2 // 4 +intc_2 // 2 +extract_uint16 +frame_dig 1 +intc_3 // 4 extract_uint16 -dig 1 -len substring3 frame_bury 2 frame_dig 1 -extract 6 32 -frame_bury 3 -frame_dig 1 frame_dig 1 intc_0 // 0 extract_uint16 frame_dig 1 -intc_3 // 2 +intc_2 // 2 extract_uint16 substring3 -frame_bury 4 -frame_dig 1 +frame_bury 3 frame_dig 1 -intc_3 // 2 -extract_uint16 frame_dig 1 -intc_2 // 4 +intc_3 // 4 extract_uint16 +dig 1 +len substring3 +frame_bury 4 +frame_dig 1 +extract 6 32 frame_bury 5 -bytec_0 // "winning_proposal" -app_global_get -frame_bury 0 -frame_dig 0 -itob -box_get -store 5 -store 4 -load 5 -assert -load 4 -frame_bury 1 itxn_begin pushint 3 // acfg itxn_field TypeEnum @@ -204,26 +248,20 @@ frame_dig 2 extract 2 0 itxn_field ConfigAssetURL frame_dig 3 -itxn_field ConfigAssetMetadataHash -frame_dig 4 extract 2 0 itxn_field ConfigAssetName -frame_dig 5 +frame_dig 4 extract 2 0 itxn_field ConfigAssetUnitName +frame_dig 5 +itxn_field ConfigAssetMetadataHash itxn_submit retsub -// create_caster -createcaster_4: -proto 0 0 -callsub create_0 -retsub - // add_proposal_caster -addproposalcaster_5: +addproposalcaster_4: proto 0 0 -bytec_1 // "" +bytec 4 // "" txna ApplicationArgs 1 frame_bury 0 frame_dig 0 @@ -231,17 +269,18 @@ callsub addproposal_1 retsub // vote_caster -votecaster_6: +votecaster_5: proto 0 0 -bytec_1 // "" +intc_0 // 0 txna ApplicationArgs 1 +btoi frame_bury 0 frame_dig 0 callsub vote_2 retsub // mint_caster -mintcaster_7: +mintcaster_6: proto 0 0 callsub mint_3 retsub \ No newline at end of file diff --git a/intermediate-en/session_3/dao/backend/smart_contracts/artifacts/dao/client.ts b/intermediate-en/session_3/dao/backend/smart_contracts/artifacts/dao/client.ts index d27cdbf..bba4851 100644 --- a/intermediate-en/session_3/dao/backend/smart_contracts/artifacts/dao/client.ts +++ b/intermediate-en/session_3/dao/backend/smart_contracts/artifacts/dao/client.ts @@ -26,11 +26,6 @@ import { SendTransactionResult, TransactionToSign, SendTransactionFrom } from '@ import { Algodv2, OnApplicationComplete, Transaction, TransactionWithSigner, AtomicTransactionComposer } from 'algosdk' export const APP_SPEC: AppSpec = { "hints": { - "create()void": { - "call_config": { - "no_op": "CREATE" - } - }, "add_proposal((string,string,string,byte[32]))void": { "structs": { "proposal": { @@ -41,15 +36,15 @@ export const APP_SPEC: AppSpec = { "string" ], [ - "unit_name", + "url", "string" ], [ - "url", + "unit_name", "string" ], [ - "hash", + "metadata_hash", "byte[32]" ] ] @@ -59,7 +54,7 @@ export const APP_SPEC: AppSpec = { "no_op": "CALL" } }, - "vote(address)void": { + "vote(uint64)void": { "call_config": { "no_op": "CALL" } @@ -71,13 +66,13 @@ export const APP_SPEC: AppSpec = { } }, "source": { - "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKaW50Y2Jsb2NrIDAgMSA0IDIKYnl0ZWNibG9jayAweDc3Njk2ZTZlNjk2ZTY3NWY3MDcyNmY3MDZmNzM2MTZjIDB4CnR4bmEgQXBwbGljYXRpb25BcmdzIDAKcHVzaGJ5dGVzIDB4NGM1YzYxYmEgLy8gImNyZWF0ZSgpdm9pZCIKPT0KYm56IG1haW5fbDgKdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMApwdXNoYnl0ZXMgMHhlZmE4YjQ0YiAvLyAiYWRkX3Byb3Bvc2FsKChzdHJpbmcsc3RyaW5nLHN0cmluZyxieXRlWzMyXSkpdm9pZCIKPT0KYm56IG1haW5fbDcKdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMApwdXNoYnl0ZXMgMHg2MjhjZTMyZCAvLyAidm90ZShhZGRyZXNzKXZvaWQiCj09CmJueiBtYWluX2w2CnR4bmEgQXBwbGljYXRpb25BcmdzIDAKcHVzaGJ5dGVzIDB4NTU4OGRjYjQgLy8gIm1pbnQoKXZvaWQiCj09CmJueiBtYWluX2w1CmVycgptYWluX2w1Ogp0eG4gT25Db21wbGV0aW9uCmludGNfMCAvLyBOb09wCj09CnR4biBBcHBsaWNhdGlvbklECmludGNfMCAvLyAwCiE9CiYmCmFzc2VydApjYWxsc3ViIG1pbnRjYXN0ZXJfNwppbnRjXzEgLy8gMQpyZXR1cm4KbWFpbl9sNjoKdHhuIE9uQ29tcGxldGlvbgppbnRjXzAgLy8gTm9PcAo9PQp0eG4gQXBwbGljYXRpb25JRAppbnRjXzAgLy8gMAohPQomJgphc3NlcnQKY2FsbHN1YiB2b3RlY2FzdGVyXzYKaW50Y18xIC8vIDEKcmV0dXJuCm1haW5fbDc6CnR4biBPbkNvbXBsZXRpb24KaW50Y18wIC8vIE5vT3AKPT0KdHhuIEFwcGxpY2F0aW9uSUQKaW50Y18wIC8vIDAKIT0KJiYKYXNzZXJ0CmNhbGxzdWIgYWRkcHJvcG9zYWxjYXN0ZXJfNQppbnRjXzEgLy8gMQpyZXR1cm4KbWFpbl9sODoKdHhuIE9uQ29tcGxldGlvbgppbnRjXzAgLy8gTm9PcAo9PQp0eG4gQXBwbGljYXRpb25JRAppbnRjXzAgLy8gMAo9PQomJgphc3NlcnQKY2FsbHN1YiBjcmVhdGVjYXN0ZXJfNAppbnRjXzEgLy8gMQpyZXR1cm4KCi8vIGNyZWF0ZQpjcmVhdGVfMDoKcHJvdG8gMCAwCnB1c2hieXRlcyAweDYzNzU3MjcyNjU2ZTc0NWY3MDcyNmY3MDZmNzM2MTZjNWY2OTY0IC8vICJjdXJyZW50X3Byb3Bvc2FsX2lkIgppbnRjXzAgLy8gMAphcHBfZ2xvYmFsX3B1dApieXRlY18wIC8vICJ3aW5uaW5nX3Byb3Bvc2FsIgpieXRlY18xIC8vICIiCmFwcF9nbG9iYWxfcHV0CnJldHN1YgoKLy8gYWRkX3Byb3Bvc2FsCmFkZHByb3Bvc2FsXzE6CnByb3RvIDEgMAppbnRjXzAgLy8gMAppbnRjXzAgLy8gMApmcmFtZV9idXJ5IDAKdHhuIFNlbmRlcgpib3hfZGVsCnBvcAp0eG4gU2VuZGVyCmZyYW1lX2RpZyAtMQpib3hfcHV0CnR4biBTZW5kZXIKYm94X2RlbApwb3AKdHhuIFNlbmRlcgpmcmFtZV9kaWcgMAppdG9iCmJveF9wdXQKcmV0c3ViCgovLyB2b3RlCnZvdGVfMjoKcHJvdG8gMSAwCmludGNfMCAvLyAwCmZyYW1lX2RpZyAtMQpib3hfZ2V0CnN0b3JlIDEKc3RvcmUgMApsb2FkIDEKYXNzZXJ0CmxvYWQgMApidG9pCmludGNfMSAvLyAxCisKYnl0ZWNfMCAvLyAid2lubmluZ19wcm9wb3NhbCIKYXBwX2dsb2JhbF9nZXQKYm94X2dldApzdG9yZSAzCnN0b3JlIDIKbG9hZCAzCmFzc2VydApsb2FkIDIKYnRvaQo+CmJ6IHZvdGVfMl9sMgpieXRlY18wIC8vICJ3aW5uaW5nX3Byb3Bvc2FsIgpmcmFtZV9kaWcgLTEKYXBwX2dsb2JhbF9wdXQKdm90ZV8yX2wyOgpmcmFtZV9kaWcgLTEKYm94X2dldApzdG9yZSAxCnN0b3JlIDAKbG9hZCAxCmFzc2VydApsb2FkIDAKYnRvaQppbnRjXzEgLy8gMQorCmZyYW1lX2J1cnkgMApmcmFtZV9kaWcgLTEKYm94X2RlbApwb3AKZnJhbWVfZGlnIC0xCmZyYW1lX2RpZyAwCml0b2IKYm94X3B1dApyZXRzdWIKCi8vIG1pbnQKbWludF8zOgpwcm90byAwIDAKaW50Y18wIC8vIDAKYnl0ZWNfMSAvLyAiIgpkdXBuIDQKZnJhbWVfZGlnIDEKZnJhbWVfZGlnIDEKaW50Y18yIC8vIDQKZXh0cmFjdF91aW50MTYKZGlnIDEKbGVuCnN1YnN0cmluZzMKZnJhbWVfYnVyeSAyCmZyYW1lX2RpZyAxCmV4dHJhY3QgNiAzMgpmcmFtZV9idXJ5IDMKZnJhbWVfZGlnIDEKZnJhbWVfZGlnIDEKaW50Y18wIC8vIDAKZXh0cmFjdF91aW50MTYKZnJhbWVfZGlnIDEKaW50Y18zIC8vIDIKZXh0cmFjdF91aW50MTYKc3Vic3RyaW5nMwpmcmFtZV9idXJ5IDQKZnJhbWVfZGlnIDEKZnJhbWVfZGlnIDEKaW50Y18zIC8vIDIKZXh0cmFjdF91aW50MTYKZnJhbWVfZGlnIDEKaW50Y18yIC8vIDQKZXh0cmFjdF91aW50MTYKc3Vic3RyaW5nMwpmcmFtZV9idXJ5IDUKYnl0ZWNfMCAvLyAid2lubmluZ19wcm9wb3NhbCIKYXBwX2dsb2JhbF9nZXQKZnJhbWVfYnVyeSAwCmZyYW1lX2RpZyAwCml0b2IKYm94X2dldApzdG9yZSA1CnN0b3JlIDQKbG9hZCA1CmFzc2VydApsb2FkIDQKZnJhbWVfYnVyeSAxCml0eG5fYmVnaW4KcHVzaGludCAzIC8vIGFjZmcKaXR4bl9maWVsZCBUeXBlRW51bQppbnRjXzEgLy8gMQppdHhuX2ZpZWxkIENvbmZpZ0Fzc2V0VG90YWwKZnJhbWVfZGlnIDIKZXh0cmFjdCAyIDAKaXR4bl9maWVsZCBDb25maWdBc3NldFVSTApmcmFtZV9kaWcgMwppdHhuX2ZpZWxkIENvbmZpZ0Fzc2V0TWV0YWRhdGFIYXNoCmZyYW1lX2RpZyA0CmV4dHJhY3QgMiAwCml0eG5fZmllbGQgQ29uZmlnQXNzZXROYW1lCmZyYW1lX2RpZyA1CmV4dHJhY3QgMiAwCml0eG5fZmllbGQgQ29uZmlnQXNzZXRVbml0TmFtZQppdHhuX3N1Ym1pdApyZXRzdWIKCi8vIGNyZWF0ZV9jYXN0ZXIKY3JlYXRlY2FzdGVyXzQ6CnByb3RvIDAgMApjYWxsc3ViIGNyZWF0ZV8wCnJldHN1YgoKLy8gYWRkX3Byb3Bvc2FsX2Nhc3RlcgphZGRwcm9wb3NhbGNhc3Rlcl81Ogpwcm90byAwIDAKYnl0ZWNfMSAvLyAiIgp0eG5hIEFwcGxpY2F0aW9uQXJncyAxCmZyYW1lX2J1cnkgMApmcmFtZV9kaWcgMApjYWxsc3ViIGFkZHByb3Bvc2FsXzEKcmV0c3ViCgovLyB2b3RlX2Nhc3Rlcgp2b3RlY2FzdGVyXzY6CnByb3RvIDAgMApieXRlY18xIC8vICIiCnR4bmEgQXBwbGljYXRpb25BcmdzIDEKZnJhbWVfYnVyeSAwCmZyYW1lX2RpZyAwCmNhbGxzdWIgdm90ZV8yCnJldHN1YgoKLy8gbWludF9jYXN0ZXIKbWludGNhc3Rlcl83Ogpwcm90byAwIDAKY2FsbHN1YiBtaW50XzMKcmV0c3Vi", + "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKaW50Y2Jsb2NrIDAgMSAyIDQKYnl0ZWNibG9jayAweDc2MmQgMHg2Mzc1NzI3MjY1NmU3NDVmNzA3MjZmNzA2ZjczNjE2YzVmNjk2NCAweDc3Njk2ZTZlNjk2ZTY3NWY3MDcyNmY3MDZmNzM2MTZjIDB4NzAyZCAweAp0eG4gTnVtQXBwQXJncwppbnRjXzAgLy8gMAo9PQpibnogbWFpbl9sOAp0eG5hIEFwcGxpY2F0aW9uQXJncyAwCnB1c2hieXRlcyAweGVmYThiNDRiIC8vICJhZGRfcHJvcG9zYWwoKHN0cmluZyxzdHJpbmcsc3RyaW5nLGJ5dGVbMzJdKSl2b2lkIgo9PQpibnogbWFpbl9sNwp0eG5hIEFwcGxpY2F0aW9uQXJncyAwCnB1c2hieXRlcyAweDMxZDVjMzAwIC8vICJ2b3RlKHVpbnQ2NCl2b2lkIgo9PQpibnogbWFpbl9sNgp0eG5hIEFwcGxpY2F0aW9uQXJncyAwCnB1c2hieXRlcyAweDU1ODhkY2I0IC8vICJtaW50KCl2b2lkIgo9PQpibnogbWFpbl9sNQplcnIKbWFpbl9sNToKdHhuIE9uQ29tcGxldGlvbgppbnRjXzAgLy8gTm9PcAo9PQp0eG4gQXBwbGljYXRpb25JRAppbnRjXzAgLy8gMAohPQomJgphc3NlcnQKY2FsbHN1YiBtaW50Y2FzdGVyXzYKaW50Y18xIC8vIDEKcmV0dXJuCm1haW5fbDY6CnR4biBPbkNvbXBsZXRpb24KaW50Y18wIC8vIE5vT3AKPT0KdHhuIEFwcGxpY2F0aW9uSUQKaW50Y18wIC8vIDAKIT0KJiYKYXNzZXJ0CmNhbGxzdWIgdm90ZWNhc3Rlcl81CmludGNfMSAvLyAxCnJldHVybgptYWluX2w3Ogp0eG4gT25Db21wbGV0aW9uCmludGNfMCAvLyBOb09wCj09CnR4biBBcHBsaWNhdGlvbklECmludGNfMCAvLyAwCiE9CiYmCmFzc2VydApjYWxsc3ViIGFkZHByb3Bvc2FsY2FzdGVyXzQKaW50Y18xIC8vIDEKcmV0dXJuCm1haW5fbDg6CnR4biBPbkNvbXBsZXRpb24KaW50Y18wIC8vIE5vT3AKPT0KYm56IG1haW5fbDEwCmVycgptYWluX2wxMDoKdHhuIEFwcGxpY2F0aW9uSUQKaW50Y18wIC8vIDAKPT0KYXNzZXJ0CmNhbGxzdWIgY3JlYXRlXzAKaW50Y18xIC8vIDEKcmV0dXJuCgovLyBjcmVhdGUKY3JlYXRlXzA6CnByb3RvIDAgMApieXRlY18xIC8vICJjdXJyZW50X3Byb3Bvc2FsX2lkIgppbnRjXzAgLy8gMAphcHBfZ2xvYmFsX3B1dApieXRlY18yIC8vICJ3aW5uaW5nX3Byb3Bvc2FsIgppbnRjXzAgLy8gMAphcHBfZ2xvYmFsX3B1dApyZXRzdWIKCi8vIGFkZF9wcm9wb3NhbAphZGRwcm9wb3NhbF8xOgpwcm90byAxIDAKaW50Y18wIC8vIDAKZHVwCmJ5dGVjXzEgLy8gImN1cnJlbnRfcHJvcG9zYWxfaWQiCmFwcF9nbG9iYWxfZ2V0CmZyYW1lX2J1cnkgMAppbnRjXzAgLy8gMApmcmFtZV9idXJ5IDEKYnl0ZWNfMyAvLyAicC0iCmZyYW1lX2RpZyAwCml0b2IKY29uY2F0CmJveF9kZWwKcG9wCmJ5dGVjXzMgLy8gInAtIgpmcmFtZV9kaWcgMAppdG9iCmNvbmNhdApmcmFtZV9kaWcgLTEKYm94X3B1dApieXRlY18wIC8vICJ2LSIKZnJhbWVfZGlnIDAKaXRvYgpjb25jYXQKYm94X2RlbApwb3AKYnl0ZWNfMCAvLyAidi0iCmZyYW1lX2RpZyAwCml0b2IKY29uY2F0CmZyYW1lX2RpZyAxCml0b2IKYm94X3B1dApieXRlY18xIC8vICJjdXJyZW50X3Byb3Bvc2FsX2lkIgpieXRlY18xIC8vICJjdXJyZW50X3Byb3Bvc2FsX2lkIgphcHBfZ2xvYmFsX2dldAppbnRjXzEgLy8gMQorCmFwcF9nbG9iYWxfcHV0CnJldHN1YgoKLy8gdm90ZQp2b3RlXzI6CnByb3RvIDEgMAppbnRjXzAgLy8gMApkdXAKYnl0ZWNfMiAvLyAid2lubmluZ19wcm9wb3NhbCIKYXBwX2dsb2JhbF9nZXQKZnJhbWVfYnVyeSAxCmJ5dGVjXzAgLy8gInYtIgpmcmFtZV9kaWcgLTEKaXRvYgpjb25jYXQKYm94X2dldApzdG9yZSAxCnN0b3JlIDAKbG9hZCAxCmFzc2VydApsb2FkIDAKYnRvaQppbnRjXzEgLy8gMQorCmZyYW1lX2J1cnkgMApieXRlY18wIC8vICJ2LSIKZnJhbWVfZGlnIC0xCml0b2IKY29uY2F0CmJveF9nZXQKc3RvcmUgMQpzdG9yZSAwCmxvYWQgMQphc3NlcnQKbG9hZCAwCmJ0b2kKaW50Y18xIC8vIDEKKwpieXRlY18wIC8vICJ2LSIKZnJhbWVfZGlnIDEKaXRvYgpjb25jYXQKYm94X2dldApzdG9yZSAzCnN0b3JlIDIKbG9hZCAzCmFzc2VydApsb2FkIDIKYnRvaQo+CmJ6IHZvdGVfMl9sMgpieXRlY18yIC8vICJ3aW5uaW5nX3Byb3Bvc2FsIgpmcmFtZV9kaWcgLTEKYXBwX2dsb2JhbF9wdXQKdm90ZV8yX2wyOgpieXRlY18wIC8vICJ2LSIKZnJhbWVfZGlnIC0xCml0b2IKY29uY2F0CmJveF9kZWwKcG9wCmJ5dGVjXzAgLy8gInYtIgpmcmFtZV9kaWcgLTEKaXRvYgpjb25jYXQKZnJhbWVfZGlnIDAKaXRvYgpib3hfcHV0CnJldHN1YgoKLy8gbWludAptaW50XzM6CnByb3RvIDAgMAppbnRjXzAgLy8gMApieXRlYyA0IC8vICIiCmR1cG4gNApieXRlY18yIC8vICJ3aW5uaW5nX3Byb3Bvc2FsIgphcHBfZ2xvYmFsX2dldApmcmFtZV9idXJ5IDAKYnl0ZWNfMyAvLyAicC0iCmZyYW1lX2RpZyAwCml0b2IKY29uY2F0CmJveF9nZXQKc3RvcmUgNQpzdG9yZSA0CmxvYWQgNQphc3NlcnQKbG9hZCA0CmZyYW1lX2J1cnkgMQpmcmFtZV9kaWcgMQpmcmFtZV9kaWcgMQppbnRjXzIgLy8gMgpleHRyYWN0X3VpbnQxNgpmcmFtZV9kaWcgMQppbnRjXzMgLy8gNApleHRyYWN0X3VpbnQxNgpzdWJzdHJpbmczCmZyYW1lX2J1cnkgMgpmcmFtZV9kaWcgMQpmcmFtZV9kaWcgMQppbnRjXzAgLy8gMApleHRyYWN0X3VpbnQxNgpmcmFtZV9kaWcgMQppbnRjXzIgLy8gMgpleHRyYWN0X3VpbnQxNgpzdWJzdHJpbmczCmZyYW1lX2J1cnkgMwpmcmFtZV9kaWcgMQpmcmFtZV9kaWcgMQppbnRjXzMgLy8gNApleHRyYWN0X3VpbnQxNgpkaWcgMQpsZW4Kc3Vic3RyaW5nMwpmcmFtZV9idXJ5IDQKZnJhbWVfZGlnIDEKZXh0cmFjdCA2IDMyCmZyYW1lX2J1cnkgNQppdHhuX2JlZ2luCnB1c2hpbnQgMyAvLyBhY2ZnCml0eG5fZmllbGQgVHlwZUVudW0KaW50Y18xIC8vIDEKaXR4bl9maWVsZCBDb25maWdBc3NldFRvdGFsCmZyYW1lX2RpZyAyCmV4dHJhY3QgMiAwCml0eG5fZmllbGQgQ29uZmlnQXNzZXRVUkwKZnJhbWVfZGlnIDMKZXh0cmFjdCAyIDAKaXR4bl9maWVsZCBDb25maWdBc3NldE5hbWUKZnJhbWVfZGlnIDQKZXh0cmFjdCAyIDAKaXR4bl9maWVsZCBDb25maWdBc3NldFVuaXROYW1lCmZyYW1lX2RpZyA1Cml0eG5fZmllbGQgQ29uZmlnQXNzZXRNZXRhZGF0YUhhc2gKaXR4bl9zdWJtaXQKcmV0c3ViCgovLyBhZGRfcHJvcG9zYWxfY2FzdGVyCmFkZHByb3Bvc2FsY2FzdGVyXzQ6CnByb3RvIDAgMApieXRlYyA0IC8vICIiCnR4bmEgQXBwbGljYXRpb25BcmdzIDEKZnJhbWVfYnVyeSAwCmZyYW1lX2RpZyAwCmNhbGxzdWIgYWRkcHJvcG9zYWxfMQpyZXRzdWIKCi8vIHZvdGVfY2FzdGVyCnZvdGVjYXN0ZXJfNToKcHJvdG8gMCAwCmludGNfMCAvLyAwCnR4bmEgQXBwbGljYXRpb25BcmdzIDEKYnRvaQpmcmFtZV9idXJ5IDAKZnJhbWVfZGlnIDAKY2FsbHN1YiB2b3RlXzIKcmV0c3ViCgovLyBtaW50X2Nhc3RlcgptaW50Y2FzdGVyXzY6CnByb3RvIDAgMApjYWxsc3ViIG1pbnRfMwpyZXRzdWI=", "clear": "I3ByYWdtYSB2ZXJzaW9uIDgKcHVzaGludCAwIC8vIDAKcmV0dXJu" }, "state": { "global": { - "num_byte_slices": 1, - "num_uints": 1 + "num_byte_slices": 0, + "num_uints": 2 }, "local": { "num_byte_slices": 0, @@ -93,7 +88,7 @@ export const APP_SPEC: AppSpec = { "descr": "" }, "winning_proposal": { - "type": "bytes", + "type": "uint64", "key": "winning_proposal", "descr": "" } @@ -106,15 +101,8 @@ export const APP_SPEC: AppSpec = { } }, "contract": { - "name": "dao", + "name": "DAO", "methods": [ - { - "name": "create", - "args": [], - "returns": { - "type": "void" - } - }, { "name": "add_proposal", "args": [ @@ -131,8 +119,8 @@ export const APP_SPEC: AppSpec = { "name": "vote", "args": [ { - "type": "address", - "name": "proposer" + "type": "uint64", + "name": "proposal_id" } ], "returns": { @@ -149,7 +137,9 @@ export const APP_SPEC: AppSpec = { ], "networks": {} }, - "bare_call_config": {} + "bare_call_config": { + "no_op": "CREATE" + } } /** @@ -207,12 +197,6 @@ export type Dao = { * Maps method signatures / names to their argument and return types. */ methods: - & Record<'create()void' | 'create', { - argsObj: { - } - argsTuple: [] - returns: void - }> & Record<'add_proposal((string,string,string,byte[32]))void' | 'add_proposal', { argsObj: { proposal: [string, string, string, Uint8Array] @@ -220,11 +204,11 @@ export type Dao = { argsTuple: [proposal: [string, string, string, Uint8Array]] returns: void }> - & Record<'vote(address)void' | 'vote', { + & Record<'vote(uint64)void' | 'vote', { argsObj: { - proposer: string + proposal_id: bigint | number } - argsTuple: [proposer: string] + argsTuple: [proposal_id: bigint | number] returns: void }> & Record<'mint()void' | 'mint', { @@ -239,7 +223,7 @@ export type Dao = { state: { global: { 'current_proposal_id'?: IntegerState - 'winning_proposal'?: BinaryState + 'winning_proposal'?: IntegerState } } } @@ -263,19 +247,19 @@ export type BareCallArgs = Omit */ export type Proposal = { name: string - unit_name: string url: string - hash: Uint8Array + unit_name: string + metadata_hash: Uint8Array } /** * Converts the tuple representation of a Proposal to the struct representation */ -export function Proposal([name, unit_name, url, hash]: [string, string, string, Uint8Array] ) { +export function Proposal([name, url, unit_name, metadata_hash]: [string, string, string, Uint8Array] ) { return { name, - unit_name, url, - hash, + unit_name, + metadata_hash, } } /** @@ -295,7 +279,7 @@ export type DaoCreateCalls = (typeof DaoCallFactory)['create'] * Defines supported create methods for this smart contract */ export type DaoCreateCallParams = - | (TypedCallParams<'create()void'> & (OnCompleteNoOp)) + | (TypedCallParams & (OnCompleteNoOp)) /** * Defines arguments required for the deploy method. */ @@ -318,16 +302,15 @@ export abstract class DaoCallFactory { static get create() { return { /** - * Constructs a create call for the dao smart contract using the create()void ABI method + * Constructs a create call for the DAO smart contract using a bare call * - * @param args Any args for the contract call - * @param params Any additional parameters for the call + * @param params Any parameters for the call * @returns A TypedCallParams object for the call */ - create(args: MethodArgs<'create()void'>, params: AppClientCallCoreParams & CoreAppCallArgs & AppClientCompilationParams & (OnCompleteNoOp) = {}) { + bare(params: BareCallArgs & AppClientCallCoreParams & CoreAppCallArgs & AppClientCompilationParams & (OnCompleteNoOp) = {}) { return { - method: 'create()void' as const, - methodArgs: Array.isArray(args) ? args : [], + method: undefined, + methodArgs: undefined, ...params, } }, @@ -349,16 +332,16 @@ export abstract class DaoCallFactory { } } /** - * Constructs a no op call for the vote(address)void ABI method + * Constructs a no op call for the vote(uint64)void ABI method * * @param args Any args for the contract call * @param params Any additional parameters for the call * @returns A TypedCallParams object for the call */ - static vote(args: MethodArgs<'vote(address)void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + static vote(args: MethodArgs<'vote(uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { return { - method: 'vote(address)void' as const, - methodArgs: Array.isArray(args) ? args : [args.proposer], + method: 'vote(uint64)void' as const, + methodArgs: Array.isArray(args) ? args : [args.proposal_id], ...params, } } @@ -379,7 +362,7 @@ export abstract class DaoCallFactory { } /** - * A client to make calls to the dao smart contract + * A client to make calls to the DAO smart contract */ export class DaoClient { /** @@ -432,7 +415,7 @@ export class DaoClient { } /** - * Idempotently deploys the dao smart contract. + * Idempotently deploys the DAO smart contract. * * @param params The arguments for the contract calls and any additional parameters for the call * @returns The deployment result @@ -453,20 +436,19 @@ export class DaoClient { const $this = this return { /** - * Creates a new instance of the dao smart contract using the create()void ABI method. + * Creates a new instance of the DAO smart contract using a bare call. * - * @param args The arguments for the smart contract call - * @param params Any additional parameters for the call + * @param args The arguments for the bare call * @returns The create result */ - async create(args: MethodArgs<'create()void'>, params: AppClientCallCoreParams & AppClientCompilationParams & (OnCompleteNoOp) = {}): Promise>> { - return $this.mapReturnValue(await $this.appClient.create(DaoCallFactory.create.create(args, params))) + bare(args: BareCallArgs & AppClientCallCoreParams & AppClientCompilationParams & CoreAppCallArgs & (OnCompleteNoOp) = {}): Promise> { + return $this.appClient.create(args) as unknown as Promise> }, } } /** - * Makes a clear_state call to an existing instance of the dao smart contract. + * Makes a clear_state call to an existing instance of the DAO smart contract. * * @param args The arguments for the bare call * @returns The clear_state result @@ -487,13 +469,13 @@ export class DaoClient { } /** - * Calls the vote(address)void ABI method. + * Calls the vote(uint64)void ABI method. * * @param args The arguments for the contract call * @param params Any additional parameters for the call * @returns The result of the call */ - public vote(args: MethodArgs<'vote(address)void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + public vote(args: MethodArgs<'vote(uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { return this.call(DaoCallFactory.vote(args, params)) } @@ -562,7 +544,7 @@ export class DaoClient { return DaoClient.getIntegerState(state, 'current_proposal_id') }, get winning_proposal() { - return DaoClient.getBinaryState(state, 'winning_proposal') + return DaoClient.getIntegerState(state, 'winning_proposal') }, } } @@ -578,7 +560,7 @@ export class DaoClient { resultMappers.push(undefined) return this }, - vote(args: MethodArgs<'vote(address)void'>, params?: AppClientCallCoreParams & CoreAppCallArgs) { + vote(args: MethodArgs<'vote(uint64)void'>, params?: AppClientCallCoreParams & CoreAppCallArgs) { promiseChain = promiseChain.then(() => client.vote(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) resultMappers.push(undefined) return this @@ -623,13 +605,13 @@ export type DaoComposer = { addProposal(args: MethodArgs<'add_proposal((string,string,string,byte[32]))void'>, params?: AppClientCallCoreParams & CoreAppCallArgs): DaoComposer<[...TReturns, MethodReturn<'add_proposal((string,string,string,byte[32]))void'>]> /** - * Calls the vote(address)void ABI method. + * Calls the vote(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 */ - vote(args: MethodArgs<'vote(address)void'>, params?: AppClientCallCoreParams & CoreAppCallArgs): DaoComposer<[...TReturns, MethodReturn<'vote(address)void'>]> + vote(args: MethodArgs<'vote(uint64)void'>, params?: AppClientCallCoreParams & CoreAppCallArgs): DaoComposer<[...TReturns, MethodReturn<'vote(uint64)void'>]> /** * Calls the mint()void ABI method. @@ -641,7 +623,7 @@ export type DaoComposer = { mint(args: MethodArgs<'mint()void'>, params?: AppClientCallCoreParams & CoreAppCallArgs): DaoComposer<[...TReturns, MethodReturn<'mint()void'>]> /** - * Makes a clear_state call to an existing instance of the dao smart contract. + * Makes a clear_state call to an existing instance of the DAO 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 diff --git a/intermediate-en/session_3/dao/backend/smart_contracts/artifacts/dao/contract.json b/intermediate-en/session_3/dao/backend/smart_contracts/artifacts/dao/contract.json index e671b37..d0f1162 100644 --- a/intermediate-en/session_3/dao/backend/smart_contracts/artifacts/dao/contract.json +++ b/intermediate-en/session_3/dao/backend/smart_contracts/artifacts/dao/contract.json @@ -1,13 +1,6 @@ { - "name": "dao", + "name": "DAO", "methods": [ - { - "name": "create", - "args": [], - "returns": { - "type": "void" - } - }, { "name": "add_proposal", "args": [ @@ -24,8 +17,8 @@ "name": "vote", "args": [ { - "type": "address", - "name": "proposer" + "type": "uint64", + "name": "proposal_id" } ], "returns": { diff --git a/intermediate-en/session_3/dao/backend/smart_contracts/dao/contract.py b/intermediate-en/session_3/dao/backend/smart_contracts/dao/contract.py index b93c691..e141fa3 100644 --- a/intermediate-en/session_3/dao/backend/smart_contracts/dao/contract.py +++ b/intermediate-en/session_3/dao/backend/smart_contracts/dao/contract.py @@ -58,7 +58,7 @@ class DAOState: app = beaker.Application("DAO", state=DAOState) -@app.create +@app.create(bare=True) def create() -> pt.Expr: return app.initialize_global_state() @@ -66,7 +66,7 @@ def create() -> pt.Expr: # In box storage: # proposal[id] = given proposal # votes[id] = 0 -@app.opt_in +@app.external def add_proposal(proposal: Proposal) -> pt.Expr: proposal_id = app.state.current_proposal_id.get() new_id = proposal_id + pt.Int(1) diff --git a/intermediate-en/session_3/dao/frontend/.copier-answers.yml b/intermediate-en/session_3/dao/frontend/.copier-answers.yml index 7a7e4c0..04b0e9c 100644 --- a/intermediate-en/session_3/dao/frontend/.copier-answers.yml +++ b/intermediate-en/session_3/dao/frontend/.copier-answers.yml @@ -1,6 +1,6 @@ # Changes here will be overwritten by Copier; NEVER EDIT MANUALLY -_commit: 0.7.1-18-g8c04365 -_src_path: https://github.com/algorandfoundation/algokit-react-frontend-template +_commit: 0.8.0 +_src_path: gh:algorandfoundation/algokit-react-frontend-template algod_port: 4001 algod_server: http://localhost algod_token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa diff --git a/intermediate-en/session_3/dao/frontend/README.md b/intermediate-en/session_3/dao/frontend/README.md index 295241f..b80aef6 100644 --- a/intermediate-en/session_3/dao/frontend/README.md +++ b/intermediate-en/session_3/dao/frontend/README.md @@ -58,4 +58,27 @@ This project makes use of React and Tailwind to provider a base project configur It has also been configured to have a productive dev experience out of the box in [VS Code](https://code.visualstudio.com/), see the [.vscode](./.vscode) folder. # Integrating with smart contracts and application clients -Refer to the detailed guidance on [integrating with smart contracts and application clients](./src/contracts/README.md). In essence, for any smart contract codebase generated with AlgoKit or ther tools that produce compile contracts into ARC34 compliant app specifications, you can use the `algokit generate` command to generate TypeScript or Python typed client. Once generated simply drag and drop the generated client into `./src/contracts` and import it into your React components as you see fit. +Refer to the detailed guidance on [integrating with smart contracts and application clients](./src/contracts/README.md). In essence, for any smart contract codebase generated with AlgoKit or other tools that produce compile contracts into ARC34 compliant app specifications, you can use the `algokit generate` command to generate TypeScript or Python typed client. Once generated simply drag and drop the generated client into `./src/contracts` and import it into your React components as you see fit. + +# Vite compatibility with `js-algorand-sdk` and `algokit clients` + +If you are receiving `address malformed` errors when sending direct calls to abi methods on AlgoKit typed clients where ABI parameters expect ABI transactions to be passed, this is a known edge case and a bug that occurs on [Vite in dev mode](https://github.com/vitejs/vite/issues/9528). A fix is in the works on [js-algorand-sdk](https://github.com/algorand/js-algorand-sdk/issues/740) side (which is used as a main low-level dependency by AlgoKit to generate typed clients), but in the meantime you can use a simple workaround described below: + +```ts +Instead of: + +const response = await myAlgoKitTypedClient + .someExternalMethod({ + some_txn_param: someTxnObject, + }) + +use: + +const response = await appClient + .compose() + .someExternalMethod({ + some_txn_param: someTxnObject, + }) + .execute() +``` + diff --git a/intermediate-en/session_3/dao/frontend/src/App.tsx b/intermediate-en/session_3/dao/frontend/src/App.tsx index 757f692..586df99 100644 --- a/intermediate-en/session_3/dao/frontend/src/App.tsx +++ b/intermediate-en/session_3/dao/frontend/src/App.tsx @@ -1,13 +1,13 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ import { DeflyWalletConnect } from '@blockshake/defly-connect' import { DaffiWalletConnect } from '@daffiwallet/connect' import { PeraWalletConnect } from '@perawallet/connect' import { PROVIDER_ID, ProvidersArray, WalletProvider, useInitializeProviders, useWallet } from '@txnlab/use-wallet' import algosdk from 'algosdk' import { SnackbarProvider } from 'notistack' -import { useState } from 'react' +import { useRef, useState } from 'react' import AppCalls from './components/AppCalls' import ConnectWallet from './components/ConnectWallet' -import Transact from './components/Transact' import { getAlgodConfigFromViteEnvironment } from './utils/network/getAlgoClientConfigs' let providersArray: ProvidersArray @@ -26,24 +26,20 @@ if (import.meta.env.VITE_ALGOD_NETWORK === '') { export default function App() { const [openWalletModal, setOpenWalletModal] = useState(false) - const [openDemoModal, setOpenDemoModal] = useState(false) - const [appCallsDemoModal, setAppCallsDemoModal] = useState(false) const { activeAddress } = useWallet() + const [appID, setAppID] = useState(0) + const nftName = useRef(null) + const unitName = useRef(null) + const fileUpload = useRef(null) + const voteProposalID = useRef(null) + const web3StorageToken = useRef(null) + + const algodConfig = getAlgodConfigFromViteEnvironment() const toggleWalletModal = () => { setOpenWalletModal(!openWalletModal) } - const toggleDemoModal = () => { - setOpenDemoModal(!openDemoModal) - } - - const toggleAppCallsModal = () => { - setAppCallsDemoModal(!appCallsDemoModal) - } - - const algodConfig = getAlgodConfigFromViteEnvironment() - const walletProviders = useInitializeProviders({ providers: providersArray, nodeConfig: { @@ -61,44 +57,75 @@ export default function App() {
-

- Welcome to
AlgoKit 🙂
-

-

- This starter has been generated using official AlgoKit React template. Refer to the resource below for next steps. -

+

NFT Minting DAO

+

This is the DAO app interface for the intermediate bootcamp!

- - Getting started - +
- {activeAddress && ( - - )} + {activeAddress && appID == 0 && } - {activeAddress && ( - + {activeAddress && appID !== 0 && ( +
+
+ + + + + + + + + + +
+ + + + +
+ +
)} -
- - - + +
diff --git a/intermediate-en/session_3/dao/frontend/src/components/AppCalls.tsx b/intermediate-en/session_3/dao/frontend/src/components/AppCalls.tsx index 04762ff..01d6168 100644 --- a/intermediate-en/session_3/dao/frontend/src/components/AppCalls.tsx +++ b/intermediate-en/session_3/dao/frontend/src/components/AppCalls.tsx @@ -1,20 +1,37 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +/* eslint-disable no-console */ import * as algokit from '@algorandfoundation/algokit-utils' -import { TransactionSignerAccount } from '@algorandfoundation/algokit-utils/types/account' -import { AppDetails } from '@algorandfoundation/algokit-utils/types/app-client' import { useWallet } from '@txnlab/use-wallet' import { useSnackbar } from 'notistack' import { useState } from 'react' import { DaoClient } from '../contracts/dao' -import { getAlgodConfigFromViteEnvironment, getIndexerConfigFromViteEnvironment } from '../utils/network/getAlgoClientConfigs' +import { getAlgodConfigFromViteEnvironment } from '../utils/network/getAlgoClientConfigs' -interface AppCallsInterface { - openModal: boolean - setModalState: (value: boolean) => void -} +type AppCallProps = { + appID: number +} & ( + | { + method: 'create' + setAppID: React.Dispatch> + } + | { + method: 'add_proposal' + name: string + unitName: string + file: File | undefined + web3StorageToken: string + } + | { + method: 'vote' + proposalID: number + } + | { + method: 'mint' + } +) -const AppCalls = ({ openModal, setModalState }: AppCallsInterface) => { +const AppCalls = (props: AppCallProps) => { const [loading, setLoading] = useState(false) - const [contractInput, setContractInput] = useState('') const algodConfig = getAlgodConfigFromViteEnvironment() const algodClient = algokit.getAlgoClient({ @@ -23,77 +40,61 @@ const AppCalls = ({ openModal, setModalState }: AppCallsInterface) => { token: algodConfig.token, }) - const indexerConfig = getIndexerConfigFromViteEnvironment() - const indexer = algokit.getAlgoIndexerClient({ - server: indexerConfig.server, - port: indexerConfig.port, - token: indexerConfig.token, - }) - const { enqueueSnackbar } = useSnackbar() const { signer, activeAddress } = useWallet() - const sendAppCall = async () => { - setLoading(true) + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const sender = { signer, addr: activeAddress! } - const appDetails = { - resolveBy: 'creatorAndName', - sender: { signer, addr: activeAddress } as TransactionSignerAccount, - creatorAddress: activeAddress, - findExistingUsing: indexer, - } as AppDetails + const appClient = new DaoClient( + { + resolveBy: 'id', + id: props.appID, + sender, + }, + algodClient, + ) - const appClient = new DaoClient(appDetails, algodClient) + let text: string + let callMethod: () => Promise + switch (props.method) { + case 'create': + text = 'Create App' + callMethod = async () => { + setLoading(true) - // Please note, in typical production scenarios, - // you wouldn't want to use deploy directly from your frontend. - // Instead, you would deploy your contract on your backend and reference it by id. - // Given the simplicity of the starter contract, we are deploying it on the frontend - // for demonstration purposes. - const deployParams = { - onSchemaBreak: 'append', - onUpdate: 'append', - } - await appClient.deploy(deployParams).catch((e: Error) => { - enqueueSnackbar(`Error deploying the contract: ${e.message}`, { variant: 'error' }) - setLoading(false) - return - }) + try { + await appClient.create.bare() + } catch (e) { + enqueueSnackbar(`Error deploying the contract: ${(e as Error).message}`, { variant: 'error' }) + setLoading(false) + return + } - const response = await appClient.hello({ name: contractInput }).catch((e: Error) => { - enqueueSnackbar(`Error calling the contract: ${e.message}`, { variant: 'error' }) - setLoading(false) - return - }) + const { appId } = await appClient.appClient.getAppReference() + setLoading(false) - enqueueSnackbar(`Response from the contract: ${response?.return}`, { variant: 'success' }) - setLoading(false) + props.setAppID(Number(appId)) + } + break + case 'add_proposal': + text = 'Propose' + callMethod = async () => {} + break + case 'vote': + text = 'Vote' + callMethod = async () => {} + break + case 'mint': + text = 'Mint' + callMethod = async () => {} + break } return ( - -
-

Say hello to your Algorand smart contract

-
- { - setContractInput(e.target.value) - }} - /> -
- - -
-
-
+ ) } diff --git a/intermediate-en/session_3/dao/frontend/src/contracts/dao.ts b/intermediate-en/session_3/dao/frontend/src/contracts/dao.ts new file mode 100644 index 0000000..bba4851 --- /dev/null +++ b/intermediate-en/session_3/dao/frontend/src/contracts/dao.ts @@ -0,0 +1,654 @@ +/* eslint-disable */ +/** + * This file was automatically generated by @algorandfoundation/algokit-client-generator. + * DO NOT MODIFY IT BY HAND. + * requires: @algorandfoundation/algokit-utils: ^2 + */ +import * as algokit from '@algorandfoundation/algokit-utils' +import { + AppCallTransactionResult, + AppCallTransactionResultOfType, + CoreAppCallArgs, + RawAppCallArgs, + AppState, + TealTemplateParams, + ABIAppCallArg, +} from '@algorandfoundation/algokit-utils/types/app' +import { + AppClientCallCoreParams, + AppClientCompilationParams, + AppClientDeployCoreParams, + AppDetails, + ApplicationClient, +} from '@algorandfoundation/algokit-utils/types/app-client' +import { AppSpec } from '@algorandfoundation/algokit-utils/types/app-spec' +import { SendTransactionResult, TransactionToSign, SendTransactionFrom } from '@algorandfoundation/algokit-utils/types/transaction' +import { Algodv2, OnApplicationComplete, Transaction, TransactionWithSigner, AtomicTransactionComposer } from 'algosdk' +export const APP_SPEC: AppSpec = { + "hints": { + "add_proposal((string,string,string,byte[32]))void": { + "structs": { + "proposal": { + "name": "Proposal", + "elements": [ + [ + "name", + "string" + ], + [ + "url", + "string" + ], + [ + "unit_name", + "string" + ], + [ + "metadata_hash", + "byte[32]" + ] + ] + } + }, + "call_config": { + "no_op": "CALL" + } + }, + "vote(uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "mint()void": { + "call_config": { + "no_op": "CALL" + } + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKaW50Y2Jsb2NrIDAgMSAyIDQKYnl0ZWNibG9jayAweDc2MmQgMHg2Mzc1NzI3MjY1NmU3NDVmNzA3MjZmNzA2ZjczNjE2YzVmNjk2NCAweDc3Njk2ZTZlNjk2ZTY3NWY3MDcyNmY3MDZmNzM2MTZjIDB4NzAyZCAweAp0eG4gTnVtQXBwQXJncwppbnRjXzAgLy8gMAo9PQpibnogbWFpbl9sOAp0eG5hIEFwcGxpY2F0aW9uQXJncyAwCnB1c2hieXRlcyAweGVmYThiNDRiIC8vICJhZGRfcHJvcG9zYWwoKHN0cmluZyxzdHJpbmcsc3RyaW5nLGJ5dGVbMzJdKSl2b2lkIgo9PQpibnogbWFpbl9sNwp0eG5hIEFwcGxpY2F0aW9uQXJncyAwCnB1c2hieXRlcyAweDMxZDVjMzAwIC8vICJ2b3RlKHVpbnQ2NCl2b2lkIgo9PQpibnogbWFpbl9sNgp0eG5hIEFwcGxpY2F0aW9uQXJncyAwCnB1c2hieXRlcyAweDU1ODhkY2I0IC8vICJtaW50KCl2b2lkIgo9PQpibnogbWFpbl9sNQplcnIKbWFpbl9sNToKdHhuIE9uQ29tcGxldGlvbgppbnRjXzAgLy8gTm9PcAo9PQp0eG4gQXBwbGljYXRpb25JRAppbnRjXzAgLy8gMAohPQomJgphc3NlcnQKY2FsbHN1YiBtaW50Y2FzdGVyXzYKaW50Y18xIC8vIDEKcmV0dXJuCm1haW5fbDY6CnR4biBPbkNvbXBsZXRpb24KaW50Y18wIC8vIE5vT3AKPT0KdHhuIEFwcGxpY2F0aW9uSUQKaW50Y18wIC8vIDAKIT0KJiYKYXNzZXJ0CmNhbGxzdWIgdm90ZWNhc3Rlcl81CmludGNfMSAvLyAxCnJldHVybgptYWluX2w3Ogp0eG4gT25Db21wbGV0aW9uCmludGNfMCAvLyBOb09wCj09CnR4biBBcHBsaWNhdGlvbklECmludGNfMCAvLyAwCiE9CiYmCmFzc2VydApjYWxsc3ViIGFkZHByb3Bvc2FsY2FzdGVyXzQKaW50Y18xIC8vIDEKcmV0dXJuCm1haW5fbDg6CnR4biBPbkNvbXBsZXRpb24KaW50Y18wIC8vIE5vT3AKPT0KYm56IG1haW5fbDEwCmVycgptYWluX2wxMDoKdHhuIEFwcGxpY2F0aW9uSUQKaW50Y18wIC8vIDAKPT0KYXNzZXJ0CmNhbGxzdWIgY3JlYXRlXzAKaW50Y18xIC8vIDEKcmV0dXJuCgovLyBjcmVhdGUKY3JlYXRlXzA6CnByb3RvIDAgMApieXRlY18xIC8vICJjdXJyZW50X3Byb3Bvc2FsX2lkIgppbnRjXzAgLy8gMAphcHBfZ2xvYmFsX3B1dApieXRlY18yIC8vICJ3aW5uaW5nX3Byb3Bvc2FsIgppbnRjXzAgLy8gMAphcHBfZ2xvYmFsX3B1dApyZXRzdWIKCi8vIGFkZF9wcm9wb3NhbAphZGRwcm9wb3NhbF8xOgpwcm90byAxIDAKaW50Y18wIC8vIDAKZHVwCmJ5dGVjXzEgLy8gImN1cnJlbnRfcHJvcG9zYWxfaWQiCmFwcF9nbG9iYWxfZ2V0CmZyYW1lX2J1cnkgMAppbnRjXzAgLy8gMApmcmFtZV9idXJ5IDEKYnl0ZWNfMyAvLyAicC0iCmZyYW1lX2RpZyAwCml0b2IKY29uY2F0CmJveF9kZWwKcG9wCmJ5dGVjXzMgLy8gInAtIgpmcmFtZV9kaWcgMAppdG9iCmNvbmNhdApmcmFtZV9kaWcgLTEKYm94X3B1dApieXRlY18wIC8vICJ2LSIKZnJhbWVfZGlnIDAKaXRvYgpjb25jYXQKYm94X2RlbApwb3AKYnl0ZWNfMCAvLyAidi0iCmZyYW1lX2RpZyAwCml0b2IKY29uY2F0CmZyYW1lX2RpZyAxCml0b2IKYm94X3B1dApieXRlY18xIC8vICJjdXJyZW50X3Byb3Bvc2FsX2lkIgpieXRlY18xIC8vICJjdXJyZW50X3Byb3Bvc2FsX2lkIgphcHBfZ2xvYmFsX2dldAppbnRjXzEgLy8gMQorCmFwcF9nbG9iYWxfcHV0CnJldHN1YgoKLy8gdm90ZQp2b3RlXzI6CnByb3RvIDEgMAppbnRjXzAgLy8gMApkdXAKYnl0ZWNfMiAvLyAid2lubmluZ19wcm9wb3NhbCIKYXBwX2dsb2JhbF9nZXQKZnJhbWVfYnVyeSAxCmJ5dGVjXzAgLy8gInYtIgpmcmFtZV9kaWcgLTEKaXRvYgpjb25jYXQKYm94X2dldApzdG9yZSAxCnN0b3JlIDAKbG9hZCAxCmFzc2VydApsb2FkIDAKYnRvaQppbnRjXzEgLy8gMQorCmZyYW1lX2J1cnkgMApieXRlY18wIC8vICJ2LSIKZnJhbWVfZGlnIC0xCml0b2IKY29uY2F0CmJveF9nZXQKc3RvcmUgMQpzdG9yZSAwCmxvYWQgMQphc3NlcnQKbG9hZCAwCmJ0b2kKaW50Y18xIC8vIDEKKwpieXRlY18wIC8vICJ2LSIKZnJhbWVfZGlnIDEKaXRvYgpjb25jYXQKYm94X2dldApzdG9yZSAzCnN0b3JlIDIKbG9hZCAzCmFzc2VydApsb2FkIDIKYnRvaQo+CmJ6IHZvdGVfMl9sMgpieXRlY18yIC8vICJ3aW5uaW5nX3Byb3Bvc2FsIgpmcmFtZV9kaWcgLTEKYXBwX2dsb2JhbF9wdXQKdm90ZV8yX2wyOgpieXRlY18wIC8vICJ2LSIKZnJhbWVfZGlnIC0xCml0b2IKY29uY2F0CmJveF9kZWwKcG9wCmJ5dGVjXzAgLy8gInYtIgpmcmFtZV9kaWcgLTEKaXRvYgpjb25jYXQKZnJhbWVfZGlnIDAKaXRvYgpib3hfcHV0CnJldHN1YgoKLy8gbWludAptaW50XzM6CnByb3RvIDAgMAppbnRjXzAgLy8gMApieXRlYyA0IC8vICIiCmR1cG4gNApieXRlY18yIC8vICJ3aW5uaW5nX3Byb3Bvc2FsIgphcHBfZ2xvYmFsX2dldApmcmFtZV9idXJ5IDAKYnl0ZWNfMyAvLyAicC0iCmZyYW1lX2RpZyAwCml0b2IKY29uY2F0CmJveF9nZXQKc3RvcmUgNQpzdG9yZSA0CmxvYWQgNQphc3NlcnQKbG9hZCA0CmZyYW1lX2J1cnkgMQpmcmFtZV9kaWcgMQpmcmFtZV9kaWcgMQppbnRjXzIgLy8gMgpleHRyYWN0X3VpbnQxNgpmcmFtZV9kaWcgMQppbnRjXzMgLy8gNApleHRyYWN0X3VpbnQxNgpzdWJzdHJpbmczCmZyYW1lX2J1cnkgMgpmcmFtZV9kaWcgMQpmcmFtZV9kaWcgMQppbnRjXzAgLy8gMApleHRyYWN0X3VpbnQxNgpmcmFtZV9kaWcgMQppbnRjXzIgLy8gMgpleHRyYWN0X3VpbnQxNgpzdWJzdHJpbmczCmZyYW1lX2J1cnkgMwpmcmFtZV9kaWcgMQpmcmFtZV9kaWcgMQppbnRjXzMgLy8gNApleHRyYWN0X3VpbnQxNgpkaWcgMQpsZW4Kc3Vic3RyaW5nMwpmcmFtZV9idXJ5IDQKZnJhbWVfZGlnIDEKZXh0cmFjdCA2IDMyCmZyYW1lX2J1cnkgNQppdHhuX2JlZ2luCnB1c2hpbnQgMyAvLyBhY2ZnCml0eG5fZmllbGQgVHlwZUVudW0KaW50Y18xIC8vIDEKaXR4bl9maWVsZCBDb25maWdBc3NldFRvdGFsCmZyYW1lX2RpZyAyCmV4dHJhY3QgMiAwCml0eG5fZmllbGQgQ29uZmlnQXNzZXRVUkwKZnJhbWVfZGlnIDMKZXh0cmFjdCAyIDAKaXR4bl9maWVsZCBDb25maWdBc3NldE5hbWUKZnJhbWVfZGlnIDQKZXh0cmFjdCAyIDAKaXR4bl9maWVsZCBDb25maWdBc3NldFVuaXROYW1lCmZyYW1lX2RpZyA1Cml0eG5fZmllbGQgQ29uZmlnQXNzZXRNZXRhZGF0YUhhc2gKaXR4bl9zdWJtaXQKcmV0c3ViCgovLyBhZGRfcHJvcG9zYWxfY2FzdGVyCmFkZHByb3Bvc2FsY2FzdGVyXzQ6CnByb3RvIDAgMApieXRlYyA0IC8vICIiCnR4bmEgQXBwbGljYXRpb25BcmdzIDEKZnJhbWVfYnVyeSAwCmZyYW1lX2RpZyAwCmNhbGxzdWIgYWRkcHJvcG9zYWxfMQpyZXRzdWIKCi8vIHZvdGVfY2FzdGVyCnZvdGVjYXN0ZXJfNToKcHJvdG8gMCAwCmludGNfMCAvLyAwCnR4bmEgQXBwbGljYXRpb25BcmdzIDEKYnRvaQpmcmFtZV9idXJ5IDAKZnJhbWVfZGlnIDAKY2FsbHN1YiB2b3RlXzIKcmV0c3ViCgovLyBtaW50X2Nhc3RlcgptaW50Y2FzdGVyXzY6CnByb3RvIDAgMApjYWxsc3ViIG1pbnRfMwpyZXRzdWI=", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDgKcHVzaGludCAwIC8vIDAKcmV0dXJu" + }, + "state": { + "global": { + "num_byte_slices": 0, + "num_uints": 2 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "schema": { + "global": { + "declared": { + "current_proposal_id": { + "type": "uint64", + "key": "current_proposal_id", + "descr": "" + }, + "winning_proposal": { + "type": "uint64", + "key": "winning_proposal", + "descr": "" + } + }, + "reserved": {} + }, + "local": { + "declared": {}, + "reserved": {} + } + }, + "contract": { + "name": "DAO", + "methods": [ + { + "name": "add_proposal", + "args": [ + { + "type": "(string,string,string,byte[32])", + "name": "proposal" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "vote", + "args": [ + { + "type": "uint64", + "name": "proposal_id" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "mint", + "args": [], + "returns": { + "type": "void" + } + } + ], + "networks": {} + }, + "bare_call_config": { + "no_op": "CREATE" + } +} + +/** + * Defines an onCompletionAction of 'no_op' + */ +export type OnCompleteNoOp = { onCompleteAction?: 'no_op' | OnApplicationComplete.NoOpOC } +/** + * Defines an onCompletionAction of 'opt_in' + */ +export type OnCompleteOptIn = { onCompleteAction: 'opt_in' | OnApplicationComplete.OptInOC } +/** + * Defines an onCompletionAction of 'close_out' + */ +export type OnCompleteCloseOut = { onCompleteAction: 'close_out' | OnApplicationComplete.CloseOutOC } +/** + * Defines an onCompletionAction of 'delete_application' + */ +export type OnCompleteDelApp = { onCompleteAction: 'delete_application' | OnApplicationComplete.DeleteApplicationOC } +/** + * Defines an onCompletionAction of 'update_application' + */ +export type OnCompleteUpdApp = { onCompleteAction: 'update_application' | OnApplicationComplete.UpdateApplicationOC } +/** + * A state record containing a single unsigned integer + */ +export type IntegerState = { + /** + * Gets the state value as a BigInt + */ + asBigInt(): bigint + /** + * Gets the state value as a number. + */ + asNumber(): number +} +/** + * A state record containing binary data + */ +export type BinaryState = { + /** + * Gets the state value as a Uint8Array + */ + asByteArray(): Uint8Array + /** + * Gets the state value as a string + */ + asString(): string +} + +/** + * Defines the types of available calls and state of the Dao smart contract. + */ +export type Dao = { + /** + * Maps method signatures / names to their argument and return types. + */ + methods: + & Record<'add_proposal((string,string,string,byte[32]))void' | 'add_proposal', { + argsObj: { + proposal: [string, string, string, Uint8Array] + } + argsTuple: [proposal: [string, string, string, Uint8Array]] + returns: void + }> + & Record<'vote(uint64)void' | 'vote', { + argsObj: { + proposal_id: bigint | number + } + argsTuple: [proposal_id: bigint | number] + returns: void + }> + & Record<'mint()void' | 'mint', { + argsObj: { + } + argsTuple: [] + returns: void + }> + /** + * Defines the shape of the global and local state of the application. + */ + state: { + global: { + 'current_proposal_id'?: IntegerState + 'winning_proposal'?: IntegerState + } + } +} +/** + * Defines the possible abi call signatures + */ +export type DaoSig = keyof Dao['methods'] +/** + * Defines an object containing all relevant parameters for a single call to the contract. Where TSignature is undefined, a bare call is made + */ +export type TypedCallParams = { + method: TSignature + methodArgs: TSignature extends undefined ? undefined : Array +} & AppClientCallCoreParams & CoreAppCallArgs +/** + * Defines the arguments required for a bare call + */ +export type BareCallArgs = Omit +/** + * Represents a Proposal result as a struct + */ +export type Proposal = { + name: string + url: string + unit_name: string + metadata_hash: Uint8Array +} +/** + * Converts the tuple representation of a Proposal to the struct representation + */ +export function Proposal([name, url, unit_name, metadata_hash]: [string, string, string, Uint8Array] ) { + return { + name, + url, + unit_name, + metadata_hash, + } +} +/** + * Maps a method signature from the Dao smart contract to the method's arguments in either tuple of struct form + */ +export type MethodArgs = Dao['methods'][TSignature]['argsObj' | 'argsTuple'] +/** + * Maps a method signature from the Dao smart contract to the method's return type + */ +export type MethodReturn = Dao['methods'][TSignature]['returns'] + +/** + * A factory for available 'create' calls + */ +export type DaoCreateCalls = (typeof DaoCallFactory)['create'] +/** + * Defines supported create methods for this smart contract + */ +export type DaoCreateCallParams = + | (TypedCallParams & (OnCompleteNoOp)) +/** + * Defines arguments required for the deploy method. + */ +export type DaoDeployArgs = { + deployTimeParams?: TealTemplateParams + /** + * A delegate which takes a create call factory and returns the create call params for this smart contract + */ + createCall?: (callFactory: DaoCreateCalls) => DaoCreateCallParams +} + + +/** + * Exposes methods for constructing all available smart contract calls + */ +export abstract class DaoCallFactory { + /** + * Gets available create call factories + */ + static get create() { + return { + /** + * Constructs a create call for the DAO smart contract using a bare call + * + * @param params Any parameters for the call + * @returns A TypedCallParams object for the call + */ + bare(params: BareCallArgs & AppClientCallCoreParams & CoreAppCallArgs & AppClientCompilationParams & (OnCompleteNoOp) = {}) { + return { + method: undefined, + methodArgs: undefined, + ...params, + } + }, + } + } + + /** + * Constructs a no op call for the add_proposal((string,string,string,byte[32]))void ABI method + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static addProposal(args: MethodArgs<'add_proposal((string,string,string,byte[32]))void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'add_proposal((string,string,string,byte[32]))void' as const, + methodArgs: Array.isArray(args) ? args : [args.proposal], + ...params, + } + } + /** + * Constructs a no op call for the vote(uint64)void ABI method + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static vote(args: MethodArgs<'vote(uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'vote(uint64)void' as const, + methodArgs: Array.isArray(args) ? args : [args.proposal_id], + ...params, + } + } + /** + * Constructs a no op call for the mint()void ABI method + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static mint(args: MethodArgs<'mint()void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'mint()void' as const, + methodArgs: Array.isArray(args) ? args : [], + ...params, + } + } +} + +/** + * A client to make calls to the DAO smart contract + */ +export class DaoClient { + /** + * The underlying `ApplicationClient` for when you want to have more flexibility + */ + public readonly appClient: ApplicationClient + + private readonly sender: SendTransactionFrom | undefined + + /** + * Creates a new instance of `DaoClient` + * + * @param appDetails appDetails The details to identify the app to deploy + * @param algod An algod client instance + */ + constructor(appDetails: AppDetails, private algod: Algodv2) { + this.sender = appDetails.sender + this.appClient = algokit.getAppClient({ + ...appDetails, + app: APP_SPEC + }, algod) + } + + /** + * Checks for decode errors on the AppCallTransactionResult and maps the return value to the specified generic type + * + * @param result The AppCallTransactionResult to be mapped + * @param returnValueFormatter An optional delegate to format the return value if required + * @returns The smart contract response with an updated return value + */ + protected mapReturnValue(result: AppCallTransactionResult, returnValueFormatter?: (value: any) => TReturn): AppCallTransactionResultOfType { + if(result.return?.decodeError) { + throw result.return.decodeError + } + const returnValue = result.return?.returnValue !== undefined && returnValueFormatter !== undefined + ? returnValueFormatter(result.return.returnValue) + : result.return?.returnValue as TReturn | undefined + return { ...result, return: returnValue } + } + + /** + * Calls the ABI method with the matching signature using an onCompletion code of NO_OP + * + * @param typedCallParams An object containing the method signature, args, and any other relevant parameters + * @param returnValueFormatter An optional delegate which when provided will be used to map non-undefined return values to the target type + * @returns The result of the smart contract call + */ + public async call(typedCallParams: TypedCallParams, returnValueFormatter?: (value: any) => MethodReturn) { + return this.mapReturnValue>(await this.appClient.call(typedCallParams), returnValueFormatter) + } + + /** + * Idempotently deploys the DAO smart contract. + * + * @param params The arguments for the contract calls and any additional parameters for the call + * @returns The deployment result + */ + public deploy(params: DaoDeployArgs & AppClientDeployCoreParams = {}): ReturnType { + const createArgs = params.createCall?.(DaoCallFactory.create) + return this.appClient.deploy({ + ...params, + createArgs, + createOnCompleteAction: createArgs?.onCompleteAction, + }) + } + + /** + * Gets available create methods + */ + public get create() { + const $this = this + return { + /** + * Creates a new instance of the DAO smart contract using a bare call. + * + * @param args The arguments for the bare call + * @returns The create result + */ + bare(args: BareCallArgs & AppClientCallCoreParams & AppClientCompilationParams & CoreAppCallArgs & (OnCompleteNoOp) = {}): Promise> { + return $this.appClient.create(args) as unknown as Promise> + }, + } + } + + /** + * Makes a clear_state call to an existing instance of the DAO smart contract. + * + * @param args The arguments for the bare call + * @returns The clear_state result + */ + public clearState(args: BareCallArgs & AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.appClient.clearState(args) + } + + /** + * Calls the add_proposal((string,string,string,byte[32]))void ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public addProposal(args: MethodArgs<'add_proposal((string,string,string,byte[32]))void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(DaoCallFactory.addProposal(args, params)) + } + + /** + * Calls the vote(uint64)void ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public vote(args: MethodArgs<'vote(uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(DaoCallFactory.vote(args, params)) + } + + /** + * Calls the mint()void ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public mint(args: MethodArgs<'mint()void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(DaoCallFactory.mint(args, params)) + } + + /** + * Extracts a binary state value out of an AppState dictionary + * + * @param state The state dictionary containing the state value + * @param key The key of the state value + * @returns A BinaryState instance containing the state value, or undefined if the key was not found + */ + private static getBinaryState(state: AppState, key: string): BinaryState | undefined { + const value = state[key] + if (!value) return undefined + if (!('valueRaw' in value)) + throw new Error(`Failed to parse state value for ${key}; received an int when expected a byte array`) + return { + asString(): string { + return value.value + }, + asByteArray(): Uint8Array { + return value.valueRaw + } + } + } + + /** + * Extracts a integer state value out of an AppState dictionary + * + * @param state The state dictionary containing the state value + * @param key The key of the state value + * @returns An IntegerState instance containing the state value, or undefined if the key was not found + */ + private static getIntegerState(state: AppState, key: string): IntegerState | undefined { + const value = state[key] + if (!value) return undefined + if ('valueRaw' in value) + throw new Error(`Failed to parse state value for ${key}; received a byte array when expected a number`) + return { + asBigInt() { + return typeof value.value === 'bigint' ? value.value : BigInt(value.value) + }, + asNumber(): number { + return typeof value.value === 'bigint' ? Number(value.value) : value.value + }, + } + } + + /** + * Returns the smart contract's global state wrapped in a strongly typed accessor with options to format the stored value + */ + public async getGlobalState(): Promise { + const state = await this.appClient.getGlobalState() + return { + get current_proposal_id() { + return DaoClient.getIntegerState(state, 'current_proposal_id') + }, + get winning_proposal() { + return DaoClient.getIntegerState(state, 'winning_proposal') + }, + } + } + + public compose(): DaoComposer { + const client = this + const atc = new AtomicTransactionComposer() + let promiseChain:Promise = Promise.resolve() + const resultMappers: Array any)> = [] + return { + addProposal(args: MethodArgs<'add_proposal((string,string,string,byte[32]))void'>, params?: AppClientCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.addProposal(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + vote(args: MethodArgs<'vote(uint64)void'>, params?: AppClientCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.vote(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + mint(args: MethodArgs<'mint()void'>, params?: AppClientCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.mint(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + clearState(args?: BareCallArgs & AppClientCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.clearState({...args, sendParams: {...args?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + addTransaction(txn: TransactionWithSigner | TransactionToSign | Transaction | Promise, defaultSender?: SendTransactionFrom) { + promiseChain = promiseChain.then(async () => atc.addTransaction(await algokit.getTransactionWithSigner(txn, defaultSender ?? client.sender))) + return this + }, + async atc() { + await promiseChain + return atc + }, + async execute() { + await promiseChain + const result = await algokit.sendAtomicTransactionComposer({ atc, sendParams: {} }, client.algod) + return { + ...result, + returns: result.returns?.map((val, i) => resultMappers[i] !== undefined ? resultMappers[i]!(val.returnValue) : val.returnValue) + } + } + } as unknown as DaoComposer + } +} +export type DaoComposer = { + /** + * Calls the add_proposal((string,string,string,byte[32]))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 + */ + addProposal(args: MethodArgs<'add_proposal((string,string,string,byte[32]))void'>, params?: AppClientCallCoreParams & CoreAppCallArgs): DaoComposer<[...TReturns, MethodReturn<'add_proposal((string,string,string,byte[32]))void'>]> + + /** + * Calls the vote(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 + */ + vote(args: MethodArgs<'vote(uint64)void'>, params?: AppClientCallCoreParams & CoreAppCallArgs): DaoComposer<[...TReturns, MethodReturn<'vote(uint64)void'>]> + + /** + * Calls the mint()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 + */ + mint(args: MethodArgs<'mint()void'>, params?: AppClientCallCoreParams & CoreAppCallArgs): DaoComposer<[...TReturns, MethodReturn<'mint()void'>]> + + /** + * Makes a clear_state call to an existing instance of the DAO smart contract. + * + * @param args The arguments for the bare call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + clearState(args?: BareCallArgs & AppClientCallCoreParams & CoreAppCallArgs): DaoComposer<[...TReturns, undefined]> + + /** + * Adds a transaction to the composer + * + * @param txn One of: A TransactionWithSigner object (returned as is), a TransactionToSign object (signer is obtained from the signer property), a Transaction object (signer is extracted from the defaultSender parameter), an async SendTransactionResult returned by one of algokit utils helpers (signer is obtained from the defaultSender parameter) + * @param defaultSender The default sender to be used to obtain a signer where the object provided to the transaction parameter does not include a signer. + */ + addTransaction(txn: TransactionWithSigner | TransactionToSign | Transaction | Promise, defaultSender?: SendTransactionFrom): DaoComposer + /** + * Returns the underlying AtomicTransactionComposer instance + */ + atc(): Promise + /** + * Executes the transaction group and returns an array of results + */ + execute(): Promise> +} +export type DaoComposerResults = { + returns: TReturns + groupId: string + txIds: string[] + transactions: Transaction[] +}