<jupyter_start><jupyter_text>HelloMember – a Smart Contract with Local State 07.0 Winter School on Smart Contracts <NAME> (<EMAIL>)2022-01-09* How to use the local state  SetupSee notebook 04.1, loading `algo_util.py`, the five accounts and the Purestake credentials* Consider hiding the code below<jupyter_code># Loading shared code and credentials
import sys, os
codepath = '..'+os.path.sep+'..'+os.path.sep+'sharedCode'
sys.path.append(codepath)
from algo_util import *
cred = load_credentials()
MyAlgo  = cred['MyAlgo']
Alice   = cred['Alice']
Bob     = cred['Bob']
Charlie = cred['Charlie']
Dina    = cred['Dina']
from algosdk import account, mnemonic
from algosdk.v2client import algod
from algosdk.future import transaction
from algosdk.future.transaction import PaymentTxn
from algosdk.future.transaction import AssetConfigTxn, AssetTransferTxn, AssetFreezeTxn
import algosdk.error
import json
import base64
import datetime
from pyteal import *
# Initialize the algod client (Testnet or Mainnet)
algod_client = algod.AlgodClient(algod_token='', algod_address=cred['algod_test'], headers=cred['purestake_token'])
last_block = algod_client.status()["last-round"]
print(f"Last committed block is: {last_block}")
print(Alice['public'])
print(Bob['public'])
print(Charlie['public'])<jupyter_output>HITPAAJ4HKANMP6EUYASXDUTCL653T7QMNHJL5NODL6XEGBM4KBLDJ2D2E
O2SLRPK4I4SWUOCYGGKHHUCFJJF5ORHFL76YO43FYTB7HUO7AHDDNNR5YA
5GIOBOLZSQEHTNNXWRJ6RGNPGCKWYJYUZZKY6YXHJVKFZXRB2YLDFDVH64<jupyter_text>HelloMember* Building on Helloworld and Hellofan, every member now gets a unique membership number* This membership number is stored in the local state at opt-in* Do not do anything else  Step 1: Define Approval program* **NEW** at opt-in, we store the membership number using `App.localPut()`* When writing to the local state, we have to specify to *which* local state* Easiest is `App.localPut(Int(0), ,  )`. * The expression `Int(0)` signifies the *current user*, i.e. the user that is currently interaction with the smart contract<jupyter_code>handle_creation = Seq(
    [
        # Initialize a GLOBAL variable
        App.globalPut(Bytes("Note"),       Bytes("Hello world!")),
        App.globalPut(Bytes("Members"),    Int(0)),                    # <---- initialize: currently we have zero members
        Return(Int(1))                                                 # Return "OK"
    ]
)

handle_optin = Seq(
    [
        App.globalPut(                                  # GLOBAL: increase number of Members
            Bytes("Members"),                           # key
            App.globalGet(Bytes("Members")) + Int(1)    # value: add 1 to current number of members
            ),
        App.localPut(                                   # LOCAL: membership number
            Int(0),                                     # which user? current one!
            Bytes("MembershipNo"),                      # key
            App.globalGet(Bytes("Members"))             # value: current members (already increased by 1)
        ),
        Return(Int(1))                                  # Return "OK"
    ]
)


handle_closeout = Return( Int(1) )                      # Not doing anything, returning "OK"  

handle_updateapp = Return( Int(0) )                     # Always FALSE ... updating not allowed

handle_deleteapp = Return(
    Txn.sender() == Global.creator_address()            # only TRUE if delete request is made by app creator
)

