Package: algorig
_______  ___      _______  _______  ______    ___   _______ 
|   _   ||   |    |       ||       ||    _ |  |   | |       |
|  |_|  ||   |    |    ___||   _   ||   | ||  |   | |    ___|
|       ||   |    |   | __ |  | |  ||   |_||_ |   | |   | __ 
|       ||   |___ |   ||  ||  |_|  ||    __  ||   | |   ||  |
|   _   ||       ||   |_| ||       ||   |  | ||   | |   |_| |
|__| |__||_______||_______||_______||___|  |_||___| |_______|Welcome to Algorig - The Ultimate Algorand Smart Contract Development Rig!Algorig is a very compact and intuitive cli tool which tries to ease your Algorand smart contract development and tooling while still preserving all the flexibility. It simply utilizes PyTeal and Algorand Python SDK to make sure that your smart contract development feels quite native and fluent.Setup / InstallationSetting up Algorand SandboxBefore we get started, we'll need an Algorand Node containing the Algod and KMD services up and running preferably in local environment to be able to interact with Algorand blockchain and manage our accounts.The shortest way to run an Algorand node for development purposes is installing Algorand sandbox locally. To accomplish this, simply checkout the Algorand sandbox repository and run it by typing the commands below.$gitclonehttps://github.com/algorand/sandbox.git
$cdsandbox
$./sanboxupOnce the sandbox up and ready, you will have the both Algod and KMD services running locally underReleaseconfiguration which is a private network suitable for local development.Here, before getting started to our smart contract development, we'll need a Algorand account that will own the smart contract we develop on the Algorand blockchain. Thankfully, the Algorand sandbox default configuration comes with a default wallet namedunencrypted-default-walletalso containing a couple of accounts those already has a significant $algo balance which is quite sufficient enough to start with.$./sandboxgoalwalletlist##################################################Wallet:unencrypted-default-wallet(default)ID:de87213c0d084688bb4e40fe2045e16a##################################################You can also list all the accounts under the default wallet comes with your sandbox installation.$./sandboxgoalaccountlist-wunencrypted-default-wallet[online]DNSNRCJ6WO4LCVNE6O6JHYSZQ7C725RVJMMTT4GCBOUH4VPMPMZYUVBFLUDNSNRCJ6WO4LCVNE6O6JHYSZQ7C725RVJMMTT4GCBOUH4VPMPMZYUVBFLU4000008000000000microAlgos[offline]DRE4XUEJBPVHHFIUWT5SGH3JIGS5RDUBWYXASA72PINNUVFJIY6SFKSLEEDRE4XUEJBPVHHFIUWT5SGH3JIGS5RDUBWYXASA72PINNUVFJIY6SFKSLEE1000002000000000microAlgos[offline]HPAMDTCS3B2BZUGP5JUNDNBKVWXYPKPC56VEYT3WYBEONPVD6HJLUHMTVQHPAMDTCS3B2BZUGP5JUNDNBKVWXYPKPC56VEYT3WYBEONPVD6HJLUHMTVQ4000008000000000microAlgosPlease refer the Algorand sandbox project page itself for more configuration options and any other details.Now feel free to pick one of the accounts listed above as a contract owner so that we can assign it while setting up our Algorig project.Get started with AlgorigSince we're done with our local Algorand node setup, now we're ready to develop an Algorand smart sontract using Algorig. Before we start, let's first configure a virtual environment located under a project directory which will be the home folder of our smart contract project.$mkdirmydefi
$cdmydefi
$python-mvenvvenv
$sourcevenv/bin/activateOnce your virtual environment is up and ready, you may now install the Algorig itself. The best way to install Algorig is simply using pip command as shown below:$pipinstallalgorigAt this point, since you put your tool belt on, you're ready initialize a fresh new Algorig project by typing the command below.$riginit--signing-addressDNSNRCJ6WO4LCVNE6O6JHYSZQ7C725RVJMMTT4GCBOUH4VPMPMZYUVBFLUThis command will create two things. The first one is the main configuration file which you will be able to configure your smart contract development environment.$catprotocol.json{"algod_address":"http://localhost:4001","algod_token":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","kmd_address":"http://localhost:4002","kmd_token":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","wallet_name":"unencrypted-default-wallet","wallet_password":"","signing_address":"DNSNRCJ6WO4LCVNE6O6JHYSZQ7C725RVJMMTT4GCBOUH4VPMPMZYUVBFLU","teal_version":4,"num_global_byte_slices":0,"num_global_ints":0,"num_local_byte_slices":0,"num_local_ints":0,"app_id":0}Here, you might have also noticed how we used the contract owner account address by utilizing the--signing-addressparameter. Likewise, the use of such cli parameters will help us overriding the default configuration values above those mostly supposed to conform the default settings of our Algorand sandbox setup done before.Furthermore,initcommand also proposes a stub python module calledprotocol.pywhich contains the main entry point to your smart contract development. It's simply a class declaration with a special nameApplicationwhich also inherits and implements a base classBaseApplicationcomes with Algorig module itself.# protocol.pyfrompytealimport*fromalgorig.appimportBaseApplicationclassApplication(BaseApplication):defget_approval_program(self):# Implement your contract here using pytealreturnInt(1)defop_example_command(self,my_str:str,my_int:int=42):# This is an example method which can be used as cli commandprint(f'my_str:{my_str}, my_int:{my_int}')You may notice thatApplicationclass simply proposes a method calledget_approval_program()the one you're expected to implement your main smart contract logic under it.Also you might have noticed theop_example_commandmethod starting with a special prefixop. Algorig simply translates these special named class methods into cli commands which can be directly used to manage your smart contract operations those are supposed to interact with your smart contracts.To see all the available commands, simple typerigorrig --help$rig--help
sage:rig[-h][-v]{init,create,update,example_command}...

