# Building Azura Chain and Gaming Application
## Create an EVM-compatible Azura Chain
To build our Azura Chain and make it EVM-compatible on Cosmos Network, we will develop the custom EVM module in our project, since Cosmos SDK does not provide EVM modules by default. Azura Chain allows users to deploy Ethereum-compatible smart contracts on Azura Chain for smooth execution without modification.
### Azura Technical Architecture
This figure shows the technical architecture of Azura. It helps explain how Azura works and functions technically.
<figure style="text-align: center;">
<img src="https://hackmd.io/_uploads/HkzelYs9A.png" alt="Azura Technical Architecture">
<figcaption>Azura Technical Architecture</figcaption>
</figure>
At the top layer, it shows that Azura will utilizes some Cosmos SDK standard modules, such as `Auth`, `Bank`, `Distribution`, `Governance`, `NFT`, `Staking`, `IBC`, etc. Moreover, some custom modules will be developed by Azura like `EVM` and other gaming modules as needed. These modules interface with the ABCI layer, which facilitates communication between the application logic and the consensus engine. At the bottom layer, the Tendermint Consensus (CometBFT) mechanism ensures consensus across the blockchain network.
Here are the summarized steps to build Azura Chain on Cosmos:
1. **Initialize Blockchain**: Utilize Cosmos SDK and Ignite CLI to initialize the blockchain, and setup a genesis account to create, sign and validate the transactions.
2. **Extend Functionalities**: Append and develop extra modules (i.e., Cosmos SDK standard modules and custom modules for the gaming ecosystem) to extend the functionality for Azura Chain. Please see the next section for more details.
3. **Launch Blockchain**: Activate the blockchain to begin operations, allowing the deployment and interaction with Solidity smart contracts on Azura Chain.
4. **Deploy Smart Contracts**: Deploy implemented Solidity smart contracts, running familiar Ethereum-based applications and protocols.
The key features and supports of Azura Chain are summarized as follows:
- **EVM Compatibility**: Azura Chain enables the execution of Ethereum smart contracts without modification.
- **Client Compatibility**: Developers can use the existing Ethereum development tools and libraries like Ethers.js and Web3.js.
- **Cosmos SDK Integration**: Azura inherits the modular architecture and scalability benefits of the Cosmos ecosystem.
- **IBC Support**: Smart contracts on Azura Chain can interact with other chains through the IBC protocol.
### Standard and Custom Modules on Azura Chain
Azura Chain features a set of modules for functionality, leveraging both its own and Cosmos SDK modules. The modules utilized or created by Azura Chain are listed below.
| Module | Description | Key Features |
|--------|-------------|--------------|
| Auth | Manages account, transaction authentication / authorization | * Secure identity management<br>* Transaction validation |
| Bank | Handles basic token operations | * Transfers between accounts<br>* Minting, burning, supply |
| Governance | Enables on-chain governance mechanism | * Proposal submission<br>* Voting and decision-making |
| NFT | Supports creation, management, transfer of NFT | * Essential for applications requiring unique digital asset representation |
| Staking | Implements Proof-of-Stake consensus mechanism | * Allows validators to stake tokens and earn rewards |
| Distribution | Manages the distribution of staking rewards | * Fair and transparent reward allocation to validators / delegators |
| IBC | Enables interoperability between different blockchains | * Cross-chain token transfers<br>* Inter-chain communications |
| EVM | Enables Ethereum compatibility on Cosmos Nework | * EVM-compatible smart contracts deployment & interaction support |
Here are the gaming custom modules provided by Azura. For more details about these modules, please refer to the [Azura Custom Gaming Modules](https://hackmd.io/@alison1013/SJxGzt15C) section.
| Gaming Module | Description |
|---------------|-------------|
| Player Profiles | Stores player statistics, achievements, and rankings |
| Matchmaking | System for finding and creating multiplayer game matches |
| Asset Management | NFT-like functionality for in-game assets<br>supporting minting, burning, and transfers |
| Game State Management | Efficient storage and retrieval of game states, including saving and loading game progress |
| Random Number Generation | Integrates a Verifiable Random Function (VRF) and transparent randomness |
| Governance Integration | Enables on-chain governance of game parameters and rules |
| State Channels | Off-chain gameplay with periodic on-chain settlements |
| Interoperability | Uses IBC to support cross-chain asset transfers and game interactions |
| Gas Optimization | Features to optimize gas costs for frequent game actions |
| AI Integration | Provides hooks to integrate AI services for NPC behavior, dynamic difficulty adjustment, etc. |
## Extend Functionalities - Modules with Azura's Logic
To follow the specific structure of Cosmos SDK modules, Azura should create new modules within the `x` directory in the repository. In Cosmos SDK-based projects, including Azura, the `x` directory is a convention for organizing and naming directories that contain custom modules. It helps distinguish between the SDK's core modules and those added by Azura for specific functionalities.
Inside the `x` directory, each custom module typically has its own directory named after the module. These custom modules can introduce new features, manage application-specific states, handle custom messages, and define unique application logic (i.e., game logic) beyond the standard Cosmos SDK modules. In a new module's directory, there are several default subdirectories, such as `client`, `keeper`, `module`, `types`, and more.
```
azura/
└── x/
└── azura_custom_module/
├── client/
├── keeper/
├── module/
├── simulation/
├── types/
├── docs/
└── ...
```
Azura will implement various components for a custom module:
- `client`: Manages user interactions with the Azura Chain node through multiple interfaces: CLI, REST API, and gRPC.
- `keeper`: Defines methods for accessing and modifying the module's state, serving as an interface between state and game logic.
- `module`: Integrates the custom module into the Cosmos SDK application, defining routes, handlers, and overall module structure.
- `simulation`: Simulates tests to evaluate module behavior under various conditions.
- `types`: Contains definitions for data structures used throughout the module, including messages, queries, states, and parameters.
- `docs`: Contains documents describing the module's design, functionality, and usage.
<figure style="text-align: center;">
<img src="https://hackmd.io/_uploads/H12HWieo0.png" alt="Custom Module Interaction Flow for Azura">
<figcaption>Custom Module Interaction Flow for Azura</figcaption>
</figure>
This diagram outlines a simplified interaction flow of a custom module in the Cosmos SDK for Azura, demonstrating how a game message is processed from different interfaces to handling the response.
- **Send Game Message**: The process begins with a game message being sent from the user interfaces (CLI, REST, or gRPC) to the `Client` component.
- **Handle Game Message**: The `Client` then forwards the message to the `Module` for routing and handling, based on the defined messge type.
- **Process Game Logic**: The `Module` interacts with the `Keeper`, which carries out the necessary game logic and state transition rules using the received message.
- **Response Result**: The processed result is then returned from the `Keeper` back through the `Module` and `Client` to the original user interfaces.
To explain this more practically, a simplified implementation example is presented in the next section: Gaming Logic Implementation on Azure Chain.
After creating and defining a new custom module, additional steps are required after the implementation, such as:
```
azura_chain/
├── x/
├── app/
│ ├── app.go
│ ├── ibc.go
│ └── ...
├── cmd/
│ ├── azurad/
│ └── ...
├── proto/
└── ...
```
- **Register Module**: Register the new module within the application constructor in `app/app.go`, which is the main entry point for defining and configuring the Cosmos SDK application.
- **Add Module CLI Commands**: Extend the CLI commands in `cmd/azurad/cmd/commands.go` for interacting with the module (`azurad` is the abbreviation for Azura Daemon, which is a customized Azura CLI).
- **Update Protobuf Files**: Update the files in `proto` if the new module defines new message types, queries, or state structures.
Note that the `app/ibc.go` file handles the setup and configuration of IBC module within the application.
## Example - Game Logic Implemention on Azura Chain
At the implementation level, there are two approaches to executing game logic on Azura Chain. One approach is to define the logic directly on the chain, while the other is to deploy EVM-compatible smart contracts as the logic on the chain. To easily understand the implementation of game logic on Azura Chain, consider the example of a simple custom module for gaming called *Game State* (module named `gamestate`) presented in the following subsections.
### Approach 1: Define Game Logic on Azura Chain
#### Define the Messages and Parameters
As mentioned earlier, the directory `x/gamestate/types` defines the messages, queries, states, and parameters used by the module. In `messages.go`, we define the messages and parameters needed for the game.
```go=
// src: x/gamestate/types/messages.go
package gamestate
const (
ModuleName = "gamestate"
StoreKey = ModuleName
)
// Represents the game state
type GameState struct {
PlayerID string
Score int
}
// Defines the SaveGame message
type MsgSaveGame struct {
PlayerID string
Score int
}
```
where `ModuleName` and `StoreKey` are constants used to identify the module and its storage key in the Cosmos SDK. `GameState` struct represents the core data of a game state, containing a `PlayerID` (string) and a `Score` (integer). `MsgSaveGame` struct defines the message structure for saving a game state. It mirrors the `GameState` structure and is used as the input for transactions to save game states.
#### Define the Keeper
As mentioned earlier, the directory `x/gamestate/keeper` handles game logic and state transition rules. It manages the game state, including the ID and score of the player, as defined in `keeper.go`.
```go=
// src: x/gamestate/keeper/keeper.go
package gamestate
import (
"x/gamestate/types" // import `types` as mentioned
sdk "github.com/cosmos/cosmos-sdk/types"
"encoding/json"
)
type Keeper struct {
storeKey sdk.StoreKey
}
func NewKeeper(storeKey sdk.StoreKey) Keeper {
return Keeper{storeKey: storeKey}
}
// Function to store a game state
func (k Keeper) SetGameState(ctx sdk.Context, state GameState) error {
store := ctx.KVStore(k.storeKey)
value, err := json.Marshal(state)
if err != nil { return err }
store.Set([]byte(state.PlayerID), value)
return nil
}
// Function to retrieve a game state
func (k Keeper) GetGameState(ctx sdk.Context, playerID string) (GameState, bool) {
store := ctx.KVStore(k.storeKey)
value := store.Get([]byte(playerID))
if value == nil { return GameState{}, false }
var state GameState
err := json.Unmarshal(value, &state)
if err != nil { return GameState{}, false }
return state, true
}
```
where `Keeper` struct manages the module's state storage, holding a `storeKey` for accessing the module's storage. `NewKeeper` is a constructor for creating a new `Keeper` instance. `SetGameState` stores a `GameState` in the module's storage. It serializes the state to JSON format and uses the `PlayerID` as the key. `GetGameState` retrieves a `GameState` from storage using the `PlayerID`. It deserializes the JSON data and returns the state indicating whether the state was found.
#### Define Message Handler
After we have defined the messages, parameters and keeper, the next step involves setting up a message handler. This handler will be responsible for processing the message `MsgSaveGame` in `module.go`.
```go=
// src: x/gamestate/module/module.go
package gamestate
import (
"x/gamestate/keeper" // import `keeper` as mentioned
"x/gamestate/types" // import `types` as mentioned
sdk "github.com/cosmos/cosmos-sdk/types"
)
// Function to create a new handler for gamestate module messages
func NewHandler(k Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
switch msg := msg.(type) {
case MsgSaveGame:
return handleMsgSaveGame(ctx, k, msg)
default:
return sdk.ErrUnknownRequest("Unknown message type").Result()
}
}
}
// Function to handle MsgSaveGame messages
func handleMsgSaveGame(ctx sdk.Context, k Keeper, msg MsgSaveGame) sdk.Result {
state := GameState{
PlayerID: msg.PlayerID,
Score: msg.Score,
}
err := k.SetGameState(ctx, state)
if err != nil {
return sdk.ErrInternal("failed to save game state").Result()
}
return sdk.Result{Events: ctx.EventManager().Events()}
}
```
where `NewHandler` creates a new handler function for processing module messages. It uses a switch statement to route different message types to their respective handlers. `handleMsgSaveGame` is the specific handler for `MsgSaveGame` messages. It creates a `GameState` from the message and uses the `Keeper` to save it, which the function `SetGameState` executes the logic of *Game State* in `keeper.go`.
### Approach 2: Deploy Contracts with Game Logic to Azura Chain
This approach is quite different from the Cosmos SDK module-based implementation when using smart contracts. The game logic included in the contract defines, stores, and retrieves the game state. Here is a simplified smart contract example of `GameState` module.
```Solidity=
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract GameStateModule {
// Defines the game state structure
struct GameState {
uint256 score;
bool exists;
}
// Represents the game states (PlayerID => GameState)
mapping(uint256 => GameState) private gameStates;
// Function to store a game state
function saveGameState(
uint256 _playerId,
uint256 _score
) external {
gameStates[_playerId] = GameState(_score, true);
}
// Function to retrieve a game state
function getGameState(
uint256 _playerId
) external view returns (uint256, bool) {
GameState memory state = gameStates[_playerId];
return (state.score, state.exists);
}
}
```
After implementing and compiling this Solidity smart contract, we can proceed by deploying them to the Azura Chain. The deployment and interaction process will follow the same steps and methods on Ethereum.