A step by step guide to building a simple Obyte Autonomous Agent (AA) for the ObyStack Game.
The ObyStack Game is a simple multi-player stack game, where players bid for a chance to win the entire stack of bytes.
To start playing on testnet, go to your testnet wallet, and pair with the ObyStack Bot using the following code:
AziMKfNVh+TNOpnFJ8qKh1DpywCyQWU20ALmX5zA5rAm@obyte.org/bb-test#StackGame
The game is run on the Obyte network using the ObyStack Game Bot and the ObyStack Game Autonomous Agent.
Find out more about ObyStack Game.
See Autonomous Agents section on the Obyte Developer Resources website for details about Autonomous Agents, its usage and the Oscript Language Reference.
Your AA can be written, tested and deployed for testing using the Obyte Testnet Oscipt Editor.
When ready, your AA can be deployed to the Mainnet network using the Obyte Mainnet Oscipt Editor.
Use the Obyte Oscript Editor to see under the hood of sample AAs.
Go to the Obyte Testnet Oscript Editor and select any template, e.g. select Just a bouner
template from the AAs
drop-down list.
Click on a Add (+) icon at the top left hand corner of the page to create a new AA.
Click on the Edit icon at the top left hand corner of the page to give your AA a name.
Remove all the code.
Start by creating the basic structure for your AA game logic as follows:
{ init: `{ // setting Game parameters // setting Game variables }`, messages: { cases: [ // case A: new Game: update state // case B: Game is running: update state // case C: Game is finished: make payments and update state ] } }
This code will not Validate
just yet, but we will be fixing this shortly.
Define some game parameters by adding the following code to the init
section of the AA.
// setting Game parameters $bot_address = 'QUONK7CUHPTGLNTZ6JE57SDVSFVDBCMM'; $commission_payout_threshold = 50000; $commission = 10000; $seed_amnt = 10000; $min_bid_amnt = 1000000; $fees = 1000;
We are setting minimum bid amount ($min_bid_amnt
) to 1,000,000 bytes (which is about £0.2) and commission ($fee
) to 10,000 bytes (which is currently about £0.02) and is 1% of the bid.
As the commission is so small, we are not going to pay it out until the commission pot reaches a certain level defined in the Commission Payout Threshold ($commission_payout_threshold
) set to 50,000,000 bytes (which is currently about £10).
The Seed Amount ($seed_amnt
) is the small amount that should always be left in the AA's balance to leave it enough funds to continue runnng and paying for transactions when taking out the commissions.
The Fees ($fees
) are set to 1,000 bytes and will be used to estimate the fees that AA will have to pay when sending payments to the winners and to the bot.
The Bot Address ($bot_address
) is the Single Wallet Address of my ObyStack Game Bot. Please change it to the address of your Bot!
Next, lets add some game variables that will be initialised every time the AA is triggered (e.g. every time a bid is made by a player or a message received from the Bot).
Add the following code to the init
section of the AA.
// setting Game variables $bid_amnt = trigger.output[[asset=base]]; $game_finished = (trigger.initial_address == $bot_address) otherwise false; if ( ($game_finished == false) AND ($bid_amnt < $min_bid_amnt) ) bounce('Your bid is too small.'); $game_status = var['game_status'] otherwise 'not started';
Bid Amount ($bid_amnt
) is set to the amount of the payment received by the AA.
The ObyStack Game Bot sends a message to the AA when the game is finished. We set the Game Finished flag ($game_finished
) to true
if the message came from our Bot.
If the Payment received by the AA has come from the player rather then the Bot (i.e. the Game Finished Flag is false) and the Bid Amount is too small, the Payment is returned to the user.
When the game is running, the Game Status Variable ($game_status
) will be set to the AA's persistent State Variable var['game_status']
. If no State Variable is set, the Game Status Variable will be set to 'not started'
.
When the game status ($game_status
) is not started
, and the AA was triggered by the user's bid rather than by the Bot ($game_finished
is false
), the new game starts. Add the following code to the case A
section of the AA:
// case A: new Game: update state { if: `{$game_finished == false AND $game_status == 'not started'}`, messages: [ { app: 'state', state: `{ var['stack_amnt'] = $bid_amnt - $commission; var['commission_pot'] += $commission - $fees; var['author'] = trigger.initial_address; var['leader'] = trigger.initial_address; var['game_status'] = 'running'; response['message'] = 'Thank you for playing'; }` } ] },
The above code will create the var['stack_amnt']
state variable and set it to the Bid Amount less Commission.
The Commission Pot is used to decide when the AA should pay commission to the Bot. Fees are subtracted from the commission charged for the 1st bid to account for the cost of running the AA.
Players wallet address will be saved in the var['author']
and the var['leader']
state variables. The author of this bid will become the Game Initiator.
The var['game_status'] will be created and set to 'running'.
A response message is an optional touch.
Validate.
When the valid bid is made by the player while the game is running, we need to add the Bid Amount less Commission to the Game Stack and update the var['leader']
state variable with the wallet's address of the player who made the bid. The deducted Commission is added to the Commission Pot.
Add the following code to the case B
section of the AA:
// case B: Game is running: update state { if: `{$game_finished == false AND $game_status == 'running'}`, messages: [ { app: 'state', state: `{ var['stack_amnt'] += ($bid_amnt - $commission); var['commission_pot'] += $commission; var['leader'] = trigger.initial_address; response['message'] = 'Thank you for playing'; }` } ] },
Validate.
When the Bot's timer has ran down, the Bot sends a message to the AA signalling the end of the current game, the AA will make payments to the winner and to the initiator of the game.
Add the following code to the case C
section of the AA:
// case C: Game is finished: make payments and update state { if: `{$game_finished}`, messages: [ // make payments // update state { app: 'state', state: `{ var['game_status'] = 'not started'; if (var['commission_pot'] >= $commission_payout_threshold) var['commission_pot'] = 0; var['commission_pot'] += $bid_amnt; // add money from the bot to the commission pot var['stack_amnt'] = 0; var['author'] = ''; var['leader'] = ''; response['message'] = 'Game finished.'; }` } ] }
When the payments to the winners and to the Bot are made, the game state variables will be initialised ready for a new game.
Note that the Commission Pot is only initialised if the Commission Payment Threshold has been reached which would have resulted in the Commission paid to the Bot.
Validate.
Let's create a case structure that supports various payment scenarios of the game.
Add the following code to the // make payments
section of the AA:
// make payments { app: 'payment', payload: { cases: [ // case 1: the game initiator is the same as the winner AND commission is payable // case 2: the game initiator is the same as the winner AND no commission is payable // case 3: the game initiator is diff from the winner AND commission is payable // case 4: the game initiator is diff from the winner AND no commission is payable ] } },
The above code will not validate, until we add at least one of the payload cases.
Add the following code to case 4
of the AA:
// case 4: the game initiator is diff from the winner AND no commission is payable { if: `{(var['author'] != var['leader']) AND (var['commission_pot'] < $commission_payout_threshold)}`, payload: { asset: 'base', outputs: [ { address: '{ var['author'] }', amount: '{ var['stack_amnt'] / 2 }' }, { address: '{ var['leader'] }', amount: '{ var['stack_amnt'] / 2 }' } ] } }
When this case is executed, the AA will make payments to the winner and to the initiator ofthe game.
Validate.
Add the following code to case 3
of the AA:
// case 3: the game initiator is diff from the winner AND commission is payable { if: `{(var['author'] != var['leader']) AND (var['commission_pot'] >= $commission_payout_threshold)}`, payload: { asset: 'base', outputs: [ { address: '{ var['author'] }', amount: '{ var['stack_amnt'] / 2 }' }, { address: '{ var['leader'] }', amount: '{ var['stack_amnt'] / 2 }' }, { address: '{ $bot_address }', amount: '{ balance[base] - var['stack_amnt'] - $seed_amnt }' } ] } },
When this case is executed, the AA will make payments to the winner and to the initiator of the game. It will also pay commission to the Bot's wallet.
Note that the above code, will pay out anything left in the Agent's balance after the winnings are paid out to the Bot as a commission while leaving the minimum amount ($seed_amnt
) required to run the AA.
Validate.
Add the following code to case 2
of the AA:
// case 2: the game initiator is the same as the winner AND no commission is payable { if: `{(var['author'] == var['leader']) AND (var['commission_pot'] < $commission_payout_threshold)}`, payload: { asset: 'base', outputs: [ { address: '{ var['leader'] }', amount: '{ var['stack_amnt'] }' } ] } },
When this case is executed, the AA will make payments to the winner or the game, who is also the initiator of this game.
Validate.
Add the following code to case 1
of the AA:
// case 1: the game initiator is the same as the winner AND commission is payable { if: `{(var['author'] == var['leader']) AND (var['commission_pot'] >= $commission_payout_threshold)}`, payload: { asset: 'base', outputs: [ { address: '{ var['leader'] }', amount: '{ var['stack_amnt'] }' }, { address: '{ $bot_address }', amount: '{ balance[base] - var['stack_amnt'] - $seed_amnt }' } ] } },
When this case is executed, the AA will make payments to the winner or the game, who is also the initiator of this game. It will also pay commission to the Bot's wallet.
As above, anything left in the AA's balance after the winnings are paid out,will be paid to the Bot as a commission while leaving the minimum amount ($seed_amnt
) required to run the AA.
Validate.
Add instructions and comments to the init
section to inform users of your Bot's pairing code and any other useful information.