I'd like to give/explain another AT example.
This is AT code for 'fund management'. The AT will store coins, and have 5 authorized users. If 3 of the 5 users send it the same message containing a destination address and an amount, the AT will make a transaction of that amount to that address. If no funds are transfered out for a set amount of time, the AT can be sent a message and the AT will assume it became inaccessable(lost keys, etc), and transfer it's funds to a set address.
FUN @txIterTime get_Block_Timestamp
^declare scratch
^declare counter
at the top we store the current time for use when iterating transactions.
declare can be used to force variable in specific positions, which can be useful to force variables to the begining if you want to pass initial data on at creation to have them initialized before the AT starts, but we don't do that here, so it's only for demo puposes
SET @numUsers #0000000000000005
SET @neededVotes #0000000000000003
SET @dormantTransferAddress #0000000000000000
SET @dormantTransferMinutes #0000000000000028
we set up some constants used, num users, num votes needed, address to tranfer for inactivity, and minutes of inactivity until transfer(should be much higher, but had it low for testing)
SET @dormantDeadline $txIterTime
FUN @dormantDeadline add_Minutes_to_Timestamp $dormantDeadline $dormantTransferMinutes
we set a deadline for when we'll transfer to fallback if no transfers out occur
^allocate allowedUsers 5
^allocate votesAccount 5
^allocate votesAmount 5
allocate sets aside the specified number of spaces and also adds a SET command setting the variable name specified to the starting address of the block so it can be used as a pointer to an array
^comment set user ids in scratch assignments
CLR @counter
SET @scratch #a9d3c7e1052e59b6
SET @($allowedUsers + $counter) $scratch
INC @counter
SET @scratch #d588a72e511f576a
SET @($allowedUsers + $counter) $scratch
INC @counter
SET @scratch #878344bc465ee397
SET @($allowedUsers + $counter) $scratch
INC @counter
SET @scratch #5b4a79c0ad8542ea
SET @($allowedUsers + $counter) $scratch
INC @counter
SET @scratch #fca2612346d6d33b
SET @($allowedUsers + $counter) $scratch
^comment end user id assignments
here we just hardcoded some user ids. for demo purposes these are the id numbers for burst accounts with passphrases a, as, asd, asdf, and asdfg.
ERR :dormantTransfer
we set an error handler. if for some reason the at get stuck and is unable to continue(trying to access address out of address space, divide by 0, etc), it will jump there instead of dieing. The risk of something like that happening here is low due to the simplicity of this at, but it's always a good idea to have a handler dumping the coins somewhere, otherwise they'll all end up in transaction fees going to the miners if you did make a mistake somewhere
PCS
pcs sets a new start point. the AT will resume from here instead of the top when we do finish calls, skipping over the initialization.
txloop:
FUN A_to_Tx_after_Timestamp $txIterTime
FUN @scratch check_A_Is_Zero
FIZ $scratch
FUN @txIterTime get_Timestamp_for_Tx_in_A
FUN @scratch get_Type_for_Tx_in_A
BZR $scratch :txloop
here we have a loop that tries to get the next transaction. an id of 0 is returned if there is none, so we finish if none was retrieved(FIZ = finish if zero). if we did get a tx id, we store the timestamp to use for the next tx retrieval attempt, and then check what type of tx we have. a normal payment is 0, but if there is a message attached it is a type 1. we ignore normal payments transfering funds in, but continue on processing if there is a message
CLR @counter
FUN B_to_Address_of_Tx_in_A
FUN @address get_B1
findUserLoop:
SET @scratch $($allowedUsers + $counter)
BEQ $address $scratch :foundUser
INC @counter
BLT $counter $numUsers :findUserLoop
here we check to see if the user is on the authorized list. we retrieve the address who sent us the tx, and loop through authorized users, and jump to :founduser if we found them in the list
^comment check dormant time
BLE $txIterTime $dormantDeadline :notFoundUser
JMP :dormantTransfer
notFoundUser:
JMP :txloop
if the user wasn't found, we check the timestamp against the inactivity timestamp. due to a limit on the distance a branch op can jump and limitations of the currently available assembler, a workaround needed to be used here of branching over a jmp. the most recent but not yet publically available version can automatically convert too far branches to branch jmp combinations, so this is a temporary issue
if the inactivity deadline is up, we jump to :dormanttransfer, and if not we return to the tx loop.
foundUser:
SET @userIndex $counter
FUN message_from_Tx_in_A_to_B
FUN @address get_B1
FUN @amount get_B2
SET @($votesAccount + $userIndex) $address
SET @($votesAmount + $userIndex) $amount
if the user was found in the authorized list, we save the counter from the loop to use as the array index for that user's state. We get their message and save the intended destination and amount as that user's current vote
CLR @voteCount
CLR @counter
countVotesLoop:
SET @scratch $($votesAccount + $counter)
BNE $scratch $address :notSameVote
SET @scratch $($votesAmount + $counter)
BNE $scratch $amount :notSameVote
INC @voteCount
notSameVote:
INC @counter
BLT $counter $numUsers :countVotesLoop
BGE $voteCount $neededVotes :votePassed
JMP :txloop
now we loop through all the votes, and count up the amount which are identical to the one we just recorded. If the amoount is at least the threshold specified in the constants at the top, we jump to :votePassed, otherwise we head back to the tx loop
votePassed:
FUN clear_B
FUN set_B1 $address
FUN send_to_Address_in_B $amount
when the vote is passed, we send that amount
CLR @counter
CLR @scratch
clearLoop:
SET @($votesAccount + $counter) $scratch
SET @($votesAmount + $counter) $scratch
INC @counter
BLT $counter $numUsers :clearLoop
we clear out all the votes after a send
^comment update dormant transfer deadline
SET @dormantDeadline $txIterTime
FUN @dormantDeadline add_Minutes_to_Timestamp $dormantDeadline $dormantTransferMinutes
JMP :txloop
then we set a new inactivity deadline, and head back to the tx loop
dormantTransfer:
FUN clear_B
FUN set_B1 $dormantTransferAddress
PCS
sendAll:
FUN send_All_to_Address_in_B
JMP :sendAll
if the inactivity deadline runs out a jump from above can take us here, and this is also the error handler. we set the fallback address as destination, and put ourselves in an infinite loop sending there. the script will halt due to lack of funds immediatly after the send, so it will only get activated when it receives more, which it will then proceed to send, then halt