Skip to content

Architecture

decent-dev edited this page Mar 4, 2019 · 16 revisions

The architecture for the PlayDBET platform are based on the assumptions that all quest and tournament entries are paid and validated on-chain on the deployed Quest and Tournament smart contracts.

Quests and tournaments can be added by DBET admins. Quest outcomes are also pushed by DBET admins on-chain after verifying whether a user has successfully completed a quest within the prescribed time to complete it.

A platform wallet address is assigned to handle user entry fees and successful quest completion prize payouts. This address would be periodically replenished with DBETs allowing users to receive payouts for all completed quests.

Admin

The PlayDBET admin is a straightforward contract-only implementation. The Admin contract has the following functions in it's implementation:

setPlatformWallet()

This is callable by the owner of the contract. It requires the following arguments:

address _platformWallet

Allows the owner of the admin contract to change the platform wallet address, which is used for receiving entry fees from quests/tournaments and processing payouts.

If successfully executed a LogOnSetPlatformWallet(address wallet) event will be emitted.

addAdmin()

This is callable by the owner of the contract. It requires the following arguments:

address admin

Allows the owner of the admin contract to add an admin to the contract. Addresses added to the Admin contract are granted admin permissions in both Quest and Tournament contracts.

If successfully executed a LogAddAdmin(address _address) event will be emitted.

removeAdmin()

This is callable by the owner of the contract. It requires the following arguments:

address admin

Allows the owner of the admin contract to remove an admin from the contract. Addresses are revoked admin permissions in both Quest and Tournament contracts.

If successfully executed a LogRemoveAdmin(address _address) event will be emitted.

Quests

An overview of the PlayDBET Quest contracts architecture is outlined in the diagram below:

Quest contracts architecture

The Quest contract has the following functions as outlined in the overview:

addQuest()

This is callable by admins of the contract. It requires the following arguments:

bytes32 id,
uint256 entryFee,
uint256 timeToComplete,
uint256 prize

Allows admins to add quests to the contract from the off-chain admin UI. Quests are required to be passed unique quest IDs along with the entry fee and prize amount in DBETs. Also, the time to complete a quest from the point of starting it - for which the prize would be valid.

If successfully executed a LogNewQuest(bytes32 id) event will be emitted.

setQuestOutcome()

This is callable by admins of the contract. It requires the following arguments:

bytes32 id,
address user,
uint8 outcome

The outcome passed here stems from the following QuestStatus enum:

enum QuestEntryStatus {
    NOT_STARTED,
    STARTED,
    SUCCESS,
    FAILED
}

Base on PlayVig's verification of a user's quest completion status, admins can pass whether the user successfully completed or failed to complete a quest.

If successfully executed, a LogSetQuestOutcome(id, user) event will be emitted.

payForQuest()

This is callable by users of the contract. It requires the following arguments:

bytes32 id,
address user

The contract will check whether the user has already started the quest and whether the transaction sender has a balance of and has approved entryFee DBETs for the contract to transfer. If all conditions are true, a UserQuestEntry will be added with a QuestEntryStatus of QuestEntryStatus.STARTED.

This allows for addresses to send quest entries on behalf of other users opening doors to multiple use cases such as coupon based entries for first time users funded by Decent.bet.

If successfully executed, a LogPayForQuest(bytes32 id, address user, address payer) event will be emitted.

cancelQuest()

This is callable by admins of the contract. It requires the following arguments:

bytes32 id

Allows admins to cancel active quests on the contract from the off-chain admin UI. Once cancelled, users will be unable to create new quest entries. Also users with existing started quest entries would be able to claim refunds on their quest entry fees.

If successfully executed a LogCancelQuest(bytes32 id) event will be emitted.

claimRefund()

This is callable by users of the contract. It requires the following arguments:

bytes32 id

The contract will check whether the user has already started the quest, whether the QuestStatus is QuestStatus.CANCELLED and whether the refund has already been claimed. If all conditions are true, the quests' entry fee is refunded to the user.

Note that this is callable only if executed while within the time limit imposed by the quests' timeToComplete.