handle_noop  = Return ( Int(1) )                        # Not doing anything, returning "OK"           
hellomember_approval_pyteal = Cond(
    [Txn.application_id() == Int(0),                       handle_creation],
    [Txn.on_completion()  == OnComplete.OptIn,             handle_optin],
    [Txn.on_completion()  == OnComplete.CloseOut,          handle_closeout],
    [Txn.on_completion()  == OnComplete.UpdateApplication, handle_updateapp],
    [Txn.on_completion()  == OnComplete.DeleteApplication, handle_deleteapp],
    [Txn.on_completion()  == OnComplete.NoOp,              handle_noop],
)<jupyter_output><empty_output><jupyter_text>Compile PyTEAL -> TEAL<jupyter_code>hellomember_approval_teal = compileTeal(hellomember_approval_pyteal, mode=Mode.Application, version=5)
print(hellomember_approval_teal)<jupyter_output>#pragma version 5
txn ApplicationID
int 0
==
bnz main_l12
txn OnCompletion
int OptIn
==
bnz main_l11
txn OnCompletion
int CloseOut
==
bnz main_l10
txn OnCompletion
int UpdateApplication
==
bnz main_l9
txn OnCompletion
int DeleteApplication
==
bnz main_l8
txn OnCompletion
int NoOp
==
bnz main_l7
err
main_l7:
int 1
return
main_l8:
txn Sender
global CreatorAddress
==
return
main_l9:
int 0
return
main_l10:
int 1
return
main_l11:
byte "Members"
byte "Members"
app_global_get
int 1
+
app_global_put
int 0
byte "MembershipNo"
byte "Members"
app_global_get
app_local_put
int 1
return
main_l12:
byte "Note"
byte "Hello world!"
app_global_put
byte "Members"
int 0
app_global_put
int 1
return<jupyter_text>Step 1b: Define Clear State program<jupyter_code>hellomember_clear_pyteal =  Return(Int(1))    # not doing anything
hellomember_clear_teal = compileTeal(hellomember_clear_pyteal,mode=Mode.Application, version=3)
print(hellomember_clear_teal)<jupyter_output>#pragma version 3
int 1
return<jupyter_text>Compile TEAL -> BytecodeThis is slightly different ... we need one additional step for Byte-encoding<jupyter_code>hellomember_approval_b64 = algod_client.compile(hellomember_approval_teal)
Hellomember_Approval =  base64.b64decode(hellomember_approval_b64['result'])