positionalarguments:{init,create,update,example_command}optionalarguments:-h,--helpshowthishelpmessageandexit-v,--versionshowprogram'sversionnumberandexitYou'll notice theexample_commandready to be typed at your finger tips. Just type the command to see the expected output.$rigexample_commandmyparam123
Hellomyparam123While this command does nothing rather than simply printing into console, such commands are generally supposed to perform some operations with your deployed smart contract by presumably utilizingApplicationCallor any other available transactions calls which we'll see later on.Write and deploy your first contractAs mentioned previously,get_approval_program()method is the main entry point to your Algorand smart contract. You're here simply expected to return a PyTeal node object and Algorig will handle the rest for you.Ok, let's write a very simple contract which only accepts application create and update transactions respectively.# protocol.pydefget_approval_program(self):# Implement your contract here using pytealreturnCond([Txn.application_id()==Int(0),Int(1)],[Txn.on_completion()==OnComplete.UpdateApplication,Int(1)],)Congrats, you just implemented your first Algorand smart contract. At this point, since you'll need to deploy your contract to Algorand blockchain, Algorig here will help us to deploy it with a built-in commandcreateby performing some magic behind in order to save us writing so many boilerplate code to achive the same.First of all, let's find out how the command works before acutally running it.$rigcreate--help
usage:rigcreate[-h][--app_argsAPP_ARGS]optionalarguments:-h,--helpshowthishelpmessageandexit--app_argsAPP_ARGIt seems to be legit using the command directly without any given parameteres in our case.Let's run the command.$rigcreate
Processingtransaction:A35EASTS6ANOO5HTAFIWZAAPSWJJ653ZFM74APMHE46ZIKXDNQDQ
........
Confirmedatround:2342525Applicationcreatedwithid:1Success! This built-in command essentially compiled your teal code, created an application create transaction automatically and sent it to Algorand blockchain throughout the Algod service by referring thealgod_addressandalgod_tokensettings located under our config file. In our case, those settings have already the default values referring the sandbox Algod service we just started locally.#protocol.json{"algod_address":"http://localhost:4001","algod_token":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",}Another side effect of this commmand is that whenever our application initially created on the blockchain, this command will save and keep theidof our application under our config file using the configuration key ofapp_id. At this point, if you dump the contents of our config file,  you'll notice theapp_idsetting which was absent previously.{"app_id":1}This setting will basically help Algorig to locate your application whenever you want to interact with it. For example, there is also another built-in command calledupdatewhich uses this setting while locating your application created previously.So now, it's a good time to also see how to deploy any changes in the contract.Ok, let's change a bit of our contract. This time let our contract to accept anApplicationCalltransaction to perform some tasks on the contract. In our case, it will simply expect a sigle arg"Hello World"to approve the transaction.# protocol.pydefget_approval_program(self):# Implement your contract here using pytealdefon_call():returnTxn.application_args[0]==Bytes('Hello World')returnCond([Txn.application_id()==Int(0),Int(1)],[Txn.on_completion()==OnComplete.UpdateApplication,Int(1)],[Txn.on_completion()==OnComplete.NoOp,on_call()],)Now you should be able to send your updates and override your existing contract using the command below:$rigupdate
Processingtransaction:H3ZBGVX4SVPAPHPZT23Q3LHIMTOQBEY2H6SDHGARCABLWRB7JNLA
......
Confirmedatround:5493Applicationupdatedsuccessfully.Congratulations, you just developed, deployed and also updated your first smart contract to Alogrand blockchain.Interact with our Smart ContractSo far, we've already seen how Algorig smoothens our Algorand smart contract development with some smart tooling methods. We already created our first smart contract and updated it by using the built-in commands. This time, let's now assume that we need to interact with our contract with a purpose. By our last update, our contract now expects us to send an application call transaction with a single parameter with the value of"Hello World.So let's try to implement such a command together to see how to develop and perform the contract operations.# protocol.pyfromalgorig.appimportBaseApplicationfromalgosdk.futureimporttransactionclassApplication(BaseApplication):...defop_send_greeting(self,greeting):self.submit(transaction.ApplicationCallTxn(sp=self.algod.suggested_params(),on_complete=transaction.OnComplete.NoOpOC,index=self.config.getint('app_id'),sender=self.config['signing_address'],app_args=[greeting)],))That's simple as it. We just implemented asend_greetingcommand to interact with our contract. Let's first locate it.$rig--help
usage:rig[-h][-v]{init,create,update,send_greeting}...