If successfully executed, a LogRefundQuestEntry(bytes32 id, address user) event will be emitted.

Tournaments

An overview of the PlayDBET Tournament contracts architecture is outlined in the diagram below:

Tournament contracts architecture

The Tournament contract has the following functions as outlined in the overview:

createPrizeTable()

This is callable by admins of the contract. It requires the following arguments:

uint256[] table

Allows admins to add prize tables to the contract from the off-chain admin UI. Prize tables are sorted arrays with percentage prize rewards corresponding to the final standing positions for a tournament's prize pool. A unique ID is generated for the prize table based on the following calculation:

bytes32 id = keccak256(
    abi.encode(
         "prize_table_",
         prizeTableCount
    )
);

Prize tables are passed as arguments when creating tournaments. If successfully executed a LogNewPrizeTable(bytes32 id, uint256 count) event is emitted.

createTournament()

This is callable by admins of the contract. It requires the following arguments:

uint256 entryFee,
uint256 entryLimit,
uint256 minEntries,
uint256 maxEntries,
uint256 rakePercent,
bytes32 prizeTable

Allows admins to create tournaments from the off-chain admin UI. Tournaments are required to be passed the entry fee, whether the tournament allows multiple entries from the same address, minimum/maximum entries for the tournament, the rake fee percent for Decent.bet and an existing prize table ID.

This generates a unique tournament ID based on the following calculation:

bytes32 id = keccak256(
    abi.encode(
        "tournament_",
        entryFee,
        entryLimit,
        minEntries,
        maxEntries,
        rakePercent,
        tournamentCount
    )
);

If successfully executed a LogNewTournament(bytes32 id, uint256 count) event will be emitted.

enterTournament()

This is callable by users of the contract. It requires the following arguments:

bytes32 id

The contract will check whether the user has already entered the tournament and throw if isMultiEntry is set to false. If the transaction sender has a balance of and has approved entryFee DBETs for the contract to transfer. If all conditions are true, an entry will be added to the tournament.

If successfully executed, a LogEnteredTournament(bytes32 id, address user) event will be emitted.

completeTournament()

This is callable by admins of the contract. It requires the following arguments:

bytes32 id
uint256[] finalStandings
uint256 uniqueFinalStandings

Allows admins to complete tournaments from the off-chain admin UI. finalStandings is a sorted array in ascending order signifying positions of users at the end of a tournament. uniqueFinalStandings signifies the amount of unique final standings that are passed in finalStandings. This is to account for multiple entries ending a tournament with the same position while calculating the final prize money.

If an empty finalStandings array is passed to the function, the tournament status is changed to TournamentStatus.FAILED allowing for users to claim refunds.

If a valid finalStandings array is passed, the tournament status is changed to TournamentStatus.COMPLETED. The platform wallet is then transferred the rake fee calculated by using getRakeFee(bytes32 id).

If successfully executed a LogCompletedTournament(bytes32 id, uint8 status) event will be emitted.

claimTournamentPrize()

This is callable by users of the contract. It requires the following arguments:

bytes32 id,
uint256 index

The contract will check whether the finalStandings index passed corresponds to a tournament entry index equating to the sender address. Users can only claim the prize tokens if the status of the tournament is TournamentStatus.COMPLETED and if the index hasn't been claimed yet.

The total prize pool is calculated using the following calculation:

(number of entries * entryFee) - rake fee

If the prize table length is greater than the final standings length, the remainder of the prize table is evenly distributed among all tournament entries.

If successfully executed, a LogClaimedTournamentPrize(bytes32 id, uint256 entryIndex, uint256 finalStandingIndex, uint256 prize) event will be emitted.

claimTournamentRefund()

This is callable by users of the contract. It requires the following arguments:

bytes32 id,
uint256 index

The contract will check whether the entry index passed equates to the senders' address in the tournament entries. Users can claim refunded prize tokens if the status of the tournament is TournamentStatus.FAILED and if the entry index's fee hasn't been refunded yet.

If successfully executed, a LogRefundedTournamentEntry(bytes32 id, uint256 entryIndex) event will be emitted.