Merkle Brothers (https://www.merklebros.com)
A governance system allows user votes to modify existing card attributes and vote new cards into the game.
Artists can introduce new cards into the card ecosystem and receive a portion of the proceeds generated from users purchasing cards.
Trading cards are represented as blockchain tracked tokens following the ERC-721 Non-Fungible Token Standard, a standard for tracking unique tokens on the Ethereum blockchain.
Users can also purchase limited edition fine-art prints of each card illustration that are tracked on the blockchain and physically connected to Ethereum using NFC technology.
- Immutable ownership. This technology allows digital assets to behave much more like physical assets. Users have actual ownership of the cards that they play with, they can sell or trade cards as they wish, and even bring the cards to other websites and games.
- Distributed governance. Users can be involved in the experience of shaping aspects of the game via weighted voting where votes are weighted by card ownership.
- Self-balancing via governance. A user majority can agree to make over-powered cards less powerful and vice-versa, or to add new cards to balance out existing cards.
- Immutable contracts. Ethereum allows for 'smart contracts' to run on the blockchain. This contract logic can be made viewable for all users, and cannot be altered once implemented. This means that a central authority cannot step in to override the decisions of the user majority (except for special legal or technical situations that require some small central authority).
/contracts/MerkleBros.sol
The smart contract is written in Solidity, a language for writing smart contracts for use in the Ethereum Virtual Machine (EVM). It describes token minting and ownership as well as card prototype creation and modification.
Contract artifacts
/build/contracts/
/migrations
Truffle is a development framework for creating Ethereum dApps (decentralized apps). It can be used to deploy contracts to local testing blockchains, to Ethereum testnets (Ropsten/Kovan/Rinkeby), or to the live Ethereum mainnet. Ganache is a tool used to create local testing blockchains.
Local Ethereum node
Geth (Go-Ethereum) is a command-line tool for running a full Ethereum node. The node is run on the same web-server with the live website. Geth communicates changes in the Ethereum blockchain state related to the smart contract. The website listens for these events and stores state in a database.
Web3/Metamask
Web3 is an Ethereum javascript API allowing Javascript to communicate with the local Ethereum node on the back-end. It is also used alongside Metamask for interacting with the Ethereum network in the browser.
./app.js
The server-backend app uses Mongodb, Express, and Nodejs. Most of app.js is event listeners waiting for updates from the local Ethereum node. The node sends updates when certain smart contract states are updated on the Ethereum network. These include things like minting new tokens, users trading tokens, and creating and altering card prototypes (the blueprints for cards).
./models
Mongodb is used to store documents related to the Ethereum state and information from website users. Models exist for Users, CardPrototypes (card blueprints), Tokens (owned instances of cardPrototypes), CardSets (sets of CardPrototypes), Actions (defined logic that CardPrototypes can perform), and Totems (a special Token that can be used to generate more tokens).
./routes
Various Express routes are used to manage user and token information, for form submissions, etc.
./public
Folder for serving the website and associated assets. Using Angular / CSS grid for some parts of the website (and regular html/css for others). Users can login and interact with the Ethereum smart contract using Metamask.
/modules/game-utilities.js
The backend game logic is organized in an object oriented style. It uses socket.io to communicate player moves and to push game state to the players. All logic is passed through a single Matchmaking object.
Matchmaking - Responsible for setting up new websocket connections, for adding users to the lobby, for instantiating new matches, and for routing communications between users and their associated GameLoop. Initialized by startMatchmaking().
- init - Setup handlers for new websocket connect/disconnects and routing client-communications (comms)
- handleAuthentication - Handle logging in users and validating cookies
- routeClientCommunication - Handle comms from authenticated users (new moves, requesting state, etc)
- createMatch - Instantiate new GameLoop/Game/Players/decks and update appropriate Matchmaking data structures.
- closeMatch - Close game and update appropriate Matchmaking data structures
- createPlayers
- createDecks
- getUser
- addUserToLobby
- checkLobby - Check lobby for >2 users and create matches with two random users. Called on setInterval
GameLoop - Responsible for altering Game state. Has a Game. A new GameLoop instance is made for each Game.
- initGame - Starts the Game instance assigned to this GameLoop instance.
- Methods for altering a player's development stat (player's action points)
- incrementDev
- incrementMaxDev
- hitDev
- damageDev
- damageMaxDev
- Methods for handling turns and ending game
- incrementTurn
- startNewTurn
- endTurn
- autoEndTurn
- checkTurnOver
- resetTurnTimers
- checkGameOver
- endGame
- setActivePlayer
- Methods for handling Fighter states
- resetFighterStates - Refresh fighters for a new turn
- applySpecials - Apply special abilities a Fighter might have
- applySpecialConditions - Apply conditions a Fighter may have been afflicted with
- clearDead - Remove dead fighters after a submitted move is resolved
- getAdjacentLanes
- Methods for handling client communications
- checkNewMove - Validate a new move (playing a card, moving/commanding a Fighter, ending turn)
- checkActionValid - Validate actions resulting from playing a card.
- submitMove - Submit a valid move to be processed by the GameLoop.
- processPlay - Process a submitted card play
- processAction - Process a submitted action associated with playing a card.
- processMove - Process moving a Fighter between lanes
- processCommand - Process a Fighter attacking another Fighter or a Player
- processEndTurn - Process a player ending their turn
- processReact - Process a player's reaction when it is not their turn (caused by certain cards)
- Methods for handling card collections
- draw - Remove cards from a collection
- drawToHand - Remove cards from a collection to a player's hand
- drawToDiscard - Remove cards from a collection to a player's discard
- view - View cards from a collection
- shuffle -Shuffle cards from a collection
Game - Holds game state and has two Players.
- getPlayer(playerNumber)
- getOtherPlayer(playerNumber)
Player - Holds player stats and has an array of Fighters that have been deployed.
- deployFighter(cardPrototype, lane)
Fighter - Represents a Fighter that exists on the board
- buildSpecials - Build a Fighter's special abilities when it is created