positionalarguments:{init,create,update,send_greeting}optionalarguments:-h,--helpshowthishelpmessageandexit-v,--versionshowprogram'sversionnumberandexitAlso you may check the further details about our new command by seeing the helper instructions of the command itself.$rigsend_greeting--help
usage:rigsend_greeting[-h]greeting

positionalarguments:greeting

optionalarguments:-h,--helpshowthishelpmessageandexitSince thesend_greetingcommand ready at your fingertips, just run it to see if it works as expected.$rigsend_greeting"Hello World"Processingtransaction:LBF5NQOM2WWIZ4ZUPAVTPKXTK7MD5TODPW2JO65UGNSASQ4IZT2Q
........
Confirmedatround:6054Perfect! You just interacted with your contract deployed on the blockchain. Now let's see what happens when we send a different parameter to our contract.$rigsend_greeting"Boooo"algosdk.error.AlgodHTTPError:TransactionPool.Remember:transaction4GFYWBASWI7T5GERJKO5R4GUUXUDH4LQGCO55BVUKJNXNCQQAKJA:transactionrejectedbyApprovalProgramVery cool, our last transaction simply rejected because you did not supply the desired parameter.Dealing with group transaction to implement atomic operationsMost transactions need to be grouped in some way and ensured all they are executed successfully which we call atomic operations.
In Algorig grouping more than one transactions is done byBaseApplication.submit_transactions()method. Let's see how it works:We'll take the popular Algorand Auction Demo'ssetupAuctionAppoperation with some brevity:# protocol.pyfromalgorig.appimportBaseApplicationfromalgosdk.futureimporttransactionclassApplication(BaseApplication):...defop_auction_setup(self,nft_holder_address,nft_id:int,nft_amount:int=1):sp=self.algod.suggested_params()fund_app_txn=transaction.PaymentTxn(sp=sp,sender=nft_holder_address,receiver=self.config['app_address'],amt=1_000)setup_app_txn=transaction.ApplicationCallTxn(sp=sp,on_complete=transaction.OnComplete.NoOpOC,sender=self.config['signing_address'],index=self.config['app_id'],app_args=['setup'],)transfer_nft_txn=transaction.AssetTransferTxn(sp=sp,sender=nft_holder_address,receiver=self.config['app_address'],index=nft_id,amt=nft_amount,)self.submit_group([fund_app_txn,setup_app_txn,transfer_nft_txn])Custom configuration settingsYou may end up adding your own settings toprotocol.jsonconfiguration file and refer them accordingly while implementing your contract.For example, you may want to keep an address belonging to an actor of an operation. In such case, simply add it toprotocol.jsonfile and refer it by using the instance fieldconfigcomes with theBaseApplicationclass instance.Let;s add one as an example.{"funder_address":"DNSNRCJ6WO4LCVNE6O6JHYSZQ7C725RVJMMTT4GCBOUH4VPMPMZYUVBFLU"}Now use it in yourApplicationclass where needed.# protocol.pyfromalgorig.appimportBaseApplicationfromalgosdk.futureimporttransactionclassApplication(BaseApplication):...defop_fund(self,amt:int):sp=self.algod.suggested_params()fund_app_txn=transaction.PaymentTxn(sp=sp,sender=self.config['funder_address'],receiver=self.config['app_address'],amt=amt)self.submit(fund_app_txn)Add settings as many as you want to keep them in the config file.Overriding the default behaviours ofBaseApplicationYou're always free to change the underlying functionality comes withBaseApplication. For instance, if you would like to modify the default behaviour of the clear state program, simply override the corresponding method as shown below.classApplication(BaseApplication):...defget_clear_state_program(self):# default behaviour was simply returning Int(1)returnTxn.sender()==\'HPAMDTCS3B2BZUGP5JUNDNBKVWXYPKPC56VEYT3WYBEONPVD6HJLUHMTVQ'...Please checkoutapp.pyto reviewBaseApplicationclass for the base implementationsContributeAny contributions are always very welcome, just before sending any pull requests, please make sure:You have setup your development environment correctlyYou have added/modifed the corresponding unit tests regarding your contributionYou have checked your code againsflake8style rulesPlease don't hesitate to contirubute if you like and use Algorig.Development EnvironmentTo start contributing, simply checkout the repository, create a virtual env and install the project locally.$gitcheckouthttps://github.com/kadirpekel/algorig
$cdalgorig
$python-mvenvvenv
$sourcevenv/bin/activate
$pipinstall-e".[dev]"Now you're ready to rock!Unit TestsAlgorig utilizespytestas test runner, just type below the command to run all the unit tests$pytestCoding StyleAlgorig code base follows the defaultflake8style guiding rules. So before sending any pull requests, please also make sure that your code passes theflake8checks.$flake8algorigDisclaimerThis project is in very early stages so please use it at your own risk.LicenseCopyright (c) 2021 Kadir Pekel.Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.