hellomember_clear_b64 = algod_client.compile(hellomember_clear_teal)
Hellomember_Clear =  base64.b64decode(hellomember_clear_b64['result'])<jupyter_output><empty_output><jupyter_text>Deploy Smart Contract Bob deploys the smart contract* Reserve global storage with `StateSchema`* New command `ApplicationCreateTxn`* See [here](https://py-algorand-sdk.readthedocs.io/en/latest/algosdk/future/transaction.htmlalgosdk.future.transaction.ApplicationCreateTxn)<jupyter_code># Step 1: Prepare the transaction
sp = algod_client.suggested_params()

# Reserve space
global_ints = 1    # for "Members"
global_bytes = 1   # for "Note"
hellomember_global_schema = transaction.StateSchema(global_ints, global_bytes)

local_ints = 1     # for "MembershipNo"
local_bytes = 0    # No local text var
hellomember_local_schema = transaction.StateSchema(local_ints, local_bytes)

txn = transaction.ApplicationCreateTxn(
      sender = Bob['public'],                    # <-- sender public
      sp = sp,                                   # <-- sp
      on_complete = 0,                           # <-- when finished do nothing
      approval_program = Hellomember_Approval,   # <-- approval program 
      clear_program = Hellomember_Clear,         # <-- clear program 
      global_schema = hellomember_global_schema, # <-- reserve global space 
      local_schema = hellomember_local_schema    # <-- reserve local space
    )
# Step 2: sign transaction
stxn = txn.sign(Bob['private'])

# Step 3: send
txid=algod_client.send_transactions([stxn])

# Step 4: wait for ...
txinfo = wait_for_confirmation(algod_client, txid)
app_id = txinfo["application-index"]
print("Created new app-id:", app_id)<jupyter_output>Created new app-id: 74314499<jupyter_text>The Smart Contract is now deployed* And there is alreasdy something to see<jupyter_code>format_state(read_global_state(algod_client,app_id))
# Program code immediately visible on the web
print('https://testnet.algoexplorer.io/application/{}'.format(app_id))<jupyter_output>https://testnet.algoexplorer.io/application/74314499<jupyter_text>Using the Smart Contract (1): Users opt-in* Users will get MebershipNo in order of opt-in transaction<jupyter_code>user = Bob

# Step 1: prepare transaction
sp = algod_client.suggested_params()
txn = transaction.ApplicationOptInTxn(user['public'], sp, app_id)

# Step 2: sign transaction
stxn = txn.sign(user['private'])

# Step 3: send
txid = algod_client.send_transactions([stxn])

# Step 4: await confirmation
txinfo = wait_for_confirmation(algod_client, txid)<jupyter_output>Current round is  19950102.
Waiting for round 19950102 to finish.
Waiting for round 19950103 to finish.
Transaction 6IPYJZYHZ3KOHTM32EHO7ZGFROSMIV3UYKA4CHM6FCVEU3KJVDCQ confirmed in round 19950104.<jupyter_text>Inspect the global state and the local states of the users<jupyter_code>format_state(read_global_state(algod_client,app_id))
read_local_state(algod_client,Alice['public'],app_id)
read_local_state(algod_client,Bob['public'],app_id)
read_local_state(algod_client,Charlie['public'],app_id)
read_local_state(algod_client,Dina['public'],app_id)<jupyter_output><empty_output><jupyter_text>Users can call the Smart contract ("make a visit")* Does not really make sense here ...  Users close out (leave) App* With a `ApplicationCloseOutTxn`* See [here](https://py-algorand-sdk.readthedocs.io/en/latest/algosdk/future/transaction.htmlalgosdk.future.transaction.ApplicationCloseOutTxn)<jupyter_code>user = Alice

# Step 1: prepare
sp = algod_client.suggested_params()
txn = transaction.ApplicationCloseOutTxn(user['public'], sp, app_id)

# Step 2: sign
stxn = txn.sign(user['private'])

# Step 3: send
txid = algod_client.send_transactions([stxn])

# Step 4: wait for condfirmation
txinfo = wait_for_confirmation(algod_client, txid)<jupyter_output>Current round is  19950119.
Waiting for round 19950119 to finish.
Waiting for round 19950120 to finish.
Transaction 2USKQXO7COXVS3WZX73OETECPWSY4RPVPCWKJC6GOVEUDOJBN6RQ confirmed in round 19950121.<jupyter_text>Inspect the global state and the local states of the users* State of leaving member is empty* Membership numbers of remaining members are unchanged<jupyter_code># Note that we do not update the number of members
format_state(read_global_state(algod_client,app_id))
read_local_state(algod_client,Alice['public'],app_id)
read_local_state(algod_client,Bob['public'],app_id)
read_local_state(algod_client,Charlie['public'],app_id)
read_local_state(algod_client,Dina['public'],app_id)<jupyter_output><empty_output><jupyter_text>Deleting the app* Rather important, because an address can only create **10 apps*** App can be deleted by creator<jupyter_code>creator = Bob

# Step 1: Prepare transaction
sp = algod_client.suggested_params()
txn = transaction.ApplicationDeleteTxn(creator['public'], sp, app_id)

# Step 2: sign
stxn = txn.sign(creator['private'])

# Step 3: send
txid = algod_client.send_transactions([stxn])

# Step4 : wait for confirmation
txinfo = wait_for_confirmation(algod_client, txid)

# display results
print("Deleted app-id:", txinfo["txn"]["txn"]["apid"])<jupyter_output>Current round is  19950129.
Waiting for round 19950129 to finish.
Waiting for round 19950130 to finish.
Transaction UUCLEPLTBLRU6ZDHJEGHCQAL3PDNOO36WFLIXIGBN2C7ER7VT5ZQ confirmed in round 19950131.
Deleted app-id: 74314499
{'fraction_non_alphanumeric': 0.09520301997974404, 'fraction_numerical': 0.02559616978178805, 'mean_word_length': 4.485858585858586, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 45, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 9, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '12', 'dir': 'jupyter-structured-clean-dedup', 'id': '104818', 'license': 'MIT', 'n_tokens_mistral': 3782, 'n_tokens_neox': 3536, 'n_words': 850, 'path': 'ClassMaterial/07 - Programming Smart Contracts/07 code/07.0.2_WSC_SmartContract_hellomember.ipynb', 'repo_name': 'gruberpeter/smartcontractscourse', 'size': '10879'}