Building Obyte Autonomous Agent for the Obyte Stack Game


A step by step guide to building a simple Obyte Autonomous Agent (AA) for the ObyStack Game.

1. About the 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.

2. Development resources

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.

3. Getting Started

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.

4. Creating initial structure

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.

5. Defining Game parameters

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!

6. Defining Game variables

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'.

7. Management of the Agent State: New Game

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.

8. Management of the Agent State: Game is running

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.

9. Management of the Agent State: Game is finished

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.

10. Making Payments

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.

Case 4: The game initiator is different from the winner AND no commission is payable

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.

case 3: The game initiator is different from the winner AND commission is payable

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.

case 2: The game initiator is the same as the winner AND no commission is payable

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.

case 1: The game initiator is the same as the winner AND commission is payable

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.

11. Adding comments to the AA

Add instructions and comments to the init section to inform users of your Bot's pairing code and any other useful information.

Validate. Deploy and Test.