PyMons
  • Introduction
  • Tokenomics
  • Battling
  • Fees and Referrals
  • Provably Fair
  • Links and Information
Powered by GitBook
On this page
  • Context
  • Picking Moves
  • Calculating Miss, Hit, Super Active Chances
  • Calculating Damage
  • Misses
  • Regular Attacks
  • Super Active Attacks

Provably Fair

A way to ensure all battles are fair and unriggable.

PreviousFees and ReferralsNextLinks and Information

Last updated 1 year ago

Context

We define a function getHash that computes the SHA256 hash of an input string and returns the bytes as a hex string:

import * as crypto from "crypto";

export function getHash(input: string) {
  return crypto.createHash("sha256").update(input).digest("hex");
}

When a game is created, the server_seed and battle_id are generated. battle_id is publicly shared, and the hash of the server_seed is displayed on the battle. The server_seed is revealed only after a battle has finished. You may verify that the server_seed and hash match

player_number is assigned 1 for the creator, and 2 for the joiner.

Picking Moves

Moves can be randomly chosen in two scenarios:

  • For a user who runs out of time in a round

  • By the bot (if called by the battle creator)

The move is chosen with the following procedure:

  • Generate the input string.

  • Compute the SHA256 hash of the input.

  • Convert the first 4 bytes of the hex string to an integer and apply modulo 3.

  • Choose fire for result 0, grass for result 1, and water for result 2.

const input: string = "move:{server_seed}:{battle_id}:{player_address}:{round_num}:{player_number}";
const hash: string = getHash(input);
const moveNumber: number = parseInt(hash.substring(0, 8), 16) % 3;

if (moveNumber == 0) {
  return AttackTypeEnum.FIRE;
} else if (moveNumber == 1) {
  return AttackTypeEnum.GRASS;
} else {
  return AttackTypeEnum.WATER;
}

Calculating Miss, Hit, Super Active Chances

After every round that isn't a draw, the winning player assigned a chance to either miss, hit a normal attack, or land a super active attack. The attack type is chosen with the following procedure:

  • Generate the input string.

  • Compute the SHA256 hash of the input.

  • Convert the first 4 bytes of the hex string to an integer and apply modulo 100.

  • Ticket ranges for the result (inclusive) and respective attack types:

    • 0 - 19: Miss

    • 20 - 51: Super Active

    • 52 - 99: Regular

const input: string = "attack_probability:{server_seed}:{battle_id}:{player_address}:{round_num}:{player_number}";
const hash: string = getHash(input);
const ticket: number = parseInt(hash.substring(0, 8), 16) % 100;

if (ticket <= 19) {
  return "Miss";
} else if (ticket >= 20 && ticket <= 51) {
  return "Super Active";
} else {
  return "Hit";
}

Calculating Damage

This is a bit more nuanced due to the slightly more complicated rules of battling and attack types. The damage ticket is generated with the following procedure:

  • Generate the input string.

  • Compute the SHA256 hash of the input.

  • Convert the first 4 bytes of the hex string to an integer.

const input: string = "damage:{server_seed}:{battle_id}:{player_address}:{round_num}:{player_number}";
const hash: string = getHash(input);
const ticket: number = parseInt(hash.substring(0, 8), 16);

The ticket must now be confined within a range between the minimum and maximum possible attack damage values for the move type.

Misses

They do 0 damage regardless.

Regular Attacks

Take the ticket modulo 21 and add 25 to confine the normal attack damage possibilities between 25 and 45 inclusive.

return (ticket % 21) + 25;

Super Active Attacks

Take the ticket modulo 15 and add 46 to confine the super active attack damage possibilities between 46 and 60 inclusive.

return (ticket % 15) + 46;
here.