To design an AT properly you need some insight knowledge of how AT is designed to work. I will try to give some hints providing an example for the Lottery case that is currently running on burst platform under the name LuckyAT. The post is rather big and I hope is simple enough to understand.
First of all you need to be aware that each AT is actually an account ( with an address without public key and only the AT can access that account's funds ). The way to "communicate" with the AT is through txs. Sending funds to the AT is achieved with a normal tx.
When the Lottery case is deployed for the first time all the variables are initialized to 0. When the lottery starts for the first time you need to initialize some of the variable properly.
( The full code of the Lottery case can be found here:
http://pastebin.com/xiDdMzEGIn the Lottery case the following first lines do that:
BNZ $payout_time :loop
SET @min_amount #00000005efeb1f00
FUN @payout_time get_Creation_Timestamp
SET @timestamp $payout_time
init:
SET @payout_balance #0000000000000000
SET @tx_info #0000000000002760
FUN @payout_time add_Minutes_to_Timestamp $payout_time $tx_info
The first line does a sanity check to see if the variable payout_time is initialized. If it is not, we are setting the variable min_amount (which is the ticket size to participate to the Lottery) and then we set payout_time to the creation timestamp (which is the "timestamp" of the block the Lottery has been deployed).
NOTE: An important concept in ATs are the "timestamps". Timestamps are constructed using the block height and the order of the tx inside the block. If you want for example to fetch the 3rd tx at block height 15885 then the corresponding timestamp will be (15885)(3). The best way to think timestamps is the combination of two integers, one for the block height and one for the tx. The Creation timestamp always uses 0 for the second part f.e (blockHeight)(0).
As stated also in
www.ciyam.org/at/at_api.html : "timestamp" does not mean a real timestamp but instead is an artificial timestamp that includes two parts. The first part is a block height (32 bits) with the second part being the number of the transaction if applicable (also 32 bits and zero if not applicable).
The third line is copying payout_time to timestamp.
The 5th line is "labelling" the following code as a branch point where you can "jump" later if needed.
The 6th and 7th lines are initializing payout_balance ( which is the total amount the lottery gathered as winnings for the winner) and tx_info respectively. Tx_info will be used as input to the API call add_Minutes_to_Timestamp along with payout_time and what actually this line does is:
payout_time = payout_time + tx_info
This way the lottery is aware after which block can send the prize to the winner and restart.
The next lines are the following:
loop:
FUN A_to_Tx_after_Timestamp $timestamp
FUN @tx_info check_A_Is_Zero
BNZ $tx_info :process_tx
FIN
Here the lottery fetches the first tx (if any) after the provided timestamp. If there is a tx ( FUN @tx_info check_A_Is_Zero ) then we proceed processing the tx else the AT stops and sets the program counter (pc) to pcs (FIN op code) ( pcs is zero at that point ) .
Setting the pc to 0 makes the AT to start from the first line ( BNZ $payout_time :loop ) the next time it will run.
Also stopping the AT using the FIN op code will "freeze" the AT until the ATs account balance changes ( f.e. until someone sends funds to the AT ). If you don’t want at this point to freeze the AT, you could change the FIN with SLP op code which will make the AT to "sleep" for just one block. ( That does not mean always that the AT will run on next block, as the block might be full with other ATs which have higher priority to run ).
If there is a tx then the Lottery continues with:
process_tx:
FUN @tx_time get_Timestamp_for_Tx_in_A
BLT $tx_time $payout_time :get_info_amount
JMP :payout
Here we get the timestamp of the tx and we check if that timestamp is less than the payout_time timestamp. If it is, we proceed fetching more info for that tx ( :get_info_amount ) else is time to pay the winner the total amount gathered ( JMP :payout ).
get_info_amount:
FUN @tx_amount get_Amount_for_Tx_in_A
FUN B_to_Address_of_Tx_in_A
FUN @tx_info get_B1
FUN B_to_Address_of_Creator
FUN @creator get_B1
BEQ $creator $tx_info :bootstrap
FUN @tx_info get_Type_for_Tx_in_A
BNZ $tx_info :skip
BEQ $tx_amount $min_amount :get_ticket
JMP :refund
Note: The Lucky AT has been programmed to not draw a ticket for funds received from the Creator's Address. This way the creator can send funds to the AT to increase the prize without participating in the draw.
The above piece of code fetches the amount of the tx, the address of the sender and the address of the creator. If these two addresses are equal we jump to :bootstrap (see above note), else we fetch the type of the tx ( 0-> normal tx, 1-> message tx). If the tx is not a message tx, we check if the amount of the tx is equal to the ticket amount. If it is we proceed drawing a ticket for that tx else we proceed on refunding that tx.
Note about the amounts: When you create an AT you set a field called minimum activation account. That amount is the minimum account required to process the tx. All the API calls that return amounts are deducting that minimum activation account ( f.e if minActivationAmount is set to 10 coins and you send a tx of 250 coins, the amount the AT will see is 240).
Moving forward we see:
get_ticket:
FUN @tx_info get_Ticket_Id_for_Tx_in_A
FIZ $tx_info
FUN B_to_Address_of_Tx_in_A
FUN set_A1 $tx_info
FUN send_A_to_Address_in_B
ADD @payout_balance $min_amount
BLE $tx_info $best_ticket :skip
SET @best_ticket $tx_info
FUN @best_account get_B1
Here we draw a ticket for that tx and if the ticket is not zero we send a message with the ticket value to the sender of the tx. After that we add the amount of the tx to the payout_balance and we check if the ticket we have draw is greater than the current best_ticket. (Note: The highest ticket wins). If the ticket we have picked is greater, we store the ticket value to best_ticket and the senders account to best_account, else we jump to skip.
Note: the API call get_Ticket_Id_for_Tx_in_A is making the AT to freeze at that point until the ticket is "ready" assuring the ticket is random ( a ticket is ready after 15 blocks from the block the tx belongs, f.e. if you make a tx at block height 14500 then the ticket will be ready at block 14515 and the AT freezes until then).
skip:
SET @timestamp $tx_time
JMP :loop
Here we set the timestamp to the tx's timestamp we just processed and jump to loop where we continue fetching txs after that timestamp.
bootstrap:
ADD @payout_balance $tx_amount
JMP :skip
Here we increase the prize ( payout_balance ) when the creator sends funds to the Lottery.
payout:
BZR $payout_balance :empty
BZR $best_ticket :empty
FUN set_B1 $best_account
FUN @block_timestamp get_Block_Timestamp
BEQ $block_timestamp $payout_time :pay_all_at_amount
FUN send_to_Address_in_B $payout_balance
JMP :finish_payout
pay_all_at_amount:
FUN send_All_to_Address_in_B
JMP :finish_payout
The above code checks that we have a winner and if we have a winner we pay him either the total ATs account or the payout_balance.
NOTE: Sometimes the AT might have more or less amount than the one it has gathered from tickets. When the ATs amount is greater it means that the processing fees were less than the "minimum activation amount's" gathered from tx's. If the ATs amount is less then the "min activation amount" was set "wrongly" and the processing of the tx's are more costly. Sometimes is difficult or impossible to have a constant min activation amount (f.e if a transaction is greater than the amount needed to participate, the tx will be refunded, thus it will consume more fees. If the tx is equal to the ticket amount then there are no fees for refunding that tx ).
empty:
SET @timestamp $tx_time
JMP :init
If there is no winner on the previous round ( none txs were sent to the Lottery) then we proceed with initialization of the variables.
refund:
FUN B_to_Address_of_Tx_in_A
BLE $tx_amount $min_amount :refund_less
SUB @tx_amount $min_amount
FUN send_to_Address_in_B $tx_amount
JMP :get_ticket
refund_less:
FUN send_to_Address_in_B $tx_amount
JMP :skip
Here the refunding takes place. There are 2 possibilities. Either the amount of the tx is greater than the ticket amount or less. If the txs amount is greater then we refund the difference ( tx_amount - min_amount) and then we draw a ticket for that tx, or we refund the total amount of the tx.
finish_payout:
SET @timestamp $payout_time
SET @best_ticket #0000000000000000
SET @best_account #0000000000000000
JMP :init
After paying the winner we set the timestamp to payout_time and we initialize best_ticket and best_account to 0 and we continue by jumping back to init.