Probably Fair

This code is part of a service called Provably Fair Service that allows for fair selection of prizes in a game. It uses a cryptographic algorithm to ensure that the selection of the winner is random and cannot be manipulated.

When a user participates in the game, they provide a client seed that is combined with a server seed generated by the service to create a random result. This result is then used to select the winner from a list of possible prizes.

To ensure transparency and fairness, the server seed is generated and stored in a way that cannot be altered or accessed until after the game is completed. This means that no one, not even the service provider, can manipulate the selection of the winner.

The code also includes a function to verify the fairness of the selection process after the game has ended. This function allows users to enter the server seed and client seed used during the game and confirm that the result was indeed generated randomly and fairly.

Overall, this service and code provide transparency and security to users by ensuring that the selection of the winner is fair and cannot be manipulated by anyone.

import { InjectRedis, Redis } from '@nestjs-modules/ioredis'
import { Injectable } from '@nestjs/common'
import provablyFair from 'provably-fair'

export interface ProvablyFairResult {
  clientSeed: string
  result: number
  serverSeedHash: string
  serverSeed: string
}

@Injectable()
export class ProvablyFairService {
  public provablyFair: any
  constructor(@InjectRedis() private readonly redis: Redis) {
    this.provablyFair = provablyFair(this.redis)
  }

  async createAndChallenge(clientSeed: string): Promise<ProvablyFairResult> {
    const serverSeedHash = this.provablyFair.generateServerSeedHash()
    return new Promise<ProvablyFairResult>((res, rej) => {
      this.provablyFair.createAndChallenge(
        {
          serverSeedHash,
          clientSeed,
          expiresIn: 60 * 60,
          guess: 5,
        },
        (err, valid, bet) => {
          if (err) return rej(err)
          res({
            clientSeed: bet.clientSeed,
            result: bet.result,
            serverSeedHash: serverSeedHash,
            serverSeed: bet.serverSeed,
          })
        }
      )
    })
  }

  async verify(
    serverSeed: string,
    clientSeed: string
  ): Promise<Pick<ProvablyFairResult, 'result'>> {
    return new Promise<Pick<ProvablyFairResult, 'result'>>((res, rej) => {
      this.provablyFair.verify(
        {
          serverSeed,
          clientSeed,
          // result,
        },
        (err, valid, bet) => {
          if (err) return rej(err)
          res({
            result: valid.result,
          })
        }
      )
    })
  }
}
  public async calculateWinner(
    roomId: string
  ): Promise<IFinishData | undefined> {
    const room = await this.roomService.getRoom(roomId, GameType.BOXES)
    const [player] = room.bets

    const { result, serverSeedHash, serverSeed } =
      await this.probablyFairService.createAndChallenge(player.seed)
    const randomNumber = Math.round(result * 100 * 1e5) / 1e5

    const { boxId } = room.metadata

    const box = await this.boxService.getBox(boxId)
    let accum = 0
    const prizes = box.prizes.map((prize) => {
      accum += prize.probability
      return {
        ...prize,
        aproxValue: accum,
      }
    })

    const winnerPrize = prizes.find((prize) => prize.aproxValue > randomNumber)
    const winAmount = winnerPrize.amount
    logger.info(`WinAmount: ${winAmount} ${winnerPrize.coinType}}`)

    return {
      roomId,
      winner: {
        amount: winAmount,
        wallet: player.wallet,
        coinType: winnerPrize.coinType,
        network: box.network,
      },
      serverSeed,
      serverSeedHash,
      playersSeeds: player.seed,
      result: randomNumber,
    }
  }
  

Last updated