# Technical Architecture

LagomChain is a scalable, tokenization-focused Proof-of-Stake blockchain that is fully compatible and interoperable with the Ethereum Virtual Machine (EVM). It is built using the [Cosmos SDK](https://github.com/cosmos/cosmos-sdk/), running on top of the [CometBFT](https://github.com/cometbft/cometbft) (a fork of [Tendermint Core](https://docs.tendermint.com/)) consensus engine. This allows fast finality, high transaction throughput, and short block times (\~2 seconds), making it an ideal infrastructure for asset tokenization and seamless on-chain operations.

This architecture allows users to perform both Cosmos and EVM formatted transactions, developers to scale EVM dApps cross-chain via [IBC](https://cosmos.network/ibc), and Tokens and assets on LagomChain can originate from multiple independent sources.

LagomChain enables these key features by:

* Leveraging [modules](https://docs.cosmos.network/v0.47/build/building-modules/intro) and other mechanisms implemented by the [Cosmos SDK](https://docs.cosmos.network/).
* Implementing CometBFT's Application Blockchain Interface ([ABCI](https://docs.tendermint.com/master/spec/abci/)) to manage the blockchain.
* Utilizing [`geth`](https://github.com/ethereum/go-ethereum) as a library to promote code reuse and improve maintainability.
* Exposing a fully compatible Web3 JSON-RPC layer for interacting with existing Ethereum clients and tooling (Metamask, Remix, Truffle, etc).

By combining these features, developers can tokenize real-world assets (RWAs), create compliant digital securities, and build DeFi applications while leveraging existing Ethereum tooling.

## Cosmos SDK[​](https://docs.evmos.org/protocol#cosmos-sdk) <a href="#cosmos-sdk" id="cosmos-sdk"></a>

LagomChain inherits the full composability and modularity of the [Cosmos SDK](https://docs.cosmos.network/), making it a sovereign blockchain with its own native token (LAGOM). Through IBC (Inter-Blockchain Communication), LagomChain enables cross-chain asset transfers and liquidity movement between different ecosystems.

The blockchain includes standard Cosmos SDK modules, working alongside LagomChain-specific modules, optimized for tokenization and asset management. These modules ensure efficient issuance, transfer, and management of tokenized assets.

For an overview of LagomChain’s custom modules, check out the [list of modules](/modules) in the documentation.

## CometBFT & ABCI[​](https://docs.evmos.org/protocol#cometbft--abci) <a href="#cometbft--abci" id="cometbft--abci"></a>

[CometBFT](https://github.com/cometbft/cometbft) consists of two chief technical components: a blockchain consensus engine and a generic application interface. The consensus engine ensures that the same transactions are recorded on every machine in the same order. The application interface, called the [Application Blockchain Interface (ABCI)](https://docs.tendermint.com/master/spec/abci/), enables the transactions to be processed in any programming language.

By integrating CometBFT as its consensus mechanism, LagomChain eliminates Ethereum's Proof-of-Work limitations, ensuring low fees, high security, and fast tokenized transactions.

CometBFT’s ABCI-based architecture allows LagomChain to customize asset tokenization mechanisms, supporting diverse use cases like real estate tokenization, stablecoins, and digital securities.

## EVM Compatibility[​](https://docs.evmos.org/protocol#evm-compatibility) <a href="#evm-compatibility" id="evm-compatibility"></a>

LagomChain enables EVM compatibility by implementing various components that together support all the EVM state transitions while ensuring the same developer experience as Ethereum:

* Ethereum-compatible transaction format within Cosmos SDK.
* Ethereum's `secp256k1` curve for the Cosmos Keyring
* `StateDB` interface for state updates and queries
* JSON-RPC client for interacting with the EVM

By maintaining Ethereum’s developer experience while enhancing it with Cosmos interoperability, LagomChain is positioned as the go-to tokenization blockchain for institutional and enterprise-grade digital assets.

To better understand LagomChain’s [EVM](/modules/evm) compatibility, explore:

* [Accounts](/concepts/accounts)
* [Gas and Fees](/concepts/gas-and-fees)
* [Token representations](/concepts/token)
* [Transactions](/concepts/transactions)

## Contributing[​](https://docs.evmos.org/protocol#contributing) <a href="#contributing" id="contributing"></a>

LagomChain is open-source and welcomes contributions to enhance its tokenization framework.

Ways to contribute:

* Run a local LagomChain node using the [CLI](#cosmos-sdk) and interact with on-chain tokenized assets.
* Contribute to GitHub – Find issues and contribute via the LagomChain Contributor Guidelines.
* Apply for open positions at LagomChain.
* Participate in [bug bounties and earn rewards](/bugs).


# LagomChain CLI

`lagomd` is the all-in-one command-line interface (CLI) for interacting with the LagomChain blockchain. It allows you to run a node, manage wallets, query blockchain data, and submit transactions. This guide will walk you through installing `lagomd`, running a LagomChain node, and interacting with the network.

### Prerequisites[​](broken://pages/OvpSYcvbBk4sC5YKn6Bh) <a href="#prerequisites" id="prerequisites"></a>

**Go**[**​**](broken://pages/OvpSYcvbBk4sC5YKn6Bh)

LagomChain is built using [Go](https://go.dev/dl/) 1.20+. Check your installed version with:

```sh
go version
```

Ensure that your GOPATH is correctly configured by running:

```sh
export PATH=$PATH:$(go env GOPATH)/bin
```

Add this to your shell startup script for persistence.

**jq**[**​**](broken://pages/OvpSYcvbBk4sC5YKn6Bh)

LagomChain scripts are using [jq](https://stedolan.github.io/jq/download/) version `1.6+`. Check your version with:

```sh
jq --version
```

### Installation[​](broken://pages/OvpSYcvbBk4sC5YKn6Bh) <a href="#installation" id="installation"></a>

You can download the latest binaries from the repo and install them, or you can build and install the `lagomd` binaries from source or using Docker.

#### Download the binaries[​](broken://pages/OvpSYcvbBk4sC5YKn6Bh) <a href="#download-the-binaries" id="download-the-binaries"></a>

* Visit the LagomChain GitHub Releases page.
* Select the latest stable release for your OS.
* Download and extract the binaries.
* Move `lagomd` to your system path:

```sh
mv lagomd $(go env GOPATH)/bin
```

* Verify installation:<br>

  ```sh
  lagomd version
  ```

#### Build From Source[​](broken://pages/OvpSYcvbBk4sC5YKn6Bh) <a href="#build-from-source" id="build-from-source"></a>

Clone and build LagomChain from source:

```
git clone https://github.com/lagomchain/lagom.git
cd lagom
git fetch
git checkout <latest-tag>
make install
```

Confirm installation:

```sh
lagomd version
```

If you encounter `command not found`, check that **Go is properly installed and configured**.

#### Docker[​](broken://pages/OvpSYcvbBk4sC5YKn6Bh) <a href="#docker" id="docker"></a>

When it comes to using Docker with LagomChain, there are two options available: Build a binary of the LagomChain daemon inside a dockerized build environment or build a Docker image, that can be used to spin up individual containers running the LagomChain binary. For information on how to achieve this, proceed to the dedicated page on [working with Docker](/lagomchain-cli/working-with-docker).

### Running a LagomChain Node[​](broken://pages/OvpSYcvbBk4sC5YKn6Bh) <a href="#run-an-evmos-node" id="run-an-evmos-node"></a>

To interact with LagomChain locally, you can run a full node that produces blocks and exposes both EVM and Cosmos endpoints. This allows you to deploy smart contracts, test transactions, and explore blockchain data.

Run the local node by executing the `local_node.sh` script in the base directory of the repository:

The script stores the node configuration including the local default endpoints under `~/.tmp-lagomd/config/config.toml`. If you have previously run the script, the script allows you to overwrite the existing configuration and start a new local node.

Once running, you should see logs indicating block production:

```sh
12:59PM INF executed block height=1 module=state num_invalid_txs=0 num_valid_txs=0
1:00PM INF indexed block height=7 module=txindex
```

For more information on how to customize a local node, head over to the [Single Node](/lagomchain-cli/single-node) page.

### Using `lagomd`[​](broken://pages/OvpSYcvbBk4sC5YKn6Bh) <a href="#using-evmosd" id="using-evmosd"></a>

After installing `lagomd`, you can interact with LagomChain using various commands. To see available options:

```sh
lagomd --help
```

**Managing Multiple Node Configurations**\
If you’re running multiple nodes, specify a config directory using:

```sh
lagomd --home ~/.lagomd
```

#### Manage wallets[​](broken://pages/OvpSYcvbBk4sC5YKn6Bh) <a href="#manage-wallets" id="manage-wallets"></a>

You can use `lagomd` to store private keys, manage accounts, and sign transactions directly via CLI.

#### **View All Wallets**

```sh
lagomd keys list --home ~/.lagomd --keyring-backend test
```

Example Outpu&#x74;**:**

```json
jsonCopyEdit{
  "address": "lagom19xnmslvl0pcmydu4m52h2gf0std5ee5pfgpyuf",
  "name": "dev0",
  "pubkey": "AzKouyoUL0UUS1qRUZdqyVsTPkCAFWwxx3+BTOw36nKp",
  "type": "local"
}
```

#### **Create a New Wallet**

```sh
lagomd keys add [name] --home ~/.lagomd --keyring-backend test
```

#### **Export Private Key for MetaMask**

```sh
lagomd keys unsafe-export-eth-key [name] --home ~/.lagomd --keyring-backend test
```

For more key management options, run:

```sh
lagomd keys --help
```

tip

For more information about the Keyring and its backend options, click [here](/concepts/keyring).

#### Interact with a Network[​](broken://pages/OvpSYcvbBk4sC5YKn6Bh) <a href="#interact-with-a-network" id="interact-with-a-network"></a>

You can use `lagomd` to query blockchain data and submit transactions.

#### **Set Network Configuration**

By default, the local node runs on:

```sh
tcp://localhost:26657
```

To view the current node configuration:

```sh
lagomd config --home ~/.lagomd
```

Example Outpu&#x74;**:**

```json
jsonCopyEdit{
  "chain-id": "lagom_986-1",
  "keyring-backend": "test",
  "output": "text",
  "node": "tcp://localhost:26657",
  "broadcast-mode": "sync"
}
```

#### **Change Network Endpoint**

To switch to a mainnet or testnet node, update the RPC endpoint using the new LagomChain RPC URLs:

```sh
lagomd config node http://188.214.128.66:26657 --home ~/.lagomd
```

or

```sh
lagomd config node http://46.166.165.25:26657 --home ~/.lagomd
```

Learn about more node configurations [here](/lagomchain-cli/configuration).

**Queries**[**​**](broken://pages/OvpSYcvbBk4sC5YKn6Bh)

You can fetch blockchain data using the `lagomd query` command (short form: `lagomd q`).

#### **Check Account Balance**

```sh
lagomd q bank balances [address] --home ~/.lagomd
```

**Example Output:**

```json
jsonCopyEdit{
  "balances": [
    {
      "amount": "99999000000000000000002500",
      "denom": "alagom"
    }
  ]
}
```

To see all available queries:

```sh
lagomd q
```

For bank-related queries:

```sh
lagomd q bank
```

**Transactions**[**​**](broken://pages/OvpSYcvbBk4sC5YKn6Bh)

You can send transactions using `lagomd tx`.

#### **Send Tokens**

```sh
lagomd tx bank send [from_key_or_address] [to_address] [amount] --home ~/.lagomd --fees 50000000000alagom -b block
```

Example Outpu&#x74;**:**

```json
jsonCopyEdit{
  "txhash": "7BA2618295B789CC24BB13E654D9187CDD264F61FC446EB756EAC07AF3E7C40A"
}
```

To see all available transaction commands:

```sh
lagomd tx
```

For bank transaction commands:

```sh
lagomd tx bank
```

Now that you've learned the basics of how to run and interact with an LagomChain network, head over to [configurations](/lagomchain-cli/configuration) for further customization.


# Configuration

The following page will guide you through the configuration of a node and a client. The node is used to run the blockchain network, produce blocks and validate transactions. The client is used as a gateway to interact with the blockchain network by sending transactions and querying the state. Additionally we walk through [running the JSON-RPC server](#running-the-json-rpc-server).

These configurations can impact the performance, security, and functionality of your node. Thus, understanding and correctly configuring your node and client is essential.

### Config and data directory[​](broken://pages/nA51291FsYM9VuLy5UQp) <a href="#config-and-data-directory" id="config-and-data-directory"></a>

By default, your config and data are stored in the folder located at the `~/.lagomd` directory. You can easily change the default directory by using the `--home` flag. It is important to note that you can have multiple home directories that each represent a different blockchain.

```
.                                   # ~/.lagomd
  ├── data/                           # Contains the databases used by the node.
  └── config/
      ├── app.toml                   # Application-related configuration file.
      ├── config.toml                # Tendermint-related configuration file.
      ├── genesis.json               # The genesis file.
      ├── node_key.json              # Private key to use for node authentication in the p2p protocol.
      └── priv_validator_key.json    # Private key to use as a validator in the consensus protocol.
```

To specify the `lagomd` config and data storage directory; you can update it using the global flag `--home <directory>`.

### Node Configuration[​](broken://pages/nA51291FsYM9VuLy5UQp) <a href="#node-configuration" id="node-configuration"></a>

The Cosmos SDK automatically generates two configuration files inside `~/.lagomd/config`:

* `config.toml` – Configures CometBFT ([Tendermint](https://docs.tendermint.com/v0.34/tendermint-core/configuration.html)) settings, including P2P networking, block creation, and consensus parameters.
* `app.toml` – Manages LagomChain-specific settings like state pruning, telemetry, gRPC, REST, and JSON-RPC configurations.

Both files are heavily commented, please refer to them directly to tweak your node.

One example config to tweak is the `minimum-gas-prices` field inside `app.toml`, which defines the minimum amount the validator node is willing to accept for processing a transaction. It is an anti spam mechanism and it will reject incoming transactions with less than the minimum gas prices.

If it's empty, make sure to edit the field with some value, for example `10token`, or else the node will halt on startup.

```
 # The minimum gas prices a validator is willing to accept for processing a
 # transaction. A transaction's fees must meet the minimum of any denomination
 # specified in this config (e.g. 0.25token1;0.0001token2).
 minimum-gas-prices = "0alagom"
```

#### Pruning of State[​](broken://pages/nA51291FsYM9VuLy5UQp) <a href="#pruning-of-state" id="pruning-of-state"></a>

There are four strategies for pruning state. These strategies apply only to state and do not apply to block storage. To set pruning, adjust the `pruning` parameter in the `~/.lagomd/config/app.toml` file. The following pruning state settings are available:

* `everything`: Deletes all old states except the current state.
* `nothing`: Stores all blockchain states (Full archival node).
* `default`: Keeps the last 100 states + every 10,000th block.
* `custom`: Allows manual control using `pruning-keep-recent` settings.

By default, every node is in `default` mode which is the recommended setting for most environments. If you would like to change your nodes pruning strategy then you must do so when the node is initialized. Passing a flag when starting `Lagom` will always override settings in the `app.toml` file, if you would like to change your node to the `everything` mode then you can pass the `--pruning everything` flag when you call `lagomd start`.

danger

**IMPORTANT**: When you are pruning state you will not be able to query the heights that are not in your store.

### Client Configuration[​](broken://pages/nA51291FsYM9VuLy5UQp) <a href="#client-configuration" id="client-configuration"></a>

We can view the default client config setting by using `lagomd config` command:

```
lagomd config
{
 "chain-id": "lagom_986-1",
 "keyring-backend": "os",
 "output": "text",
 "node": "tcp://localhost:26657",
 "broadcast-mode": "sync"
}
```

You can update values dynamically, e.g., changing the chain ID:

```sh
lagomd config chain-id lagom_986-1
```

Alternatively, you can edit `client.toml` directly:

```toml
# LagomChain Client Configuration

chain-id = "lagom_986-1"
keyring-backend = "os"
output = "json"
node = "tcp://localhost:26657"
broadcast-mode = "sync"
```

### Running the JSON-RPC Server[​](broken://pages/nA51291FsYM9VuLy5UQp) <a href="#running-the-json-rpc-server" id="running-the-json-rpc-server"></a>

This section walks through the steps to enable the JSON-RPC server. JSON-RPC is provided on multiple transports. LagomChain supports JSON-RPC over HTTP and WebSocket. In terms of requirements we recommend a server with minimum 8-core CPU and 64gb of RAM. You must have ports 8545 and 8546 open on your firewall.

tip

**Important**: You cannot use all JSON RPC methods unless your node stores the entire copy of the blockchain locally.

#### Enable Server[​](broken://pages/nA51291FsYM9VuLy5UQp) <a href="#enable-server" id="enable-server"></a>

To enable RPC server use the following flag (set to true by default).

```
lagomd start --json-rpc.enable
```

#### Defining Namespaces[​](broken://pages/nA51291FsYM9VuLy5UQp) <a href="#defining-namespaces" id="defining-namespaces"></a>

`Eth`,`Net` and `Web3` namespaces are enabled by default, but for the JSON-RPC you need to add more namespaces. In order to enable other namespaces edit `app.toml` file.

```
# API defines a list of JSON-RPC namespaces that should be enabled
# Example: "eth,txpool,personal,net,debug,web3"
api = "eth,net,web3,txpool,debug,personal"
```

#### Set a Gas Cap[​](broken://pages/nA51291FsYM9VuLy5UQp) <a href="#set-a-gas-cap" id="set-a-gas-cap"></a>

`eth_call` and `eth_estimateGas` define a global gas cap over rpc for DoS protection. You can override the default gas cap value of 25,000,000 by passing a custom value in `app.toml`:

```
# GasCap sets a cap on gas that can be used in eth_call/estimateGas (0=infinite). Default: 25,000,000.
gas-cap = 25000000
```

#### CORS[​](broken://pages/nA51291FsYM9VuLy5UQp) <a href="#cors" id="cors"></a>

If accessing the RPC from a browser, CORS will need to be enabled with the appropriate domain set. Otherwise, JavaScript calls are limit by the same-origin policy and requests will fail.

The CORS setting can be updated from the `app.toml`

```
###############################################################################
###                           API Configuration                             ###
###############################################################################

[api]

# ...

# EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk).
enabled-unsafe-cors = true # default false
```

#### Pruning[​](broken://pages/nA51291FsYM9VuLy5UQp) <a href="#pruning" id="pruning"></a>

For all methods to work correctly, your node must be archival (store the entire copy of the blockchain locally). Pruning must be disabled. The pruning settings can be updated from the `app.toml`

```
###############################################################################
###                           Base Configuration                            ###
###############################################################################

# The minimum gas prices a validator is willing to accept for processing a
# transaction. A transaction's fees must meet the minimum of any denomination
# specified in this config (e.g. 0.25token1;0.0001token2).

# ...

# default: the last 100 states are kept in addition to every 500th state; pruning at 10 block intervals
# nothing: all historic states will be saved, nothing will be deleted (i.e. archiving node)
# everything: all saved states will be deleted, storing only the current state; pruning at 10 block intervals
# custom: allow pruning options to be manually specified through 'pruning-keep-recent', 'pruning-keep-every', >
pruning = "nothing"
pruning-keep-recent = "0"
pruning-keep-every = "0"
pruning-interval = "0"
```

#### WebSocket Server[​](broken://pages/nA51291FsYM9VuLy5UQp) <a href="#websocket-server" id="websocket-server"></a>

Websocket is a bidirectional transport protocol. A Websocket connection is maintained by client and server until it is explicitly terminated by one. Most modern browsers support Websocket which means it has good tooling.

Because Websocket is bidirectional, servers can push events to clients. That makes Websocket a good choice for use-cases involving event subscription. Another benefit of Websocket is that after the handshake procedure, the overhead of individual messages is low, making it good for sending high number of requests. The WebSocket Server can be enabled from the `app.toml`

```
# Address defines the EVM WebSocket server address to bind to.
ws-address = "0.0.0.0:8546"
```


# Working With Docker

There are multiple ways to use LagomChain with Docker. If you want to run LagomChain inside a Docker setup and possibly connect the Docker container to other containerized compatible blockchain binaries, check out the guide on [building a Docker image containing the LagomChain binary](#building-a-docker-image-containing-the-binary). If you instead want to generate a binary for use outside of Docker, but want to ensure the correct dependencies are used by building the binary inside a Docker container, then go ahead to the section on [building the LagomChain binary with Docker](#building-the-binary-with-docker).

note

The given instructions have been tested on *Ubuntu 18.04.2 LTS* with *Docker 20.10.2* and *macOS 13.2.1* with *Docker 20.10.22*.

### Prerequisites[​](broken://pages/7yC7FjBmYr8kj92FaxbV) <a href="#prerequisites" id="prerequisites"></a>

* [Install Docker](https://docs.docker.com/get-docker/)

### General Setup[​](broken://pages/7yC7FjBmYr8kj92FaxbV) <a href="#general-setup" id="general-setup"></a>

In order to build LagomChain binaries with Docker, it is necessary to

* clone the LagomChain repository to your local machine (e.g. `git clone [email protected]/LagomChain/LagomChain.git`)
* checkout the commit, branch, or release tag you want to build (e.g. `git checkout v11.0.2`)

### Building A Docker Image Containing The Binary[​](broken://pages/7yC7FjBmYr8kj92FaxbV) <a href="#building-a-docker-image-containing-the-binary" id="building-a-docker-image-containing-the-binary"></a>

To build a Docker image, that contains the LagomChain binary, step into the cloned repository and run the following command in a terminal session:

This will create an image with the name `tharsishq/lagomchain` and the version tag `latest`. Now it is possible to run the `lagomd` binary in the container, e.g. evaluating its version:

```
docker run -it --rm tharsishq/lagomchain:latest lagomd version
```

### Building The Binary With Docker[​](broken://pages/7yC7FjBmYr8kj92FaxbV) <a href="#building-the-binary-with-docker" id="building-the-binary-with-docker"></a>

It is possible to build the `lagomd` binary deterministically using Docker. The container system that Docker provides offers the ability to create an instance of the LagomChain binary in an isolated environment.

#### Building the Image[​](broken://pages/7yC7FjBmYr8kj92FaxbV) <a href="#building-the-image" id="building-the-image"></a>

Run the following command to launch a build for all supported architectures (currently **linux/amd64**):

```
make distclean build-reproducible
```

The build system generates both the binaries and deterministic build report in the `artifacts` directory. The `artifacts/build_report` file contains the list of the build artifacts and their respective checksums, and can be used to verify build sanity. An example of its contents follows:

```
App: lagomd
Version: 11.0.2
Commit: 8eeeac7ae42a5b2695fea7f56868f3c6e9bc2378
Files:
 6b5939adfd9a8ce964d78fcaab16091a  lagomd-11.0.2-linux-amd64
 ac503925c535ddb8ee0fbebbb96d0eb9  lagomd-11.0.2.tar.gz
Checksums-Sha256:
 0857d59c285a87b7d354aa6d566db90c56663d938a88d41d35415da490708aea  lagomd-11.0.2-linux-amd64
 5005814fc34abc02d7e30dcfbe67e363c1b593efb774e0c97ebb7ec713baf306  lagomd-11.0.2.tar.gz
```

#### Builder Image[​](broken://pages/7yC7FjBmYr8kj92FaxbV) <a href="#builder-image" id="builder-image"></a>

The [Tendermint builder Docker image](https://github.com/tendermint/images/tree/master/rbuilder) provides a deterministic build environment that is used to build Cosmos SDK applications. It provides a way to be reasonably sure that the executables are really built from the git source. It also makes sure that the same, tested dependencies are used and statically built into the executable.

***

Now that you have built the LagomChain binary, either for local use or in a Docker container, you'll find information to run a node instance in the following section on [setting up a local network](/lagomchain-cli/single-node).


# Single Node

This guide will help you set up a single node network on LagomChain. Running a single node is ideal for developers testing applications, smart contracts, and blockchain functionality due to its speed and simplicity.

For multi-node deployments, refer to the [Multi-Node](/lagomchain-cli/multi-node) Setup Guide.

### Prerequisite Readings[​](broken://pages/a1AlQHndEOrVTY0NVwH8) <a href="#prerequisite-readings" id="prerequisite-readings"></a>

* [Install Binary](/lagomchain-cli)

### Automated Script[​](broken://pages/a1AlQHndEOrVTY0NVwH8) <a href="#automated-script" id="automated-script"></a>

The simplest way to start a local LagomChain node is by using the provided helper script on the base level of the LagomChain repository, which will create a sensible default configuration for testing purposes:

tip

To avoid overwriting any data for a real node used in production, it was decided to store the automatically generated testing configuration at `~/.tmp-lagomd` instead of the default `~/.lagomd`.

When working with the `local_node.sh` script, it is necessary to extend all `lagomd` commands, that target the local test node, with the `--home ~/.tmp-lagomd` flag. This is mandatory, because the `home` directory cannot be stored in the `lagomd` configuration, which can be seen in the output below. For ease of use, it might be sensible to export this directory path as an environment variable:

```
$ export TMP=$HOME/.tmp-lagomd`
$ lagomd config --home $TMP
{
"chain-id": "lagom_986-1",
"keyring-backend": "test",
"output": "text",
"node": "tcp://localhost:26657",
"broadcast-mode": "sync"
}
```

You can customize the local node script by changing the configuration variables. See the following excerpt from the script for ideas on what can be adjusted:

```
# Customize the name of your keys, the chain-id, moniker of the node, keyring backend, and more
KEYS[0]="dev0"
KEYS[1]="dev1"
KEYS[2]="dev2"
CHAINID="lagom_986-1
MONIKER="localtestnet"
# Remember to change to other types of keyring like 'file' in-case exposing to outside world,
# otherwise your balance will be wiped quickly
# The keyring test does not require private key to steal tokens from you
KEYRING="test"
KEYALGO="eth_secp256k1"
LOGLEVEL="info"
# Set dedicated home directory for the lagomd instance
HOMEDIR="$HOME/.tmp-lagomd"
# to trace evm
#TRACE="--trace"
TRACE=""

[...]

  # Adjust this set a different maximum gas limit
  jq '.consensus_params["block"]["max_gas"]="10000000"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"

[...]

```

### Manual Deployment[​](broken://pages/a1AlQHndEOrVTY0NVwH8) <a href="#manual-deployment" id="manual-deployment"></a>

This guide helps you create a single validator node that runs a network locally for testing and other development related uses.

#### Initialize the chain[​](broken://pages/a1AlQHndEOrVTY0NVwH8) <a href="#initialize-the-chain" id="initialize-the-chain"></a>

Before actually running the node, we need to initialize the chain, and most importantly its genesis file. This is done with the `init` subcommand:

```
$MONIKER=testing
$KEY=dev0
$CHAINID="lagom_986-1"

# The argument $MONIKER is the custom username of your node, it should be human-readable.
lagomd init $MONIKER --chain-id=$CHAINID
```

tip

You can [edit](/lagomchain-cli/configuration#client-configuration) this `moniker` later by updating the `config.toml` file.

The command above creates all the configuration files needed for your node and validator to run, as well as a default genesis file, which defines the initial state of the network. All these [configuration files](/lagomchain-cli/configuration#client-configuration) are in `~/.lagomd` by default, but you can overwrite the location of this folder by passing the `--home` flag.

#### Genesis Procedure[​](broken://pages/a1AlQHndEOrVTY0NVwH8) <a href="#genesis-procedure" id="genesis-procedure"></a>

#### Adding Genesis Accounts[​](broken://pages/a1AlQHndEOrVTY0NVwH8) <a href="#adding-genesis-accounts" id="adding-genesis-accounts"></a>

Before starting the chain, you need to populate the state with at least one account using the [keyring](/concepts/keyring):

```
lagomd keys add my_validator
```

Once you have created a local account, go ahead and grant it some `alagom` tokens in your chain's genesis file. Doing so will also make sure your chain is aware of this account's existence:

```
lagomd add-genesis-account my_validator 10000000000alagom
```

Now that your account has some tokens, you need to add a validator to your chain.

For this guide, you will add your local node (created via the `init` command above) as a validator of your chain. Validators can be declared before a chain is first started via a special transaction included in the genesis file called a `gentx`:

```
# Create a gentx
# NOTE: this command lets you set the number of coins.
# Make sure this account has some coins with the genesis.app_state.staking.params.bond_denom denom
lagomd add-genesis-account my_validator 1000000000stake,10000000000alagom
```

A `gentx` does three things:

1. Registers the `validator` account you created as a validator operator account (i.e. the account that controls the validator).
2. Self-delegates the provided `amount` of staking tokens.
3. Link the operator account with a Tendermint node pubkey that will be used for signing blocks. If no `--pubkey` flag is provided, it defaults to the local node pubkey created via the `lagomd init` command above.

For more information on `gentx`, use the following command:

#### Collecting `gentx`[​](broken://pages/a1AlQHndEOrVTY0NVwH8) <a href="#collecting-gentx" id="collecting-gentx"></a>

By default, the genesis file do not contain any `gentxs`. A `gentx` is a transaction that bonds staking token present in the genesis file under `accounts` to a validator, essentially creating a validator at genesis. The chain will start as soon as more than 2/3rds of the validators (weighted by voting power) that are the recipient of a valid `gentx` come online after `genesis_time`.

A `gentx` can be added manually to the genesis file, or via the following command:

```
# Add the gentx to the genesis file
lagomd collect-gentxs
```

This command will add all the `gentxs` stored in `~/.lagomd/config/gentx` to the genesis file.

#### Run Single Node[​](broken://pages/a1AlQHndEOrVTY0NVwH8) <a href="#run-single-node" id="run-single-node"></a>

Finally, check the correctness of the `genesis.json` file:

Now that everything is set up, you can finally start your node:

tip

To check all the available customizable options when running the node, use the `--help` flag.

You should see blocks come in.

The previous command allow you to run a single node. This is enough for the next section on interacting with this node, but you may wish to run multiple nodes at the same time, and see how consensus happens between them.

You can then stop the node using `Ctrl+C`.

### Further Configuration[​](broken://pages/a1AlQHndEOrVTY0NVwH8) <a href="#further-configuration" id="further-configuration"></a>

#### Key Management[​](broken://pages/a1AlQHndEOrVTY0NVwH8) <a href="#key-management" id="key-management"></a>

To use the same key every time, replace:

```sh
lagomd keys add $KEY
```

With:

```sh
shCopyEditecho "your mnemonic here" | lagomd keys add $KEY --recover
```

LagomChain only supports 24-word mnemonics.

Export a Private Key for MetaMask

```sh
lagomd keys unsafe-export-eth-key $KEY
```

For more key management options:

```sh
lagomd keys --help
```

#### Keyring backend options[​](broken://pages/a1AlQHndEOrVTY0NVwH8) <a href="#keyring-backend-options" id="keyring-backend-options"></a>

The instructions above include commands to use `test` as the `keyring-backend`. This is an unsecured keyring that doesn't require entering a password and should not be used in production. Otherwise, LagomChain supports using a file or OS keyring backend for key storage. To create and use a file stored key instead of defaulting to the OS keyring, add the flag `--keyring-backend file` to any relevant command and the password prompt will occur through the command line. This can also be saved as a CLI config option with:

```
lagomd config keyring-backend file
```

tip

For more information about the Keyring and its backend options, click [here](/concepts/keyring).

#### Enable Tracing[​](broken://pages/a1AlQHndEOrVTY0NVwH8) <a href="#enable-tracing" id="enable-tracing"></a>

To enable tracing when running the node, modify the last line of the `local_node.sh` script to be the following command, where:

* `$TRACER` is the EVM tracer type to collect execution traces from the EVM transaction execution (eg. `json|struct|access_list|markdown`)
* `$TRACESTORE` is the output file which contains KVStore tracing (eg. `store.txt`)

```
lagomd start --evm.tracer $TRACER --tracestore $TRACESTORE --pruning=nothing $TRACE --log_level $LOGLEVEL --minimum-gas-prices=0.0001alagom --json-rpc.api eth,txpool,personal,net,debug,web3
```

### Clearing data from chain[​](broken://pages/a1AlQHndEOrVTY0NVwH8) <a href="#clearing-data-from-chain" id="clearing-data-from-chain"></a>

#### Reset Data[​](broken://pages/a1AlQHndEOrVTY0NVwH8) <a href="#reset-data" id="reset-data"></a>

Alternatively, you can **reset** the blockchain database, remove the node's address book files, and reset the `priv_validator.json` to the genesis state.

danger

If you are running a **validator node**, always be careful when doing `lagomd unsafe-reset-all`. You should never use this command if you are not switching `chain-id`.

danger

**IMPORTANT**: Make sure that every node has a unique `priv_validator.json`. **Do not** copy the `priv_validator.json` from an old node to multiple new nodes. Running two nodes with the same `priv_validator.json` will cause you to double sign!

First, remove the outdated files and reset the data.

```
rm $HOME/.lagomd/config/addrbook.json $HOME/.lagomd/config/genesis.json
lagomd tendermint unsafe-reset-all --home $HOME/.lagomd
```

Your node is now in a pristine state while keeping the original `priv_validator.json` and `config.toml`. If you had any sentry nodes or full nodes setup before, your node will still try to connect to them, but may fail if they haven't also been upgraded.

#### Delete Data[​](broken://pages/a1AlQHndEOrVTY0NVwH8) <a href="#delete-data" id="delete-data"></a>

Data for the `lagomd` binary should be stored at \~/.lagomd, respectively by default. To **delete** the existing binaries and configuration, run:

To clear all data except key storage (if keyring backend chosen) and then you can rerun the full node installation commands from above to start the node again.

### Recording Transactions Per Second (TPS)[​](broken://pages/a1AlQHndEOrVTY0NVwH8) <a href="#recording-transactions-per-second-tps" id="recording-transactions-per-second-tps"></a>

In order to get a progressive value of the transactions per second, we use Prometheus to return the values. The Prometheus exporter runs at address [http://localhost:8877](http://localhost:8877/) so please add this section to your [Prometheus installation](https://opencensus.io/codelabs/prometheus/#1) config.yaml file like this

```
global:
scrape_interval: 10s

external_labels:
  monitor: 'lagom'

scrape_configs:
- job_name: 'lagom'

  scrape_interval: 10s

  static_configs:
    - targets: ['localhost:8877']
```

and then run Prometheus like this

```
prometheus --config.file=prom_config.yaml
```

and then visit the Prometheus dashboard at <http://localhost:9090/> then navigate to the expression area and enter the following expression

```
rate(lagomd_transactions_processed[1m])
```

which will show the rate of transactions processed.


# Multi Node

Following this page, you can run a localnet setup with docker that consists of a 4-node local chain. This setup can be useful for developers to test their applications and protocol features on a multi-node setup.

A similar setup is used by the LagomChain team to get insights about the impact of new features and testing different user flows. This testing setup can be found on the LagomChain testing repository.

#### Build & Start[​](broken://pages/EWknQlTHCCgKUGULC74Z) <a href="#build--start" id="build--start"></a>

To build start a 4 node testnet using [docker](https://docs.docker.com/engine/installation/), run:

This command creates a 4-node network using the `lagomdnode` Docker image. The ports for each node are found in this table:

| Node ID      | P2P Port | Tendermint RPC Port | REST/ Ethereum JSON-RPC Port | WebSocket Port |
| ------------ | -------- | ------------------- | ---------------------------- | -------------- |
| lagom`node0` | `26656`  | `26657`             | `8545`                       | `8546`         |
| lagom`node1` | `26659`  | `26660`             | `8547`                       | `8548`         |
| lagom`node2` | `26661`  | `26662`             | `8549`                       | `8550`         |
| lagom`node3` | `26663`  | `26664`             | `8551`                       | `8552`         |

To update the binary, just rebuild it and restart the nodes

The command above command will run containers in the background using Docker compose. You will see the network being created:

```
...
Creating network "lagom_localnet" with driver "bridge"
Creating lagomdnode0 ... done
Creating lagomdnode2 ... done
Creating lagomdnode1 ... done
Creating lagomdnode3 ... done
```

#### Stop Localnet[​](broken://pages/EWknQlTHCCgKUGULC74Z) <a href="#stop-localnet" id="stop-localnet"></a>

Once you are done, execute:

#### Configuration[​](broken://pages/EWknQlTHCCgKUGULC74Z) <a href="#configuration" id="configuration"></a>

The `make localnet-start` creates files for a 4-node testnet in `./build` by calling the `lagomd testnet` command. This outputs a handful of files in the `./build` directory:

```
tree -L 3 build/

build/
├── lagomd
├── lagomd
├── gentxs
│   ├── node0.json
│   ├── node1.json
│   ├── node2.json
│   └── node3.json
├── node0
│   ├── lagomd
│   │   ├── key_seed.json
│   │   └── keyring-test-cosmos
│   └── lagomd
│       ├── config
│       ├── data
│       └── lagomd.log
├── node1
│   ├── lagomd
│   │   ├── key_seed.json
│   │   └── keyring-test-cosmos
│   └── lagomd
│       ├── config
│       ├── data
│       └── lagomd.log
├── node2
│   ├── lagomd
│   │   ├── key_seed.json
│   │   └── keyring-test-cosmos
│   └── lagomd
│       ├── config
│       ├── data
│       └── lagomd.log
└── node3
├── lagomd
│   ├── key_seed.json
│   └── keyring-test-cosmos
└── lagomd
    ├── config
    ├── data
    └── lagomd.log
```

Each `./build/nodeN` directory is mounted to the `/`lagom`d` directory in each container.

#### Logging[​](broken://pages/EWknQlTHCCgKUGULC74Z) <a href="#logging" id="logging"></a>

In order to see the logs of a particular node you can use the following command:

```
# node 0: daemon logs
docker exec lagomdnode0 tail lagomd.log

# node 0: REST & RPC logs
docker exec lagomdnode0 tail lagomd.log
```

The logs for the daemon will look like:

```
I[2020-07-29|17:33:52.452] starting ABCI with Tendermint                module=main
E[2020-07-29|17:33:53.394] Can't add peer's address to addrbook         module=p2p err="Cannot add non-routable address [email protected]:26656"
E[2020-07-29|17:33:53.394] Can't add peer's address to addrbook         module=p2p err="Cannot add non-routable address [email protected]:26656"
E[2020-07-29|17:33:53.394] Can't add peer's address to addrbook         module=p2p err="Cannot add non-routable address [email protected]:26656"
I[2020-07-29|17:33:58.828] Executed block                               module=state height=88 validTxs=0 invalidTxs=0
I[2020-07-29|17:33:58.830] Committed state                              module=state height=88 txs=0 appHash=90CC5FA53CF8B5EC49653A14DA20888AD81C92FCF646F04D501453FD89FCC791
I[2020-07-29|17:34:04.032] Executed block                               module=state height=89 validTxs=0 invalidTxs=0
I[2020-07-29|17:34:04.034] Committed state                              module=state height=89 txs=0 appHash=0B54C4DB1A0DACB1EEDCD662B221C048C826D309FD2A2F31FF26BAE8D2D7D8D7
I[2020-07-29|17:34:09.381] Executed block                               module=state height=90 validTxs=0 invalidTxs=0
I[2020-07-29|17:34:09.383] Committed state                              module=state height=90 txs=0 appHash=75FD1EE834F0669D5E717C812F36B21D5F20B3CCBB45E8B8D415CB9C4513DE51
I[2020-07-29|17:34:14.700] Executed block                               module=state height=91 validTxs=0 invalidTxs=0
```

tip

You can disregard the `Can't add peer's address to addrbook` warning. As long as the blocks are being produced and the app hashes are the same for each node, there should not be any issues.

Whereas the logs for the REST & RPC server would look like:

```
I[2020-07-30|09:39:17.488] Starting application REST service (chain-id: "7305661614933169792")... module=rest-server
I[2020-07-30|09:39:17.488] Starting RPC HTTP server on 127.0.0.1:8545   module=rest-server
...
```

**Follow Logs**[**​**](broken://pages/EWknQlTHCCgKUGULC74Z)

You can also watch logs as they are produced via Docker with the `--follow` (`-f`) flag, for example:

```
docker logs -f lagomdnode0
```

#### Interact with the Localnet[​](broken://pages/EWknQlTHCCgKUGULC74Z) <a href="#interact-with-the-localnet" id="interact-with-the-localnet"></a>

**Ethereum JSON-RPC & Websocket Ports**[**​**](broken://pages/EWknQlTHCCgKUGULC74Z)

To interact with the testnet via WebSockets or RPC/API, you will send your request to the corresponding ports:

| EVM JSON-RPC | Eth Websocket |
| ------------ | ------------- |
| `8545`       | `8546`        |

You can send a curl command such as:

```
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1}' -H "Content-Type: application/json" 192.162.10.1:8545
```

tip

The IP address will be the public IP of the docker container.

Additional instructions on how to interact with the WebSocket can be found on the events documentation.

#### Keys & Accounts[​](broken://pages/EWknQlTHCCgKUGULC74Z) <a href="#keys--accounts" id="keys--accounts"></a>

To interact with lagom`d` and start querying state or creating txs, you use the lagom`d` directory of any given node as your `home`, for example:

```
lagomd keys list --home ./build/node0/lagomd
```

Now that accounts exists, you may create new accounts and send those accounts funds!

tip

**Note**: Each node's seed is located at `./build/nodeN/lagomd/key_seed.json` and can be restored to the CLI using the `lagomd keys add --restore` command

#### Special Binaries[​](broken://pages/EWknQlTHCCgKUGULC74Z) <a href="#special-binaries" id="special-binaries"></a>

If you have multiple binaries with different names, you can specify which one to run with the BINARY environment variable. The path of the binary is relative to the attached volume. For example:

```
# Run with custom binary
BINARY=lagom make localnet-start
```


# Alternative Databases

To use a different database than the default one (levelDB), you may need to build the `lagomd` binary manually with specific flags and configurations.

Learn about the different options supported.

### Prerequisites[​](broken://pages/4SOTfJoxZqCyZ3B6VMWP) <a href="#prerequisites" id="prerequisites"></a>

* Golang version `>=1.22.2` ([installation guide](https://go.dev/doc/install))
* Source code of the desired `lagomd` version. For example, if you want to use `v19.0.0`, execute the following command to download only the necessary code:

  ```
  git clone -b v19.0.0 --single-branch https://github.com/lagomchain/lagomchain
  ```

### Pebble DB[​](broken://pages/4SOTfJoxZqCyZ3B6VMWP) <a href="#pebble-db" id="pebble-db"></a>

#### Install `lagomd` binary from source[​](broken://pages/4SOTfJoxZqCyZ3B6VMWP) <a href="#install-evmosd-binary-from-source" id="install-evmosd-binary-from-source"></a>

```
# compile and install the binary
COSMOS_BUILD_OPTIONS=pebbledb make install
```

Check the binary version has the `-pebbledb` suffix

```
❯ lagomd version
v19.0.0-pebbledb
```

danger

NOTE: if using a version **before v19**, you'll need to replace the cometbft-db dependency before installing the binary:

```
# cd into the directory where you have the LagomChain protocol source code
cd lagom

# replace the cometbft-db dependency
go mod edit -replace github.com/cometbft/cometbft-db=github.com/notional-labs/cometbft-db@pebble
go mod tidy

# compile and install the binary
go install -ldflags "-w -s -X github.com/cosmos/cosmos-sdk/types.DBBackend=pebbledb \
 -X github.com/cosmos/cosmos-sdk/version.Version=$(git describe --tags)-pebbledb \
 -X github.com/cosmos/cosmos-sdk/version.Commit=$(git log -1 --format='%H')" -tags pebbledb ./...
```

#### Update configuration[​](broken://pages/4SOTfJoxZqCyZ3B6VMWP) <a href="#update-configuration" id="update-configuration"></a>

Make sure to update the `db_backend` configuration parameter in the `config.toml`:

#### Build docker image[​](broken://pages/4SOTfJoxZqCyZ3B6VMWP) <a href="#build-docker-image" id="build-docker-image"></a>

To build a docker image with the `lagomd` binary compiled to use pebbledb, run the following command:

```
make build-docker-pebbledb
```

### Rocks DB[​](broken://pages/4SOTfJoxZqCyZ3B6VMWP) <a href="#rocks-db" id="rocks-db"></a>

To set up a node with rocksDB, you need to install the [corresponding library](https://github.com/facebook/rocksdb) and related dependencies.

The installation process described below applies to Ubuntu OS. For other operating systems, refer to the [rocksdb installation guide](https://github.com/facebook/rocksdb/blob/v9.2.1/INSTALL.md).

#### Install dependencies[​](broken://pages/4SOTfJoxZqCyZ3B6VMWP) <a href="#install-dependencies" id="install-dependencies"></a>

* `gflags`

  ```
  sudo apt-get install libgflags-dev
  ```

  If this doesn't work and you're using Ubuntu, [here's a nice tutorial](https://askubuntu.com/questions/312173/installing-gflags-12-04)
* `snappy`

  ```
  sudo apt-get install libsnappy-dev
  ```
* `zlib`

  ```
  sudo apt-get install zlib1g-dev
  ```
* `bzip2`

  ```
  sudo apt-get install libbz2-dev
  ```
* `lz4`

  ```
  sudo apt-get install liblz4-dev
  ```
* `zstandard`

  ```
  sudo apt-get install libzstd-dev
  ```
* `gcc` >= 7

  ```
  sudo apt-get install build-essential
  ```
* `clang` >= 5

  ```
  sudo apt-get install clang
  ```

Install all dependencies at once with this command:

```
sudo apt-get install libgflags-dev libsnappy-dev zlib1g-dev libbz2-dev liblz4-dev libzstd-dev build-essential clang
```

#### Install `librocksdb`[​](broken://pages/4SOTfJoxZqCyZ3B6VMWP) <a href="#install-librocksdb" id="install-librocksdb"></a>

To install this library, you will need to clone the [rocksdb repository](https://github.com/facebook/rocksdb).

Clone only the required version of it. To find out which is the required version, check the tag of the `grocksdb` dependency in the `go.mod` file of the lagomchain repository. For example, if the `go.mod` has:

```
github.com/linxGnu/grocksdb v1.9.2
```

You should check in the [grocksdb repo](https://github.com/linxGnu/grocksdb/releases), which RocksDB version is supported in the `v1.9.2` tag. In this case, `v1.9.2` supports RocksDB `v9.2.1`.

To install `librocksdb v9.2.1`, run the following commands:

```
# remove rocksdb repo from your machine if you have a previous version installed
rm -rf rocksdb

# download the source code of the desired version
git clone -b v9.2.1 --single-branch https://github.com/facebook/rocksdb

# cd into the directory where the source code was downloaded
cd rocksdb

# take note of the path where you have the rocksdb code
# you will need this for building the lagomd binary
PATH_TO_ROCKSDB=$(pwd)

# install librocksdb
PORTABLE=1 WITH_JNI=0 WITH_BENCHMARK_TOOLS=0 \
WITH_TESTS=1 WITH_TOOLS=0 WITH_CORE_TOOLS=1 \
WITH_BZ2=1 WITH_LZ4=1 WITH_SNAPPY=1 WITH_ZLIB=1 \
WITH_ZSTD=1 WITH_GFLAGS=0 USE_RTTI=1 \
make static_lib
```

The installation process may take several minutes.

#### Install `lagomd` binary[​](broken://pages/4SOTfJoxZqCyZ3B6VMWP) <a href="#install-evmosd-binary" id="install-evmosd-binary"></a>

Once this completes, install the `lagomd` binary with rocksDB support

```
# cd into the directory where the lagomchain source code is
cd lagomchain

# compile and install the binary
# IMPORTANT: make sure to have the PATH_TO_ROCKSDB with the path where you cloned the rocksdb repository
CGO_CFLAGS="-I"$PATH_TO_ROCKSDB"/include" \
CGO_LDFLAGS="-L"$PATH_TO_ROCKSDB" -lrocksdb -lstdc++ -lm -lz -lbz2 -lsnappy -llz4 -lzstd" \
COSMOS_BUILD_OPTIONS=rocksdb \
make install
```

If getting the errors related to dynamic loading of shared libraries:

```
.../rocksdb/env/env_posix.cc:108: undefined reference to `dlclose'
.../rocksdb/env/env_posix.cc:113: undefined reference to `dlsym'
...
```

Retry the command adding the dynamic linker library in your executable, the `-ldl` flag in the `CGO_LDFLAGS`:

```
CGO_ENABLED=1 \
CGO_CFLAGS="-I"$PATH_TO_ROCKSDB"/include" \
CGO_LDFLAGS="-L"$PATH_TO_ROCKSDB" -lrocksdb -lstdc++ -lm -lz -lbz2 -lsnappy -llz4 -lzstd -ldl" \
COSMOS_BUILD_OPTIONS=rocksdb \
make install
```

Check the binary version has the `-rocksdb` suffix

```
❯ lagomd version
v19.0.0-rocksdb
```

#### Update database configuration[​](broken://pages/4SOTfJoxZqCyZ3B6VMWP) <a href="#update-database-configuration" id="update-database-configuration"></a>

Before starting the process, make sure to update the `db_backend` configuration parameter in the `config.toml`:

### Version DB & MemIAVL[​](broken://pages/4SOTfJoxZqCyZ3B6VMWP) <a href="#version-db--memiavl" id="version-db--memiavl"></a>

#### Version DB[​](broken://pages/4SOTfJoxZqCyZ3B6VMWP) <a href="#version-db" id="version-db"></a>

VersionDB is a solution developed by the Cronos team to address the size of the IAVL database. For more information about it, refer to these resources:

* [VersionDB documentation](https://github.com/crypto-org-chain/cronos/tree/main/versiondb)
* [Blog post](https://blog.cronos.org/p/optimising-cronos-node-storage-with)

**Prerequisites**[**​**](broken://pages/4SOTfJoxZqCyZ3B6VMWP)

* `lagomd` binary with `librocksdb`. Refer to [the previous section](#rocks-db) for the procedure on how to build this binary.

**Update configuration**[**​**](broken://pages/4SOTfJoxZqCyZ3B6VMWP)

To enable versionDB, add `versiondb` to the list of `store.streamers` in `app.toml`:

```
[store]
streamers = ["versiondb"]
```

When starting the node with this configuration, you should see a `version.db` file in the `data` directory.

**Migration**[**​**](broken://pages/4SOTfJoxZqCyZ3B6VMWP)

If you have an existing database and want to migrate this data to versionDB, follow the [migration guide](https://github.com/crypto-org-chain/cronos/wiki/VersionDB-Migration).

#### MemIAVL[​](broken://pages/4SOTfJoxZqCyZ3B6VMWP) <a href="#memiavl" id="memiavl"></a>

MemIAVL is a solution developed by the Cronos team to address performance issues of the current IAVL implementation ([benchmarks here](https://github.com/crypto-org-chain/cronos/wiki/MemIAVL-Benchmark)). For more information about it, check [the documentation](https://github.com/crypto-org-chain/cronos/wiki/MemIAVL).

**Prerequisites**[**​**](broken://pages/4SOTfJoxZqCyZ3B6VMWP)

* `lagomd` binary with `librocksdb`. Refer to [the RocksDB section](broken://pages/4SOTfJoxZqCyZ3B6VMWP) for the procedure on how to build this binary.

**Update configuration**[**​**](broken://pages/4SOTfJoxZqCyZ3B6VMWP)

To enable MemIAVL turn on the `memiavl.enable` config item in `app.toml`. MemIAVL only supports pruned node, the default configuration (`memiavl.snapshot-keep-recent=0`) is equivalent to `pruning=everything`. To support historical grpc query services, you should enable versionDB together with it. If you need to support very old merkle proof generations, don't use memIAVL.

The default MemIAVL section in `app.toml`:

```
[memiavl]

# Enable defines if the memiavl should be enabled.
enable = false

# ZeroCopy defines if the memiavl should return slices pointing to mmap-ed buffers directly (zero-copy),
# the zero-copied slices must not be retained beyond current block's execution.
zero-copy = false

# AsyncCommitBuffer defines the size of asynchronous commit queue, this greatly improve block catching-up
# performance, -1 means synchronous commit.
async-commit-buffer = 0

# SnapshotKeepRecent defines what many old snapshots (excluding the latest one) to keep after new snapshots are taken.
snapshot-keep-recent = 0

# SnapshotInterval defines the block interval the memiavl snapshot is taken, default to 1000.
snapshot-interval = 1000

# CacheSize defines the size of the cache for each memiavl store, default to 1000.
cache-size = 1000
```

When starting the node with this configuration, you should see a `memiavl.db` file in the `data` directory.


# CLI Commands

### CLI Flags[​](broken://pages/eAbPajhZyy1pJWjnDly8) <a href="#cli-flags" id="cli-flags"></a>

A list of commonly used flags of `lagomd` is listed below:

| Option              | Description                                   | Type            | Default Value                                                                                                     |
| ------------------- | --------------------------------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------- |
| `--chain-id`        | Full Chain ID                                 | `string`        | `""`                                                                                                              |
| `--home`            | Directory for config and data                 | `string`        | `~/.lagomd`                                                                                                       |
| `--keyring-backend` | Select keyring's backend                      | `string`        | `"os"`                                                                                                            |
| `--output`          | Output format                                 | `string`        | `"text"`                                                                                                          |
| `--node`            | Tendermint RPC interface                      | `<host>:<port>` | <p><code>"</code>tcp\://188.214.128.66:26657<code>"</code><br>or<br><code>"</code>tcp\://46.166.165.25:26657"</p> |
| `--from`            | Name or address of account with which to sign | `string`        | `""`                                                                                                              |

### Command list[​](broken://pages/eAbPajhZyy1pJWjnDly8) <a href="#command-list" id="command-list"></a>

A list of commonly used `lagomd` commands. You can obtain the full list by using the `lagomd -h` command.

| Command            | Description                                                     | Subcommands (example)                                                     |
| ------------------ | --------------------------------------------------------------- | ------------------------------------------------------------------------- |
| `keys`             | Keys management                                                 | `list`, `show`, `add`, `add --recover`, `delete`                          |
| `tx`               | Transactions subcommands                                        | `bank send`, `ibc-transfer transfer`, `distribution withdraw-all-rewards` |
| `query`            | Query subcommands                                               | `bank balance`, `staking validators`, `gov proposals`                     |
| `tendermint`       | Tendermint subcommands                                          | `show-address`, `show-node-id`, `version`                                 |
| `config`           | Client configuration                                            |                                                                           |
| `init`             | Initialize full node                                            |                                                                           |
| `start`            | Run full node                                                   |                                                                           |
| `version`          | LagomChain version                                              |                                                                           |
| `validate-genesis` | Validates the genesis file                                      |                                                                           |
| `status`           | Query remote node for status                                    |                                                                           |
| `block`            | Query a specific block persisted in the db (defaults to latest) |                                                                           |


# Drafting a proposal

The `draft-proposal` command in the LagomChain CLI is part of the Cosmos-SDK governance module and is used to generate a draft proposal JSON file. This generated proposal JSON file contains a skeleton structure for a governance proposal.

### Command Syntax[​](broken://pages/43EhCd8DdBQGjNdBYsPb) <a href="#command-syntax" id="command-syntax"></a>

```
lagomd tx gov draft-proposal [flags]
```

### Usage[​](broken://pages/43EhCd8DdBQGjNdBYsPb) <a href="#usage" id="usage"></a>

To create a draft proposal using the `lagomd tx gov draft-proposal` command, follow these steps:

1. Run the command

   ```
   lagomd tx gov draft-proposal
   ```
2. The command will present a list of proposal types for selection. The available options typically include:

   ```
   Use the arrow keys to navigate: ↓ ↑ → ← 
    ? Select proposal type: 
        text
        community-pool-spend
        software-upgrade
        cancel-software-upgrade
      ▸ other
   ```

   In case you don't find the required proposal (e.g. update params), choose the `other` option. It will show an extensive list of the supported messages:

   ```
   ✔ other
   Use the arrow keys to navigate: ↓ ↑ → ← 
   ? Select proposal message type:: 
   ↑   /lagom.erc20.v1.MsgConvertERC20
     ▸ /lagom.erc20.v1.MsgUpdateParams
       /lagom.vesting.v2.MsgFundVestingAccount
       /lagom.vesting.v2.MsgUpdateVestingFunder
   ↓   /lagom.inflation.v1.MsgUpdateParams
   ```
3. Follow the on-screen instructions to complete the process. The command will generate a JSON file that you can use for your proposal.
4. Once the JSON file is generated, you can make any necessary changes to the proposal information within the file.
5. Finally, use the generated JSON file as input when submitting your proposal using the `lagomd tx gov submit-proposal` command.

   ```
   lagomd tx gov submit-proposal draft_proposal.json [flags]
   ```


# Concepts


# Accounts

Crypto Wallets (or Accounts) can be created and represented in unique ways on different blockchains. For developers who interface with account types on LagomChain, e.g. during wallet integration on their dApp frontend, it is therefore important to understand that accounts on LagomChain are implemented to be compatible with Ethereum type addresses.

### Prerequisite Readings[​](broken://pages/EbRWzpSy6YIZvHYU7PsZ) <a href="#prerequisite-readings" id="prerequisite-readings"></a>

* [Cosmos SDK Accounts](https://docs.cosmos.network/main/learn/beginner/accounts)
* [Ethereum Accounts](https://ethereum.org/en/whitepaper/#ethereum-accounts)

### Creating Accounts[​](broken://pages/EbRWzpSy6YIZvHYU7PsZ) <a href="#creating-accounts" id="creating-accounts"></a>

To create one account you can either create a private key, a keystore file (a private key protected by a password), or a mnemonic phrase (a string of words that can access multiple private keys).

Aside from having different security features, the biggest difference between each of these is that a private key or keystore file only creates one account. Creating a mnemonic phrase gives you control of many accounts, all accessible with that same phrase.

Cosmos blockchains, like LagomChain, support creating accounts with mnemonic phrases, otherwise known as [hierarchical deterministic key generation](https://github.com/confio/cosmos-hd-key-derivation-spec) (HD keys). This allows the user to create accounts on multiple blockchains without having to manage multiple secrets.

HD keys generate addresses by taking the mnemonic phrase and combining it with a piece of information called a [derivation path](https://learnmeabitcoin.com/technical/derivation-paths). Blockchains can differ in which derivation path they support. To access all accounts from an mnemonic phrase on a blockchain, it is therefore important to use that blockchain's specific derivation path.

### Representing Accounts[​](broken://pages/EbRWzpSy6YIZvHYU7PsZ) <a href="#representing-accounts" id="representing-accounts"></a>

The terms "account" and "address" are often used interchangeably to describe crypto wallets. In the Cosmos SDK, an account designates a pair of public key (PubKey) and private key (PrivKey). The derivation path defines what the private key, public key, and address would be.

The PubKey can be derived to generate various addresses in different formats, which are used to identify users (among other parties) in the application. A common address form for Cosmos chains is the bech32 format (e.g. lagomchain`1...`). Addresses are also associated with messages to identify the sender of the message.

The PrivKey is used to generate digital signatures to prove that an address associated with the PrivKey approved of a given message. The proof is performed by applying a cryptographic scheme to the PrivKey, known as Elliptic Curve Digital Signature Algorithm (ECDSA), to generate a PubKey that is compared with the address in the message.

### LagomChain Accounts[​](broken://pages/EbRWzpSy6YIZvHYU7PsZ) <a href="#evmos-accounts" id="evmos-accounts"></a>

LagomChain defines its own custom `Account` type to implement a HD wallet that is compatible with Ethereum type addresses. It uses Ethereum's ECDSA secp256k1 curve for keys (`eth_secp265k1`) and satisfies the [EIP84](https://github.com/ethereum/EIPs/issues/84) for full [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) paths. This cryptographic curve is not to be confused with [Bitcoin's ECDSA secp256k1](https://en.bitcoin.it/wiki/Secp256k1) curve.

The root HD path for LagomChain-based accounts is `m/44'/60'/0'/0`. LagomChain uses the Coin type `60` to support Ethereum type accounts, unlike many other Cosmos chains that use Coin type `118` ([list of coin types](https://github.com/satoshilabs/slips/blob/master/slip-0044.md))

The custom LagomChain EthAccount satisfies the `AccountI` interface from the Cosmos SDK auth module and includes additional fields that are required for Ethereum type addresses:

```
// EthAccountI represents the interface of an EVM compatible account
type EthAccountI interface {
    authtypes.AccountI
    // EthAddress returns the ethereum Address representation of the AccAddress
    EthAddress() common.Address
    // CodeHash is the keccak256 hash of the contract code (if any)
    GetCodeHash() common.Hash
    // SetCodeHash sets the code hash to the account fields
    SetCodeHash(code common.Hash) error
    // Type returns the type of Ethereum Account (EOA or Contract)
    Type() int8
}
```

For more information on Ethereum accounts head over to the [x/evm module](/modules/evm#concepts).

#### Addresses and Public Keys[​](broken://pages/EbRWzpSy6YIZvHYU7PsZ) <a href="#addresses-and-public-keys" id="addresses-and-public-keys"></a>

[BIP-0173](https://github.com/satoshilabs/slips/blob/master/slip-0173.md) defines a new format for segregated witness output addresses that contains a human-readable part that identifies the Bech32 usage. LagomChain uses the following HRP (human readable prefix) as the base HRP:

| Network    | Mainnet    | Testnet    |
| ---------- | ---------- | ---------- |
| LagomChain | lagomchain | lagomchain |

There are 3 main types of HRP for the `Addresses`/`PubKeys` available by default on LagomChain:

* Addresses and Keys for **accounts**, which identify users (e.g. the sender of a `message`). They are derived using the **`eth_secp256k1`** curve.
* Addresses and Keys for **validator operators**, which identify the operators of validators. They are derived using the **`eth_secp256k1`** curve.
* Addresses and Keys for **consensus nodes**, which identify the validator nodes participating in consensus. They are derived using the **`ed25519`** curve.

|                    | Address bech32 Prefix | Pubkey bech32 Prefix   | Curve           | Address byte length | Pubkey byte length |
| ------------------ | --------------------- | ---------------------- | --------------- | ------------------- | ------------------ |
| Accounts           | lagomchain            | lagomchain`pub`        | `eth_secp256k1` | `20`                | `33` (compressed)  |
| Validator Operator | lagomchain`valoper`   | lagomchain`valoperpub` | `eth_secp256k1` | `20`                | `33` (compressed)  |
| Consensus Nodes    | lagomchain`valcons`   | lagomchain`valconspub` | `ed25519`       | `20`                | `32`               |

#### Address formats for clients[​](broken://pages/EbRWzpSy6YIZvHYU7PsZ) <a href="#address-formats-for-clients" id="address-formats-for-clients"></a>

`EthAccount` can be represented in both [Bech32](https://en.bitcoin.it/wiki/Bech32) (lagomchain`1...`) and hex (`0x...`) formats for Ethereum's Web3 tooling compatibility.

The Bech32 format is the default format for Cosmos-SDK queries and transactions through CLI and REST clients. The hex format on the other hand, is the Ethereum `common.Address` representation of a Cosmos `sdk.AccAddress`.

* **Address (Bech32)**: lagomchain`1z3t55m0l9h0eupuz3dp5t5cypyv674jj7mz2jw`
* **Address (**[**EIP55**](https://eips.ethereum.org/EIPS/eip-55) **Hex)**: `0x91defC7fE5603DFA8CC9B655cF5772459BF10c6f`
* **Compressed Public Key**: `{"@type":"/ethermint.crypto.v1.ethsecp256k1.PubKey","key":"AsV5oddeB+hkByIJo/4lZiVUgXTzNfBPKC73cZ4K1YD2"}`

#### Address conversion[​](broken://pages/EbRWzpSy6YIZvHYU7PsZ) <a href="#address-conversion" id="address-conversion"></a>

The `lagomd debug addr <address>` can be used to convert an address between hex and bech32 formats. For example:

Bech32

```
 $ lagomd debug addr lagom1z3t55m0l9h0eupuz3dp5t5cypyv674jj7mz2jw
  Address: [20 87 74 109 255 45 223 158 7 130 139 67 69 211 4 9 25 175 86 82]
  Address (hex): 14574A6DFF2DDF9E07828B4345D3040919AF5652
  Bech32 Acc: lagom1z3t55m0l9h0eupuz3dp5t5cypyv674jj7mz2jw
  Bech32 Val: lagomvaloper1z3t55m0l9h0eupuz3dp5t5cypyv674jjn4d6nn
```

Hex

```
 $ lagomd debug addr 14574A6DFF2DDF9E07828B4345D3040919AF5652
  Address: [20 87 74 109 255 45 223 158 7 130 139 67 69 211 4 9 25 175 86 82]
  Address (hex): 14574A6DFF2DDF9E07828B4345D3040919AF5652
  Bech32 Acc: lagom1z3t55m0l9h0eupuz3dp5t5cypyv674jj7mz2jw
  Bech32 Val: lagomvaloper1z3t55m0l9h0eupuz3dp5t5cypyv674jjn4d6nn
```

#### Key output[​](broken://pages/EbRWzpSy6YIZvHYU7PsZ) <a href="#key-output" id="key-output"></a>

tip

The Cosmos SDK Keyring output (i.e `lagomd keys`) only supports addresses and public keys in Bech32 format.

We can use the `keys show` command of `lagomd` with the flag `--bech <type> (acc|val|cons)` to obtain the addresses and keys as mentioned above,

Accounts

```
 $ lagomd keys show dev0 --bech acc
- name: dev0
  type: local
  address: lagom1z3t55m0l9h0eupuz3dp5t5cypyv674jj7mz2jw
  pubkey: '{"@type":"/ethermint.crypto.v1.ethsecp256k1.PubKey","key":"AsV5oddeB+hkByIJo/4lZiVUgXTzNfBPKC73cZ4K1YD2"}'
  mnemonic: ""
```

Validator

```
 $ lagomd keys show dev0 --bech val
- name: dev0
  type: local
  address: lagomvaloper1z3t55m0l9h0eupuz3dp5t5cypyv674jjn4d6nn
  pubkey: '{"@type":"/ethermint.crypto.v1.ethsecp256k1.PubKey","key":"AsV5oddeB+hkByIJo/4lZiVUgXTzNfBPKC73cZ4K1YD2"}'
  mnemonic: ""
```

Consensus

```
 $ lagomd keys show dev0 --bech cons
- name: dev0
  type: local
  address: lagomvalcons1rllqa5d97n6zyjhy6cnscc7zu30zjn3f7wyj2n
  pubkey: '{"@type":"/ethermint.crypto.v1.ethsecp256k1.PubKey","key":"A/fVLgIqiLykFQxum96JkSOoTemrXD0tFaFQ1B0cpB2c"}'
  mnemonic: ""
```

### Querying an Account[​](broken://pages/EbRWzpSy6YIZvHYU7PsZ) <a href="#querying-an-account" id="querying-an-account"></a>

You can query an account address using the CLI, gRPC or

#### Command Line Interface[​](broken://pages/EbRWzpSy6YIZvHYU7PsZ) <a href="#command-line-interface" id="command-line-interface"></a>

```
# NOTE: the --output (-o) flag will define the output format in JSON or YAML (text)
lagomd q auth account $(lagomd keys show dev0 -a) -o text

'@type': /ethermint.types.v1.EthAccount
base_account:
account_number: "0"
address: lagom1z3t55m0l9h0eupuz3dp5t5cypyv674jj7mz2jw
pub_key:
  '@type': /ethermint.crypto.v1.ethsecp256k1.PubKey
  key: AsV5oddeB+hkByIJo/4lZiVUgXTzNfBPKC73cZ4K1YD2
sequence: "1"
code_hash: 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
```

#### Cosmos gRPC and REST[​](broken://pages/EbRWzpSy6YIZvHYU7PsZ) <a href="#cosmos-grpc-and-rest" id="cosmos-grpc-and-rest"></a>

```
# GET /cosmos/auth/v1beta1/accounts/{address}
curl -X GET "http://localhost:10337/cosmos/auth/v1beta1/accounts/lagom14au322k9munkmx5wrchz9q30juf5wjgz2cfqku" -H "accept: application/json"
```

#### JSON-RPC[​](broken://pages/EbRWzpSy6YIZvHYU7PsZ) <a href="#json-rpc" id="json-rpc"></a>

To retrieve the Ethereum hex address using Web3, use the JSON-RPC `eth_accounts` or `personal_listAccounts` endpoints:

```
# query against a local node
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1}' -H "Content-Type: application/json" http://localhost:8545

curl -X POST --data '{"jsonrpc":"2.0","method":"personal_listAccounts","params":[],"id":1}' -H "Content-Type: application/json" http://localhost:8545
```


# EIP-155: Replay Protection

[EIP-155](https://eips.ethereum.org/EIPS/eip-155) is an Ethereum Improvement Proposal that introduces replay protection for transactions by including the chain ID in the signed transaction data. This prevents replay attacks, where a valid transaction from one network is rebroadcasted on another network without the sender’s consent.

This was necessary, because Ethereum-based transactions rely on the Hex representation of addresses, which are not necessarily unique to a given network. This means that single signed transaction could be valid on multiple networks, as the same addresses are involved e.g. in a token transfer. This holds the potential for exploits and is addressed by enforcing the EIP-155 replay protection.

Cosmos SDK-based blockchains use Bech32 representations for addresses, which contain a unique prefix per chain. This means, that for Cosmos transactions, replay protection is inherently present as addresses of a given chain are not valid addresses on other chains. However, as LagomChain also accepts EVM transactions, handling only those transactions that conform to EIP-155 becomes a requirement again.

This requires special care to be taken when selecting an EIP-155 compliant [chain ID](/concepts/chain-id) to avoid duplication amongst chains.

### Configuring Replay Protection[​](broken://pages/fubw0AiV3zvxDzf0ACoT) <a href="#configuring-replay-protection" id="configuring-replay-protection"></a>

By default, replay protection is enabled on any LagomChain node. There are two distinct steps required to accept unprotected transactions, i.e. those that do not contain the chain ID in the signed transaction data:

1. **Disable Module Parameter**: The [EVM module](/modules/evm) contains a governance controlled parameter, that globally dictates if unprotected transactions are supported. This has to be disabled via a governance vote or by setting the `allow_unprotected_txs` field to `true` in the genesis of a [local node](/lagomchain-cli/single-node).
2. **Adjust Node Configuration**: When the global parameter is set accordingly, each node operator has the option to individually opt into allowing unprotected transactions to be sent to their nodes. This configuration is explained in the section on node configuration.


# Chain ID

A Chain ID is a unique identifier assigned to a blockchain network. It helps to:

* Differentiate networks (Mainnet, Testnet, Devnet).
* Ensure transactions are broadcasted to the correct network.
* Prevent replay attacks by including the Chain ID in signed transactions (EIP-155 compliance).

***

### **LagomChain's Chain ID Format**

LagomChain follows a structured **Chain ID format**, which includes:

1. **Identifier** – Defines the blockchain name.
2. **EIP-155 Number** – Immutable replay protection number.
3. **Version Number** – Represents the current network version and is incremented upon upgrades or forks.

#### **Chain ID Format in Genesis**

```
{identifier}_{EIP155}-{version}
```

Exampl&#x65;**:**

```
lagom_986-1
```

***

### **Official Chain IDs**

#### **Mainnet:**

```
lagom_986-1
```

#### **Testnet:**

```
lagom_testnet-986-1
```

Certain upgrades may require an increase in the version number, but not all protocol changes necessitate a Chain ID change.

***

### **The Chain Identifier in LagomChain**

Every blockchain must have a unique chain-id defined in `genesis.json`.\
LagomChain’s Chain ID is used in:

* EIP-155 replay protection to prevent cross-chain transaction replays.
* Cosmos SDK standardization for smooth chain upgrades.
* Tendermint consensus rules, ensuring network integrity.

#### **Example Configuration in `genesis.json`**

```json
{
  "chain_id": "lagom_986-1"
}
```

***

### **Chain ID Upgrade Process**

When upgrading the LagomChain network, the version number must be incremented to avoid consensus issues.

#### Example of Chain ID Upgrad&#x65;**:**

| **Previous Chain ID** | **Upgraded Chain ID** | **Reason for Change**                       |
| --------------------- | --------------------- | ------------------------------------------- |
| `lagom_986-1`         | `lagom_986-2`         | Major upgrade requiring new consensus rules |
| `lagom_testnet-986-1` | `lagom_testnet-986-2` | Testnet upgrade for new feature testing     |

***

### **Why Chain ID Matters**

#### **1. Ensures Network Uniqueness**

Each blockchain network must have a distinct Chain ID to differentiate it from others.

#### **2. Prevents Replay Attacks (EIP-155 Compliance)**

Transactions signed on one network cannot be replayed on another due to the Chain ID being embedded in the transaction data.

#### **3. Enables Seamless Upgrades**

By following the structured Chain ID format, LagomChain ensures smooth protocol upgrades without breaking consensus.


# Encoding

Encoding refers to the process of converting data from one format to another for security, efficiency, and compatibility. In blockchain networks, encoding is essential for:

* Secure data storage and transmission
* Efficient serialization of transactions and blocks
* Interoperability with different blockchain protocols

***

### Encoding Formats in LagomChain

#### 1. Protocol Buffers (Protobuf) – Cosmos SDK Standard

With the Cosmos Stargate release, Protobuf is the primary encoding format for:

* Client serialization (transactions, queries)
* State serialization (genesis files, network parameters)

Protobuf Advantages:

* Smaller and faster than JSON
* Language-agnostic and supports multiple programming languages
* Highly extensible for future upgrades

All EVM module types in LagomChain (such as transaction messages and query services) are implemented as protocol buffer messages.

***

#### 2. Recursive Length Prefix (RLP) – Ethereum Compatibility

LagomChain supports Recursive Length Prefix (RLP), the primary encoding format in Ethereum’s execution layer.

RLP is used for:

* Serializing Ethereum transactions
* Encoding Merkle tree structures
* Hash verification and signing

Ethereum transactions are signed using the RLP hash of the transaction data. Blocks are also identified by the RLP hash of their headers.

RLP Encoding Rules:

* Integers are represented in big-endian format, without leading zeroes.
* A single byte (0x00 to 0x7F) is encoded as itself.
* Strings shorter than 55 bytes are prefixed with a length byte (0x80 + length).
* Longer strings and lists require additional length encoding.

Although Ethereum 2.0 replaces RLP with Simple Serialize (SSZ) for its consensus layer, RLP remains the standard for Ethereum transactions and execution clients.

***

#### 3. Amino – Legacy Cosmos SDK Encoding

The Cosmos SDK originally used Amino encoding, which remains supported for:

* Backwards compatibility
* Client encoding and Ledger device signing

However, LagomChain does not use Amino for EVM transactions.

***

### RLP in LagomChain’s EVM Module

LagomChain encodes EVM transactions (`MsgEthereumTx`) using RLP to ensure Ethereum compatibility.

RLP Encoding for Ethereum Transactions:

* Converts the transaction structure to Ethereum’s format.
* Marshals the transaction data using RLP serialization.

Example: Encoding an Ethereum Transaction in LagomChain’s EVM Module (Go Code)

```go
// TxEncoder overwrites sdk.TxEncoder to support MsgEthereumTx
func (g txConfig) TxEncoder() sdk.TxEncoder {
  return func(tx sdk.Tx) ([]byte, error) {
    msg, ok := tx.(*evmtypes.MsgEthereumTx)
    if ok {
      return msg.AsTransaction().MarshalBinary()
    }
    return g.TxConfig.TxEncoder()(tx)
  }
}
```

**Example: Decoding an Ethereum Transaction in LagomChain’s EVM Module (Go Code)**

```go
// TxDecoder overwrites sdk.TxDecoder to support MsgEthereumTx
func (g txConfig) TxDecoder() sdk.TxDecoder {
  return func(txBytes []byte) (sdk.Tx, error) {
    tx := &ethtypes.Transaction{}
    err := tx.UnmarshalBinary(txBytes)
    if err == nil {
      msg := &evmtypes.MsgEthereumTx{}
      msg.FromEthereumTx(tx)
      return msg, nil
    }
    return g.TxConfig.TxDecoder()(txBytes)
  }
}
```

By integrating RLP encoding/decoding, LagomChain ensures that:

* Transactions are formatted correctly for Ethereum clients and tools.
* JSON-RPC messages conform to Ethereum’s expected structure.
* The network remains fully EVM-compatible while operating on Cosmos SDK.


# Gas and Fees

Users need to pay a fee to submit transactions on the LagomChain network. As fees are handled differently on Ethereum and Cosmos, it is important to understand how the LagomChain blockchain implements an Ethereum-type fee calculation, that is compatible with the Cosmos SDK.

Therefore this overview explains the basics of gas calculation, how to provide fees for transactions and how the Ethereum-type fee calculation uses a fee market (EIP-1559) for prioritizing transactions.

### Prerequisite Readings[​](broken://pages/x9ylZ9pGPP6OC7U1Cvf2) <a href="#prerequisite-readings" id="prerequisite-readings"></a>

* [Cosmos SDK Gas](https://docs.cosmos.network/main/learn/beginner/gas-fees.html)
* [Ethereum Gas](https://ethereum.org/en/developers/docs/gas/)

### Basics[​](broken://pages/x9ylZ9pGPP6OC7U1Cvf2) <a href="#basics" id="basics"></a>

#### Why do Transactions Need Fees?[​](broken://pages/x9ylZ9pGPP6OC7U1Cvf2) <a href="#why-do-transactions-need-fees" id="why-do-transactions-need-fees"></a>

If anyone can submit transactions to a network at no cost, the network can be overrun by a handful of actors sending large numbers of fraudulent transactions to clog up the network and stop it from working.

The solution to this is a concept called “gas," which is a resource consumed throughout transaction execution. In practice, a small amount of gas is spent on each step of code execution, thus effectively charging for use of a validator’s resources and preventing malicious actors from halting a network at will.

#### What is Gas?[​](broken://pages/x9ylZ9pGPP6OC7U1Cvf2) <a href="#what-is-gas" id="what-is-gas"></a>

In general, gas is a unit that measures the computational intensity of a particular transaction — in other words, how much work would be required to evaluate and perform the job. Complex, multi-step transactions, such as a Cosmos transaction that delegates to a dozen validators, require more gas than simple, single-step transactions, such as a Cosmos transaction to send tokens to another address.

When referring to a transaction, “gas” refers to the total quantity of gas required for the transaction. For example, a transaction may require 300,000 units of gas to be executed.

Gas can be thought of as electricity (kWh) within a house or factory, or fuel for automobiles. The idea is that it costs something to get somewhere.

More on Gas:

* [Cosmos Gas Fees](https://docs.cosmos.network/main/learn/beginner/gas-fees)
* [Cosmos Tx Lifecycle](https://docs.cosmos.network/main/learn/beginner/tx-lifecycle.html)
* [Ethereum Gas](https://ethereum.org/en/developers/docs/gas/)

#### How is Gas Calculated?[​](broken://pages/x9ylZ9pGPP6OC7U1Cvf2) <a href="#how-is-gas-calculated" id="how-is-gas-calculated"></a>

In general, there’s no way to know exactly how much gas a transaction will cost without simply running it. Using the Cosmos SDK, this can be done by [simulating the Tx](https://docs.cosmos.network/main/run-node/txs#simulating-a-transaction). Otherwise, there are ways to estimate the amount of gas a transaction will require, based on the details of the transaction fields, and data. In the case of the EVM, for example, each bytecode operation has a [corresponding amount of gas](https://ethereum.org/en/developers/docs/evm/opcodes/).

More on Gas Calculations:

* [Estimate Gas](https://docs.ethers.org/v5/api/providers/provider/#Provider-estimateGas)
* [Executing EVM Bytecode](https://ethereum.org/en/developers/docs/evm/opcodes/)
* [Simulate a Cosmos SDK Tx](https://docs.cosmos.network/main/run-node/txs#simulating-a-transaction)

#### How does Gas Relate to Fees?[​](broken://pages/x9ylZ9pGPP6OC7U1Cvf2) <a href="#how-does-gas-relate-to-fees" id="how-does-gas-relate-to-fees"></a>

While gas refers to the computational work required for execution, fees refer to the amount of the tokens you actually spend to execute the transaction. They are derived using the following formula:

```
Total Fees = Gas * Gas Price (the price per unit of gas)
```

If “gas” was measured in kWh, the “gas price” would be the rate (in dollars per kWh) determined by your energy provider, and the “fees” would be your bill. Just as with electricity, gas price is liable to fluctuate over a given day, depending on network traffic.

More on Gas vs. Fees:

* [Cosmos Gas and Fees](https://docs.cosmos.network/main/learn/beginner/gas-fees)
* [Ethereum Gas and Fees](https://ethereum.org/en/developers/docs/gas/)

#### How are Fees Handled on Cosmos?[​](broken://pages/x9ylZ9pGPP6OC7U1Cvf2) <a href="#how-are-fees-handled-on-cosmos" id="how-are-fees-handled-on-cosmos"></a>

Gas fees on Cosmos are relatively straightforward. As a user, you specify two fields:

1. A `GasLimit` corresponding to an upper bound on execution gas, defined as `GasWanted`
2. One of `Fees` or `GasPrice`, which will be used to specify or calculate the transaction fees

The node will entirely consume the fees provided, then begin to execute the transaction. If the `GasLimit` is found to be insufficient during execution, the transaction will fail and roll back any changes made, without refunding the fees provided.

Validators for Cosmos SDK-based chains can specify their `min-gas-prices` that they will enforce when selecting transactions to include in blocks. Thus, transactions with insufficient fees will encounter delays or fail outright.

At the beginning of each block, fees from the previous block are [allocated to validators and delegators](https://docs.cosmos.network/main/modules/distribution), after which they can be withdrawn and spent.

#### How are Fees Handled on Ethereum?[​](broken://pages/x9ylZ9pGPP6OC7U1Cvf2) <a href="#how-are-fees-handled-on-ethereum" id="how-are-fees-handled-on-ethereum"></a>

Fees on Ethereum include multiple implementations that were introduced over time.

Originally, a user would specify a `GasPrice` and `GasLimit` within a transaction—much like a Cosmos SDK transaction. A block proposer would receive the entire gas fee from each transaction in the block, and they would select transactions to include accordingly.

With proposal EIP-1559 and the London Hard fork, gas calculation changed. The `GasPrice` from above has now been split into two separate components: a `BaseFee` and `PriorityFee`. The `BaseFee` is calculated automatically based on the block size and is burned once the block is mined. The `PriorityFee` goes to the proposer and represents a tip, or an incentive for a proposer to include the transaction in a block.

```
Gas Price = Base Fee + Priority Fee
```

Within a transaction, users can specify a `max_fee_per_gas` corresponding to the total `GasPrice` and a `max_priority_fee_per_gas` corresponding to a maximum `PriorityFee`, in addition to specifying the `gas_limit` as before. All surplus gas that was not required for execution is refunded to the user.

More on Ethereum Fees:

* [Gas Calculation Docs](https://ethereum.org/en/developers/docs/gas/)
* [Proposal EIP-1559](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md)

### Implementation[​](broken://pages/x9ylZ9pGPP6OC7U1Cvf2) <a href="#implementation" id="implementation"></a>

#### How are Gas and Fees Handled on LagomChain?[​](broken://pages/x9ylZ9pGPP6OC7U1Cvf2) <a href="#how-are-gas-and-fees-handled-on-evmos" id="how-are-gas-and-fees-handled-on-evmos"></a>

Fundamentally, LagomChainmos is a Cosmos SDK chain that enables EVM compatibility as part of a Cosmos SDK module. As a result of this architecture, all EVM transactions are ultimately encoded as Cosmos SDK transactions and update a Cosmos SDK-managed state.

Since all transactions are represented as Cosmos SDK transactions, transaction fees can be treated identically across execution layers. In practice, dealing with fees includes standard Cosmos SDK logic, some Ethereum logic, and custom LagomChainmos logic. For the most part, fees are collected by the `fee_collector` module, then paid out to validators and delegators. A few key distinctions are as follows:

1. Fee Market Module

   In order to support EIP-1559 gas and fee calculation on LagomChain’ EVM layer, LagomChain tracks the gas supplied for each block and uses that to calculate a base fee for future EVM transactions, thus enabling EVM dynamic fees and transaction prioritization as specified by EIP-1559.

   For EVM transactions, each node bypasses their local `min-gas-prices` configuration, and instead applies EIP-1559 fee logic—the gas price simply must be greater than both the global `min-gas-price` and the block's `BaseFee`, and the surplus is considered a priority tip. This allows validators to compute Ethereum fees without applying Cosmos SDK fee logic.

   Unlike on Ethereum, the `BaseFee` on LagomChainos is not burned, and instead is distributed to validators and delegators. Furthermore, the `BaseFee` is lower-bounded by the global `min-gas-price` (currently, the global `min-gas-price` parameter is set to zero, although it can be updated via Governance).
2. EVM Gas Refunds

   LagomChain refunds a fraction (at least 50% by default) of the unused gas for EVM transactions to approximate the current behavior on Ethereum. Why not always 100%?

#### Detailed Timeline[​](broken://pages/x9ylZ9pGPP6OC7U1Cvf2) <a href="#detailed-timeline" id="detailed-timeline"></a>

1. Nodes execute the previous block and run the `EndBlock` hook
   * As part of this hook, the FeeMarket (EIP-1559) module tracks the total `TransientGasWanted` from the transactions on this block. This will be used for the next block’s `BaseFee`.
2. Nodes receive transactions for a subsequent block and gossip these transactions to peers
   * These can be sorted and prioritized by the included fee price (using EIP-1559 fee priority mechanics for EVM transactions, to be included in the next block
3. Nodes run `BeginBlock` for the subsequent block
   * The FeeMarket module calculates the to be applied for this block using the total `GasWanted` from the previous block.
   * The Distribution module [distributes](https://docs.cosmos.network/main/modules/distribution#begin-block) the previous block’s fee rewards to validators and delegators
4. For each valid transaction that will be included in this block, nodes perform the following:
   * They run an `AnteHandler` corresponding to the transaction type. This process:
     1. Performs basic transaction validation
     2. Verifies the fees provided are greater than the global and local minimum validator values *and* greater than the `BaseFee` calculated
     3. (For Ethereum transactions) Preemptively consumes gas for the EVM transaction
     4. Deducts the transaction fees from the user and transfers them to the `fee_collector` module
     5. Increments the `TransientGasWanted` in the current block, to be used to calculate the next block’s `BaseFee`
   * Then, for standard Cosmos Transactions, nodes:
     1. Execute the transaction and update the state
     2. Consume gas for the transaction
   * For Ethereum Transactions, nodes:
     1. Execute the transaction and update the state
     2. Calculate the gas used and compare it to the gas supplied, then refund a designated portion of the surplus
5. Nodes run `EndBlock` for this block and store the block’s `GasWanted`

### Detailed Mechanics[​](broken://pages/x9ylZ9pGPP6OC7U1Cvf2) <a href="#detailed-mechanics" id="detailed-mechanics"></a>

#### Cosmos `Gas`[​](broken://pages/x9ylZ9pGPP6OC7U1Cvf2) <a href="#cosmos-gas" id="cosmos-gas"></a>

In the Cosmos SDK, gas is tracked in the main `GasMeter` and the `BlockGasMeter`:

* `GasMeter`: keeps track of the gas consumed during executions that lead to state transitions. It is reset on every transaction execution.
* `BlockGasMeter`: keeps track of the gas consumed in a block and enforces that the gas does not go over a predefined limit. This limit is defined in the Tendermint consensus parameters and can be changed via governance parameter change proposals.

Since gas is priced per-byte, the same interaction is more gas-intensive with larger parameter values than smaller (unlike Ethereum's `uint256` values, Cosmos SDK numericals are represented using [Big.Int](https://pkg.go.dev/math/big#Int) types, which are dynamically sized).

More information regarding gas as part of the Cosmos SDK can be found [here](https://docs.cosmos.network/main/learn/beginner/gas-fees.html).

#### Matching EVM Gas consumption[​](broken://pages/x9ylZ9pGPP6OC7U1Cvf2) <a href="#matching-evm-gas-consumption" id="matching-evm-gas-consumption"></a>

LagomChain is an EVM-compatible chain that supports Ethereum Web3 tooling. For this reason, gas consumption must be equatable with other EVMs, most importantly Ethereum.

The main difference between EVM and Cosmos state transitions, is that the EVM uses a [gas table](https://github.com/ethereum/go-ethereum/blob/master/params/protocol_params.go) for each OPCODE, whereas Cosmos uses a `GasConfig` that charges gas for each CRUD operation by setting a flat and per-byte cost for accessing the database.

+++ <https://github.com/cosmos/cosmos-sdk/blob/3fd376bd5659f076a4dc79b644573299fd1ec1bf/store/types/gas.go#L187-L196>

In order to match the gas consumed by the EVM, the gas consumption logic from the SDK is ignored, and instead the gas consumed is calculated by subtracting the state transition leftover gas plus refund from the gas limit defined on the message.

To ignore the SDK gas consumption, we reset the transaction `GasMeter` count to 0 and manually set it to the `gasUsed` value computed by the EVM module at the end of the execution.

#### `AnteHandler`[​](broken://pages/x9ylZ9pGPP6OC7U1Cvf2) <a href="#antehandler" id="antehandler"></a>

The Cosmos SDK [`AnteHandler`](https://docs.cosmos.network/main/learn/beginner/gas-fees.html#antehandler) performs basic checks prior to transaction execution. These checks are usually signature verification, transaction field validation, transaction fees, etc.

Regarding gas consumption and fees, the `AnteHandler` checks that the user has enough balance to cover for the tx cost (amount plus fees) as well as checking that the gas limit defined in the message is greater or equal than the computed intrinsic gas for the message.

#### Gas Refunds[​](broken://pages/x9ylZ9pGPP6OC7U1Cvf2) <a href="#gas-refunds" id="gas-refunds"></a>

In the EVM, gas can be specified prior to execution. The totality of the gas specified is consumed at the beginning of the execution (during the `AnteHandler` step) and the remaining gas is refunded back to the user if any gas is left over after the execution. Additionally the EVM can also define gas to be refunded back to the user but those will be capped to a fraction of the used gas depending on the fork/version being used.

#### Zero-Fee Transactions[​](broken://pages/x9ylZ9pGPP6OC7U1Cvf2) <a href="#zero-fee-transactions" id="zero-fee-transactions"></a>

In Cosmos, a minimum gas price is not enforced by the `AnteHandler` as the `min-gas-prices` is checked against the local node/validator. In other words, the minimum fees accepted are determined by the validators of the network, and each validator can specify a different minimum value for their fees. This potentially allows end users to submit 0 fee transactions if there is at least one single validator that is willing to include transactions with `0` gas price in their blocks proposed.

For this same reason, in LagomChain it is possible to send transactions with `0` fees for transaction types other than the ones defined by the `evm` module. EVM module transactions cannot have `0` fees as gas is required inherently by the EVM. This check is done by the EVM transactions stateless validation (i.e `ValidateBasic`) function as well as on the custom `AnteHandler` defined by LagomChain.

#### Gas Estimation[​](broken://pages/x9ylZ9pGPP6OC7U1Cvf2) <a href="#gas-estimation" id="gas-estimation"></a>

Ethereum provides a JSON-RPC endpoint `eth_estimateGas` to help users set up a correct gas limit in their transactions.

For that reason, a specific query API `EstimateGas` is implemented in LagomChain. It will apply the transaction against the current block/state and perform a binary search in order to find the optimal gas value to return to the user (the same transaction will be applied over and over until we find the minimum gas needed before it fails). The reason we need to use a binary search is that the gas required for the transaction might be higher than the value returned by the EVM after applying the transaction, so we need to try until we find the optimal value.

A cache context will be used during the whole execution to avoid changes be persisted in the state.

For Cosmos Tx's, developers can use Cosmos SDK's [transaction simulation](https://docs.cosmos.network/main/run-node/txs#simulating-a-transaction) to create an accurate estimate.

#### Cross-Chain Gas and Fees[​](broken://pages/x9ylZ9pGPP6OC7U1Cvf2) <a href="#cross-chain-gas-and-fees" id="cross-chain-gas-and-fees"></a>

Let’s say a user transfers tokens from Chain A to LagomChainos via IBC-transfer and wants to execute an LagomChainos transaction—however, they don’t have any LagomChain tokens to cover fees. The Cosmos SDK introduced `Tips` as a solution to this issue; a user can cover fees using a different token—in this case, tokens from Chain A.

To cover transaction fees using a tip, this user can sign a transaction with a tip and no fees, then send the transaction to a fee relayer. The fee relayer will then cover the fee in the native currency (LagomChain in this case), and receive the tip in payment, behaving as an intermediary exchange.

### Dealing with gas and fees with the LagomChain CLI[​](broken://pages/x9ylZ9pGPP6OC7U1Cvf2) <a href="#dealing-with-gas-and-fees-with-the-evmos-cli" id="dealing-with-gas-and-fees-with-the-evmos-cli"></a>

When broadcasting a transaction using the LagomChain CLI client, users should keep into consideration the options available. There are three flags to consider when sending a transaction to the network:

* `--fees`: fees to pay along with transaction; eg: 10alagom. Defaults to the required fees.
* `--gas`: the gas limit to set per-transaction; the default value is 200000.
* `--gas-prices`: gas prices to determine the transaction fee (e.g. 10alagom).

However, not all of them need to be defined on each transaction. The correct combinations are:

* `--fees=auto`: estimates fees and gas automatically (same behavior as `--gas=auto`). Throws an error if using any other fees-related flag (e.i, `--gas-prices` , `--fees`)
* `--gas=auto`: same behavior as `--fees=auto`. Throws an error if using any other fees-related flag (e.i, `--gas-prices` , `--fees`)
* `--gas={int}`: uses the specified gas amount and the required fees for the transaction
* `--fees={int}{denom}`: uses the specified fees for the tx. Uses gas default value (200000) for the tx.
* `--fees={int}{denom} --gas={int}`: uses specified gas and fees. Calculates gas-prices with the provided params
* `--gas-prices={int}{denom}`: uses the provided gas price and the default gas amount (200000)
* `--gas-prices={int}{denom} --gas={int}`: uses the gas specified on for the tx and calculates the fee with the corresponding parameters.

The reader should note that the former two options provide a frendlier user experience for new users, and the latter are for more advanced users, who desire more control over these parameters.

The team introduced the `auto` flag option that calculates automatically the gas and fees required to execute a transaction. In this way, new users or developers can perform transactions without the hustle of defining specific gas and fees values.

Using the `auto` flag sometimes may fail on estimating the right gas and fees based on network traffic. To overcome this, you can use a higher value for the `--gas-adjustment` flag. By default, this is set to `1.2`. When the estimated values are insufficient, retry with a higher gas adjustment, for example, `--gas-adjustment 1.3`.

It is not possible to use the `--gas-prices` and `--fees` flags combined. If so, the user will get an error stating that cannot provide both fees and gas prices.

Keep in mind that the above combinations may fail if the provided fees or gas amount is insufficient. If that is the case, the CLI will return an error message with the specific reason. For example:

```
raw_log: 'out of gas in location: submit proposal; gasWanted: 200000, gasUsed: 263940.
  Please retry with a gas (--gas flag) amount higher than gasUsed: out of gas'
```


# IBC Relayers

Relayers facilitate cross-chain communication by transmitting packets of data between independent blockchains, functioning like a decentralized postal service. They enable seamless interoperability through the Inter-Blockchain Communication (IBC) protocol, allowing sovereign blockchains to exchange messages and transfer value, including tokens. IBC relayers are specialized software programs that handle this process, ensuring secure and efficient communication between blockchain networks that support IBC.

![TAO-IBC](https://tutorials.cosmos.network/resized-images/600/academy/3-ibc/images/connectionstate.png)

Relayers play a crucial role in facilitating cross-chain communication by establishing clients, connections, and channels between blockchains. The Inter-Blockchain Communication (IBC) protocol operates across two layers:

* **TAO Layer** – The core functionality of IBC, enabling blockchains to exchange packets of information through dedicated channels. It relies on smart contract modules with light clients that verify the validity of state updates from other chains.
* **APP Layer** – Built on top of TAO, allowing the development of application-specific protocols that leverage IBC for seamless interoperability.

IBC is currently enabled on [54 networks](https://docs.lagomchain.com/concepts/www.mapofzones.com), processing over 60 million transactions per month. Relayers are essential to maintaining the integrity and efficiency of this system, as they can handle high transaction volumes. However, network congestion can still occur, making infrastructure scaling an ongoing priority. Users can contribute to the stability of IBC by delegating tokens to validators that also operate relayers, helping to enhance network resilience and performance.

Most relayers also operate validator nodes on one or more Cosmos ecosystem blockchains. The more support these relayers receive as validators, the more likely they will be encouraged to continue operating at a loss on their relayer nodes. Additionally, the knowledge that relayers are valued in such a way should encourage even more validators to set up relayer infrastructure of their own.


# Key Management

A mnemonic phrase, also known as a seed phrase, is a sequence of words used to recover or restore a cryptocurrency wallet. It serves as a backup mechanism, allowing users to regain access to their funds if they lose access to their original wallet.

When creating a wallet, a 12- or 24-word mnemonic phrase is generated, which should be kept secure and private.

***

### Importance of Mnemonic Phrases

Cryptocurrencies are stored in a decentralized manner, meaning no central authority can restore access to lost funds. If you lose access to your wallet (e.g., forget your password or lose your device), your mnemonic phrase is the only way to recover your account.

To protect your mnemonic phrase:

* Store it securely on a physical medium (e.g., written on paper) or in a secure digital format.
* Make multiple copies and store them in different locations to prevent total loss.

***

### **Mnemonic Phrase vs. Private Key**

| **Feature**        | **Mnemonic Phrase (Seed Phrase)**              | **Private Key**                          |
| ------------------ | ---------------------------------------------- | ---------------------------------------- |
| **Purpose**        | Generates multiple private keys                | Grants direct access to a single address |
| **Format**         | 12 or 24 words                                 | Long alphanumeric string                 |
| **Recoverability** | Can restore multiple accounts                  | If lost, funds cannot be recovered       |
| **Security Risk**  | Losing it means losing all associated accounts | Losing it affects only one address       |

A mnemonic phrase is used to derive multiple private keys, whereas a private key is specific to a single cryptocurrency address. Since the mnemonic phrase is the root of all private keys, losing it has severe consequences.

***

## **Managing Keys with LagomChain CLI**

#### **1. Creating a New Key (Generates Mnemonic Phrase)**

When you create a new key, you receive a mnemonic phrase for backup.

```sh
lagomd keys add mykey
```

**Example Output:**

```json
{
  "name": "mykey",
  "type": "local",
  "address": "lagom1n253dl2tgyhxjm592p580c38r4dn8023ctv28d",
  "pubkey": '{"@type":"/ethermint.crypto.v1.ethsecp256k1.PubKey","key":"ArJhve4v5HkLm+F7ViASU/rAGx7YrwU4+XKV2MNJt+Cq"}',
  "mnemonic": "<12 or 24-word mnemonic phrase>"
}
```

**Important:** Write down the mnemonic phrase and store it securely.

***

#### **2. Restoring a Key from a Mnemonic Phrase**

If a key is lost, restore it using the mnemonic phrase:

```sh
lagomd keys add mykey-restored --recover
```

**You will be prompted to enter the mnemonic phrase.**

**Example Output:**

```json
{
  "name": "mykey-restored",
  "type": "local",
  "address": "lagom1n253dl2tgyhxjm592p580c38r4dn8023ctv28d",
  "pubkey": '{"@type":"/ethermint.crypto.v1.ethsecp256k1.PubKey","key":"ArJhve4v5HkLm+F7ViASU/rAGx7YrwU4+XKV2MNJt+Cq"}'
}
```

***

## **Exporting and Importing Private Keys**

If you need to back up or transfer a key without using the mnemonic phrase, you can export and import private keys.

### **Tendermint-Formatted Private Keys**

#### **1. Export a Private Key**

```sh
lagomd keys export mykey
```

You will be prompted to enter a decryption passphrase.

**Example Output:**

```
-----BEGIN TENDERMINT PRIVATE KEY-----
kdf: bcrypt
salt: 14559BB13D881A86E0F4D3872B8B2C82
type: secp256k1

# <Tendermint private key>
-----END TENDERMINT PRIVATE KEY-----
```

Save this output to a secure file:

```sh
echo "-----BEGIN TENDERMINT PRIVATE KEY-----
# <Tendermint private key>
-----END TENDERMINT PRIVATE KEY-----" > mykey.export
```

#### **2. Import a Private Key**

To restore an exported key:

```sh
lagomd keys import mykey-imported ./mykey.export
```

***

### **Ethereum-Formatted Private Keys**

#### **1. Export a MetaMask-Compatible Private Key**

LagomChain allows exporting Ethereum-compatible private keys for use in MetaMask and other wallets.

```sh
lagomd keys unsafe-export-eth-key mykey > mykey.export
```

**Warning:** This method exports the unencrypted private key, which should be stored securely.

You will be prompted with:

```
**WARNING** this is an unsafe way to export your unencrypted private key, are you sure? [y/N]: y
```

Enter your keyring passphrase to proceed.

#### **2. Import an Ethereum-Formatted Private Key**

```sh
lagomd keys unsafe-import-eth-key mykey-imported ./mykey.export
```

You will be prompted to enter a new encryption passphrase for the imported key.

***

## **Verifying Stored Keys**

To check that your keys have been correctly restored, imported, or created, list all stored keys:

```sh
lagomd keys list
```

📌 **Example Output:**

```json
[
  {
    "name": "mykey-imported",
    "type": "local",
    "address": "lagom1n253dl2tgyhxjm592p580c38r4dn8023ctv28d",
    "pubkey": '{"@type":"/ethermint.crypto.v1.ethsecp256k1.PubKey","key":"ArJhve4v5HkLm+F7ViASU/rAGx7YrwU4+XKV2MNJt+Cq"}'
  },
  {
    "name": "mykey-restored",
    "type": "local",
    "address": "lagom1n253dl2tgyhxjm592p580c38r4dn8023ctv28d",
    "pubkey": '{"@type":"/ethermint.crypto.v1.ethsecp256k1.PubKey","key":"ArJhve4v5HkLm+F7ViASU/rAGx7YrwU4+XKV2MNJt+Cq"}'
  },
  {
    "name": "mykey",
    "type": "local",
    "address": "lagom1n253dl2tgyhxjm592p580c38r4dn8023ctv28d",
    "pubkey": '{"@type":"/ethermint.crypto.v1.ethsecp256k1.PubKey","key":"ArJhve4v5HkLm+F7ViASU/rAGx7YrwU4+XKV2MNJt+Cq"}'
  }
]
```

***

## **Security Considerations**

* Never share your mnemonic phrase or private key. Anyone with access can control your funds.
* Store multiple copies of your mnemonic phrase securely. Losing it means you cannot recover your wallet.
* Avoid exporting private keys unless necessary. If needed, encrypt them securely.


# Keyring

Create, import, export and delete keys using the CLI keyring.

The keyring holds the private/public keypairs used to interact with the node. For instance, a validator key needs to be set up before running the node, so that blocks can be correctly signed. The private key can be stored in different locations, called ["backends"](#keyring-backends), such as a file or the operating system's own key storage.

tip

In case, you need a refresher on private key and key management, please reference our [Key Management](/concepts/key-management).

### Add keys[​](broken://pages/DNEGCMcw2QSkhPz7pDwa) <a href="#add-keys" id="add-keys"></a>

You can use the following commands for help with the `keys` command and for more information about a particular subcommand, respectively:

```
lagomd keys [command] --help
```

To create a new key in the keyring, run the `add` subcommand with a `<key_name>` argument. You will have to provide a password for the newly generated key. This key will be used in the next section.

```
lagomd keys add dev0

# Put the generated address in a variable for later use.
MY_VALIDATOR_ADDRESS=$(lagomd keys show dev0 -a)
```

This command generates a new 24-word mnemonic phrase, persists it to the relevant backend, and outputs information about the keypair. If this keypair will be used to hold value-bearing tokens, be sure to write down the mnemonic phrase somewhere safe!

By default, the keyring generates a `eth_secp256k1` key. The keyring also supports `ed25519` keys, which may be created by passing the `--algo` flag. A keyring can of course hold both types of keys simultaneously.

tip

**Note**: The Ethereum address associated with a public key can be derived by taking the full Ethereum public key of type `eth_secp256k1`, computing the `Keccak-256` hash, and truncating the first twelve bytes.

danger

**NOTE**: Cosmos `secp256k1` keys are not supported on LagomChain due to compatibility issues with Ethereum transactions.

### Keyring Backends[​](broken://pages/DNEGCMcw2QSkhPz7pDwa) <a href="#keyring-backends" id="keyring-backends"></a>

#### OS[​](broken://pages/DNEGCMcw2QSkhPz7pDwa) <a href="#os" id="os"></a>

tip

**`os`** is the default option since operating system's default credentials managers are designed to meet users' most common needs and provide them with a comfortable experience without compromising on security.

The `os` backend relies on operating system-specific defaults to handle key storage securely. Typically, an operating system's credential sub-system handles password prompts, private keys storage, and user sessions according to the user's password policies. Here is a list of the most popular operating systems and their respective passwords manager:

* macOS (since Mac OS 8.6): [Keychain](https://support.apple.com/en-gb/guide/keychain-access/welcome/mac)
* Windows: [Credentials Management API](https://docs.microsoft.com/en-us/windows/win32/secauthn/credentials-management)
* GNU/Linux:
* [libsecret](https://gitlab.gnome.org/GNOME/libsecret)
* [kwallet](https://api.kde.org/frameworks/kwallet/html/index.html)

GNU/Linux distributions that use GNOME as default desktop environment typically come with [Seahorse](https://wiki.gnome.org/Apps/Seahorse). Users of KDE based distributions are commonly provided with [KDE Wallet Manager](https://userbase.kde.org/KDE_Wallet_Manager). Whilst the former is in fact a `libsecret` convenient frontend, the latter is a `kwallet` client.

The recommended backends for headless environments are `file` and `pass`.

#### File[​](broken://pages/DNEGCMcw2QSkhPz7pDwa) <a href="#file" id="file"></a>

The `file` stores the keyring encrypted within the app's configuration directory. This keyring will request a password each time it is accessed, which may occur multiple times in a single command resulting in repeated password prompts. If using bash scripts to execute commands using the `file` option you may want to utilize the following format for multiple prompts:

```
# assuming that KEYPASSWD is set in the environment
yes $KEYPASSWD | lagomd keys add me
yes $KEYPASSWD | lagomd keys show me
# start lagomd with keyring-backend flag
lagomd --keyring-backend=file start
```

tip

The first time you add a key to an empty keyring, you will be prompted to type the password twice.

#### Password Store[​](broken://pages/DNEGCMcw2QSkhPz7pDwa) <a href="#password-store" id="password-store"></a>

The `pass` backend uses the [pass](https://www.passwordstore.org/) utility to manage on-disk encryption of keys' sensitive data and metadata. Keys are stored inside `gpg` encrypted files within app-specific directories. `pass` is available for the most popular UNIX operating systems as well as GNU/Linux distributions. Please refer to its manual page for information on how to download and install it.

tip

**`pass`** uses [GnuPG](https://gnupg.org/) for encryption. `gpg` automatically invokes the `gpg-agent` daemon upon execution, which handles the caching of GnuPG credentials. Please refer to `gpg-agent` man page for more information on how to configure cache parameters such as credentials TTL and passphrase expiration.

The password store must be set up prior to first use:

Replace `<GPG_KEY_ID>` with your GPG key ID. You can use your personal GPG key or an alternative one you may want to use specifically to encrypt the password store.

#### KDE Wallet Manager[​](broken://pages/DNEGCMcw2QSkhPz7pDwa) <a href="#kde-wallet-manager" id="kde-wallet-manager"></a>

The `kwallet` backend uses `KDE Wallet Manager`, which comes installed by default on the GNU/Linux distributions that ships KDE as default desktop environment. Please refer to [KWallet Handbook](https://docs.kde.org/stable5/en/kwalletmanager/kwallet5/) for more information.

#### Testing[​](broken://pages/DNEGCMcw2QSkhPz7pDwa) <a href="#testing" id="testing"></a>

The `test` backend is a password-less variation of the `file` backend. Keys are stored **unencrypted** on disk. This keyring is provided for testing purposes only. Use at your own risk!

#### In Memory[​](broken://pages/DNEGCMcw2QSkhPz7pDwa) <a href="#in-memory" id="in-memory"></a>

The `memory` backend stores keys in memory. The keys are immediately deleted after the program has exited.

danger

**IMPORTANT**: Provided for testing purposes only. The `memory` backend is **not** recommended for use in production environments. Use at your own risk!


# State Export/Imort

LagomChain can dump the entire application state to a JSON file. This, besides upgrades, can be useful for manual analysis of the state at a given height.

### Export State[​](broken://pages/kr3FCey94LsN2JcUc44r) <a href="#export-state" id="export-state"></a>

Export state with:

```
lagomd export > new_genesis.json
```

You can also export state from a particular height (at the end of processing the block of that height):

```
lagomd export --height [height] > new_genesis.json
```

If you plan to start a new network for 0 height (i.e genesis) from the exported state, export with the `--for-zero-height` flag:

```
lagomd export --height [height] --for-zero-height > new_genesis.json
```

### Manually Migrate State[​](broken://pages/kr3FCey94LsN2JcUc44r) <a href="#manually-migrate-state" id="manually-migrate-state"></a>

If you want to migrate state manually, e.g. for local testing purpose. Note that for regular chain upgrades, a manual state migration is not required.

After exporting your state into a json file, you can replace the old `genesis.json` with `new_genesis.json`.

```
cp -f genesis.json new_genesis.json
mv new_genesis.json genesis.json
```

At this point, you might want to run a script to update the exported genesis into a genesis state that is compatible with your new version.

You can use the `migrate` command to migrate from a given version to the next one (eg: `v0.X.X` to `v1.X.X`):

```
lagomd migrate TARGET_VERSION GENESIS_FILE --chain-id=<new_chain_id> --genesis-time=<yyyy-mm-ddThh:mm:ssZ>
```


# Multisig

Multisig (multi-signature) accounts enhance security and decentralization by requiring multiple signatures to approve transactions. A multisig account in LagomChain is a special type of account that requires multiple private keys to sign transactions before they are considered valid.

Multisig accounts are useful for:

* Enhancing security by distributing signing authority.
* Enforcing multi-party approvals for transactions.
* Reducing risks of a single point of failure.

***

### **How Multisig Works**

A multisig account is defined by:

1. **Threshold** – The minimum number of required signatures.
2. **Public Keys** – The set of keys that can sign transactions.

Each transaction must be signed individually by the specified keys. Once the required number of signatures is collected, they are combined into a multi-signature to authorize the transaction. If fewer than the threshold signatures are present, the transaction is invalid.

***

## **Creating a Multisig Account**

#### **Step 1: Generate a Multisig Key**

Use the following command to create a multisig key:

```sh
lagomd keys add --multisig=name1,name2,name3[...] --multisig-threshold=K new_multisig_key
```

* `K` is the minimum number of required signatures.
* `--multisig` specifies the public keys that will be combined.
* `new_multisig_key` is the name of the new multisig account.

**Example:**

```sh
lagomd keys add --multisig=p1,p2,p3 --multisig-threshold=2 multisig_wallet
```

This command creates a multisig account that requires two out of three (`2/3`) signatures.

Multisig addresses can also be generated on-the-fly using:

```sh
lagomd keys show --multisig-threshold=K name1 name2 name3 [...]
```

***

## **Signing a Multisig Transaction**

#### **Step 1: Create the Multisig Key**

Assume that three users (`test1`, `test2`, and `test3`) want to create a multisig account.

1. First, import the public key of `test3` into the keyring:

```sh
lagomd keys add test3 --pubkey=<public_key>
```

2. Generate the multisig key with a 2/3 threshold:

```sh
lagomd keys add multi --multisig=test1,test2,test3 --multisig-threshold=2
```

3. Verify the multisig account:

```sh
lagomd keys show multi
```

4. Add tokens to the multisig wallet:

```sh
lagomd tx bank send test1 multi 10000000000000000000alagom --chain-id=lagom_986-1 --gas=auto --fees=1000000alagom --broadcast-mode=block
```

***

#### **Step 2: Create an Unsigned Transaction**

To send 5 LAGOM from the multisig account to another address:

```sh
lagomd tx bank send \
    lagom1recipientaddress \
    multi \
    5000000000000000000alagom \
    --gas=200000 \
    --fees=1000000alagom \
    --chain-id=lagom_986-1 \
    --generate-only > unsignedTx.json
```

This creates an unsigned transaction file (`unsignedTx.json`).

***

#### **Step 3: Sign Individually**

Each signer (`test1` and `test2`) must sign the transaction separately.

**Sign with test1:**

```sh
lagomd tx sign \
    unsignedTx.json \
    --multisig=multi \
    --from=test1 \
    --output-document=test1sig.json \
    --chain-id=lagom_986-1
```

**Sign with test2:**

```sh
lagomd tx sign \
    unsignedTx.json \
    --multisig=multi \
    --from=test2 \
    --output-document=test2sig.json \
    --chain-id=lagom_986-1
```

***

#### **Step 4: Combine Multisignatures**

Now, combine the individual signatures into a final multisig transaction:

```sh
lagomd tx multisign \
    unsignedTx.json \
    multi \
    test1sig.json test2sig.json \
    --output-document=signedTx.json \
    --chain-id=lagom_986-1
```

This produces the final signed transaction file (`signedTx.json`), which contains the required threshold signatures.

***

#### **Step 5: Broadcast the Multisig Transaction**

To broadcast the fully signed transaction:

```sh
lagomd tx broadcast signedTx.json --chain-id=lagom_986-1 --broadcast-mode=block
```

Once broadcasted, the transaction will be processed and recorded on the LagomChain blockchain.

***

## **Summary of Multisig Commands**

| **Action**                         | **Command**                                                                                     |
| ---------------------------------- | ----------------------------------------------------------------------------------------------- |
| **Create a multisig key**          | `lagomd keys add --multisig=name1,name2 --multisig-threshold=K new_key`                         |
| **Check multisig details**         | `lagomd keys show multi`                                                                        |
| **Send funds to multisig account** | `lagomd tx bank send sender multi amount --chain-id=lagom_986-1`                                |
| **Create an unsigned transaction** | `lagomd tx bank send recipient multi amount --generate-only > unsignedTx.json`                  |
| **Sign transaction (each signer)** | `lagomd tx sign unsignedTx.json --from=signer --output-document=signerSig.json`                 |
| **Combine signatures**             | `lagomd tx multisign unsignedTx.json multi sig1.json sig2.json --output-document=signedTx.json` |
| **Broadcast the transaction**      | `lagomd tx broadcast signedTx.json --chain-id=lagom_986-1`                                      |

***

## **Security Considerations**

* Private keys should never be shared. Each participant must sign transactions independently.
* Ensure the correct threshold is set to prevent unwanted transactions.
* Backup your multisig key and participants' public keys to avoid losing access.


# Pending State

When a transaction is submitted to the Ethereum network, it first goes into the pending status, waiting to be executed by the nodes. A transaction can be in the pending state for a longer duration if the gas price is set very low in the transaction and the nodes are busy processing other higher gas price transactions.

During the pending state, the transaction initiator is allowed to change the transaction fields at any time. They can do so by sending another transaction with the same nonce.

### Prerequisite Readings[​](broken://pages/Uqiga5lmALS07FXtFFOP) <a href="#prerequisite-readings" id="prerequisite-readings"></a>

* [Cosmos SDK Mempool](https://docs.cosmos.network/main/building-apps/app-mempool)

### LagomChain vs Ethereum[​](broken://pages/Uqiga5lmALS07FXtFFOP) <a href="#evmos-vs-ethereum" id="evmos-vs-ethereum"></a>

In Ethereum, pending blocks are generated as they are queued for production by miners. These pending blocks include pending transactions that are picked out by miners, based on the highest reward paid in gas. This mechanism exists as block finality is not possible on the Ethereum network. Blocks are committed with probabilistic finality, which means that transactions and blocks become less likely to become reverted as more time (and blocks) passes.

LagomChain is designed quite differently on this front as there is no concept of a "pending state". LagomChain uses [Tendermint Core](https://docs.tendermint.com/) BFT consensus which provides instant finality for transaction. For this reason, Ethermint does not require a pending state mechanism, as all (if not most) of the transactions will be committed to the next block (avg. block time on Cosmos chains is \~8s). However, this causes a few hiccups in terms of the Ethereum Web3-compatible queries that can be made to pending state.

Another significant difference with Ethereum, is that blocks are produced by validators or block producers, who include transactions from their local mempool into blocks in a first-in-first-out (FIFO) fashion. Transactions on LagomChain cannot be ordered or cherry picked out from the Tendermint node [mempool](https://docs.tendermint.com/v0.34/tendermint-core/mempool.html).

### Pending State Queries[​](broken://pages/Uqiga5lmALS07FXtFFOP) <a href="#pending-state-queries" id="pending-state-queries"></a>

LagomChain will make queries which will account for any unconfirmed transactions present in a node's transaction mempool. A pending state query made will be subjective and the query will be made on the target node's mempool. Thus, the pending state will not be the same for the same query to two different nodes.

#### JSON-RPC Calls on Pending Transactions[​](broken://pages/Uqiga5lmALS07FXtFFOP) <a href="#json-rpc-calls-on-pending-transactions" id="json-rpc-calls-on-pending-transactions"></a>

* `eth_getBalance`
* `eth_getTransactionCount`
* `eth_getBlockTransactionCountByNumber`
* `eth_getBlockByNumber`
* `eth_getTransactionByHash`
* `eth_getTransactionByBlockNumberAndIndex`
* `eth_sendTransaction`


# Signing

Signing is the process of creating a digital signature using a private key to verify a transaction on the LagomChain network. This cryptographic process ensures:

* Authenticity – Verifies that the transaction was authorized by the rightful owner.
* Integrity – Ensures that the transaction data has not been tampered with.

Signing can be performed using wallets (e.g., MetaMask, Ledger, Keplr) or through the [CLI](/lagomchain-cli).

***

### EIP-712: Standardized Signing for LagomChain

[EIP-712](https://eips.ethereum.org/EIPS/eip-712) is a signing standard designed to make typed-data transactions more human-readable and secure. It allows users to:

* Clearly see what they are signing.
* Reduce susceptibility to phishing attacks.
* Sign structured data rather than raw transaction bytes.

Although EIP-712 is not an Ethereum transaction type, it provides a standardized method for signing structured data, enhancing security and compatibility across Ethereum-based and Cosmos-based ecosystems.

***

### How EIP-712 Works in LagomChain

LagomChain utilizes EIP-712 to encode Cosmos transactions in a format that is compatible with Ethereum signers. This ensures that transactions can be securely signed using MetaMask, Ledger hardware wallets, and Keplr.

#### Signing Process

1. A Cosmos transaction is represented as a JSON sign-doc.
2. The JSON sign-doc is converted into an EIP-712 object, containing structured types and messages.
3. The EIP-712 object is signed using an Ethereum-compatible wallet (MetaMask, Ledger, or Keplr).
4. The node verifies the signature using the same EIP-712 standard.

***

### Why LagomChain Uses EIP-712 for Signing?

Ethereum Wallet Compatibility – Users can sign transactions with MetaMask, Ledger, and Keplr without additional modifications.\
Improved Security – Prevents blind signing attacks by displaying human-readable transaction details.\
Interoperability – Bridges the Ethereum and Cosmos ecosystems, enabling seamless cross-chain interactions.

By adopting EIP-712, LagomChain enhances user experience, security, and cross-chain compatibility, making it easier for users to interact with both Ethereum and Cosmos-based networks.


# Token

### The LAGOMCHAIN Token (LAGOM)[​](broken://pages/7AoSdUMEJ86YYBrLMnzU) <a href="#the-evmos-token" id="the-evmos-token"></a>

The LAGOM token is the native asset of LagomChain, used for:

* Staking – Securing the network through Proof-of-Stake.
* Governance – Participating in on-chain governance proposals.
* Gas Fees – Paying transaction fees for executing smart contracts on the EVM.
* Validator & User Rewards – Distributing fees collected from network activity.

LagomChain uses [Atto](https://en.wikipedia.org/wiki/Metric_prefix) LAGOM as the smallest denomination to maintain parity with Ethereum.

#### **Denomination Structure**

```
CopyEdit1 LAGOM = 10¹⁸ aLAGOM
```

This follows Ethereum’s denomination model:

```
CopyEdit1 ETH = 10¹⁸ wei
```

***

## **Types of Assets on LagomChain**

LagomChain supports multiple asset types, enabling seamless interaction between the Cosmos ecosystem and Ethereum-compatible tokens.

#### 1. Native LAGOM Token

The primary utility token used for staking, governance, and gas fees.

#### 2. IBC Coins (Inter-Blockchain Communication)

LagomChain enables cross-chain asset transfers via IBC, allowing users to interact with other Cosmos-based blockchains.

#### 3. Ethereum-Compatible Tokens

LagomChain supports Ethereum’s token standards, including:

* ERC-20 – Fungible tokens.
* ERC-721 – Non-fungible tokens (NFTs).
* ERC-1155 – Multi-token standard.

***

## Cosmos Coins on LagomChain

LagomChain allows users to hold Cosmos-native coins, which can be used for:

* Staking on the LagomChain network.
* Governance deposits for protocol proposals.
* IBC Transfers between LagomChain and other Cosmos blockchains.
* Gas fees for executing transactions on both Cosmos and EVM modules.

***

## Ethereum-Compatible Tokens & Smart Contracts

LagomChain is fully compatible with Ethereum’s token standards, enabling:

* Deployment and interaction with ERC-20 tokens.
* Support for NFT standards (ERC-721, ERC-1155).
* Seamless token transfers between Ethereum and LagomChain.

***

## Unified Token Representation on LagomChain

LagomChain introduces a Single Token Representation feature to improve user experience. This simplifies how ERC-20 tokens and IBC coins are displayed, making asset management more intuitive.

Key Benefits:

* Users do not need to differentiate between Cosmos-based and Ethereum-based tokens.
* The protocol automatically handles conversions, ensuring smooth interaction.
* Token registration is required for governance approval before assets are listed.

For more details on token registration and management, visit the LagomChain Assets Page.


# Transactions

A transaction refers to an action initiated by an account which changes the state of the blockchain. To effectively perform the state change, every transaction is broadcasted to the whole network. Any node can broadcast a request for a transaction to be executed on the blockchain state machine; after this happens, a validator will validate, execute the transaction and propagate the resulting state change to the rest of the network.

To process every transaction, computation resources on the network are consumed. Thus, the concept of "gas" arises as a reference to the computation required to process the transaction by a validator. Users have to pay a fee for this computation, all transactions require an associated fee. This fee is calculated based on the gas required to execute the transaction and the gas price.

Additionally, a transaction needs to be signed using the sender's private key. This proves that the transaction could only have come from the sender and was not sent fraudulently.

In a nutshell, the transaction lifecycle once a signed transaction is submitted to the network is the following:

* A transaction hash is cryptographically generated.
* The transaction is broadcasted to the network and added to a transaction pool consisting of all other pending network transactions.
* A validator must pick your transaction and include it in a block in order to verify the transaction and consider it "successful".

For a more detailed explanation of the transaction lifecyle, see [the corresponding section](https://docs.cosmos.network/main/basics/tx-lifecycle).

The transaction hash is a unique identifier and can be used to check transaction information, for example, the events emitted, if was successful or not.

Transactions can fail for various reasons. For example, the provided gas or fees may be insufficient. Also, the transaction validation may fail. Each transaction has specific conditions that must fullfil to be considered valid. A widespread validation is that the sender is the transaction signer. In such a case, if you send a transaction where the sender address is different than the signer's address, the transation will fail, even if the fees are sufficient.

Nowadays, transactions can not only perform state transitions on the chain in which are submitted, but also can execute transactions on another blockchains. Interchain transactions are possible through the [Inter-Blockchain Communication protocol (IBC)](https://ibcprotocol.org/). Find a more detailed explanation on the section below.

### Transaction Types[​](broken://pages/vBNoZnee10CSDoBuHgHr) <a href="#transaction-types" id="transaction-types"></a>

LagomChain supports two transaction types:

1. Cosmos transactions
2. Ethereum transactions

This is possible because LagomChain uses the [Cosmos-SDK](https://docs.cosmos.network/main) and implements the [Ethereum Virtual Machine](https://ethereum.org/en/developers/docs/evm/) as a module. In this way, LagomChainvmos provides the features and functionalities of Ethereum and Cosmos chains combined, and more.

Although most of the information included on both of these transaction types is similar, there are differences among them. An important difference, is that Cosmos transactions allow multiple messages on the same transaction. Conversely, Ethereum transactions don't have this possibility. To bring these two types together, LagomChain implements Ethereum transactions as a single [`sdk.Msg`](https://godoc.org/github.com/cosmos/cosmos-sdk/types#Msg) contained in an [`auth.StdTx`](https://pkg.go.dev/github.com/cosmos/cosmos-sdk/x/auth#StdTx). All relevant Ethereum transaction information is contained in this message. This includes the signature, gas, payload, etc.

Find more information about these two types on the following sections.

#### Cosmos Transactions[​](broken://pages/vBNoZnee10CSDoBuHgHr) <a href="#cosmos-transactions" id="cosmos-transactions"></a>

On Cosmos chains, transactions are comprised of metadata held in contexts and `sdk.Msg`s that trigger state changes within a module through the module's Protobuf [Msg service](https://docs.cosmos.network/main/building-modules/msg-services).

When users want to interact with an application and make state changes (e.g. sending coins), they create transactions. Cosmos transactions can have multiple `sdk.Msg`s. Each of these must be signed using the private key associated with the appropriate account(s), before the transaction is broadcasted to the network.

A Cosmos transaction includes the following information:

* `Msgs`: an array of msgs (`sdk.Msg`)
* `GasLimit`: option chosen by the users for how to calculate how much gas they will need to pay
* `FeeAmount`: max amount user is willing to pay in fees
* `TimeoutHeight`: block height until which the transaction is valid
* `Signatures`: array of signatures from all signers of the tx
* `Memo`: a note or comment to send with the transaction

To submit a Cosmos transaction, users must use one of the provided clients.

#### Ethereum Transactions[​](broken://pages/vBNoZnee10CSDoBuHgHr) <a href="#ethereum-transactions" id="ethereum-transactions"></a>

Ethereum transactions refer to actions initiated by EOAs (externally-owned accounts, managed by humans), rather than internal smart contract calls. Ethereum transactions transform the state of the EVM and therefore must be broadcasted to the entire network.

Ethereum transactions also require a fee, known as `gas`. ([EIP-1559](https://eips.ethereum.org/EIPS/eip-1559)) introduced the idea of a base fee, along with a priority fee which serves as an incentive for miners to include specific transactions in blocks.

There are several categories of Ethereum transactions:

* regular transactions: transactions from one account to another
* contract deployment transactions: transactions without a `to` address, where the contract code is sent in the `data` field
* execution of a contract: transactions that interact with a deployed smart contract, where the `to` address is the smart contract address

An Ethereum transaction includes the following information:

* `recipient`: receiving address
* `signature`: sender's signature
* `nonce`: counter of tx number from account
* `value`: amount of ETH to transfer (in wei)
* `data`: include arbitrary data. Used when deploying a smart contract or making a smart contract method call
* `gasLimit`: max amount of gas to be consumed
* `maxPriorityFeePerGas`: mas gas to be included as tip to validators
* `maxFeePerGas`: max amount of gas to be paid for tx

For more information on Ethereum transactions and the transaction lifecycle, [go here](https://ethereum.org/en/developers/docs/transactions/).

LagomChain supports the following Ethereum transactions.

tip

**Note**: Unprotected legacy transactions are not supported by default.

* Dynamic Fee Transactions ([EIP-1559](https://eips.ethereum.org/EIPS/eip-1559))
* Access List Transactions ([EIP-2930](https://eips.ethereum.org/EIPS/eip-2930))
* Legacy Transactions ([EIP-2718](https://eips.ethereum.org/EIPS/eip-2718))

LagomChain is capable of processing Ethereum transactions by wrapping them on a `sdk.Msg`. LagomChain achieves this by using the `MsgEthereumTx`. This message encapsulates an Ethereum transaction as an SDK message and contains the necessary transaction data fields.

One remark about the `MsgEthereumTx` is that it implements both the `sdk.Msg` and `sdk.Tx` interfaces (generally SDK messages only implement the former, while the latter is a group of messages bundled together). The reason of this, is because the `MsgEthereumTx` must not be included in a `auth.StdTx` (SDK's standard transaction type) as it performs gas and fee checks using the Ethereum logic from Geth instead of the Cosmos SDK checks done on the auth module `AnteHandler`.

**Ethereum Tx Type**[**​**](broken://pages/vBNoZnee10CSDoBuHgHr)

There are three types of transaction types used in LagomChain's [Go Ethereum](https://github.com/ethereum/go-ethereum/blob/b946b7a13b749c99979e312c83dce34cac8dd7b1/core/types/transaction.go#L43-L48) implementation that came from Ethereum Improvement Proposals(EIPs):

1. LegacyTxType (EIP-155): The LegacyTxType represents the original transaction format that existed before Ethereum Improvement Proposal (EIP) 155. These transactions do not include a chain ID, which makes them vulnerable to replay attacks. EIP-155 was introduced to solve this problem by incorporating a chain ID, which uniquely identifies a specific Ethereum chain to prevent cross-chain replay attacks.
2. AccessListTxType (EIP-2930): AccessListTxType was introduced with EIP-2930 as part of the Berlin upgrade. This new transaction type allows users to specify an access list – a list of addresses and storage keys that the transaction plans to access. The primary goal of access lists is to mitigate some of the gas cost increases introduced with EIP-2929, which increased gas costs for state access operations to improve denial-of-service (DoS) attack resistance. By specifying an access list, users can avoid paying higher gas costs for subsequent accesses to the same addresses and storage keys within the same transaction.
3. DynamicFeeTxType (EIP-1559): DynamicFeeTxType was introduced with EIP-1559 as part of the London upgrade. This transaction type brought significant changes to Ethereum's fee market, with the aim of making gas fees more predictable and improving user experience. EIP-1559 transactions include two main components: a base fee and a priority fee (or tip). The base fee is algorithmically determined by the network, while the priority fee is set by users to incentivize miners to include their transaction. The base fee is burned, effectively reducing the overall ETH supply, while the priority fee goes to miners as a reward for their work. DynamicFeeTxType transactions allow for more predictable and efficient gas fee management.

These transaction types represent Ethereum's continuous evolution and improvements to its network, helping address challenges related to scalability, security, and user experience.

#### Interchain Transactions[​](broken://pages/vBNoZnee10CSDoBuHgHr) <a href="#interchain-transactions" id="interchain-transactions"></a>

Interchain transactions refer to the transfer of digital assets or data between two or more different blockchain networks.

Each blockchain network has its own unique protocol and data structure, making it difficult to directly transfer assets or data from one blockchain to another. Interchain transactions allow for the transfer of assets and data between different blockchains by using intermediary mechanisms or protocols.

One such mechanism is a cross-chain bridge, which acts as a connector between different blockchains, enabling the transfer of assets or data. Cross-chain bridges typically require some form of trust or consensus mechanism to ensure the security and integrity of the transaction.

Another possibility is to use the [IBC (Inter-Blockchain Communication)](https://ibcprotocol.org/) protocol. To make an interchain transaction using IBC a user needs to:

* Choose the source and destination blockchain networks that the user wants to transfer assets or data between.
* Ensure that both blockchain networks have implemented the IBC protocol
* Ensure there's a connection and channel established between the two blockchain networks using IBC
* Initiate the transfer of assets or data: this is done by sending a transaction from the source blockchain to the destination blockchain through the IBC channel

Interchain transactions are becoming increasingly important as the number of different blockchain networks and applications continues to grow. They enable the interoperability of different blockchain networks, allowing for greater flexibility and efficiency in the transfer of digital assets and data.

### Transaction Receipts[​](broken://pages/vBNoZnee10CSDoBuHgHr) <a href="#transaction-receipts" id="transaction-receipts"></a>

A transaction receipt shows data returned by an Ethereum client to represent the result of a particular transaction, including a hash of the transaction, its block number, the amount of gas used, and, in case of deployment of a smart contract, the address of the contract. Additionally, it includes custom information from the events emitted in the smart contract.

A receipt contains the following information:

* `transactionHash` : hash of the transaction.
* `transactionIndex`: integer of the transactions index position in the block.
* `blockHash`: hash of the block where this transaction was in.
* `blockNumber`: block number where this transaction was in.
* `from`: address of the sender.
* `to`: address of the receiver. null when its a contract creation transaction.
* `cumulativeGasUsed` : The total amount of gas used when this transaction was executed in the block.
* `effectiveGasPrice` : The sum of the base fee and tip paid per unit of gas.
* `gasUsed` : The amount of gas used by this specific transaction alone.
* `contractAddress` : The contract address created, if the transaction was a contract creation, otherwise null.
* `logs`: Array of log objects, which this transaction generated.
* `logsBloom`: Bloom filter for light clients to quickly retrieve related logs.
* `type`: integer of the transaction type, 0x00 for legacy transactions, 0x01 for access list types, 0x02 for dynamic fees. It also returns either.
* `root` : transaction stateroot (pre Byzantium)
* `status`: either 1 (success) or 0 (failure)


# Modules

Here is a list of all production-grade modules that can be used on the LagomChain blockchain, along with their respective documentation:

* [epochs](/modules/epochs) - Executes custom state transitions every period (*aka* epoch).
* [erc20](/modules/erc20) - Trustless, on-chain bidirectional internal conversion of tokens between LagomChain' EVM and Cosmos runtimes.
* [evm](/modules/evm) - Smart Contract deployment and execution on Cosmos
* [feemarket](/modules/feemarket) - Fee market implementation based on the EIP-1559 specification.
* [inflation](/modules/inflation) - Mint tokens and allocate them to staking rewards and the community pool.
* [vesting](/modules/vesting) - Vesting accounts with lockup and clawback capabilities.

### Cosmos SDK[​](https://docs.evmos.org/protocol/modules#cosmos-sdk) <a href="#cosmos-sdk" id="cosmos-sdk"></a>

LagomChain uses the following Cosmos SDK modules:

* [auth](https://docs.cosmos.network/main/modules/auth) - Authentication of accounts and transactions for Cosmos SDK applications.
* [authz](https://docs.cosmos.network/main/modules/authz) - Authorization for accounts to perform actions on behalf of other accounts.
* [bank](https://docs.cosmos.network/main/modules/bank) - Token transfer functionalities.
* [capability](https://ibc.cosmos.network/main/ibc/capability-module) - Object capability implementation.
* [distribution](https://docs.cosmos.network/main/modules/distribution) - Fee distribution, and staking token provision distribution.
* [evidence](https://docs.cosmos.network/main/modules/evidence) - Evidence handling for double signing, misbehaviour, etc.
* [feegrant](https://docs.cosmos.network/main/modules/feegrant) - Grant fee allowances for executing transactions.
* [genutil](https://github.com/cosmos/cosmos-sdk/tree/main/x/genutil) - variety of genesis utility functionalities for usage within a blockchain application
* [gov](https://docs.cosmos.network/main/modules/gov) - On-chain proposals and voting.
* [params](https://docs.cosmos.network/main/modules/params) - Globally available parameter store.
* [slashing](https://docs.cosmos.network/main/modules/slashing) - Validator punishment mechanisms.
* [staking](https://docs.cosmos.network/main/modules/staking) - Proof-of-Stake layer for public blockchains.
* [upgrade](https://docs.cosmos.network/main/modules/upgrade) - Software upgrades handling and coordination.

### IBC[​](https://docs.evmos.org/protocol/modules#ibc) <a href="#ibc" id="ibc"></a>

LagomChain uses the following the IBC modules for the SDK:

* [interchain-accounts](https://ibc.cosmos.network/main/apps/interchain-accounts/overview.html)
* [transfer](https://ibc.cosmos.network/main/apps/transfer/overview.html)

<br>


# epochs

### Abstract[​](broken://pages/mpUK0ijuB0MUzu2DJwoI) <a href="#abstract" id="abstract"></a>

This document specifies the internal `x/epochs` module of the LagomChain Hub.

Often, when working with the [Cosmos SDK](https://github.com/cosmos/cosmos-sdk), we would like to run certain pieces of code every so often.

The purpose of the `epochs` module is to allow other modules to maintain that they would like to be signaled once in a time period. So, another module can specify it wants to execute certain code once a week, starting at UTC-time = x. `epochs` creates a generalized epoch interface to other modules so they can be more easily signaled upon such events.

### Contents[​](broken://pages/mpUK0ijuB0MUzu2DJwoI) <a href="#contents" id="contents"></a>

1. [**Concept**](#contents)
2. [**State**](#state)
3. [**Events**](#events)
4. [**Keeper**](#keepers)
5. [**Hooks**](#hooks)
6. [**Queries**](#queries)
7. [**Future improvements**](#future-improvements)

### Concepts[​](broken://pages/mpUK0ijuB0MUzu2DJwoI) <a href="#concepts" id="concepts"></a>

The `epochs` module defines on-chain timers that execute at fixed time intervals. Other LagomChain modules can then register logic to be executed at the timer ticks. We refer to the period in between two timer ticks as an "epoch".

Every timer has a unique identifier, and every epoch will have a start time and an end time, where `end time = start time + timer interval`.

### State[​](broken://pages/mpUK0ijuB0MUzu2DJwoI) <a href="#state" id="state"></a>

#### State Objects[​](broken://pages/mpUK0ijuB0MUzu2DJwoI) <a href="#state-objects" id="state-objects"></a>

The `x/epochs` module keeps the following `objects in state`:

| State Object | Description         | Key                  | Value               | Store |
| ------------ | ------------------- | -------------------- | ------------------- | ----- |
| `EpochInfo`  | Epoch info bytecode | `[]byte{identifier}` | `[]byte{epochInfo}` | KV    |

**EpochInfo**[**​**](broken://pages/mpUK0ijuB0MUzu2DJwoI)

An `EpochInfo` defines several variables:

1. `identifier` keeps an epoch identification string
2. `start_time` keeps the start time for epoch counting: if block height passes `start_time`, then `epoch_counting_started` is set
3. `duration` keeps the target epoch duration
4. `current_epoch` keeps the current active epoch number
5. `current_epoch_start_time` keeps the start time of the current epoch
6. `epoch_counting_started` is a flag set with `start_time`, at which point `epoch_number` will be counted
7. `current_epoch_start_height` keeps the start block height of the current epoch

```
message EpochInfo {
    string identifier = 1;
    google.protobuf.Timestamp start_time = 2 [
        (gogoproto.stdtime) = true,
        (gogoproto.nullable) = false,
        (gogoproto.moretags) = "yaml:\"start_time\""
    ];
    google.protobuf.Duration duration = 3 [
        (gogoproto.nullable) = false,
        (gogoproto.stdduration) = true,
        (gogoproto.jsontag) = "duration,omitempty",
        (gogoproto.moretags) = "yaml:\"duration\""
    ];
    int64 current_epoch = 4;
    google.protobuf.Timestamp current_epoch_start_time = 5 [
        (gogoproto.stdtime) = true,
        (gogoproto.nullable) = false,
        (gogoproto.moretags) = "yaml:\"current_epoch_start_time\""
    ];
    bool epoch_counting_started = 6;
    reserved 7;
    int64 current_epoch_start_height = 8;
}
```

The `epochs` module keeps these `EpochInfo` objects in state, which are initialized at genesis and are modified on begin blockers or end blockers.

**Genesis State**[**​**](broken://pages/mpUK0ijuB0MUzu2DJwoI)

The `x/epochs` module's `GenesisState` defines the state necessary for initializing the chain from a previously exported height. It contains a slice containing all the `EpochInfo` objects kept in state:

```
// Genesis State defines the epoch module's genesis state
type GenesisState struct {
    // list of EpochInfo structs corresponding to all epochs
    Epochs []EpochInfo `protobuf:"bytes,1,rep,name=epochs,proto3" json:"epochs"`
}
```

### Events[​](broken://pages/mpUK0ijuB0MUzu2DJwoI) <a href="#events" id="events"></a>

The `x/epochs` module emits the following events:

#### BeginBlocker[​](broken://pages/mpUK0ijuB0MUzu2DJwoI) <a href="#beginblocker" id="beginblocker"></a>

| Type          | Attribute Key    | Attribute Value  |
| ------------- | ---------------- | ---------------- |
| `epoch_start` | `"epoch_number"` | `{epoch_number}` |
| `epoch_start` | `"start_time"`   | `{start_time}`   |

#### EndBlocker[​](broken://pages/mpUK0ijuB0MUzu2DJwoI) <a href="#endblocker" id="endblocker"></a>

| Type        | Attribute Key    | Attribute Value  |
| ----------- | ---------------- | ---------------- |
| `epoch_end` | `"epoch_number"` | `{epoch_number}` |

### Keepers[​](broken://pages/mpUK0ijuB0MUzu2DJwoI) <a href="#keepers" id="keepers"></a>

The `x/epochs` module only exposes one keeper, the epochs keeper, which can be used to manage epochs.

#### Epochs Keeper[​](broken://pages/mpUK0ijuB0MUzu2DJwoI) <a href="#epochs-keeper" id="epochs-keeper"></a>

Presently only one fully-permissioned epochs keeper is exposed, which has the ability to both read and write the `EpochInfo` for all epochs, and to iterate over all stored epochs.

```
// Keeper of epoch nodule maintains collections of epochs and hooks.
type Keeper struct {
    cdc      codec.Codec
    storeKey storetypes.StoreKey
    hooks    types.EpochHooks
}
```

```
// Keeper is the interface for epoch module keeper
type Keeper interface {
  // GetEpochInfo returns epoch info by identifier
  GetEpochInfo(ctx sdk.Context, identifier string) types.EpochInfo

  // SetEpochInfo set epoch info
  SetEpochInfo(ctx sdk.Context, epoch types.EpochInfo)

  // DeleteEpochInfo delete epoch info
  DeleteEpochInfo(ctx sdk.Context, identifier string)

  // IterateEpochInfo iterate through epochs
  IterateEpochInfo(ctx sdk.Context, fn func(index int64, epochInfo types.EpochInfo) (stop bool))

  // Get all epoch infos
  AllEpochInfos(ctx sdk.Context) []types.EpochInfo
}
```

### Hooks[​](broken://pages/mpUK0ijuB0MUzu2DJwoI) <a href="#hooks" id="hooks"></a>

The `x/epochs` module implements hooks so that other modules can use epochs to allow facets of the [Cosmos SDK](https://github.com/cosmos/cosmos-sdk) to run on specific schedules.

#### Hooks Implementation[​](broken://pages/mpUK0ijuB0MUzu2DJwoI) <a href="#hooks-implementation" id="hooks-implementation"></a>

```
// combine multiple epoch hooks, all hook functions are run in array sequence
type MultiEpochHooks []types.EpochHooks

// AfterEpochEnd is called when epoch is going to be ended, epochNumber is the
// number of epoch that is ending
func (mh MultiEpochHooks) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNumber int64) {...}

// BeforeEpochStart is called when epoch is going to be started, epochNumber is
// the number of epoch that is starting
func (mh MultiEpochHooks) BeforeEpochStart(ctx sdk.Context, epochIdentifier string, epochNumber int64) {...}

// AfterEpochEnd executes the indicated hook after epochs ends
func (k Keeper) AfterEpochEnd(ctx sdk.Context, identifier string, epochNumber int64) {...}

// BeforeEpochStart executes the indicated hook before the epochs
func (k Keeper) BeforeEpochStart(ctx sdk.Context, identifier string, epochNumber int64) {...}
```

#### Recieving Hooks[​](broken://pages/mpUK0ijuB0MUzu2DJwoI) <a href="#recieving-hooks" id="recieving-hooks"></a>

When other modules (outside of `x/epochs`) recieve hooks, they need to filter the value `epochIdentifier`, and only do executions for a specific `epochIdentifier`.

The filtered values from `epochIdentifier` could be stored in the `Params` of other modules, so they can be modified by governance.

Governance can change epoch periods from `week` to `day` as needed.

### Queries[​](broken://pages/mpUK0ijuB0MUzu2DJwoI) <a href="#queries" id="queries"></a>

The `x/epochs` module provides the following queries to check the module's state.

```
service Query {
  // EpochInfos provide running epochInfos
  rpc EpochInfos(QueryEpochsInfoRequest) returns (QueryEpochsInfoResponse) {}
  // CurrentEpoch provide current epoch of specified identifier
  rpc CurrentEpoch(QueryCurrentEpochRequest) returns (QueryCurrentEpochResponse) {}
}
```

### Future Improvements[​](broken://pages/mpUK0ijuB0MUzu2DJwoI) <a href="#future-improvements" id="future-improvements"></a>

#### Correct Usage[​](broken://pages/mpUK0ijuB0MUzu2DJwoI) <a href="#correct-usage" id="correct-usage"></a>

In the current design, each epoch should be at least two blocks, as the start block should be different from the endblock. Because of this, the time allocated to each epoch will be `max(block_time x 2, epoch_duration)`. For example: if the `epoch_duration` is set to `1s`, and `block_time` is `5s`, actual epoch time should be `10s`.

It is recommended to configure `epoch_duration` to be more than two times the `block_time`, to use this module correctly. If there is a mismatch between the `epoch_duration` and the actual epoch time, as in the example above, then module logic could become invalid.

#### Block-Time Drifts[​](broken://pages/mpUK0ijuB0MUzu2DJwoI) <a href="#block-time-drifts" id="block-time-drifts"></a>

This implementation of the `x/epochs` module has block-time drifts based on the value of `block_time`. For example: if we have an epoch of 100 units that ends at `t=100`, and we have a block at `t=97` and a block at `t=104` and `t=110`, this epoch ends at `t=104`, and the new epoch will start at `t=110`.

There are time drifts here, varying about 1-2 blocks time, which will slow down epochs.


# erc20

### Abstract[​](#abstract) <a href="#abstract" id="abstract"></a>

This document specifies the internal `x/erc20` module of the LagomChain Hub.

The `x/erc20` module enables the LagomChain Hub to support a trustless, on-chain bidirectional internal conversion of tokens between LagomChain' EVM and Cosmos runtimes, specifically the `x/evm` and `x/bank` modules. This allows token holders on LagomChain to instantaneously convert their native Cosmos `sdk.Coins` (in this document referred to as "Coin(s)") to ERC-20 (aka "Token(s)") and vice versa, while retaining fungibility with the original asset on the issuing environment/runtime (EVM or Cosmos) and preserving ownership of the ERC-20 contract.

This conversion functionality is fully governed by native LAGOM token holders who manage the canonical `TokenPair` registrations (ie, ERC20 ←→ Coin mappings). This governance functionality is implemented using the Cosmos-SDK `gov` module with custom proposal types for registering and updating the canonical mappings respectively.

Why is this important? Cosmos and the EVM are two runtimes that are not compatible by default. The native Cosmos Coins cannot be used in applications that require the ERC-20 standard. Cosmos coins are held on the `x/bank` module (with access to module methods like querying the supply or balances) and ERC-20 Tokens live on smart contracts. This problem is similar to [wETH](https://coinmarketcap.com/alexandria/article/what-is-wrapped-ethereum-weth), with the difference, that it not only applies to gas tokens (like LAGOM), but to all Cosmos Coins (IBC vouchers, staking and gov coins, etc.) as well.

With the `x/erc20` users on LagomChain can

* use existing native cosmos assets (like OSMO or ATOM) on EVM-based chains, e.g. for Trading IBC tokens on DeFi protocols, buying NFT, etc.
* transfer existing tokens on Ethereum and other EVM-based chains to LagomChain to take advantage of application-specific chains in the Cosmos ecosystem
* build new applications that are based on ERC-20 smart contracts and have access to the Cosmos ecosystem.

### Contents[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#contents" id="contents"></a>

1. [**Concepts**](#concepts)
2. [**State**](#state)
3. [**State Transitions**](#state-transitions)
4. [**Transactions**](#transactions)
5. [**Hooks**](#hooks)
6. [**Events**](#events)
7. [**Parameters**](#parameters)
8. [**Clients**](#clients)

### Concepts[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#concepts" id="concepts"></a>

#### Token Pair[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#token-pair" id="token-pair"></a>

The `x/erc20` module maintains a canonical one-to-one mapping of native Cosmos Coin denomination to ERC20 Token contract addresses (i.e `sdk.Coin` ←→ ERC20), called `TokenPair`. The conversion of the ERC20 tokens ←→ Coin of a given pair can be enabled or disabled via governance.

#### Token Pair Registration[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#token-pair-registration" id="token-pair-registration"></a>

Users can register a new token pair proposal through the governance module and initiate a vote to include the token pair in the module. Depending on which exists first, the coin or the token, you can either register a Cosmos Coin or a ERC20 Token to create a token pair. One proposal can inculde several token pairs.

When the proposal passes, the erc20 module registers the Cosmos Coin and ERC20 Token mapping on the application's store.

**Registration of a Cosmos Coin**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

A native Cosmos Coin corresponds to an `sdk.Coin` that is native to the bank module. It can be either the native staking/gas denomination (e.g. LAGOM, ATOM, etc) or an IBC fungible token voucher (i.e. with denom format of `ibc/{hash}`).

When a proposal is initiated for an existing native Cosmos Coin, the erc20 module will deploy a factory ERC20 contract, representing the ERC20 token for the token pair, giving the module ownership of that contract.

**Registration of an ERC20 token**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

A proposal for an existing (i.e already deployed) ERC20 contract can be initiated too. In this case, the ERC20 maintains the original owner of the contract and uses an escrow & mint / burn & unescrow mechanism similar to the one defined by the [ICS20 - Fungible Token Transfer](https://github.com/cosmos/ibc/blob/master/spec/app/ics-020-fungible-token-transfer) specification. The token pair is composed of the original ERC20 token and a corresponding native Cosmos coin denomination.

**Token details and metadata**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

Coin metadata is derived from the ERC20 token details (name, symbol, decimals) and vice versa. A special case is also described below that for the ERC20 representation of IBC fungible token (ICS20) vouchers.

**Coin Metadata to ERC20 details**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

During the registration of a Cosmos Coin the following bank `Metadata` is used to deploy a ERC20 contract:

* **Name**
* **Symbol**
* **Decimals**

The native Cosmos Coin contains a more extensive metadata than the ERC20 and includes all necessary details for the conversion into a ERC20 Token, which requires no additional population of data.

**IBC voucher Metadata to ERC20 details**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

IBC vouchers should comply to the following standard:

* **Name**: `{NAME} channel-{channel}`
* **Symbol**: `ibc{NAME}-{channel}`
* **Decimals**: derived from bank `Metadata`

**ERC20 details to Coin Metadata**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

During the Registration of an ERC20 Token the Coin metadata is derived from the ERC20 metadata and the bank metadata:

* **Description**: `Cosmos coin token representation of {contractAddress}`
* **DenomUnits**:
  * Coin: `0`
  * ERC20: `{uint32(erc20Data.Decimals)}`
* **Base**: `{"erc20/%s", address}`
* **Display**: `{erc20Data.Name}`
* **Name**: `{types.CreateDenom(strContract)}`
* **Symbol:** `{erc20Data.Symbol}`

#### Token Pair Modifiers[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#token-pair-modifiers" id="token-pair-modifiers"></a>

A valid token pair can be modified through several governance proposals. The internal conversion of a token pair can be toggled with `ToggleTokenConversionProposal`, so that the conversions between the token pair's tokens can be enabled or disabled.

#### Token Conversion[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#token-conversion" id="token-conversion"></a>

Once a token pair proposal passes, the module allows for the conversion of that token pair. Holders of native Cosmos coins and IBC vouchers on the LagomChain chain can convert their Coin into ERC20 Tokens, which can then be used in LagomChain EVM, by creating a `ConvertCoin` Tx. Vice versa, the `ConvertERC20` Tx allows holders of ERC20 tokens on the LagomChain chain to convert ERC-20 tokens back to their native Cosmos Coin representation.

Depending on the ownership of the ERC20 contract, the ERC20 tokens either follow a burn/mint or a transfer/escrow mechanism during conversion.

#### Malicious Contracts[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#malicious-contracts" id="malicious-contracts"></a>

The ERC20 standard is an interface that defines a set of method signatures (name, arguments and output) without defining its methods' internal logic. Therefore it is possible for developers to deploy contracts that contain hidden malicious behaviour within those methods. For instance, the ERC20 `transfer` method, which is responsible for sending an `amount` of tokens to a given `recipient` could include code to siphon some amount of tokens intended for the recipient into a different predefined account, which is owned by the malicious contract deployer.

More sophisticated malicious implementations might also inherit code from customized ERC20 contracts that include malicous behaviour. For an overview of more extensive examples, please review the x/erc20 audit, section `IF-LAGOM-06: IERC20 Contracts may execute arbitrary code`.

As the `x/erc20` module allows any arbitrary ERC20 contract to be registered through governance, it is essential that the proposer or the voters manually verify during voting phase that the proposed contract uses the default ERC20.sol implementation.

Here are our recommendations for the reviewing process:

* contract solidity code should be verified and accessable (e.g. using an explorer)
* contract should be audited by a reputabele auditor
* inherited contracts need to be verified for correctness

### State[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#state" id="state"></a>

#### State Objects[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#state-objects" id="state-objects"></a>

The `x/erc20` module keeps the following objects in state:

| State Object       | Description                                    | Key                         | Value               | Store |
| ------------------ | ---------------------------------------------- | --------------------------- | ------------------- | ----- |
| `TokenPair`        | Token Pair bytecode                            | `[]byte{1} + []byte(id)`    | `[]byte{tokenPair}` | KV    |
| `TokenPairByERC20` | Token Pair id bytecode by erc20 contract bytes | `[]byte{2} + []byte(erc20)` | `[]byte(id)`        | KV    |
| `TokenPairByDenom` | Token Pair id bytecode by denom string         | `[]byte{3} + []byte(denom)` | `[]byte(id)`        | KV    |

**Token Pair**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

One-to-one mapping of native Cosmos coin denomination to ERC20 token contract addresses (i.e `sdk.Coin` ←→ ERC20).

```
type TokenPair struct {
    // address of ERC20 contract token
    Erc20Address string `protobuf:"bytes,1,opt,name=erc20_address,json=erc20Address,proto3" json:"erc20_address,omitempty"`
    // cosmos base denomination to be mapped to
    Denom string `protobuf:"bytes,2,opt,name=denom,proto3" json:"denom,omitempty"`
    // shows token mapping enable status
    Enabled bool `protobuf:"varint,3,opt,name=enabled,proto3" json:"enabled,omitempty"`
    // ERC20 owner address ENUM (0 invalid, 1 ModuleAccount, 2 external address
    ContractOwner Owner `protobuf:"varint,4,opt,name=contract_owner,json=contractOwner,proto3,enum=lagom.erc20.v1.Owner" json:"contract_owner,omitempty"`
}
```

**Token pair ID**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

The unique identifier of a `TokenPair` is obtained by obtaining the SHA256 hash of the ERC20 hex contract address and the Coin denomination using the following function:

```
tokenPairId = sha256(erc20 + "|" + denom)
```

**Token Origin**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

The `ConvertCoin` and `ConvertERC20` functionalities use the owner field to check whether the token being used is a native Coin or a native ERC20. The field is based on the token registration proposal type (`RegisterCoinProposal` = 1, `RegisterERC20Proposal` = 2).

The `Owner` enumerates the ownership of a ERC20 contract.

```
type Owner int32

const (
    // OWNER_UNSPECIFIED defines an invalid/undefined owner.
    OWNER_UNSPECIFIED Owner = 0
    // OWNER_MODULE erc20 is owned by the erc20 module account.
    OWNER_MODULE Owner = 1
    // EXTERNAL erc20 is owned by an external account.
    OWNER_EXTERNAL Owner = 2
)
```

The `Owner` can be checked with the following helper functions:

```
// IsNativeCoin returns true if the owner of the ERC20 contract is the
// erc20 module account
func (tp TokenPair) IsNativeCoin() bool {
    return tp.ContractOwner == OWNER_MODULE
}

// IsNativeERC20 returns true if the owner of the ERC20 contract not the
// erc20 module account
func (tp TokenPair) IsNativeERC20() bool {
    return tp.ContractOwner == OWNER_EXTERNAL
}
```

**Token Pair by ERC20 and by Denom**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

`TokenPairByERC20` and `TokenPairByDenom` are additional state objects for querying a token pair id.

#### Genesis State[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#genesis-state" id="genesis-state"></a>

The `x/erc20` module's `GenesisState` defines the state necessary for initializing the chain from a previous exported height. It contains the module parameters and the registered token pairs :

```
// GenesisState defines the module's genesis state.
type GenesisState struct {
    // module parameters
    Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"`
    // registered token pairs
    TokenPairs []TokenPair `protobuf:"bytes,2,rep,name=token_pairs,json=tokenPairs,proto3" json:"token_pairs"`
}
```

### State Transitions[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#state-transitions" id="state-transitions"></a>

The erc20 modules allows for two types of registration state transitions. Depending on how token pairs are registered, with `RegisterCoinProposal` or `RegisterERC20Proposal`, there are four possible conversion state transitions.

#### Token Pair Registration[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#token-pair-registration-1" id="token-pair-registration-1"></a>

Both the Cosmos coin and the ERC20 token registration allow for registering several token pairs with one proposal. For simplicity, the following description describes the registration of only one token pair per proposal.

**1. Register Coin**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

A user registers a native Cosmos Coin. Once the proposal passes (i.e is approved by governance), the ERC20 module uses a factory pattern to deploy an ERC20 token contract representation of the Cosmos Coin. Note that the native LAGOM coin cannot be registered, as any coin including "evm" in its denomination cannot be registered. Instead, the LAGOM token can be converted by Nomand's wrapped LagomChain (WLAGOM) contract.

1. User submits a `RegisterCoinProposal`
2. Validators of the LagomChain Hub vote on the proposal using `MsgVote` and proposal passes
3. If Cosmos coin or IBC voucher exist on the bank module supply, create the ERC20 token contract on the EVM based on the ERC20Mintable ([ERC20Mintable by openzeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC20)) interface
   * Initial supply: 0
   * Token details (Name, Symbol, Decimals, etc) are derived from the bank module `Metadata` field on the proposal content.

**2. Register ERC20**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

A user registers a ERC20 token contract that is already deployed on the EVM module. Once the proposal passes (i.e. is approved by governance), the ERC20 module creates a Cosmos coin representation of the ERC20 token.

1. User submits a `RegisterERC20Proposal`
2. Validators of the LAGOMCHAIN chain vote on the proposal using `MsgVote` and proposal passes
3. If ERC-20 contract is deployed on the EVM module, create a bank coin `Metadata` from the ERC20 details.

#### Token Pair Conversion[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#token-pair-conversion" id="token-pair-conversion"></a>

Conversion of a registered `TokenPair` can be done via:

* Cosmos transaction (`ConvertCoin` and `ConvertERC20)`
* Ethereum transaction (i.e sending a `MsgEthereumTx` that leverages the EVM hook)

**1. Registered Coin**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

tip

**Context:** A `TokenPair` has been created through a `RegisterCoinProposal` governance proposal. The proposal created an `ERC20` contract ([ERC20Mintable by openzeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC20)) of the ERC20 token representation of the Coin from the `ModuleAccount`, assigning it as the `owner` of the contract and thus granting it the permission to call the `mint()` and `burnFrom()` methods of the ERC20.

**Invariants**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

* Only the `ModuleAccount` should have the Minter Role on the ERC20. Otherwise, the user could unilaterally mint an infinite supply of the ERC20 token and then convert them to the native Coin
* The user and the `ModuleAccount` (owner) should be the only ones that have the Burn Role for a Cosmos Coin
* There shouldn't exist any native Cosmos Coin ERC20 Contract (eg LAGOM, Atom, Osmo ERC20 contracts) that is not owned by the governance
* Token/Coin supply is maintained at all times:
  * Total Coin supply = Coins + Escrowed Coins
  * Total Token supply = Escrowed Coins = Minted Tokens

**1.1 Coin to ERC20**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

1. User submits `ConvertCoin` Tx
2. Check if conversion is allowed for the pair, sender and recipient
   * global parameter is enabled
   * token pair is enabled
   * sender tokens are not vesting (checked in the bank module)
   * recipient address is not blacklisted
3. If Coin is a native Cosmos Coin and Token Owner is `ModuleAccount`
   1. Escrow Cosmos coin by sending them to the erc20 module account
   2. Call `mint()` ERC20 tokens from the `ModuleAccount` address and send minted tokens to recipient address
4. Check if token balance increased by amount

**1.2 ERC20 to Coin**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

1. User submits a `ConvertERC20` Tx
2. Check if conversion is allowed for the pair, sender and recipient (see [1.1 Coin to ERC20](broken://pages/FSYNg5BzUVZelax1e1Mu))
3. If token is a ERC20 and Token Owner is `ModuleAccount`
   1. Call `burnCoins()` on ERC20 to burn ERC20 tokens from the user balance
   2. Send Coins (previously escrowed, see [1.1 Coin to ERC20](broken://pages/FSYNg5BzUVZelax1e1Mu)) from module to the recipient address.
4. Check if
   * Coin balance increased by amount
   * Token balance decreased by amount

**2. Registered ERC20**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

tip

**Context:** A `TokenPair` has been created through a `RegisterERC20Proposal` governance proposal. The `ModuleAccount` is not the owner of the contract, so it can't mint new tokens or burn on behalf of the user. The mechanism described below follows the same model as the ICS20 standard, by using escrow & mint / burn & unescrow logic.

**Invariants**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

* ERC20 Token supply on the EVM runtime is maintained at all times:
  * Escrowed ERC20 + Minted Cosmos Coin representation of ERC20 = Burned Cosmos Coin representation of ERC20 + Unescrowed ERC20
    * Convert 10 ERC20 → Coin, the total supply increases by 10. Mint on Cosmos side, no changes on EVM
    * Convert 10 Coin → ERC20, the total supply decreases by 10. Burn on Cosmos side , no changes of supply on EVM
  * Total ERC20 token supply = Non Escrowed Tokens + Escrowed Tokens (on Module account address)
  * Total Coin supply for the native ERC20 = Escrowed ERC20 Tokens on module account (i.e balance) = Minted Coins

**2.1 ERC20 to Coin**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

1. User submits a `ConvertERC20` Tx
2. Check if conversion is allowed for the pair, sender and recipient (See [1.1 Coin to ERC20](broken://pages/FSYNg5BzUVZelax1e1Mu))
3. If token is a ERC20 and Token Owner is **not** `ModuleAccount`
   1. Escrow ERC20 token by sending them to the erc20 module account
   2. Mint Cosmos coins of the corresponding token pair denomination and send coins to the recipient address
4. Check if
   * Coin balance increased by amount
   * Token balance decreased by amount
5. Fail if unexpected `Approval` event found in logs to prevent malicious contract behaviour

**2.2 Coin to ERC20**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

1. User submits `ConvertCoin` Tx
2. Check if conversion is allowed for the pair, sender and recipient
3. If coin is a native Cosmos coin and Token Owner is **not** `ModuleAccount`
   1. Escrow Cosmos Coins by sending them to the erc20 module account
   2. Unlock escrowed ERC20 from the module address by sending it to the recipient
   3. Burn escrowed Cosmos coins
4. Check if token balance increased by amount
5. Fail if unexpected `Approval` event found in logs to prevent malicious contract behaviour

### Transactions[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#transactions" id="transactions"></a>

This section defines the `sdk.Msg` concrete types that result in the state transitions defined on the previous section.

#### `RegisterCoinProposal`[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#registercoinproposal" id="registercoinproposal"></a>

A gov `Content` type to register a token pair from a Cosmos Coin. Governance users vote on this proposal and it automatically executes the custom handler for `RegisterCoinProposal` when the vote passes.

```
type RegisterCoinProposal struct {
    // title of the proposal
    Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
    // proposal description
    Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
    // metadata slice of the native Cosmos coins
    Metadata []types.Metadata `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata"`
}
```

The proposal content stateless validation fails if:

* Title is invalid (length or char)
* Description is invalid (length or char)
* Metadata is invalid
  * Name and Symbol are not blank
  * Base and Display denominations are valid coin denominations
  * Base and Display denominations are present in the DenomUnit slice
  * Base denomination has exponent 0
  * Denomination units are sorted in ascending order
  * Denomination units not duplicated

#### `RegisterERC20Proposal`[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#registererc20proposal" id="registererc20proposal"></a>

A gov `Content` type to register a token pair from an ERC20 Token. Governance users vote on this proposal and it automatically executes the custom handler for `RegisterERC20Proposal` when the vote passes.

```
type RegisterERC20Proposal struct {
    // title of the proposal
    Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
    // proposal description
    Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
    // contract addresses of ERC20 tokens
    Erc20Addresses []string `protobuf:"bytes,3,rep,name=erc20addresses,proto3" json:"erc20addresses,omitempty"`
}
```

The proposal Content stateless validation fails if:

* Title is invalid (length or char)
* Description is invalid (length or char)
* ERC20Addresses is invalid

#### `MsgConvertCoin`[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#msgconvertcoin" id="msgconvertcoin"></a>

A user broadcasts a `MsgConvertCoin` message to convert a Cosmos Coin to a ERC20 token.

```
type MsgConvertCoin struct {
    // Cosmos coin which denomination is registered on erc20 bridge.
    // The coin amount defines the total ERC20 tokens to convert.
    Coin types.Coin `protobuf:"bytes,1,opt,name=coin,proto3" json:"coin"`
    // recipient hex address to receive ERC20 token
    Receiver string `protobuf:"bytes,2,opt,name=receiver,proto3" json:"receiver,omitempty"`
    // cosmos bech32 address from the owner of the given ERC20 tokens
    Sender string `protobuf:"bytes,3,opt,name=sender,proto3" json:"sender,omitempty"`
}
```

Message stateless validation fails if:

* Coin is invalid (invalid denom or non-positive amount)
* Receiver hex address is invalid
* Sender bech32 address is invalid

#### `MsgConvertERC20`[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#msgconverterc20" id="msgconverterc20"></a>

A user broadcasts a `MsgConvertERC20` message to convert a ERC20 token to a native Cosmos coin.

```
type MsgConvertERC20 struct {
    // ERC20 token contract address registered on erc20 bridge
    ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"`
    // amount of ERC20 tokens to mint
    Amount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,2,opt,name=amount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"amount"`
    // bech32 address to receive SDK coins.
    Receiver string `protobuf:"bytes,3,opt,name=receiver,proto3" json:"receiver,omitempty"`
    // sender hex address from the owner of the given ERC20 tokens
    Sender string `protobuf:"bytes,4,opt,name=sender,proto3" json:"sender,omitempty"`
}
```

Message stateless validation fails if:

* Contract address is invalid
* Amount is not positive
* Receiver bech32 address is invalid
* Sender hex address is invalid

#### `ToggleTokenConversionProposal`[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#toggletokenconversionproposal" id="toggletokenconversionproposal"></a>

A gov Content type to toggle the internal conversion of a token pair.

```
type ToggleTokenConversionProposal struct {
    // title of the proposal
    Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
    // proposal description
    Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
    // token identifier can be either the hex contract address of the ERC20 or the
    // Cosmos base denomination
    Token string `protobuf:"bytes,3,opt,name=token,proto3" json:"token,omitempty"`
}
```

### Hooks[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#hooks" id="hooks"></a>

The erc20 module implements transaction hooks from the EVM in order to trigger token pair conversion.

#### EVM Hooks[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#evm-hooks" id="evm-hooks"></a>

The EVM hooks allows users to convert ERC20s to Cosmos Coins by sending an Ethereum tx transfer to the module account address. This enables native conversion of tokens via Metamask and EVM-enabled wallets for both token pairs that have been registered through a native Cosmos coin or an ERC20 token. Note that additional coin/token balance checks for sender and receiver to prevent malicious contract behaviour (as performed in the [`ConvertERC20` msg](broken://pages/FSYNg5BzUVZelax1e1Mu)) cannot be done here, as the balance prior to the transaction is not available in the hook.

**Registered Coin: ERC20 to Coin**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

1. User transfers ERC20 tokens to the `ModuleAccount` address to escrow them
2. Check if the ERC20 Token that was transferred from the sender is a native ERC20 or a native Cosmos Coin by looking at the [Ethereum event logs](https://medium.com/mycrypto/understanding-event-logs-on-the-ethereum-blockchain-f4ae7ba50378#:~:text=A%20log%20record%20can%20be,or%20a%20change%20of%20ownership.\&text=Each%20log%20record%20consists%20of,going%20on%20in%20an%20event)
3. If the token contract address corresponds to the ERC20 representation of a native Cosmos Coin
   1. Call `burn()` ERC20 method from the `ModuleAccount`. Note that this is the same as 1.2, but since the tokens are already on the ModuleAccount balance, we burn the tokens from the module address instead of calling `burnFrom()`. Also note that we don't need to mint because [1.1 coin to erc20](broken://pages/FSYNg5BzUVZelax1e1Mu) escrows the coin
   2. Transfer Cosmos Coin to the bech32 account address of the sender hex address

**Registered ERC20: ERC20 to Coin**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

1. User transfers coins to the`ModuleAccount` to escrow them
2. Check if the ERC20 Token that was transferred is a native ERC20 or a native cosmos coin
3. If the token contract address is a native ERC20 token
   1. Mint Cosmos Coin
   2. Transfer Cosmos Coin to the bech32 account address of the sender hex

### Events[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#events" id="events"></a>

The `x/erc20` module emits the following events:

#### Register Coin Proposal[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#register-coin-proposal" id="register-coin-proposal"></a>

| Type            | Attribute Key   | Attribute Value   |
| --------------- | --------------- | ----------------- |
| `register_coin` | `"cosmos_coin"` | `{denom}`         |
| `register_coin` | `"erc20_token"` | `{erc20_address}` |

#### Register ERC20 Proposal[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#register-erc20-proposal" id="register-erc20-proposal"></a>

| Type             | Attribute Key   | Attribute Value   |
| ---------------- | --------------- | ----------------- |
| `register_erc20` | `"cosmos_coin"` | `{denom}`         |
| `register_erc20` | `"erc20_token"` | `{erc20_address}` |

#### Toggle Token Conversion[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#toggle-token-conversion" id="toggle-token-conversion"></a>

| Type                      | Attribute Key   | Attribute Value   |
| ------------------------- | --------------- | ----------------- |
| `toggle_token_conversion` | `"erc20_token"` | `{erc20_address}` |
| `toggle_token_conversion` | `"cosmos_coin"` | `{denom}`         |

#### Convert Coin[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#convert-coin" id="convert-coin"></a>

| Type           | Attribute Key   | Attribute Value              |
| -------------- | --------------- | ---------------------------- |
| `convert_coin` | `"sender"`      | `{msg.Sender}`               |
| `convert_coin` | `"receiver"`    | `{msg.Receiver}`             |
| `convert_coin` | `"amount"`      | `{msg.Coin.Amount.String()}` |
| `convert_coin` | `"cosmos_coin"` | `{denom}`                    |
| `convert_coin` | `"erc20_token"` | `{erc20_address}`            |

#### Convert ERC20[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#convert-erc20" id="convert-erc20"></a>

| Type            | Attribute Key   | Attribute Value         |
| --------------- | --------------- | ----------------------- |
| `convert_erc20` | `"sender"`      | `{msg.Sender}`          |
| `convert_erc20` | `"receiver"`    | `{msg.Receiver}`        |
| `convert_erc20` | `"amount"`      | `{msg.Amount.String()}` |
| `convert_erc20` | `"cosmos_coin"` | `{denom}`               |
| `convert_erc20` | `"erc20_token"` | `{msg.ContractAddress}` |

### Parameters[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#parameters" id="parameters"></a>

The erc20 module contains the following parameters:

| Key             | Type | Default Value |
| --------------- | ---- | ------------- |
| `EnableErc20`   | bool | `true`        |
| `EnableEVMHook` | bool | `true`        |

#### Enable ERC20[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#enable-erc20" id="enable-erc20"></a>

The `EnableErc20` parameter toggles all state transitions in the module. When the parameter is disabled, it will prevent all token pair registration and conversion functionality.

#### Enable EVM Hook[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#enable-evm-hook" id="enable-evm-hook"></a>

The `EnableEVMHook` parameter enables the EVM hook to convert an ERC20 token to a Cosmos Coin by transferring the Tokens through a `MsgEthereumTx` to the `ModuleAddress` Ethereum address.

### Clients[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#clients" id="clients"></a>

#### CLI[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#cli" id="cli"></a>

Find below a list of  `lagomd` commands added with the `x/erc20` module. You can obtain the full list by using the `lagomd -h` command. A CLI command can look like this:

```
lagomd query erc20 params
```

**Queries**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

| Command         | Subcommand    | Description                    |
| --------------- | ------------- | ------------------------------ |
| `query` `erc20` | `params`      | Get erc20 params               |
| `query` `erc20` | `token-pair`  | Get registered token pair      |
| `query` `erc20` | `token-pairs` | Get all registered token pairs |

**Transactions**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

| Command      | Subcommand      | Description                    |
| ------------ | --------------- | ------------------------------ |
| `tx` `erc20` | `convert-coin`  | Convert a Cosmos Coin to ERC20 |
| `tx` `erc20` | `convert-erc20` | Convert a ERC20 to Cosmos Coin |

**Proposals**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

The `tx gov submit-legacy-proposal` commands allow users to query create a proposal using the governance module CLI:

**`register-coin`**

Allows users to submit a `RegisterCoinProposal`. Submit a proposal to register a Cosmos coin to the erc20 along with an initial deposit. Upon passing, the proposal details must be supplied via a JSON file.

```
lagomd tx gov submit-legacy-proposal register-coin METADATA_FILE [flags]
```

Where METADATA\_FILE contains (example):

```
{
  "metadata": [
    {
            "description": "The native staking and governance token of the Osmosis chain",
            "denom_units": [
                {
                        "denom": "ibc/<HASH>",
                        "exponent": 0,
                        "aliases": ["ibcuosmo"]
                },
                {
                        "denom": "OSMO",
                        "exponent": 6
                }
            ],
            "base": "ibc/<HASH>",
            "display": "OSMO",
            "name": "Osmo",
            "symbol": "OSMO"
        }
    ]
}
```

**`register-erc20`**

Allows users to submit a `RegisterERC20Proposal`. Submit a proposal to register ERC20 tokens along with an initial deposit. To register multiple tokens in one proposal pass them after each other e.g. `register-erc20 <contract-address1> <contract-address2>`.

```
lagomd tx gov submit-legacy-proposal register-erc20 ERC20_ADDRESS... [flags]
```

**`toggle-token-conversion`**

Allows users to submit a `ToggleTokenConversionProposal`.

```
lagomd tx gov submit-legacy-proposal toggle-token-conversion TOKEN [flags]
```

**Update Params**

Allows users to submit a `MsgUpdateParams` with the desired changes on the `x/erc20` module parameters. To do this, you will have to provide a JSON file with the correspondiong message in the `submit-proposal` command.

For more information on how to draft a proposal, refer to the Drafting a proposal section.

```
lagomd tx gov submit-proposal proposal.json [flags]
```

#### gRPC[​](broken://pages/FSYNg5BzUVZelax1e1Mu) <a href="#grpc" id="grpc"></a>

**Queries**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

<table><thead><tr><th width="117.800048828125">Verb</th><th>Method</th><th>Description</th></tr></thead><tbody><tr><td><code>gRPC</code></td><td><a href="http://188.214.128.66:9090/lagom.erc20.v1.Query/Params"><code>http://188.214.128.66:9090/lagom.erc20.v1.Query/Params</code></a><br>or <br><a href="http://46.166.165.25:9090/lagom.erc20.v1.Query/Params"><code>http://46.166.165.25:9090/lagom.erc20.v1.Query/Params</code></a></td><td>Get erc20 params</td></tr><tr><td><code>gRPC</code></td><td><a href="http://188.214.128.66:9090/lagom.erc20.v1.Query/TokenPair"><code>http://188.214.128.66:9090/lagom.erc20.v1.Query/TokenPair</code></a><br>or <br><a href="http://46.166.165.25:9090/lagom.erc20.v1.Query/TokenPair"><code>http://46.166.165.25:9090/lagom.erc20.v1.Query/TokenPair</code></a></td><td>Get registered token pair</td></tr><tr><td><code>gRPC</code></td><td><a href="http://188.214.128.66:9090/lagom.erc20.v1.Query/TokenPairs"><code>http://188.214.128.66:9090/lagom.erc20.v1.Query/TokenPairs</code></a><br>or<br><a href="http://46.166.165.25:9090/lagom.erc20.v1.Query/TokenPairs"><code>http://46.166.165.25:9090/lagom.erc20.v1.Query/TokenPairs</code></a></td><td>Get all registered token pairs</td></tr><tr><td><code>GET</code></td><td><a href="http://188.214.128.66:1317/lagom/erc20/v1/params"><code>http://188.214.128.66:1317/lagom/erc20/v1/params</code></a><br>or<br><a href="http://46.166.165.25:1317/lagom/erc20/v1/params"><code>http://46.166.165.25:1317/lagom/erc20/v1/params</code></a></td><td>Get erc20 params</td></tr><tr><td><code>GET</code></td><td><a href="http://188.214.128.66:1317/lagom/erc20/v1/token_pair"><code>http://188.214.128.66:1317/lagom/erc20/v1/token_pair</code></a><br>or<br><a href="http://46.166.165.25:1317/lagom/erc20/v1/token_pair"><code>http://46.166.165.25:1317/lagom/erc20/v1/token_pair</code></a></td><td>Get registered token pair</td></tr><tr><td><code>GET</code></td><td><a href="http://188.214.128.66:1317/lagom/erc20/v1/token_pairs"><code>http://188.214.128.66:1317/lagom/erc20/v1/token_pairs</code></a><br>or<br><a href="http://46.166.165.25:1317/lagom/erc20/v1/token_pairs"><code>http://46.166.165.25:1317/lagom/erc20/v1/token_pairs</code></a></td><td>Get all registered token pairs</td></tr></tbody></table>

**Transactions**[**​**](broken://pages/FSYNg5BzUVZelax1e1Mu)

<table><thead><tr><th width="122.5999755859375">Verb</th><th>Method</th><th>Description</th></tr></thead><tbody><tr><td><code>gRPC</code></td><td><a href="http://188.214.128.66:1317/lagom/erc20/v1/tx/convert_coin"><code>http://188.214.128.66:1317/lagom/erc20/v1/tx/convert_coin</code></a></td><td>Convert a Cosmos Coin to ERC20</td></tr><tr><td><code>gRPC</code></td><td><a href="http://188.214.128.66:1317/lagom/erc20/v1/tx/convert_erc20"><code>http://188.214.128.66:1317/lagom/erc20/v1/tx/convert_erc20</code></a></td><td>Convert a ERC20 to Cosmos Coin</td></tr><tr><td><code>GET</code></td><td><a href="http://188.214.128.66:1317/lagom/erc20/v1/tx/convert_coin"><code>http://188.214.128.66:1317/lagom/erc20/v1/tx/convert_coin</code></a></td><td>Convert a Cosmos Coin to ERC20</td></tr><tr><td><code>GET</code></td><td><a href="http://188.214.128.66:1317/lagom/erc20/v1/tx/convert_erc20"><code>http://188.214.128.66:1317/lagom/erc20/v1/tx/convert_erc20</code></a></td><td>Convert a ERC20 to Cosmos Coin</td></tr></tbody></table>


# evm

### Abstract[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#abstract" id="abstract"></a>

This document defines the specification of the Ethereum Virtual Machine (EVM) as a Cosmos SDK module.

Since the introduction of Ethereum in 2015, the ability to control digital assets through [**smart contracts**](https://www.fon.hum.uva.nl/rob/Courses/InformationInSpeech/CDROM/Literature/LOTwinterschool2006/szabo.best.vwh.net/idea.html) has attracted a large community of developers to build decentralized applications on the Ethereum Virtual Machine (EVM). This community is continuously creating extensive tooling and introducing standards, which are further increasing the adoption rate of EVM compatible technology.

The growth of EVM-based chains (e.g. Ethereum), however, has uncovered several scalability challenges that are often referred to as the [trilemma of decentralization, security, and scalability](https://vitalik.eth.limo/general/2021/04/07/sharding.html). Developers are frustrated by high gas fees, slow transaction speed & throughput, and chain-specific governance that can only undergo slow change because of its wide range of deployed applications. A solution is required that eliminates these concerns for developers, who build applications within a familiar EVM environment.

The `x/evm` module provides this EVM familiarity on a scalable, high-throughput Proof-of-Stake blockchain. It is built as a [Cosmos SDK module](https://docs.cosmos.network/main/build/building-modules/intro) which allows for the deployment of smart contracts, interaction with the EVM state machine (state transitions), and the use of EVM tooling. It can be used on Cosmos application-specific blockchains, which alleviate the aforementioned concerns through high transaction throughput via [Tendermint Core](https://github.com/tendermint/tendermint), fast transaction finality, and horizontal scalability via [IBC](https://ibcprotocol.org/).

The `x/evm` module is part of the [ethermint library](https://pkg.go.dev/github.com/evmos/ethermint).

### Contents[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#contents" id="contents"></a>

1. [**Concepts**](#concepts)
2. [**State**](#state-1)
3. [**State Transitions**](#state-transitions)
4. [**Transactions**](#transactions)
5. [**ABCI**](#abci)
6. [**Hooks**](#hooks)
7. [**Events**](#events)
8. [**Parameters**](#parameters)
9. [**Client**](#client)

### Module Architecture[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#module-architecture" id="module-architecture"></a>

> **NOTE:**: If you're not familiar with the overall module structure from the SDK modules, please check this [document](https://docs.cosmos.network/main/build/building-modules/structure) as prerequisite reading.

```
evm/
├── client
│   └── cli
│       ├── query.go      # CLI query commands for the module
│       └── tx.go         # CLI transaction commands for the module
├── keeper
│   ├── keeper.go         # ABCI BeginBlock and EndBlock logic
│   ├── keeper.go         # Store keeper that handles the business logic of the module and has access to a specific subtree of the state tree.
│   ├── params.go         # Parameter getter and setter
│   ├── querier.go        # State query functions
│   └── statedb.go        # Functions from types/statedb with a passed in sdk.Context
├── types
│   ├── chain_config.go
│   ├── codec.go          # Type registration for encoding
│   ├── errors.go         # Module-specific errors
│   ├── events.go         # Events exposed to the Tendermint PubSub/Websocket
│   ├── genesis.go        # Genesis state for the module
│   ├── journal.go        # Ethereum Journal of state transitions
│   ├── keys.go           # Store keys and utility functions
│   ├── logs.go           # Types for persisting Ethereum tx logs on state after chain upgrades
│   ├── msg.go            # EVM module transaction messages
│   ├── params.go         # Module parameters that can be customized with governance parameter change proposals
│   ├── state_object.go   # EVM state object
│   ├── statedb.go        # Implementation of the StateDb interface
│   ├── storage.go        # Implementation of the Ethereum state storage map using arrays to prevent non-determinism
│   └── tx_data.go        # Ethereum transaction data types
├── genesis.go            # ABCI InitGenesis and ExportGenesis functionality
├── handler.go            # Message routing
└── module.go             # Module setup for the module manager
```

### Concepts[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#concepts" id="concepts"></a>

#### EVM[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#evm-1" id="evm-1"></a>

The Ethereum Virtual Machine (EVM) is a computation engine which can be thought of as one single entity maintained by thousands of connected computers (nodes) running an Ethereum client. As a virtual machine ([VM](https://en.wikipedia.org/wiki/Virtual_machine)), the EVM is responsible for computing changes to the state deterministically regardless of its environment (hardware and OS). This means that every node has to get the exact same result given an identical starting state and transaction (tx).

The EVM is considered to be the part of the Ethereum protocol that handles the deployment and execution of [smart contracts](https://ethereum.org/en/developers/docs/smart-contracts/). To make a clear distinction:

* The Ethereum protocol describes a blockchain, in which all Ethereum accounts and smart contracts live. It has only one canonical state (a data structure, which keeps all accounts) at any given block in the chain.
* The EVM, however, is the [state machine](https://en.wikipedia.org/wiki/Finite-state_machine) that defines the rules for computing a new valid state from block to block. It is an isolated runtime, which means that code running inside the EVM has no access to network, filesystem, or other processes (not external APIs).

The `x/evm` module implements the EVM as a Cosmos SDK module. It allows users to interact with the EVM by submitting Ethereum txs and executing their containing messages on the given state to evoke a state transition.

**State**[**​**](broken://pages/NpqRewc2B4hzigulBBNu)

The Ethereum state is a data structure, implemented as a [Merkle Patricia Tree](https://en.wikipedia.org/wiki/Merkle_tree), that keeps all accounts on the chain. The EVM makes changes to this data structure resulting in a new state with a different state root. Ethereum can therefore be seen as a state chain that transitions from one state to another by executing transactions in a block using the EVM. A new block of txs can be described through its block header (parent hash, block number, time stamp, nonce, receipts,...).

**Accounts**[**​**](broken://pages/NpqRewc2B4hzigulBBNu)

There are two types of accounts that can be stored in state at a given address:

* **Externally Owned Account (EOA)**: Has nonce (tx counter) and balance
* **Smart Contract**: Has nonce, balance, (immutable) code hash, storage root (another Merkle Patricia Trie)

Smart contracts are just like regular accounts on the blockchain, which additionally store executable code in an Ethereum-specific binary format, known as **EVM bytecode**. They are typically written in an Ethereum high level language, such as Solidity, which is compiled down to EVM bytecode and deployed on the blockchain by submitting a transaction using an Ethereum client.

**Architecture**[**​**](broken://pages/NpqRewc2B4hzigulBBNu)

The EVM operates as a stack-based machine. It's main architecture components consist of:

* Virtual ROM: contract code is pulled into this read only memory when processing txs
* Machine state (volatile): changes as the EVM runs and is wiped clean after processing each tx
  * Program counter (PC)
  * Gas: keeps track of how much gas is used
  * Stack and Memory: compute state changes
* Access to account storage (persistent)

**State Transitions with Smart Contracts**[**​**](broken://pages/NpqRewc2B4hzigulBBNu)

Typically smart contracts expose a public ABI, which is a list of supported ways a user can interact with a contract. To interact with a contract and invoke a state transition, a user will submit a tx carrying any amount of gas and a data payload formatted according to the ABI, specifying the type of interaction and any additional parameters. When the tx is received, the EVM executes the smart contracts' EVM bytecode using the tx payload.

**Executing EVM bytecode**[**​**](broken://pages/NpqRewc2B4hzigulBBNu)

A contract's EVM bytecode consists of basic operations (add, multiply, store, etc...), called **Opcodes**. Each Opcode execution requires gas that needs to be paid with the tx. The EVM is therefore considered quasi-turing complete, as it allows any arbitrary computation, but the amount of computations during a contract execution is limited to the amount of gas provided in the tx. Each Opcode's [**gas cost**](https://www.evm.codes/) reflects the cost of running these operations on actual computer hardware (e.g. `ADD = 3gas` and `SSTORE = 100gas`). To calculate the gas consumption of a tx, the gas cost is multiplied by the **gas price**, which can change depending on the demand of the network at the time. If the network is under heavy load, you might have to pay a higher gas price to get your tx executed. If the gas limit is hit (out of gas exception) no changes to the Ethereum state are applied, except that the sender's nonce increments and their balance goes down to pay for wasting the EVM's time.

Smart contracts can also call other smart contracts. Each call to a new contract creates a new instance of the EVM (including a new stack and memory). Each call passes the sandbox state to the next EVM. If the gas runs out, all state changes are discarded. Otherwise, they are kept.

For further reading, please refer to:

* [EVM](https://eth.wiki/concepts/evm/evm)
* [EVM Architecture](https://cypherpunks-core.github.io/ethereumbook/13evm.html#evm_architecture)
* [What is Ethereum](https://ethdocs.org/en/latest/introduction/what-is-ethereum.html#what-is-ethereum)
* [Opcodes](https://www.ethervm.io/)

#### LagomChain as Geth implementation[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#evmos-as-geth-implementation" id="evmos-as-geth-implementation"></a>

LagomChain contains an implementation of the [Ethereum protocol in Golang](https://geth.ethereum.org/docs/getting-started) (Geth) as a Cosmos SDK module. Geth includes an implementation of the EVM to compute state transitions. Have a look at the [go-ethereum source code](https://github.com/ethereum/go-ethereum/blob/master/core/vm/instructions.go) to see how the EVM opcodes are implemented. Just as Geth can be run as an Ethereum node, LagomChain can be run as a node to compute state transitions with the EVM. LagomChain supports Geth's standard Ethereum JSON-RPC APIs in order to be Web3 and EVM compatible.

**JSON-RPC**[**​**](broken://pages/NpqRewc2B4hzigulBBNu)

JSON-RPC is a stateless, lightweight remote procedure call (RPC) protocol. Primarily this specification defines several data structures and the rules around their processing. It is transport agnostic in that the concepts can be used within the same process, over sockets, over HTTP, or in many various message passing environments. It uses JSON (RFC 4627) as a data format.

**JSON-RPC Example: `eth_call`**[**​**](broken://pages/NpqRewc2B4hzigulBBNu)

The JSON-RPC method `eth_call` allows you to execute messages against contracts. Usually, you need to send a transaction to a Geth node to include it in the mempool, then nodes gossip between each other and eventually the transaction is included in a block and gets executed. `eth_call` however lets you send data to a contract and see what happens without committing a transaction.

In the Geth implementation, calling the endpoint roughly goes through the following steps:

1. The `eth_call` request is transformed to call the `func (s *PublicBlockchainAPI) Call()` function using the `eth` namespace
2. [`Call()`](https://github.com/ethereum/go-ethereum/blob/master/internal/ethapi/api.go#L982) is given the transaction arguments, the block to call against and optional arguments that modify the state to call against. It then calls `DoCall()`.
3. [`DoCall()`](https://github.com/ethereum/go-ethereum/blob/d575a2d3bc76dfbdefdd68b6cffff115542faf75/internal/ethapi/api.go#L891) transforms the arguments into a `ethtypes.message`, instantiates an EVM and applies the message with `core.ApplyMessage`
4. [`ApplyMessage()`](https://github.com/ethereum/go-ethereum/blob/d575a2d3bc76dfbdefdd68b6cffff115542faf75/core/state_transition.go#L180) calls the state transition `TransitionDb()`
5. [`TransitionDb()`](https://github.com/ethereum/go-ethereum/blob/d575a2d3bc76dfbdefdd68b6cffff115542faf75/core/state_transition.go#L275) either `Create()`s a new contract or `Call()`s a contract
6. [`evm.Call()`](https://github.com/ethereum/go-ethereum/blob/d575a2d3bc76dfbdefdd68b6cffff115542faf75/core/vm/evm.go#L168) runs the interpreter `evm.interpreter.Run()` to execute the message. If the execution fails, the state is reverted to a snapshot taken before the execution and gas is consumed.
7. [`Run()`](https://github.com/ethereum/go-ethereum/blob/d575a2d3bc76dfbdefdd68b6cffff115542faf75/core/vm/interpreter.go#L116) performs a loop to execute the opcodes.

The LagomChain implementation is similar and makes use of the gRPC query client which is included in the Cosmos SDK:

1. `eth_call` request is transformed to call the `func (e *PublicAPI) Call` function using the `eth` namespace
2. `Call()` calls `doCall()`
3. `doCall()` transforms the arguments into a `EthCallRequest` and calls `EthCall()` using the query client of the evm module.
4. `EthCall()` transforms the arguments into a `ethtypes.message` and calls \`ApplyMessageWithConfig()
5. `ApplyMessageWithConfig()` instantiates an EVM and either `Create()`s a new contract or `Call()`s a contract using the Geth implementation.

**StateDB**[**​**](broken://pages/NpqRewc2B4hzigulBBNu)

The `StateDB` interface from [go-ethereum](https://github.com/ethereum/go-ethereum/blob/master/core/vm/interface.go) represents an EVM database for full state querying. EVM state transitions are enabled by this interface, which in the `x/evm` module is implemented by the `Keeper`. The implementation of this interface is what makes LagomChain EVM compatible.

#### Consensus Engine[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#consensus-engine" id="consensus-engine"></a>

The application using the `x/evm` module interacts with the Tendermint Core Consensus Engine over an Application Blockchain Interface (ABCI). Together, the application and Tendermint Core form the programs that run a complete blockchain and combine business logic with decentralized data storage.

Ethereum transactions which are submitted to the `x/evm` module take part in this consensus process before being executed and changing the application state. We encourage to understand the basics of the [Tendermint consensus engine](https://docs.tendermint.com/main/introduction/what-is-tendermint.html#intro-to-abci) in order to understand state transitions in detail.

#### Transaction Logs[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#transaction-logs" id="transaction-logs"></a>

On every `x/evm` transaction, the result contains the Ethereum `Log`s from the state machine execution that are used by the JSON-RPC Web3 server for filter querying and for processing the EVM Hooks.

The tx logs are stored in the transient store during tx execution and then emitted through cosmos events after the transaction has been processed. They can be queried via gRPC and JSON-RPC.

#### Block Bloom[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#block-bloom" id="block-bloom"></a>

Bloom is the bloom filter value in bytes for each block that can be used for filter queries. The block bloom value is stored in the transient store and then emitted through a cosmos event during `EndBlock` processing. They can be queried via gRPC and JSON-RPC.

tip

**Note**: Since they are not stored on state, Transaction Logs and Block Blooms are not persisted after upgrades. A user must use an archival node after upgrades in order to obtain legacy chain events.

### State[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#state-1" id="state-1"></a>

This section gives you an overview of the objects stored in the `x/evm` module state, functionalities that are derived from the go-ethereum `StateDB` interface, and its implementation through the Keeper as well as the state implementation at genesis.

#### State Objects[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#state-objects" id="state-objects"></a>

The `x/evm` module keeps the following objects in state:

**State**[**​**](broken://pages/NpqRewc2B4hzigulBBNu)

|             | Description                                                                                                                              | Key                           | Value               | Store     |
| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | ------------------- | --------- |
| Code        | Smart contract bytecode                                                                                                                  | `[]byte{1} + []byte(address)` | `[]byte{code}`      | KV        |
| Storage     | Smart contract storage                                                                                                                   | `[]byte{2} + [32]byte{key}`   | `[32]byte(value)`   | KV        |
| Block Bloom | Block bloom filter, used to accumulate the bloom filter of current block, emitted to events at end blocker.                              | `[]byte{1} + []byte(tx.Hash)` | `protobuf([]Log)`   | Transient |
| Tx Index    | Index of current transaction in current block.                                                                                           | `[]byte{2}`                   | `BigEndian(uint64)` | Transient |
| Log Size    | Number of the logs emitted so far in current block. Used to decide the log index of following logs.                                      | `[]byte{3}`                   | `BigEndian(uint64)` | Transient |
| Gas Used    | Amount of gas used by ethereum messages of current cosmos-sdk tx, it's necessary when cosmos-sdk tx contains multiple ethereum messages. | `[]byte{4}`                   | `BigEndian(uint64)` | Transient |

#### StateDB[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#statedb-1" id="statedb-1"></a>

The `StateDB` interface is implemented by the `StateDB` in the `x/evm/statedb` module to represent an EVM database for full state querying of both contracts and accounts. Within the Ethereum protocol, `StateDB`s are used to store anything within the IAVL tree and take care of caching and storing nested states.

```
// github.com/ethereum/go-ethereum/core/vm/interface.go
type StateDB interface {
 CreateAccount(common.Address)

 SubBalance(common.Address, *big.Int)
 AddBalance(common.Address, *big.Int)
 GetBalance(common.Address) *big.Int

 GetNonce(common.Address) uint64
 SetNonce(common.Address, uint64)

 GetCodeHash(common.Address) common.Hash
 GetCode(common.Address) []byte
 SetCode(common.Address, []byte)
 GetCodeSize(common.Address) int

 AddRefund(uint64)
 SubRefund(uint64)
 GetRefund() uint64

 GetCommittedState(common.Address, common.Hash) common.Hash
 GetState(common.Address, common.Hash) common.Hash
 SetState(common.Address, common.Hash, common.Hash)

 Suicide(common.Address) bool
 HasSuicided(common.Address) bool

 // Exist reports whether the given account exists in state.
 // Notably this should also return true for suicided accounts.
 Exist(common.Address) bool
 // Empty returns whether the given account is empty. Empty
 // is defined according to EIP161 (balance = nonce = code = 0).
 Empty(common.Address) bool

 PrepareAccessList(sender common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList)
 AddressInAccessList(addr common.Address) bool
 SlotInAccessList(addr common.Address, slot common.Hash) (addressOk bool, slotOk bool)
 // AddAddressToAccessList adds the given address to the access list. This operation is safe to perform
 // even if the feature/fork is not active yet
 AddAddressToAccessList(addr common.Address)
 // AddSlotToAccessList adds the given (address,slot) to the access list. This operation is safe to perform
 // even if the feature/fork is not active yet
 AddSlotToAccessList(addr common.Address, slot common.Hash)

 RevertToSnapshot(int)
 Snapshot() int

 AddLog(*types.Log)
 AddPreimage(common.Hash, []byte)

 ForEachStorage(common.Address, func(common.Hash, common.Hash) bool) error
}
```

The `StateDB` in the `x/evm` provides the following functionalities:

**CRUD of Ethereum accounts**[**​**](broken://pages/NpqRewc2B4hzigulBBNu)

You can create `EthAccount` instances from the provided address and set the value to store on the `AccountKeeper`with `createAccount()`. If an account with the given address already exists, this function also resets any preexisting code and storage associated with that address.

An account's coin balance can be is managed through the `BankKeeper` and can be read with `GetBalance()` and updated with `AddBalance()` and `SubBalance()`.

* `GetBalance()` returns the EVM denomination balance of the provided address. The denomination is obtained from the module parameters.
* `AddBalance()` adds the given amount to the address balance coin by minting new coins and transferring them to the address. The coin denomination is obtained from the module parameters.
* `SubBalance()` subtracts the given amount from the address balance by transferring the coins to an escrow account and then burning them. The coin denomination is obtained from the module parameters. This function performs a no-op if the amount is negative or the user doesn't have enough funds for the transfer.

The nonce (or transaction sequence) can be obtained from the Account `Sequence` via the auth module `AccountKeeper`.

* `GetNonce()` retrieves the account with the given address and returns the tx sequence (i.e nonce). The function performs a no-op if the account is not found.
* `SetNonce()` sets the given nonce as the sequence of the address' account. If the account doesn't exist, a new one will be created from the address.

The smart contract bytecode containing arbitrary contract logic is stored on the `EVMKeeper` and it can be queried with `GetCodeHash()` ,`GetCode()` & `GetCodeSize()`and updated with `SetCode()`.

* `GetCodeHash()` fetches the account from the store and returns its code hash. If the account doesn't exist or is not an EthAccount type, it returns the empty code hash value.
* `GetCode()` returns the code byte array associated with the given address. If the code hash from the account is empty, this function returns nil.
* `SetCode()` stores the code byte array to the application KVStore and sets the code hash to the given account. The code is deleted from the store if it is empty.
* `GetCodeSize()` returns the size of the contract code associated with this object, or zero if none.

Gas refunded needs to be tracked and stored in a separate variable in order to add it subtract/add it from/to the gas used value after the EVM execution has finalized. The refund value is cleared on every transaction and at the end of every block.

* `AddRefund()` adds the given amount of gas to the in-memory refund value.
* `SubRefund()` subtracts the given amount of gas from the in-memory refund value. This function will panic if gas amount is greater than the current refund.
* `GetRefund()` returns the amount of gas available for return after the tx execution finalizes. This value is reset to 0 on every transaction.

The state is stored on the `EVMKeeper`. It can be queried with `GetCommittedState()`, `GetState()` and updated with `SetState()`.

* `GetCommittedState()` returns the value set in store for the given key hash. If the key is not registered this function returns the empty hash.
* `GetState()` returns the in-memory dirty state for the given key hash, if not exist load the committed value from KVStore.
* `SetState()` sets the given hashes (key, value) to the state. If the value hash is empty, this function deletes the key from the state, the new value is kept in dirty state at first, and will be committed to KVStore in the end.

Accounts can also be set to a suicide state. When a contract commits suicide, the account is marked as suicided, when committing the code, storage and account are deleted (from the next block and forward).

* `Suicide()` marks the given account as suicided and clears the account balance of the EVM tokens.
* `HasSuicided()` queries the in-memory flag to check if the account has been marked as suicided in the current transaction. Accounts that are suicided will be returned as non-nil during queries and "cleared" after the block has been committed.

To check account existence use `Exist()` and `Empty()`.

* `Exist()` returns true if the given account exists in store or if it has been marked as suicided.
* `Empty()` returns true if the address meets the following conditions:
  * nonce is 0
  * balance amount for evm denom is 0
  * account code hash is empty

**EIP2930 functionality**[**​**](broken://pages/NpqRewc2B4hzigulBBNu)

Supports a transaction type that contains an [access list](https://eips.ethereum.org/EIPS/eip-2930), a list of addresses and storage keys, that the transaction plans to access. The access list state is kept in memory and discarded after the transaction committed.

* `PrepareAccessList()` handles the preparatory steps for executing a state transition in regard to both EIP-2929 and EIP-2930. This method should only be called if Yolov3/Berlin/2929+2930 is applicable at the current number.
  * Add sender to access list (EIP-2929)
  * Add destination to access list (EIP-2929)
  * Add precompiles to access list (EIP-2929)
  * Add the contents of the optional tx access list (EIP-2930)
* `AddressInAccessList()` returns true if the address is registered.
* `SlotInAccessList()` checks if the address and the slots are registered.
* `AddAddressToAccessList()` adds the given address to the access list. If the address is already in the access list, this function performs a no-op.
* `AddSlotToAccessList()` adds the given (address, slot) to the access list. If the address and slot are already in the access list, this function performs a no-op.

**Snapshot state and Revert functionality**[**​**](broken://pages/NpqRewc2B4hzigulBBNu)

The EVM uses state-reverting exceptions to handle errors. Such an exception will undo all changes made to the state in the current call (and all its sub-calls), and the caller could handle the error and don't propagate. You can use `Snapshot()` to identify the current state with a revision and revert the state to a given revision with `RevertToSnapshot()` to support this feature.

* `Snapshot()` creates a new snapshot and returns the identifier.
* `RevertToSnapshot(rev)` undo all the modifications up to the snapshot identified as `rev`.

LagomChain adapted the [go-ethereum journal implementation](https://github.com/ethereum/go-ethereum/blob/master/core/state/journal.go#L39) to support this, it uses a list of journal logs to record all the state modification operations done so far, snapshot is consists of a unique id and an index in the log list, and to revert to a snapshot it just undoes the journal logs after the snapshot index in reversed order.

**Ethereum Transaction logs**[**​**](broken://pages/NpqRewc2B4hzigulBBNu)

With `AddLog()` you can append the given Ethereum `Log` to the list of logs associated with the transaction hash kept in the current state. This function also fills in the tx hash, block hash, tx index and log index fields before setting the log to store.

#### Keeper[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#keeper" id="keeper"></a>

The EVM module `Keeper` grants access to the EVM module state and implements `statedb.Keeper` interface to support the `StateDB` implementation. The Keeper contains a store key that allows the DB to write to a concrete subtree of the multistore that is only accessible by the EVM module. Instead of using a trie and database for querying and persistence (the `StateDB` implementation), LagomChain uses the Cosmos `KVStore` (key-value store) and Cosmos SDK `Keeper` to facilitate state transitions.

To support the interface functionality, it imports 4 module Keepers:

* `auth`: CRUD accounts
* `bank`: accounting (supply) and CRUD of balances
* `staking`: query historical headers
* `fee market`: EIP-1559 base fee for processing `DynamicFeeTx` after the `London` hard fork has been activated on the `ChainConfig` parameters

```
type Keeper struct {
 // Protobuf codec
 cdc codec.BinaryCodec
 // Store key required for the EVM Prefix KVStore. It is required by:
 // - storing account's Storage State
 // - storing account's Code
 // - storing Bloom filters by block height. Needed for the Web3 API.
 // For the full list, check the module specification
 storeKey sdk.StoreKey

 // key to access the transient store, which is reset on every block during Commit
 transientKey sdk.StoreKey

 // module specific parameter space that can be configured through governance
 paramSpace paramtypes.Subspace
 // access to account state
 accountKeeper types.AccountKeeper
 // update balance and accounting operations with coins
 bankKeeper types.BankKeeper
 // access historical headers for EVM state transition execution
 stakingKeeper types.StakingKeeper
 // fetch EIP1559 base fee and parameters
 feeMarketKeeper types.FeeMarketKeeper

 // chain ID number obtained from the context's chain id
 eip155ChainID *big.Int

 // Tracer used to collect execution traces from the EVM transaction execution
 tracer string
 // trace EVM state transition execution. This value is obtained from the `--trace` flag.
 // For more info check https://geth.ethereum.org/docs/dapp/tracing
 debug bool

 // EVM Hooks for tx post-processing
 hooks types.EvmHooks
}
```

#### Genesis State[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#genesis-state" id="genesis-state"></a>

The `x/evm` module `GenesisState` defines the state necessary for initializing the chain from a previous exported height. It contains the `GenesisAccounts` and the module parameters

```
type GenesisState struct {
  // accounts is an array containing the ethereum genesis accounts.
  Accounts []GenesisAccount `protobuf:"bytes,1,rep,name=accounts,proto3" json:"accounts"`
  // params defines all the parameters of the module.
  Params Params `protobuf:"bytes,2,opt,name=params,proto3" json:"params"`
}
```

#### Genesis Accounts[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#genesis-accounts" id="genesis-accounts"></a>

The `GenesisAccount` type corresponds to an adaptation of the Ethereum `GenesisAccount` type. It defines an account to be initialized in the genesis state.

Its main difference is that the one on LagomChain uses a custom `Storage` type that uses a slice instead of maps for the evm `State` (due to non-determinism), and that it doesn't contain the private key field.

It is also important to note that since the `auth` module on the Cosmos SDK manages the account state, the `Address` field must correspond to an existing `EthAccount` that is stored in the `auth`'s module `Keeper` (i.e `AccountKeeper`). Addresses use the [**EIP55**](https://eips.ethereum.org/EIPS/eip-55) hex [**format**](https://docs.evmos.org/protocol/concepts/accounts#address-formats-for-clients) on `genesis.json`.

```
type GenesisAccount struct {
  // address defines an ethereum hex formated address of an account
  Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
  // code defines the hex bytes of the account code.
  Code string `protobuf:"bytes,2,opt,name=code,proto3" json:"code,omitempty"`
  // storage defines the set of state key values for the account.
  Storage Storage `protobuf:"bytes,3,rep,name=storage,proto3,castrepeated=Storage" json:"storage"`
}
```

### State Transitions[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#state-transitions" id="state-transitions"></a>

The `x/evm` module allows for users to submit Ethereum transactions (`Tx`) and execute their containing messages to evoke state transitions on the given state.

Users submit transactions client-side to broadcast it to the network. When the transaction is included in a block during consensus, it is executed server-side. We highly recommend to understand the basics of the [Tendermint consensus engine](https://docs.tendermint.com/main/introduction/what-is-tendermint.html#intro-to-abci) to understand the State Transitions in detail.

#### Client-Side[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#client-side" id="client-side"></a>

tip

This is based on the `eth_sendTransaction` JSON-RPC

1. A user submits a transaction via one of the available JSON-RPC endpoints using an Ethereum-compatible client or wallet (eg Metamask, WalletConnect, Ledger, etc): a. eth (public) namespace:
   * `eth_sendTransaction`
   * `eth_sendRawTransaction` b. personal (private) namespace:
   * `personal_sendTransaction`
2. An instance of `MsgEthereumTx` is created after populating the RPC transaction using `SetTxDefaults` to fill missing tx arguments with default values
3. The `Tx` fields are validated (stateless) using `ValidateBasic()`
4. The `Tx` is **signed** using the key associated with the sender address and the latest ethereum hard fork (`London`, `Berlin`, etc) from the `ChainConfig`
5. The `Tx` is **built** from the msg fields using the Cosmos Config builder
6. The `Tx` is **broadcast** in [sync mode](https://docs.cosmos.network/main/user/run-node/txs#broadcasting-a-transaction) to ensure to wait for a [`CheckTx`](https://docs.tendermint.com/main/introduction/what-is-tendermint.html#intro-to-abci) execution response. Transactions are validated by the application using `CheckTx()`, before being added to the mempool of the consensus engine.
7. JSON-RPC user receives a response with the [`RLP`](https://eth.wiki/en/fundamentals/rlp) hash of the transaction fields. This hash is different from the default hash used by SDK Transactions that calculates the `sha256` hash of the transaction bytes.

#### Server-Side[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#server-side" id="server-side"></a>

Once a block (containing the `Tx`) has been committed during consensus, it is applied to the application in a series of ABCI msgs server-side.

Each `Tx` is handled by the application by calling [`RunTx`](https://docs.cosmos.network/main/learn/advanced/baseapp). After a stateless validation on each `sdk.Msg` in the `Tx`, the `AnteHandler` confirms whether the `Tx` is an Ethereum or SDK transaction. As an Ethereum transaction it's containing msgs are then handled by the `x/evm` module to update the application's state.

**AnteHandler**[**​**](broken://pages/NpqRewc2B4hzigulBBNu)

The `anteHandler` is run for every transaction. It checks if the `Tx` is an Ethereum transaction and routes it to an internal ante handler. Here, `Tx`s are handled using EthereumTx extension options to process them differently than normal Cosmos SDK transactions. The `antehandler` runs through a series of options and their `AnteHandle` functions for each `Tx`:

* `EthSetUpContextDecorator()` is adapted from SetUpContextDecorator from cosmos-sdk, it ignores gas consumption by setting the gas meter to infinite
* `EthValidateBasicDecorator(evmKeeper)` validates the fields of an Ethereum type Cosmos `Tx` msg
* `EthSigVerificationDecorator(evmKeeper)` validates that the registered chain id is the same as the one on the message, and that the signer address matches the one defined on the message. It's not skipped for RecheckTx, because it set `From` address which is critical from other ante handler to work. Failure in RecheckTx will prevent tx to be included into block, especially when CheckTx succeed, in which case user won't see the error message.
* `EthAccountVerificationDecorator(ak, bankKeeper, evmKeeper)` will verify, that the sender balance is greater than the total transaction cost. The account will be set to store if it doesn't exist, i.e cannot be found on store. This AnteHandler decorator will fail if:
  * any of the msgs is not a MsgEthereumTx
  * from address is empty
  * account balance is lower than the transaction cost
* `EthNonceVerificationDecorator(ak)` validates that the transaction nonces are valid and equivalent to the sender account’s current nonce.
* `EthGasConsumeDecorator(evmKeeper)` validates that the Ethereum tx message has enough to cover intrinsic gas (during CheckTx only) and that the sender has enough balance to pay for the gas cost. Intrinsic gas for a transaction is the amount of gas that the transaction uses before the transaction is executed. The gas is a constant value plus any cost incurred by additional bytes of data supplied with the transaction. This AnteHandler decorator will fail if:
  * the transaction contains more than one message
  * the message is not a MsgEthereumTx
  * sender account cannot be found
  * transaction's gas limit is lower than the intrinsic gas
  * user doesn't have enough balance to deduct the transaction fees (gas\_limit \* gas\_price)
  * transaction or block gas meter runs out of gas
* `CanTransferDecorator(evmKeeper, feeMarketKeeper)` creates an EVM from the message and calls the BlockContext CanTransfer function to see if the address can execute the transaction.
* `EthIncrementSenderSequenceDecorator(ak)` handles incrementing the sequence of the signer (i.e sender). If the transaction is a contract creation, the nonce will be incremented during the transaction execution and not within this AnteHandler decorator.

The options `authante.NewMempoolFeeDecorator()`, `authante.NewTxTimeoutHeightDecorator()` and `authante.NewValidateMemoDecorator(ak)` are the same as for a Cosmos `Tx`. Click [here](https://docs.cosmos.network/main/learn/beginner/gas-fees.html#antehandler) for more on the `anteHandler`.

**EVM module**[**​**](broken://pages/NpqRewc2B4hzigulBBNu)

After authentication through the `antehandler`, each `sdk.Msg` (in this case `MsgEthereumTx`) in the `Tx` is delivered to the Msg Handler in the `x/evm` module and runs through the following the steps:

1. Convert `Msg` to an ethereum `Tx` type
2. Apply `Tx` with `EVMConfig` and attempt to perform a state transition, that will only be persisted (committed) to the underlying KVStore if the transaction does not fail:
   1. Confirm that `EVMConfig` is created
   2. Create the ethereum signer using chain config value from `EVMConfig`
   3. Set the ethereum transaction hash to the (impermanent) transient store so that it's also available on the StateDB functions
   4. Generate a new EVM instance
   5. Confirm that EVM params for contract creation (`EnableCreate`) and contract execution (`EnableCall`) are enabled
   6. Apply message. If `To` address is `nil`, create new contract using code as deployment code. Else call contract at given address with the given input as parameters
   7. Calculate gas used by the evm operation
3. If `Tx` applied successfully
   1. Execute EVM `Tx` postprocessing hooks. If hooks return error, revert the whole `Tx`
   2. Refund gas according to Ethereum gas accounting rules
   3. Update block bloom filter value using the logs generated from the tx
   4. Emit SDK events for the transaction fields and tx logs

### Transactions[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#transactions" id="transactions"></a>

This section defines the `sdk.Msg` concrete types that result in the state transitions defined on the previous section.

### `MsgEthereumTx`[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#msgethereumtx" id="msgethereumtx"></a>

An EVM state transition can be achieved by using the `MsgEthereumTx`. This message encapsulates an Ethereum transaction data (`TxData`) as a `sdk.Msg`. It contains the necessary transaction data fields. Note, that the `MsgEthereumTx` implements both the [`sdk.Msg`](https://github.com/cosmos/cosmos-sdk/blob/v0.39.2/types/tx_msg.go#L7-L29) and [`sdk.Tx`](https://github.com/cosmos/cosmos-sdk/blob/v0.39.2/types/tx_msg.go#L33-L41) interfaces. Normally, SDK messages only implement the former, while the latter is a group of messages bundled together.

```
type MsgEthereumTx struct {
 // inner transaction data
 Data *types.Any `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
 // DEPRECATED: encoded storage size of the transaction
 Size_ float64 `protobuf:"fixed64,2,opt,name=size,proto3" json:"-"`
 // transaction hash in hex format
 Hash string `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty" rlp:"-"`
 // ethereum signer address in hex format. This address value is checked
 // against the address derived from the signature (V, R, S) using the
 // secp256k1 elliptic curve
 From string `protobuf:"bytes,4,opt,name=from,proto3" json:"from,omitempty"`
}
```

This message field validation is expected to fail if:

* `From` field is defined and the address is invalid
* `TxData` stateless validation fails

The transaction execution is expected to fail if:

* Any of the custom `AnteHandler` Ethereum decorators checks fail:
  * Minimum gas amount requirements for transaction
  * Tx sender account doesn't exist or hasn't enough balance for fees
  * Account sequence doesn't match the transaction `Data.AccountNonce`
  * Message signature verification fails
* EVM contract creation (i.e `evm.Create`) fails, or `evm.Call` fails

**Conversion**[**​**](broken://pages/NpqRewc2B4hzigulBBNu)

The `MsgEthreumTx` can be converted to the go-ethereum `Transaction` and `Message` types in order to create and call evm contracts.

```
// AsTransaction creates an Ethereum Transaction type from the msg fields
func (msg MsgEthereumTx) AsTransaction() *ethtypes.Transaction {
 txData, err := UnpackTxData(msg.Data)
 if err != nil {
  return nil
 }

 return ethtypes.NewTx(txData.AsEthereumData())
}

// AsMessage returns the transaction as a core.Message.
func (tx *Transaction) AsMessage(s Signer, baseFee *big.Int) (Message, error) {
 msg := Message{
  nonce:      tx.Nonce(),
  gasLimit:   tx.Gas(),
  gasPrice:   new(big.Int).Set(tx.GasPrice()),
  gasFeeCap:  new(big.Int).Set(tx.GasFeeCap()),
  gasTipCap:  new(big.Int).Set(tx.GasTipCap()),
  to:         tx.To(),
  amount:     tx.Value(),
  data:       tx.Data(),
  accessList: tx.AccessList(),
  isFake:     false,
 }
 // If baseFee provided, set gasPrice to effectiveGasPrice.
 if baseFee != nil {
  msg.gasPrice = math.BigMin(msg.gasPrice.Add(msg.gasTipCap, baseFee), msg.gasFeeCap)
 }
 var err error
 msg.from, err = Sender(s, tx)
 return msg, err
}
```

**Signing**[**​**](broken://pages/NpqRewc2B4hzigulBBNu)

In order for the signature verification to be valid, the `TxData` must contain the `v | r | s` values from the `Signer`. Sign calculates a secp256k1 ECDSA signature and signs the transaction. It takes a keyring signer and the chainID to sign an Ethereum transaction according to EIP-155 standard. This method mutates the transaction as it populates the V, R, S fields of the Transaction's Signature. The function will fail if the sender address is not defined for the msg or if the sender is not registered on the keyring.

```
// Sign calculates a secp256k1 ECDSA signature and signs the transaction. It
// takes a keyring signer and the chainID to sign an Ethereum transaction according to
// EIP-155 standard.
// This method mutates the transaction as it populates the V, R, S
// fields of the Transaction's Signature.
// The function will fail if the sender address is not defined for the msg or if
// the sender is not registered on the keyring
func (msg *MsgEthereumTx) Sign(ethSigner ethtypes.Signer, keyringSigner keyring.Signer) error {
 from := msg.GetFrom()
 if from.Empty() {
  return fmt.Errorf("sender address not defined for message")
 }

 tx := msg.AsTransaction()
 txHash := ethSigner.Hash(tx)

 sig, _, err := keyringSigner.SignByAddress(from, txHash.Bytes())
 if err != nil {
  return err
 }

 tx, err = tx.WithSignature(ethSigner, sig)
 if err != nil {
  return err
 }

 msg.FromEthereumTx(tx)
 return nil
}
```

#### TxData[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#txdata" id="txdata"></a>

The `MsgEthereumTx` supports the 3 valid Ethereum transaction data types from go-ethereum: `LegacyTx`, `AccessListTx` and `DynamicFeeTx`. These types are defined as protobuf messages and packed into a `proto.Any` interface type in the `MsgEthereumTx` field.

* `LegacyTx`: [EIP-155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md) transaction type
* `DynamicFeeTx`: [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) transaction type. Enabled by London hard fork block
* `AccessListTx`: [EIP-2930](https://eips.ethereum.org/EIPS/eip-2930) transaction type. Enabled by Berlin hard fork block

#### `LegacyTx`[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#legacytx" id="legacytx"></a>

The transaction data of regular Ethereum transactions.

```
type LegacyTx struct {
 // nonce corresponds to the account nonce (transaction sequence).
 Nonce uint64 `protobuf:"varint,1,opt,name=nonce,proto3" json:"nonce,omitempty"`
 // gas price defines the value for each gas unit
 GasPrice *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,2,opt,name=gas_price,json=gasPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"gas_price,omitempty"`
 // gas defines the gas limit defined for the transaction.
 GasLimit uint64 `protobuf:"varint,3,opt,name=gas,proto3" json:"gas,omitempty"`
 // hex formatted address of the recipient
 To string `protobuf:"bytes,4,opt,name=to,proto3" json:"to,omitempty"`
 // value defines the unsigned integer value of the transaction amount.
 Amount *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,5,opt,name=value,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"value,omitempty"`
 // input defines the data payload bytes of the transaction.
 Data []byte `protobuf:"bytes,6,opt,name=data,proto3" json:"data,omitempty"`
 // v defines the signature value
 V []byte `protobuf:"bytes,7,opt,name=v,proto3" json:"v,omitempty"`
 // r defines the signature value
 R []byte `protobuf:"bytes,8,opt,name=r,proto3" json:"r,omitempty"`
 // s define the signature value
 S []byte `protobuf:"bytes,9,opt,name=s,proto3" json:"s,omitempty"`
}
```

This message field validation is expected to fail if:

* `GasPrice` is invalid (`nil` , negative or out of int256 bound)
* `Fee` (gasprice \* gaslimit) is invalid
* `Amount` is invalid (negative or out of int256 bound)
* `To` address is invalid (non valid ethereum hex address)

#### `DynamicFeeTx`[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#dynamicfeetx" id="dynamicfeetx"></a>

The transaction data of EIP-1559 dynamic fee transactions.

```
type DynamicFeeTx struct {
 // destination EVM chain ID
 ChainID *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"chainID"`
 // nonce corresponds to the account nonce (transaction sequence).
 Nonce uint64 `protobuf:"varint,2,opt,name=nonce,proto3" json:"nonce,omitempty"`
 // gas tip cap defines the max value for the gas tip
 GasTipCap *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=gas_tip_cap,json=gasTipCap,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"gas_tip_cap,omitempty"`
 // gas fee cap defines the max value for the gas fee
 GasFeeCap *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,4,opt,name=gas_fee_cap,json=gasFeeCap,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"gas_fee_cap,omitempty"`
 // gas defines the gas limit defined for the transaction.
 GasLimit uint64 `protobuf:"varint,5,opt,name=gas,proto3" json:"gas,omitempty"`
 // hex formatted address of the recipient
 To string `protobuf:"bytes,6,opt,name=to,proto3" json:"to,omitempty"`
 // value defines the the transaction amount.
 Amount *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,7,opt,name=value,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"value,omitempty"`
 // input defines the data payload bytes of the transaction.
 Data     []byte     `protobuf:"bytes,8,opt,name=data,proto3" json:"data,omitempty"`
 Accesses AccessList `protobuf:"bytes,9,rep,name=accesses,proto3,castrepeated=AccessList" json:"accessList"`
 // v defines the signature value
 V []byte `protobuf:"bytes,10,opt,name=v,proto3" json:"v,omitempty"`
 // r defines the signature value
 R []byte `protobuf:"bytes,11,opt,name=r,proto3" json:"r,omitempty"`
 // s define the signature value
 S []byte `protobuf:"bytes,12,opt,name=s,proto3" json:"s,omitempty"`
}
```

This message field validation is expected to fail if:

* `GasTipCap` is invalid (`nil` , negative or overflows int256)
* `GasFeeCap` is invalid (`nil` , negative or overflows int256)
* `GasFeeCap` is less than `GasTipCap`
* `Fee` (gas price \* gas limit) is invalid (overflows int256)
* `Amount` is invalid (negative or overflows int256)
* `To` address is invalid (non-valid ethereum hex address)
* `ChainID` is `nil`

#### `AccessListTx`[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#accesslisttx" id="accesslisttx"></a>

The transaction data of EIP-2930 access list transactions.

```
type AccessListTx struct {
 // destination EVM chain ID
 ChainID *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"chainID"`
 // nonce corresponds to the account nonce (transaction sequence).
 Nonce uint64 `protobuf:"varint,2,opt,name=nonce,proto3" json:"nonce,omitempty"`
 // gas price defines the value for each gas unit
 GasPrice *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=gas_price,json=gasPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"gas_price,omitempty"`
 // gas defines the gas limit defined for the transaction.
 GasLimit uint64 `protobuf:"varint,4,opt,name=gas,proto3" json:"gas,omitempty"`
 // hex formatted address of the recipient
 To string `protobuf:"bytes,5,opt,name=to,proto3" json:"to,omitempty"`
 // value defines the unsigned integer value of the transaction amount.
 Amount *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,6,opt,name=value,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"value,omitempty"`
 // input defines the data payload bytes of the transaction.
 Data     []byte     `protobuf:"bytes,7,opt,name=data,proto3" json:"data,omitempty"`
 Accesses AccessList `protobuf:"bytes,8,rep,name=accesses,proto3,castrepeated=AccessList" json:"accessList"`
 // v defines the signature value
 V []byte `protobuf:"bytes,9,opt,name=v,proto3" json:"v,omitempty"`
 // r defines the signature value
 R []byte `protobuf:"bytes,10,opt,name=r,proto3" json:"r,omitempty"`
 // s define the signature value
 S []byte `protobuf:"bytes,11,opt,name=s,proto3" json:"s,omitempty"`
}
```

This message field validation is expected to fail if:

* `GasPrice` is invalid (`nil` , negative or overflows int256)
* `Fee` (gas price \* gas limit) is invalid (overflows int256)
* `Amount` is invalid (negative or overflows int256)
* `To` address is invalid (non-valid ethereum hex address)
* `ChainID` is `nil`

### ABCI[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#abci" id="abci"></a>

The Application Blockchain Interface (ABCI) allows the application to interact with the Tendermint Consensus engine. The application maintains several ABCI connections with Tendermint. The most relevant for the `x/evm` is the [Consensus connection at Commit](https://docs.tendermint.com/v0.33/app-dev/app-development.html#consensus-connection). This connection is responsible for block execution and calls the functions `InitChain` (containing `InitGenesis`), `BeginBlock`, `DeliverTx`, `EndBlock`, `Commit` . `InitChain` is only called the first time a new blockchain is started and `DeliverTx` is called for each transaction in the block.

#### InitGenesis[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#initgenesis" id="initgenesis"></a>

`InitGenesis` initializes the EVM module genesis state by setting the `GenesisState` fields to the store. In particular, it sets the parameters and genesis accounts (state and code).

#### ExportGenesis[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#exportgenesis" id="exportgenesis"></a>

The `ExportGenesis` ABCI function exports the genesis state of the EVM module. In particular, it retrieves all the accounts with their bytecode, balance and storage, the transaction logs, and the EVM parameters and chain configuration.

#### BeginBlock[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#beginblock" id="beginblock"></a>

The EVM module `BeginBlock` logic is executed prior to handling the state transitions from the transactions. The main objective of this function is to:

* Set the context for the current block so that the block header, store, gas meter, etc. are available to the `Keeper` once one of the `StateDB` functions are called during EVM state transitions.
* Set the EIP-155 `ChainID` number (obtained from the full chain-id), in case it hasn't been set before during `InitChain`

#### EndBlock[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#endblock" id="endblock"></a>

The EVM module `EndBlock` logic occurs after executing all the state transitions from the transactions. The main objective of this function is to:

* Emit Block bloom events
  * This is due for web3 compatibility as the Ethereum headers contain this type as a field. The JSON-RPC service uses this event query to construct an Ethereum header from a Tendermint header.
  * The block bloom filter value is obtained from the transient store and then emitted

### Hooks[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#hooks" id="hooks"></a>

The `x/evm` module implements an `EvmHooks` interface that extend and customize the `Tx` processing logic externally.

This supports EVM contracts to call native cosmos modules by

1. defining a log signature and emitting the specific log from the smart contract,
2. recognizing those logs in the native tx processing code, and
3. converting them to native module calls.

To do this, the interface includes a `PostTxProcessing` hook that registers custom `Tx` hooks in the `EvmKeeper`. These `Tx` hooks are processed after the EVM state transition is finalized and doesn't fail. Note that there are no default hooks implemented in the EVM module.

```
type EvmHooks interface {
 // Must be called after tx is processed successfully, if return an error, the whole transaction is reverted.
 PostTxProcessing(ctx sdk.Context, msg core.Message, receipt *ethtypes.Receipt) error
}
```

### `PostTxProcessing`[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#posttxprocessing" id="posttxprocessing"></a>

`PostTxProcessing` is only called after an EVM transaction finished successfully and delegates the call to underlying hooks. If no hook has been registered, this function returns with a `nil` error.

```
func (k *Keeper) PostTxProcessing(ctx sdk.Context, msg core.Message, receipt *ethtypes.Receipt) error {
 if k.hooks == nil {
  return nil
 }
 return k.hooks.PostTxProcessing(k.Ctx(), msg, receipt)
}
```

It's executed in the same cache context as the EVM transaction, if it returns an error, the whole EVM transaction is reverted, if the hook implementor doesn't want to revert the tx, they can always return `nil` instead.

The error returned by the hooks is translated to a VM error `failed to process native logs`, the detailed error message is stored in the return value. The message is sent to native modules asynchronously, there's no way for the caller to catch and recover the error.

#### Use Case: Call Native ERC20 Module on LagomChain[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#use-case-call-native-erc20-module-on-evmos" id="use-case-call-native-erc20-module-on-evmos"></a>

Here is an example taken from the LagomChain erc20 module that shows how the `EVMHooks` supports a contract calling a native module to convert ERC-20 Tokens into Cosmos native Coins. Following the steps from above.

You can define and emit a `Transfer` log signature in the smart contract like this:

```
event Transfer(address indexed from, address indexed to, uint256 value);

function _transfer(address sender, address recipient, uint256 amount) internal virtual {
  require(sender != address(0), "ERC20: transfer from the zero address");
  require(recipient != address(0), "ERC20: transfer to the zero address");

  _beforeTokenTransfer(sender, recipient, amount);

  _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
  _balances[recipient] = _balances[recipient].add(amount);
  emit Transfer(sender, recipient, amount);
}
```

The application will register a `BankSendHook` to the `EvmKeeper`. It recognizes the ethereum tx `Log` and converts it to a call to the bank module's `SendCoinsFromAccountToAccount` method:

```

const ERC20EventTransfer = "Transfer"

// PostTxProcessing implements EvmHooks.PostTxProcessing
func (k Keeper) PostTxProcessing(
 ctx sdk.Context,
 msg core.Message,
 receipt *ethtypes.Receipt,
) error {
 params := h.k.GetParams(ctx)
 if !params.EnableErc20 || !params.EnableEVMHook {
  // no error is returned to allow for other post-processing txs
  // to pass
  return nil
 }

 erc20 := contracts.ERC20BurnableContract.ABI

 for i, log := range receipt.Logs {
  if len(log.Topics) < 3 {
   continue
  }

  eventID := log.Topics[0] // event ID

  event, err := erc20.EventByID(eventID)
  if err != nil {
   // invalid event for ERC20
   continue
  }

  if event.Name != types.ERC20EventTransfer {
   h.k.Logger(ctx).Info("emitted event", "name", event.Name, "signature", event.Sig)
   continue
  }

  transferEvent, err := erc20.Unpack(event.Name, log.Data)
  if err != nil {
   h.k.Logger(ctx).Error("failed to unpack transfer event", "error", err.Error())
   continue
  }

  if len(transferEvent) == 0 {
   continue
  }

  tokens, ok := transferEvent[0].(*big.Int)
  // safety check and ignore if amount not positive
  if !ok || tokens == nil || tokens.Sign() != 1 {
   continue
  }

  // check that the contract is a registered token pair
  contractAddr := log.Address

  id := h.k.GetERC20Map(ctx, contractAddr)

  if len(id) == 0 {
   // no token is registered for the caller contract
   continue
  }

  pair, found := h.k.GetTokenPair(ctx, id)
  if !found {
   continue
  }

  // check that conversion for the pair is enabled
  if !pair.Enabled {
   // continue to allow transfers for the ERC20 in case the token pair is disabled
   h.k.Logger(ctx).Debug(
    "ERC20 token -> Cosmos coin conversion is disabled for pair",
    "coin", pair.Denom, "contract", pair.Erc20Address,
   )
   continue
  }

  // ignore as the burning always transfers to the zero address
  to := common.BytesToAddress(log.Topics[2].Bytes())
  if !bytes.Equal(to.Bytes(), types.ModuleAddress.Bytes()) {
   continue
  }

  // check that the event is Burn from the ERC20Burnable interface
  // NOTE: assume that if they are burning the token that has been registered as a pair, they want to mint a Cosmos coin

  // create the corresponding sdk.Coin that is paired with ERC20
  coins := sdk.Coins{{Denom: pair.Denom, Amount: sdk.NewIntFromBigInt(tokens)}}

  // Mint the coin only if ERC20 is external
  switch pair.ContractOwner {
  case types.OWNER_MODULE:
   _, err = h.k.CallEVM(ctx, erc20, types.ModuleAddress, contractAddr, true, "burn", tokens)
  case types.OWNER_EXTERNAL:
   err = h.k.bankKeeper.MintCoins(ctx, types.ModuleName, coins)
  default:
   err = types.ErrUndefinedOwner
  }

  if err != nil {
   h.k.Logger(ctx).Debug(
    "failed to process EVM hook for ER20 -> coin conversion",
    "coin", pair.Denom, "contract", pair.Erc20Address, "error", err.Error(),
   )
   continue
  }

  // Only need last 20 bytes from log.topics
  from := common.BytesToAddress(log.Topics[1].Bytes())
  recipient := sdk.AccAddress(from.Bytes())

  // transfer the tokens from ModuleAccount to sender address
  if err := h.k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, recipient, coins); err != nil {
   h.k.Logger(ctx).Debug(
    "failed to process EVM hook for ER20 -> coin conversion",
    "tx-hash", receipt.TxHash.Hex(), "log-idx", i,
    "coin", pair.Denom, "contract", pair.Erc20Address, "error", err.Error(),
   )
   continue
  }
 }

 return nil
```

Lastly, register the hook in `app.go`:

```
app.EvmKeeper = app.EvmKeeper.SetHooks(app.Erc20Keeper)
```

### Events[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#events" id="events"></a>

The `x/evm` module emits the Cosmos SDK events after a state execution. The EVM module emits events of the relevant transaction fields, as well as the transaction logs (ethereum events).

#### MsgEthereumTx[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#msgethereumtx-1" id="msgethereumtx-1"></a>

| Type         | Attribute Key      | Attribute Value         |
| ------------ | ------------------ | ----------------------- |
| ethereum\_tx | `"amount"`         | `{amount}`              |
| ethereum\_tx | `"recipient"`      | `{hex_address}`         |
| ethereum\_tx | `"contract"`       | `{hex_address}`         |
| ethereum\_tx | `"txHash"`         | `{tendermint_hex_hash}` |
| ethereum\_tx | `"ethereumTxHash"` | `{hex_hash}`            |
| ethereum\_tx | `"txIndex"`        | `{tx_index}`            |
| ethereum\_tx | `"txGasUsed"`      | `{gas_used}`            |
| tx\_log      | `"txLog"`          | `{tx_log}`              |
| message      | `"sender"`         | `{eth_address}`         |
| message      | `"action"`         | `"ethereum"`            |
| message      | `"module"`         | `"evm"`                 |

Additionally, the EVM module emits an event during `EndBlock` for the filter query block bloom.

#### ABCI[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#abci-1" id="abci-1"></a>

| Type         | Attribute Key | Attribute Value      |
| ------------ | ------------- | -------------------- |
| block\_bloom | `"bloom"`     | `string(bloomBytes)` |

### Parameters[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#parameters" id="parameters"></a>

The evm module contains the following parameters:

#### Params[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#params" id="params"></a>

| Key                   | Type          | Default Value      |
| --------------------- | ------------- | ------------------ |
| `EVMDenom`            | string        | `"alagom"`         |
| ~~`EnableCreate`~~    | bool          | `true`             |
| ~~`EnableCall`~~      | bool          | `true`             |
| `ExtraEIPs`           | \[]int        | TBD                |
| `ChainConfig`         | ChainConfig   | See ChainConfig    |
| `AllowUnprotectedTxs` | bool          | false              |
| `ActivePrecompiles`   | \[]string     | \[]                |
| `AccessControl`       | AccessControl | Permissionless EVM |

#### EVM denom[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#evm-denom" id="evm-denom"></a>

The evm denomination parameter defines the token denomination used on the EVM state transitions and gas consumption for EVM messages.

For example, on Ethereum, the `evm_denom` would be `ETH`. In the case of LagomChain, the default denomination is the **atto lagomchain**. In terms of precision, `LAGOM` and `ETH` share the same value, *i.e.* `1 LAGOM = 10^18 atto LAGOM` and `1 ETH = 10^18 wei`.

tip

Note: SDK applications that want to import the EVM module as a dependency will need to set their own `evm_denom` (i.e not `"alagom"`).

#### Enable Create[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#enable-create" id="enable-create"></a>

**(deprecated in v19.0.0)** The enable create parameter toggles state transitions that use the `vm.Create` function. When the parameter is disabled, it will prevent all contract creation functionality.

#### Enable Transfer[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#enable-transfer" id="enable-transfer"></a>

**(deprecated in v19.0.0)** The enable transfer toggles state transitions that use the `vm.Call` function. When the parameter is disabled, it will prevent transfers between accounts and executing a smart contract call.

The extra EIPs parameter defines the set of activateable Ethereum Improvement Proposals ([**EIPs**](https://ethereum.org/en/eips/)) on the Ethereum VM `Config` that apply custom jump tables.

tip

NOTE: some of these EIPs are already enabled by the chain configuration, depending on the hard fork number.

The supported activateable EIPS are:

* [**EIP 1344**](https://eips.ethereum.org/EIPS/eip-1344)
* [**EIP 1884**](https://eips.ethereum.org/EIPS/eip-1884)
* [**EIP 2200**](https://eips.ethereum.org/EIPS/eip-2200)
* [**EIP 2315**](https://eips.ethereum.org/EIPS/eip-2315)
* [**EIP 2929**](https://eips.ethereum.org/EIPS/eip-2929)
* [**EIP 3198**](https://eips.ethereum.org/EIPS/eip-3198)
* [**EIP 3529**](https://eips.ethereum.org/EIPS/eip-3529)
* [**EIP 3855**](https://eips.ethereum.org/EIPS/eip-3855)

#### Chain Config[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#chain-config" id="chain-config"></a>

The `ChainConfig` is a protobuf wrapper type that contains the same fields as the go-ethereum `ChainConfig` parameters, but using `*sdk.Int` types instead of `*big.Int`.

By default, all block configuration fields but `ConstantinopleBlock`, are enabled at genesis (height 0).

**ChainConfig Defaults**[**​**](broken://pages/NpqRewc2B4hzigulBBNu)

| Name                | Default Value                                                        |
| ------------------- | -------------------------------------------------------------------- |
| HomesteadBlock      | 0                                                                    |
| DAOForkBlock        | 0                                                                    |
| DAOForkSupport      | `true`                                                               |
| EIP150Block         | 0                                                                    |
| EIP150Hash          | `0x0000000000000000000000000000000000000000000000000000000000000000` |
| EIP155Block         | 0                                                                    |
| EIP158Block         | 0                                                                    |
| ByzantiumBlock      | 0                                                                    |
| ConstantinopleBlock | 0                                                                    |
| PetersburgBlock     | 0                                                                    |
| IstanbulBlock       | 0                                                                    |
| MuirGlacierBlock    | 0                                                                    |
| BerlinBlock         | 0                                                                    |
| LondonBlock         | 0                                                                    |
| ArrowGlacierBlock   | 0                                                                    |
| GrayGlacierBlock    | 0                                                                    |
| MergeNetsplitBlock  | 0                                                                    |
| ShanghaiBlock       | 0                                                                    |
| CancunBlock.        | 0                                                                    |

#### Allow Unprotected Transactions[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#allow-unprotected-transactions" id="allow-unprotected-transactions"></a>

This parameter enforces EIP-155 replay protection globally for all nodes partaking in consensus. If disabled, this delegates control of replay protection to the individual nodes (read more [here](about:/validate/setup-and-configuration/configuration.md#eip-155-replay-protection)).

#### Active Precompiles[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#active-precompiles" id="active-precompiles"></a>

This parameter governs which EVM Extensions are enabled on the given network. It accepts a list of addresses in Hex format, which is evaluated in EVM transactions to only allow interactions with the selected precompiled contracts.

#### Access Control[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#access-control" id="access-control"></a>

(added in v19.0.0) This parameter enables detailed control of the EVM. The former parameters `enable_create` and `enable_call` have been extended to give exact control of who can access these features.

By default, the EVM is *permissionless*, meaning that everyone can deploy smart contracts and send EVM transaction unless they have specifically been blacklisted. The blacklisted addresses can be defined in the corresponding `AccessControlList`.

By setting the individual `AccessControlType` for either the create or call functionality as *restricted*, the EVM does not accept further interactions with the specific functionality.

When defining the control type as being *permissioned*, the given list of addresses is interpreted as a collection of whitelisted addresses, which are the only ones capable of deploying contracts or calling the EVM respectively.

### Client[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#client" id="client"></a>

A user can query and interact with the `evm` module using the CLI, JSON-RPC, gRPC or REST.

#### CLI[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#cli" id="cli"></a>

Find below a list of `lagomd` commands added with the `x/evm` module. You can obtain the full list by using the `lagomd -h` command.

**Queries**[**​**](broken://pages/NpqRewc2B4hzigulBBNu)

The `query` commands allow users to query `evm` state.

**`code`**

Allows users to query the smart contract code at a given address.

```
lagomd query evm code ADDRESS [flags]
```

```
# Example
$ lagomd query evm code 0x7bf7b17da59880d9bcca24915679668db75f9397

# Output
code: "0xef616c92f3cfc9e92dc270d6acff9cea213cecc7020a76ee4395af09bdceb4837a1ebdb5735e11e7d3adb6104e0c3ac55180b4ddf5e54d022cc5e8837f6a4f971b"
```

**`storage`**

Allows users to query storage for an account with a given key and height.

```
lagomd query evm storage ADDRESS KEY [flags]
```

```
# Example
$ lagomd query evm storage 0x0f54f47bf9b8e317b214ccd6a7c3e38b893cd7f0 0 --height 0

# Output
value: "0x0000000000000000000000000000000000000000000000000000000000000000"
```

**Transactions**[**​**](broken://pages/NpqRewc2B4hzigulBBNu)

The `tx` commands allow users to interact with the `evm` module.

**`raw`**

Allows users to build cosmos transactions from raw ethereum transaction.

```
lagommd tx evm raw TX_HEX [flags]
```

```
# Example
$ lagomd tx evm raw 0xf9ff74c86aefeb5f6019d77280bbb44fb695b4d45cfe97e6eed7acd62905f4a85034d5c68ed25a2e7a8eeb9baf1b84

# Output
value: "0x0000000000000000000000000000000000000000000000000000000000000000"
```

#### JSON-RPC[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#json-rpc-1" id="json-rpc-1"></a>

For an overview on the JSON-RPC methods and namespaces supported on LagomChain.

#### gRPC[​](broken://pages/NpqRewc2B4hzigulBBNu) <a href="#grpc" id="grpc"></a>

**Queries**[**​**](broken://pages/NpqRewc2B4hzigulBBNu)

| Verb   | Method                                               | Description                                                                  |
| ------ | ---------------------------------------------------- | ---------------------------------------------------------------------------- |
| `gRPC` | `ethermint.evm.v1.Query/Account`                     | Get an Ethereum account                                                      |
| `gRPC` | `ethermint.evm.v1.Query/CosmosAccount`               | Get an Ethereum account's Cosmos Address                                     |
| `gRPC` | `ethermint.evm.v1.Query/ValidatorAccount`            | Get an Ethereum account's from a validator consensus Address                 |
| `gRPC` | `ethermint.evm.v1.Query/Balance`                     | Get the balance of a the EVM denomination for a single EthAccount.           |
| `gRPC` | `ethermint.evm.v1.Query/Storage`                     | Get the balance of all coins for a single account                            |
| `gRPC` | `ethermint.evm.v1.Query/Code`                        | Get the balance of all coins for a single account                            |
| `gRPC` | `ethermint.evm.v1.Query/Params`                      | Get the parameters of x/evm module                                           |
| `gRPC` | `ethermint.evm.v1.Query/EthCall`                     | Implements the eth\_call rpc api                                             |
| `gRPC` | `ethermint.evm.v1.Query/EstimateGas`                 | Implements the eth\_estimateGas rpc api                                      |
| `gRPC` | `ethermint.evm.v1.Query/TraceTx`                     | Implements the debug\_traceTransaction rpc api                               |
| `gRPC` | `ethermint.evm.v1.Query/TraceBlock`                  | Implements the debug\_traceBlockByNumber and debug\_traceBlockByHash rpc api |
| `GET`  | `/ethermint/evm/v1/account/{address}`                | Get an Ethereum account                                                      |
| `GET`  | `/ethermint/evm/v1/cosmos_account/{address}`         | Get an Ethereum account's Cosmos Address                                     |
| `GET`  | `/ethermint/evm/v1/validator_account/{cons_address}` | Get an Ethereum account's from a validator consensus Address                 |
| `GET`  | `/ethermint/evm/v1/balances/{address}`               | Get the balance of a the EVM denomination for a single EthAccount.           |
| `GET`  | `/ethermint/evm/v1/storage/{address}/{key}`          | Get the balance of all coins for a single account                            |
| `GET`  | `/ethermint/evm/v1/codes/{address}`                  | Get the balance of all coins for a single account                            |
| `GET`  | `/ethermint/evm/v1/params`                           | Get the parameters of x/evm module                                           |
| `GET`  | `/ethermint/evm/v1/eth_call`                         | Implements the eth\_call rpc api                                             |
| `GET`  | `/ethermint/evm/v1/estimate_gas`                     | Implements the eth\_estimateGas rpc api                                      |
| `GET`  | `/ethermint/evm/v1/trace_tx`                         | Implements the debug\_traceTransaction rpc api                               |
| `GET`  | `/ethermint/evm/v1/trace_block`                      | Implements the debug\_traceBlockByNumber and debug\_traceBlockByHash rpc api |

**Transactions**[**​**](broken://pages/NpqRewc2B4hzigulBBNu)

| Verb   | Method                            | Description                     |
| ------ | --------------------------------- | ------------------------------- |
| `gRPC` | `ethermint.evm.v1.Msg/EthereumTx` | Submit an Ethereum transactions |
| `POST` | `/ethermint/evm/v1/ethereum_tx`   | Submit an Ethereum transactions |


# feemarket

### Abstract[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#abstract" id="abstract"></a>

This document specifies the feemarket module, which allows defining a global transaction fee for the network.

This module has been designed to support EIP-1559 in cosmos-sdk.

The `MempoolFeeDecorator` in `x/auth` module needs to be overwritten to check the `baseFee` along with the `minimal-gas-prices` allowing to implement a global fee mechanism which vary depending on the network activity.

For more reference to EIP-1559:

<https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md>

### Contents[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#contents" id="contents"></a>

1. [**Concepts**](#concepts)
2. [**State**](#state)
3. [**Begin Block**](#begin-block)
4. [**End Block**](#end-block)
5. [**Keeper**](#keeper)
6. [**Events**](#events)
7. [**Params**](#parameters)
8. [**Client**](#client)
9. [**AnteHandlers**](#antehandlers)

### Concepts[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#concepts" id="concepts"></a>

#### EIP-1559: Fee Market[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#eip-1559-fee-market" id="eip-1559-fee-market"></a>

[EIP-1559](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md) describes a pricing mechanism that was proposed on Ethereum to improve to calculation of transaction fees. It includes a fixed-per-block network fee that is burned and dynamically expands/contracts block sizes to deal with peaks of network congestion.

Before EIP-1559 the transaction fee is calculated with

```
fee = gasPrice * gasLimit
```

where `gasPrice` is the price per gas and `gasLimit` describes the amount of gas required to perform the transaction. The more complex operations a transaction requires, the higher the gas limit To submit a transaction, the signer needs to specify the `gasPrice`.

With EIP-1559 enabled, the transaction fee is calculated with

```
fee = (baseFee + priorityTip) * gasLimit
```

where `baseFee` is the fixed-per-block network fee per gas and `priorityTip` is an additional fee per gas that can be set optionally. Note, that both the base fee and the priority tip are gas prices. To submit a transaction with EIP-1559, the signer needs to specify the `gasFeeCap`, which is the maximum fee per gas they are willing to pay in total. Optionally, the `priorityTip` can be specified, which covers both the priority fee and the block's network fee per gas (aka: base fee).

tip

The Cosmos SDK uses a different terminology for `gas` than Ethereum. What is called `gasLimit` on Ethereum is called `gasWanted` on Cosmos. You might encounter both terminologies on LagomChain since it builds Ethereum on top of the SDK, e.g. when using different wallets like Keplr for Cosmos and Metamask for Ethereum.

#### Base Fee[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#base-fee" id="base-fee"></a>

The base fee per gas (aka base fee) is a global gas price defined at the consensus level. It is stored as a module parameter and is adjusted at the end of each block based on the total gas used in the previous block and gas target (`block gas limit / elasticity multiplier`):

* it increases when blocks are above the gas target,
* it decreases when blocks are below the gas target.

Instead of burning the base fee (as implemented on Ethereum), the `feemarket` module allocates the base fee for regular [Cosmos SDK fee distribution](https://docs.cosmos.network/main/modules/distribution).

#### Priority Tip[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#priority-tip" id="priority-tip"></a>

In EIP-1559, the `max_priority_fee_per_gas`, often referred to as `tip`, is an additional gas price that can be added to the `baseFee` in order to incentivize transaction prioritization. The higher the tip, the more likely the transaction is included in the block.

Until the Cosmos SDK version v0.46, however, there is no notion of transaction prioritization. Thus, the tip for an EIP-1559 transaction on LagomChain should be zero (`MaxPriorityFeePerGas` JSON-RPC endpoint returns `0`). Have a look at the mempool docs to read more about how to leverage transaction prioritization.

#### Effective Gas price[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#effective-gas-price" id="effective-gas-price"></a>

For EIP-1559 transactions (dynamic fee transactions) the effective gas price describes the maximum gas price that a transaction is willing to provide. It is derived from the transaction arguments and the base fee parameter. Depending on which one is smaller, the effective gas price is either the `baseFee + tip` or the `gasFeeCap`

```
min(baseFee + gasTipCap, gasFeeCap)
```

#### Local vs. Global Minimum Gas Prices[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#local-vs-global-minimum-gas-prices" id="local-vs-global-minimum-gas-prices"></a>

Minimum gas prices are used to discard spam transactions in the network, by raising the cost of transactions to the point that it is not economically viable for the spammer. This is achieved by defining a minimum gas price for accepting txs in the mempool for both Cosmos and EVM transactions. A transaction is discarded from the mempool if it doesn't provide at least one of the two types of min gas prices:

Minimum gas prices are used to discard spam transactions in the network, by raising the cost of transactions to the point that it is not economically viable for the spammer. This is achieved by defining a minimum gas price for accepting txs in the mempool for both Cosmos and EVM transactions. A transaction is discarded from the mempool if it doesn't provide at least one of the two types of min gas prices:

1. the local min gas prices that validators can set on their node config and
2. the global min gas price, which is set as a parameter in the `feemarket` module, which can be changed through governance.

The lower bound for a transaction gas price is determined by comparing of gas price bounds according to three cases:

1. If the effective gas price (`effective gas price = base fee + priority tip`) or the local minimum gas price is lower than the global `MinGasPrice` (`min-gas-price (local) < MinGasPrice (global) OR EffectiveGasPrice < MinGasPrice`), then `MinGasPrice` is used as a lower bound.
2. If transactions are rejected due to having a gas price lower than `MinGasPrice`, users need to resend the transactions with a gas price higher or equal to `MinGasPrice`.
3. If the effective gas price or the local `minimum-gas-price` is higher than the global `MinGasPrice`, then the larger value of the two is used as a lower bound. In the case of EIP-1559, users must increase the priority fee for their transactions to be valid.

The comparison of transaction gas price and the lower bound is implemented through AnteHandler decorators. For EVM transactions, this is done in the `EthMempoolFeeDecorator` and `EthMinGasPriceDecorator` `AnteHandler` and for Cosmos transactions in `NewMempoolFeeDecorator` and `MinGasPriceDecorator` `AnteHandler`.

tip

If the base fee decreases to a value below the global `MinGasPrice`, it is set to the `MinGasPrice`. This is implemented, so that the base fee can't drop to gas prices that wouldn't allow transactions to be accepted in the mempool, because of a higher `MinGasPrice`.

### State[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#state" id="state"></a>

The x/feemarket module keeps in the state variable needed to the fee calculation:

Only BlockGasUsed in previous block needs to be tracked in state for the next base fee calculation.

|              | Description           | Key         | Value              | Store |
| ------------ | --------------------- | ----------- | ------------------ | ----- |
| BlockGasUsed | gas used in the block | `[]byte{1}` | `[]byte{gas_used}` | KV    |

### Begin block[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#begin-block" id="begin-block"></a>

The base fee is calculated at the beginning of each block.

#### Base Fee[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#base-fee-1" id="base-fee-1"></a>

**Disabling base fee**[**​**](broken://pages/w1OsPfQLwFt8DcVSlrrQ)

We introduce two parameters : `NoBaseFee`and `EnableHeight`

`NoBaseFee` controls the feemarket base fee value. If set to true, no calculation is done and the base fee returned by the keeper is zero.

`EnableHeight` controls the height we start the calculation.

* If `NoBaseFee = false` and `height < EnableHeight`, the base fee value will be equal to `base_fee` defined in the genesis and the `BeginBlock` will return without further computation.
* If `NoBaseFee = false` and `height >= EnableHeight`, the base fee is dynamically calculated upon each block at `BeginBlock`.

Those parameters allow us to introduce a static base fee or activate the base fee at a later stage.

**Enabling base fee**[**​**](broken://pages/w1OsPfQLwFt8DcVSlrrQ)

To enable EIP-1559 with the EVM, the following parameters should be set :

* NoBaseFee should be false
* EnableHeight should be set to a positive integer >= upgrade height. It defines at which height the chain starts the base fee adjustment
* LondonBlock evm's param should be set to a positive integer >= upgrade height. It defines at which height the chain starts to accept EIP-1559 transactions.

**Calculation**[**​**](broken://pages/w1OsPfQLwFt8DcVSlrrQ)

The base fee is initialized at `EnableHeight` to the `InitialBaseFee` value defined in the genesis file.

The base fee is after adjusted according to the total gas used in the previous block.

```
parent_gas_target = parent_gas_limit / ELASTICITY_MULTIPLIER

if EnableHeight == block.number
    base_fee = INITIAL_BASE_FEE
else if parent_gas_used == parent_gas_target:
    base_fee = parent_base_fee
else if parent_gas_used > parent_gas_target:
    gas_used_delta = parent_gas_used - parent_gas_target
    base_fee_delta = max(parent_base_fee * gas_used_delta / parent_gas_target / BASE_FEE_MAX_CHANGE_DENOMINATOR, 1)
    base_fee = parent_base_fee + base_fee_delta
else:
    gas_used_delta = parent_gas_target - parent_gas_used
    base_fee_delta = parent_base_fee * gas_used_delta / parent_gas_target / BASE_FEE_MAX_CHANGE_DENOMINATOR
    base_fee = parent_base_fee - base_fee_delta

```

### End block[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#end-block" id="end-block"></a>

The `block_gas_used` value is updated at the end of each block.

#### Block Gas Used[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#block-gas-used" id="block-gas-used"></a>

The total gas used by current block is stored in the KVStore at `EndBlock`.

It is initialized to `block_gas` defined in the genesis.

### Keeper[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#keeper" id="keeper"></a>

The feemarket module provides this exported keeper that can be passed to other modules, which require access to the base fee value

```
type Keeper interface {
    GetBaseFee(ctx sdk.Context) *big.Int
}
```

### Events[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#events" id="events"></a>

The `x/feemarket` module emits the following events:

#### BeginBlocker[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#beginblocker" id="beginblocker"></a>

| Type        | Attribute Key | Attribute Value |
| ----------- | ------------- | --------------- |
| fee\_market | base\_fee     | {baseGasPrices} |

#### EndBlocker[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#endblocker" id="endblocker"></a>

| Type       | Attribute Key | Attribute Value |
| ---------- | ------------- | --------------- |
| block\_gas | height        | {blockHeight}   |
| block\_gas | amount        | {blockGasUsed}  |

### Parameters[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#parameters" id="parameters"></a>

The `x/feemarket` module contains the following parameters:

| Key                      | Type    | Default Values | Description                                                                                                             |
| ------------------------ | ------- | -------------- | ----------------------------------------------------------------------------------------------------------------------- |
| NoBaseFee                | bool    | false          | control the base fee adjustment                                                                                         |
| BaseFeeChangeDenominator | uint32  | 8              | bounds the amount the base fee that can change between blocks                                                           |
| ElasticityMultiplier     | uint32  | 2              | bounds the threshold which the base fee will increase or decrease depending on the total gas used in the previous block |
| BaseFee                  | uint32  | 1000000000     | base fee for EIP-1559 blocks                                                                                            |
| EnableHeight             | uint32  | 0              | height which enable fee adjustment                                                                                      |
| MinGasPrice              | sdk.Dec | 0              | global minimum gas price that needs to be paid to include a transaction in a block                                      |

### Client[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#client" id="client"></a>

#### CLI[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#cli" id="cli"></a>

A user can query and interact with the `feemarket` module using the CLI.

**Queries**[**​**](broken://pages/w1OsPfQLwFt8DcVSlrrQ)

The `query` commands allow users to query `feemarket` state.

```
lagomd query feemarket --help
```

**Base Fee**[**​**](broken://pages/w1OsPfQLwFt8DcVSlrrQ)

The `base-fee` command allows users to query the block base fee by height.

```
lagomd query feemarket base-fee [flags]
```

Example:

```
lagomd query feemarket base-fee ...
```

Example Output:

**Block Gas**[**​**](broken://pages/w1OsPfQLwFt8DcVSlrrQ)

The `block-gas` command allows users to query the block gas by height.

```
lagomd query feemarket block-gas [flags]
```

Example:

```
lagomd query feemarket block-gas ...
```

Example Output:

**Params**[**​**](broken://pages/w1OsPfQLwFt8DcVSlrrQ)

The `params` command allows users to query the module params.

```
lagomd query params subspace [subspace] [key] [flags]
```

Example:

```
lagomd query params subspace feemarket ElasticityMultiplier ...
```

Example Output:

```
key: ElasticityMultiplier
subspace: feemarket
value: "2"
```

#### gRPC[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#grpc" id="grpc"></a>

**Queries**[**​**](broken://pages/w1OsPfQLwFt8DcVSlrrQ)

| Verb   | Method                                  | Description            |
| ------ | --------------------------------------- | ---------------------- |
| `gRPC` | `ethermint.feemarket.v1.Query/Params`   | Get the module params  |
| `gRPC` | `ethermint.feemarket.v1.Query/BaseFee`  | Get the block base fee |
| `gRPC` | `ethermint.feemarket.v1.Query/BlockGas` | Get the block gas used |
| `GET`  | `/ethermint/feemarket/v1/params`        | Get the module params  |
| `GET`  | `/ethermint/feemarket/v1/base_fee`      | Get the block base fee |
| `GET`  | `/ethermint/feemarket/v1/block_gas`     | Get the block gas used |

### AnteHandlers[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#antehandlers" id="antehandlers"></a>

The `x/feemarket` module provides `AnteDecorator`s that are recursively chained together into a single [`Antehandler`](https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-alpha1/docs/architecture/adr-010-modular-antehandler.md). These decorators perform basic validity checks on an Ethereum or Cosmos SDK transaction, such that it could be thrown out of the transaction Mempool.

Note that the `AnteHandler` is run for every transaction and called on both `CheckTx` and `DeliverTx`.

#### Decorators[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#decorators" id="decorators"></a>

#### `MinGasPriceDecorator`[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#mingaspricedecorator" id="mingaspricedecorator"></a>

Rejects Cosmos SDK transactions with transaction fees lower than `MinGasPrice * GasLimit`.

#### `EthMinGasPriceDecorator`[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#ethmingaspricedecorator" id="ethmingaspricedecorator"></a>

Rejects EVM transactions with transactions fees lower than `MinGasPrice * GasLimit`.

* For `LegacyTx` and `AccessListTx`, the `GasPrice * GasLimit` is used.
* For EIP-1559 (*aka.* `DynamicFeeTx`), the `EffectivePrice * GasLimit` is used.

tip

**Note**: For dynamic transactions, if the `feemarket` formula results in a `BaseFee` that lowers `EffectivePrice < MinGasPrices`, the users must increase the `GasTipCap` (priority fee) until `EffectivePrice > MinGasPrices`. Transactions with `MinGasPrices * GasLimit < transaction fee < EffectiveFee` are rejected by the `feemarket` `AnteHandle`.

#### `EthGasConsumeDecorator`[​](broken://pages/w1OsPfQLwFt8DcVSlrrQ) <a href="#ethgasconsumedecorator" id="ethgasconsumedecorator"></a>

Calculates the effective fees to deduct and the tx priority according to EIP-1559 spec, then deducts the fees and sets the tx priority in the response.

```
effectivePrice = min(baseFee + tipFeeCap, gasFeeCap)
effectiveTipFee = effectivePrice - baseFee
priority = effectiveTipFee / DefaultPriorityReduction
```

When there are multiple messages in the transaction, choose the lowest priority in them.


# inflation

### Abstract[​](broken://pages/KzTc5v4bNck0gBTBmy4V) <a href="#abstract" id="abstract"></a>

The `x/inflation` module mints new LagomChain tokens and allocates them in daily epochs according to the LagomChain Token Model distribution to

* Community Pool `50%`.
* Staking Rewards `50%`,
* Usage Incentives: `0%`,

It replaces the Cosmos SDK `x/mint` module, that other Cosmos chains are using.

The allocation of new coins incentivizes specific behaviour in the LagomChain network. Inflation allocates funds to 1) the community pool(managed by sdk `x/distribution` module) to fund spending proposals, and 2) the `Fee Collector account` (in the sdk `x/auth` module) to increase staking rewards. The now deprecated `x/incentives` module account (3) does not accrue tokens anymore.

### Contents[​](broken://pages/KzTc5v4bNck0gBTBmy4V) <a href="#contents" id="contents"></a>

1. [**Concepts**](#concepts)
2. [**State**](#state)
3. [**Hooks**](#hooks)
4. [**Events**](#events)
5. [**Parameters**](#parameters)
6. [**Clients**](#clients)

### Concepts[​](broken://pages/KzTc5v4bNck0gBTBmy4V) <a href="#concepts" id="concepts"></a>

#### Inflation[​](broken://pages/KzTc5v4bNck0gBTBmy4V) <a href="#inflation-1" id="inflation-1"></a>

In a Proof of Stake (PoS) blockchain, inflation is used as a tool to incentivize participation in the network. Inflation creates and distributes new tokens to participants who can use their tokens to either interact with the protocol or stake their assets to earn rewards and vote for governance proposals.

Especially in an early stage of a network, where staking rewards are high and there are fewer possibilities to interact with the network, inflation can be used as the major tool to incentivize staking and thereby securing the network.

With more stakers, the network becomes increasingly stable and decentralized. It becomes *stable*, because assets are locked up instead of causing price changes through trading. And it becomes *decentralized,* because the power to vote for governance proposals is distributed amongst more people.

#### LagomChain Token Model[​](broken://pages/KzTc5v4bNck0gBTBmy4V) <a href="#evmos-token-model" id="evmos-token-model"></a>

The LagomChain Token Model outlines how the LagomChain network is secured through a balanced incentivized interest from users, developers and validators. In this model, inflation plays a major role in sustaining this balance. With an initial supply of 200 million and over 300 million tokens being issued through inflation during the first year, the model suggests an exponential decline in inflation to issue 1 billion LagomChain tokens within the first 4 years.

We implement two different inflation mechanisms to support the token model:

1. linear inflation for team vesting and
2. exponential inflation for staking rewards and community pool.

**Linear Inflation - Team Vesting**[**​**](broken://pages/KzTc5v4bNck0gBTBmy4V)

The Team Vesting distribution in the Token Model is implemented in a way that minimized the amount of taxable events. An initial supply of 200M allocated to `vesting accounts` at genesis. This amount is equal to the total inflation allocated for team vesting after 4 years (`20% * 1B = 200M`). Over time, `unvested` tokens on these accounts are converted into `vested` tokens at a linear rate. Team members cannot delegate, transfer or execute Ethereum transaction with `unvested` tokens until they are unlocked represented as `vested` tokens.

**Exponential Inflation - The Half Life**[**​**](broken://pages/KzTc5v4bNck0gBTBmy4V)

The inflation distribution for staking and community pool is implemented through an exponential formula, a.k.a. the Half Life.

Inflation is minted in daily epochs. During a period of 365 epochs (one year), a daily provision (`epochProvison`) of LagomChain tokens is minted and allocated to staking rewards and the community pool. The epoch provision depends on module parameters and is recalculated at the end of every epoch.

The calculation of the epoch provision is done according to the following formula:

```
periodProvision = exponentialDecay       *  bondingIncentive
f(x)            = (a * (1 - r) ^ x + c)  *  (1 + maxVariance * (1 - bondedRatio / bondingTarget))


epochProvision = periodProvision / epochsPerPeriod

where (with default values):
x = variable    = year
a = 300,000,000 = initial value
r = 0.5         = decay factor
c = 9,375,000   = long term supply

bondedRatio   = variable  = fraction of the staking tokens which are currently bonded
maxVariance   = 0.0       = the max amount to increase inflation
bondingTarget = 0.66      = our optimal bonded ratio
```

```
Example with bondedRatio = bondingTarget:

period  periodProvision  cumulated      epochProvision
f(0)    309 375 000      309 375 000     847 602
f(1)    159 375 000      468 750 000     436 643
f(2)     84 375 000      553 125 000     231 164
f(3)     46 875 000      600 000 000     128 424
```

Note, that after discussion with the validator community, it was decided to decrease the inflation to 1/3 during the upgrade to v16.0.0.

### State[​](broken://pages/KzTc5v4bNck0gBTBmy4V) <a href="#state" id="state"></a>

#### State Objects[​](broken://pages/KzTc5v4bNck0gBTBmy4V) <a href="#state-objects" id="state-objects"></a>

The `x/inflation` module keeps the following objects in state:

| State Object    | Description                    | Key         | Value                     | Store |
| --------------- | ------------------------------ | ----------- | ------------------------- | ----- |
| Period          | Period Counter                 | `[]byte{1}` | `[]byte{period}`          | KV    |
| EpochIdentifier | Epoch identifier bytes         | `[]byte{3}` | `[]byte{epochIdentifier}` | KV    |
| EpochsPerPeriod | Epochs per period bytes        | `[]byte{4}` | `[]byte{epochsPerPeriod}` | KV    |
| SkippedEpochs   | Number of skipped epochs bytes | `[]byte{5}` | `[]byte{skippedEpochs}`   | KV    |

**Period**[**​**](broken://pages/KzTc5v4bNck0gBTBmy4V)

Counter to keep track of amount of past periods, based on the epochs per period.

**EpochIdentifier**[**​**](broken://pages/KzTc5v4bNck0gBTBmy4V)

Identifier to trigger epoch hooks.

**EpochsPerPeriod**[**​**](broken://pages/KzTc5v4bNck0gBTBmy4V)

Amount of epochs in one period

#### Genesis State[​](broken://pages/KzTc5v4bNck0gBTBmy4V) <a href="#genesis-state" id="genesis-state"></a>

The `x/inflation` module's `GenesisState` defines the state necessary for initializing the chain from a previously exported height. It contains the module parameters, the current period, epoch identifier, epochs per period and the number of skipped epochs. :

```
type GenesisState struct {
    // params defines all the parameters of the module.
    Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"`
    // amount of past periods, based on the epochs per period param
    Period uint64 `protobuf:"varint,2,opt,name=period,proto3" json:"period,omitempty"`
    // inflation epoch identifier
    EpochIdentifier string `protobuf:"bytes,3,opt,name=epoch_identifier,json=epochIdentifier,proto3" json:"epoch_identifier,omitempty"`
    // number of epochs after which inflation is recalculated
    EpochsPerPeriod int64 `protobuf:"varint,4,opt,name=epochs_per_period,json=epochsPerPeriod,proto3" json:"epochs_per_period,omitempty"`
    // number of epochs that have passed while inflation is disabled
    SkippedEpochs uint64 `protobuf:"varint,5,opt,name=skipped_epochs,json=skippedEpochs,proto3" json:"skipped_epochs,omitempty"`
}
```

### Hooks[​](broken://pages/KzTc5v4bNck0gBTBmy4V) <a href="#hooks" id="hooks"></a>

The `x/inflation` module implements the `AfterEpochEnd` hook from the `x/epoch` module in order to allocate inflation.

#### Epoch Hook: Inflation[​](broken://pages/KzTc5v4bNck0gBTBmy4V) <a href="#epoch-hook-inflation" id="epoch-hook-inflation"></a>

The epoch hook handles the inflation logic which is run at the end of each epoch. It is responsible for minting and allocating the epoch mint provision as well as updating it:

1. Check if inflation is disabled. If it is, skip inflation, increment number of skipped epochs and return without proceeding to the next steps.
2. A block is committed, that signalizes that an `epoch` has ended (block `header.Time` has surpassed `epoch_start` + `epochIdentifier`).
3. Mint coin in amount of calculated `epochMintProvision` and allocate according to inflation distribution to staking rewards and community pool.
4. If a period ends with the current epoch, increment the period by `1` and set new value to the store.

### Events[​](broken://pages/KzTc5v4bNck0gBTBmy4V) <a href="#events" id="events"></a>

The `x/inflation` module emits the following events:

#### Inflation[​](broken://pages/KzTc5v4bNck0gBTBmy4V) <a href="#inflation-2" id="inflation-2"></a>

| Type        | Attribute Key        | Attribute Value                               |
| ----------- | -------------------- | --------------------------------------------- |
| `inflation` | `"epoch_provisions"` | `{fmt.Sprintf("%d", epochNumber)}`            |
| `inflation` | `"epoch_number"`     | `{strconv.FormatUint(uint64(in.Epochs), 10)}` |
| `inflation` | `"amount"`           | `{mintedCoin.Amount.String()}`                |

### Parameters[​](broken://pages/KzTc5v4bNck0gBTBmy4V) <a href="#parameters" id="parameters"></a>

The `x/inflation` module contains the parameters described below. All parameters can be modified via governance.

| Key                                   | Type                   | Default Value                                       |
| ------------------------------------- | ---------------------- | --------------------------------------------------- |
| `ParamStoreKeyMintDenom`              | string                 | `evm.DefaultEVMDenom` // “alagom”                   |
| `ParamStoreKeyExponentialCalculation` | ExponentialCalculation | `A: sdk.NewDec(int64(300_000_000))`                 |
|                                       |                        | `R: sdk.NewDecWithPrec(50, 2)`                      |
|                                       |                        | `C: sdk.NewDec(int64(9_375_000))`                   |
|                                       |                        | `BondingTarget: sdk.NewDecWithPrec(66, 2)`          |
|                                       |                        | `MaxVariance: sdk.ZeroDec()`                        |
| `ParamStoreKeyInflationDistribution`  | InflationDistribution  | `StakingRewards: sdk.NewDecWithPrec(500000000, 9)`  |
|                                       |                        | `UsageIncentives: sdk.NewDecWithPrec(000000000, 9)` |
|                                       |                        | `CommunityPool: sdk.NewDecWithPrec(500000000, 9)`   |
| `ParamStoreKeyEnableInflation`        | bool                   | `true`                                              |

#### Mint Denom[​](broken://pages/KzTc5v4bNck0gBTBmy4V) <a href="#mint-denom" id="mint-denom"></a>

The `ParamStoreKeyMintDenom` parameter sets the denomination in which new coins are minted.

#### Exponential Calculation[​](broken://pages/KzTc5v4bNck0gBTBmy4V) <a href="#exponential-calculation" id="exponential-calculation"></a>

The `ParamStoreKeyExponentialCalculation` parameter holds all values required for the calculation of the `epochMintProvision`. The values `A`, `R` and `C` describe the decrease of inflation over time. The `BondingTarget` and `MaxVariance` allow for an increase in inflation, which is automatically regulated by the `bonded ratio`, the portion of staked tokens in the network. The exact formula can be found under [Concepts](broken://pages/KzTc5v4bNck0gBTBmy4V).

#### Inflation Distribution[​](broken://pages/KzTc5v4bNck0gBTBmy4V) <a href="#inflation-distribution" id="inflation-distribution"></a>

The `ParamStoreKeyInflationDistribution` parameter defines the distribution in which inflation is allocated through minting on each epoch (`stakingRewards`, `CommunityPool`).

#### Enable Inflation[​](broken://pages/KzTc5v4bNck0gBTBmy4V) <a href="#enable-inflation" id="enable-inflation"></a>

The `ParamStoreKeyEnableInflation` parameter enables the daily inflation. If it is disabled, no tokens are minted and the number of skipped epochs increases for each passed epoch.

### Clients[​](broken://pages/KzTc5v4bNck0gBTBmy4V) <a href="#clients" id="clients"></a>

A user can query the `x/inflation` module using the CLI, JSON-RPC, gRPC or REST.

#### CLI[​](broken://pages/KzTc5v4bNck0gBTBmy4V) <a href="#cli" id="cli"></a>

Find below a list of `lagomd` commands added with the `x/inflation` module. You can obtain the full list by using the `lagomd -h` command.

**Queries**[**​**](broken://pages/KzTc5v4bNck0gBTBmy4V)

The `query` commands allow users to query `inflation` state.

**`period`**

Allows users to query the current inflation period.

```
lagomd query inflation period [flags]
```

**`epoch-mint-provision`**

Allows users to query the current inflation epoch provisions value.

```
lagomd query inflation epoch-mint-provision [flags]
```

**`skipped-epochs`**

Allows users to query the current number of skipped epochs.

```
lagomd query inflation skipped-epochs [flags]
```

**`total-supply`**

Allows users to query the total supply of tokens in circulation.

```
lagomd query inflation total-supply [flags]
```

**`inflation-rate`**

Allows users to query the inflation rate of the current period.

```
lagomd query inflation inflation-rate [flags]
```

**`params`**

Allows users to query the current inflation parameters.

```
lagomd query inflation params [flags]
```

**Proposals**[**​**](broken://pages/KzTc5v4bNck0gBTBmy4V)

**Update Params**

Allows users to submit a `MsgUpdateParams` with the desired changes on the `x/inflation` module parameters. To do this, you will have to provide a JSON file with the correspondiong message in the `submit-proposal` command.

For more information on how to draft a proposal, refer to the Drafting a proposal section.

```
lagomd tx gov submit-proposal proposal.json [flags]
```

#### gRPC[​](broken://pages/KzTc5v4bNck0gBTBmy4V) <a href="#grpc" id="grpc"></a>

**Queries**[**​**](broken://pages/KzTc5v4bNck0gBTBmy4V)

<table><thead><tr><th>Verb</th><th>Method</th><th width="250">Description</th></tr></thead><tbody><tr><td><code>gRPC</code></td><td><code>lagom.inflation.v1.Query/Period</code></td><td>Gets current inflation period</td></tr><tr><td><code>gRPC</code></td><td><code>lagom.inflation.v1.Query/EpochMintProvision</code></td><td>Gets current inflation epoch provisions value</td></tr><tr><td><code>gRPC</code></td><td><code>lagom.inflation.v1.Query/Params</code></td><td>Gets current inflation parameters</td></tr><tr><td><code>gRPC</code></td><td><code>lagom.inflation.v1.Query/SkippedEpochs</code></td><td>Gets current number of skipped epochs</td></tr><tr><td><code>gRPC</code></td><td><code>lagom.inflation.v1.Query/TotalSupply</code></td><td>Gets current total supply</td></tr><tr><td><code>gRPC</code></td><td><code>lagom.inflation.v1.Query/InflationRate</code></td><td>Gets current inflation rate</td></tr><tr><td><code>GET</code></td><td><code>/lagom/inflation/v1/period</code></td><td>Gets current inflation period</td></tr><tr><td><code>GET</code></td><td><code>/lagom/inflation/v1/epoch_mint_provision</code></td><td>Gets current inflation epoch provisions value</td></tr><tr><td><code>GET</code></td><td><code>/lagom/inflation/v1/skipped_epochs</code></td><td>Gets current number of skipped epochs</td></tr><tr><td><code>GET</code></td><td><code>/lagom/inflation/v1/total_supply</code></td><td>Gets current total supply</td></tr><tr><td><code>GET</code></td><td><code>/lagom/inflation/v1/inflation_rate</code></td><td>Gets current inflation rate</td></tr><tr><td><code>GET</code></td><td><code>/lagom/inflation/v1/params</code></td><td>Gets current inflation parameters</td></tr></tbody></table>


# vesting

### Abstract[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#abstract" id="abstract"></a>

This document specifies the internal `x/vesting` module of the LagomChain Hub.

The `x/vesting` module introduces the `ClawbackVestingAccount`, a new vesting account type that implements the Cosmos SDK [`VestingAccount`](https://docs.cosmos.network/main/modules/auth/vesting#vesting-account-types) interface. This account is used to allocate tokens that are subject to vesting, lockup, and clawback.

The `ClawbackVestingAccount` allows any two parties to agree on a future rewarding schedule, where tokens are granted permissions over time. The parties can use this account to enforce legal contracts or commit to mutual long-term interests.

In this commitment, vesting is the mechanism for gradually earning permission to transfer and delegate allocated tokens. Additionally, the lockup provides a mechanism to prevent the right to transfer allocated tokens and perform Ethereum transactions from the account. Both vesting and lockup are defined in schedules at account creation. At any time, the funder of a `ClawbackVestingAccount` can perform a clawback to retrieve unvested tokens. The circumstances under which a clawback should be performed can be agreed upon in a contract (e.g. smart contract).

For LagomChain, the `ClawbackVestingAccount` is used to allocate tokens to core team members and advisors to incentivize long-term participation in the project.

### Contents[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#contents" id="contents"></a>

1. [**Concepts**](#concepts)
2. [**State**](#state)
3. [**State Transitions**](#state-transitions)
4. [**Transactions**](#transactions)
5. [**AnteHandlers**](#antehandlers)
6. [**Events**](#events)
7. [**Clients**](#clients)

### References[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#references" id="references"></a>

* SDK vesting specification: <https://docs.cosmos.network/main/modules/auth/vesting>
* SDK vesting implementation: <https://github.com/cosmos/cosmos-sdk/tree/master/x/auth/vesting>
* Agoric’s Vesting Clawback Account: <https://github.com/Agoric/agoric-sdk/issues/4085>
* Agoric’s `vestcalc` tool: <https://github.com/agoric-labs/cosmos-sdk/tree/Agoric/x/auth/vesting/cmd/vestcalc>

### Concepts[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#concepts" id="concepts"></a>

#### Vesting[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#vesting-1" id="vesting-1"></a>

Vesting describes the process of converting `unvested` into `vested` tokens without transferring the ownership of those tokens. In an unvested state, tokens cannot be transferred to other accounts, delegated to validators, or used for governance. A vesting schedule describes the amount and time at which tokens are vested. The duration until which the first tokens are vested is called the `cliff`.

#### Lockup[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#lockup" id="lockup"></a>

The lockup describes the schedule by which tokens are converted from a `locked` to an `unlocked` state. As long as all tokens are locked, the account cannot perform any transaction that spend LAGOM. However, the account can perform transactions that don't spend LAGOM tokens. Additionally, locked tokens cannot be transferred to other accounts. In the case in which tokens are both locked and vested at the same time, it is possible to delegate them to validators, but not transfer them to other accounts.

The following table summarizes the actions that are allowed for tokens that are subject to the combination of vesting and lockup:

| Token Status            | Transfer | Delegate | Vote | Eth Txs that spend LAGOM\*\* | Eth Txs that don't spend LAGOM (amount = 0)\*\* |
| ----------------------- | -------- | -------- | ---- | ---------------------------- | ----------------------------------------------- |
| `locked` & `unvested`   | ❌        | ❌        | ❌    | ❌                            | ✅                                               |
| `locked` & `vested`     | ❌        | ✅        | ✅    | ❌                            | ✅                                               |
| `unlocked` & `unvested` | ❌        | ❌        | ❌    | ❌                            | ✅                                               |
| `unlocked` & `vested`\* | ✅        | ✅        | ✅    | ✅                            | ✅                                               |

\*Staking rewards are unlocked and vested

\*\*EVM transactions only fail if they involve sending locked or unvested LAGOM tokens, e.g. send LAGOM to EOA or Smart Contract (fails if amount > 0 ).

#### Schedules[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#schedules" id="schedules"></a>

Vesting and lockup schedules specify the amount and time at which tokens are vested or unlocked. They are defined as [`periods`](https://docs.cosmos.network/main/modules/auth/vesting#period) where each period has its own length and amount. A typical vesting schedule for instance would be defined starting with a one-year period to represent the vesting cliff, followed by several monthly vesting periods until the total allocated vesting amount is vested.

Vesting or lockup schedules can be easily created with Agoric’s [`vestcalc`](https://github.com/agoric-labs/cosmos-sdk/tree/Agoric/x/auth/vesting/cmd/vestcalc) tool. E.g. to calculate a four-year vesting schedule with a one year cliff, starting in January 2022, you can run vestcalc with:

```
vestcalc --write --start=2022-01-01 --coins=200000000000000000000000alagom --months=48 --cliffs=2023-01-01
```

#### Clawback[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#clawback" id="clawback"></a>

In case a `ClawbackVestingAccount`'s underlying commitment or contract is breached, the clawback provides a mechanism to return unvested funds. The account authorized to perform the clawback is defined during `ClawbackVestingAccount` account creation. It can be:

* The governance module if allowed
* The address specified as the `FunderAddress`

It should be noted that the information if an account has governance clawback enabled or not is not stored with the account itself but it is stored directly in the vesting module.

When a clawback is initiated, or by the funder or the governance, unvested tokens are send to the destination address specified in the clawback message. If no destination address is specified, the default is to return tokens to the funder.

### State[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#state" id="state"></a>

#### State Objects[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#state-objects" id="state-objects"></a>

The `x/vesting` module does not keep objects in its own store. Instead, it uses the SDK `auth` module to store account objects in state using the [Account Interface](https://docs.cosmos.network/main/modules/auth#account-interface). Accounts are exposed externally as an interface and stored internally as a clawback vesting account.

#### ClawbackVestingAccount[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#clawbackvestingaccount" id="clawbackvestingaccount"></a>

An instance that implements the [Vesting Account](https://docs.cosmos.network/main/modules/auth/vesting#vesting-account-types) interface. It provides an account that can hold contributions subject to lockup, or vesting which is subject to clawback of unvested tokens, or a combination (tokens vest, but are still locked).

```
type ClawbackVestingAccount struct {
    // base_vesting_account implements the VestingAccount interface. It contains
    // all the necessary fields needed for any vesting account implementation
    *types.BaseVestingAccount `protobuf:"bytes,1,opt,name=base_vesting_account,json=baseVestingAccount,proto3,embedded=base_vesting_account" json:"base_vesting_account,omitempty"`
    // funder_address specifies the account which can perform clawback
    FunderAddress string `protobuf:"bytes,2,opt,name=funder_address,json=funderAddress,proto3" json:"funder_address,omitempty"`
    // start_time defines the time at which the vesting period begins
    StartTime time.Time `protobuf:"bytes,3,opt,name=start_time,json=startTime,proto3,stdtime" json:"start_time"`
    // lockup_periods defines the unlocking schedule relative to the start_time
    LockupPeriods []types.Period `protobuf:"bytes,4,rep,name=lockup_periods,json=lockupPeriods,proto3" json:"lockup_periods"`
    // vesting_periods defines the vesting schedule relative to the start_time
    VestingPeriods []types.Period `protobuf:"bytes,5,rep,name=vesting_periods,json=vestingPeriods,proto3" json:"vesting_periods"`
}
```

**BaseVestingAccount**[**​**](broken://pages/yFcy6dQYvCkUqfTOo6Q6)

Implements the `VestingAccount` interface. It contains all the necessary fields needed for any vesting account implementation.

**FunderAddress**[**​**](broken://pages/yFcy6dQYvCkUqfTOo6Q6)

Specifies the account which provides the original tokens and can perform clawback.

**StartTime**[**​**](broken://pages/yFcy6dQYvCkUqfTOo6Q6)

Defines the time at which the vesting and lockup schedules begin.

**LockupPeriods**[**​**](broken://pages/yFcy6dQYvCkUqfTOo6Q6)

Defines the unlocking schedule relative to the start time.

**VestingPeriods**[**​**](broken://pages/yFcy6dQYvCkUqfTOo6Q6)

Defines the vesting schedule relative to the start time.

#### Genesis State[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#genesis-state" id="genesis-state"></a>

The `x/vesting` module allows the definition of `ClawbackVestingAccounts` at genesis. In this case, the account balance must be logged in the SDK `bank` module balances or automatically adjusted through the `add-genesis-account` CLI command.

### State Transitions[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#state-transitions" id="state-transitions"></a>

The `x/vesting` module allows for state transitions that create and update a clawback vesting account with `CreateClawbackVestingAccount` or perform a clawback of unvested funds with `Clawback`.

#### Create Clawback Vesting Account[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#create-clawback-vesting-account" id="create-clawback-vesting-account"></a>

An externally owned account can be converted to a clawback vesting account by the owner. Upon creation, the owner assigns a funder, who is able to fund the account with vesting and/or lockup schedules. The account has also the possibility to specify if the vested tokens can be clawbacked from the governance.

1. Owner submits a `MsgCreateClawbackVestingAccount` through one of the clients.
2. Check if
   1. the vesting account address is not blocked.
   2. the account at the vesting account address is not already a vesting account.
3. Create a clawback vesting account at the target address with empty vesting and lockup schedules.

#### Fund Clawback Vesting Account[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#fund-clawback-vesting-account" id="fund-clawback-vesting-account"></a>

The funder of a clawback vesting account can fund it with vesting and/or lockup schedules. If a vesting account already has funds, the schedules are merged together.

1. Funder submits a `MsgFundVestingAccount` through one of the clients.
2. Check if
   1. the vesting address is not a blocked address.
   2. the vesting address is a clawback vesting account.
   3. there is at least one vesting or lockup schedule provided. If one of them is absent, default to instant vesting or unlock schedule.
3. lockup and vesting total amounts are equal.
4. Update the clawback vesting account and send coins from the funder to the vesting account, merging any existing schedules with the new funding.

#### Clawback[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#clawback-1" id="clawback-1"></a>

The funding address is the only address that can perform the clawback.

1. Funder submits a `MsgClawback` through one of the clients.
2. Check if
   1. a destination address is given and default to funder address if not
   2. the destination address is not blocked
   3. the account exists and is a clawback vesting account
   4. account funder is same as in msg
3. Transfer unvested tokens from the clawback vesting account to the destination address, update the lockup schedule and remove future vesting events.

#### Update Clawback Vesting Account Funder[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#update-clawback-vesting-account-funder" id="update-clawback-vesting-account-funder"></a>

The funding address of an existing clawback vesting account can be updated only by the current funder.

1. Funder submits a `MsgUpdateVestingFunder` through one of the clients.
2. Check if
   1. the new funder address is not blocked
   2. the vesting account exists and is a clawback vesting account
   3. account funder is same as in msg
3. Update the vesting account funder with the new funder address.

#### Convert Vesting Account[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#convert-vesting-account" id="convert-vesting-account"></a>

Once all tokens are vested, the vesting account can be converted back to an `EthAccount`.

1. Owner of vesting account submits a `MsgConvertVestingAccount` through one of the clients.
2. Check if
   1. the vesting account exists and is a clawback vesting account
   2. the vesting account's vesting and locked schedules have concluded
3. Convert the vesting account to an `EthAccount`

### Transactions[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#transactions" id="transactions"></a>

This section defines the concrete `sdk.Msg` types, that result in the state transitions defined on the previous section.

#### `CreateClawbackVestingAccount`[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#createclawbackvestingaccount" id="createclawbackvestingaccount"></a>

```
type MsgCreateClawbackVestingAccount struct {
    // funder_address specifies the account that will be able to fund the vesting account
    FunderAddress string `protobuf:"bytes,1,opt,name=funder_address,json=funderAddress,proto3" json:"funder_address,omitempty"`
    // vesting_address specifies the address that will receive the vesting tokens
    VestingAddress string `protobuf:"bytes,2,opt,name=vesting_address,json=vestingAddress,proto3" json:"vesting_address,omitempty"`
    // enable_gov_clawback specifies whether the governance module can clawback this account
    EnableGovClawback bool `protobuf:"varint,3,opt,name=enable_gov_clawback,json=enableGovClawback,proto3" json:"enable_gov_clawback,omitempty"`
}
```

The msg content stateless validation fails if:

* `FunderAddress` or `VestingAddress` are invalid

#### `FundVestingAccount`[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#fundvestingaccount" id="fundvestingaccount"></a>

```
type MsgFundVestingAccount struct {
    // funder_address specifies the account that funds the vesting account
    FunderAddress string `protobuf:"bytes,1,opt,name=funder_address,json=funderAddress,proto3" json:"funder_address,omitempty"`
    // vesting_address specifies the account that receives the funds
    VestingAddress string `protobuf:"bytes,2,opt,name=vesting_address,json=vestingAddress,proto3" json:"vesting_address,omitempty"`
    // start_time defines the time at which the vesting period begins
    StartTime time.Time `protobuf:"bytes,3,opt,name=start_time,json=startTime,proto3,stdtime" json:"start_time"`
    // lockup_periods defines the unlocking schedule relative to the start_time
    LockupPeriods github_com_cosmos_cosmos_sdk_x_auth_vesting_types.Periods `protobuf:"bytes,4,rep,name=lockup_periods,json=lockupPeriods,proto3,castrepeated=github.com/cosmos/cosmos-sdk/x/auth/vesting/types.Periods" json:"lockup_periods"`
    // vesting_periods defines the vesting schedule relative to the start_time
    VestingPeriods github_com_cosmos_cosmos_sdk_x_auth_vesting_types.Periods `protobuf:"bytes,5,rep,name=vesting_periods,json=vestingPeriods,proto3,castrepeated=github.com/cosmos/cosmos-sdk/x/auth/vesting/types.Periods" json:"vesting_periods"`
}
```

The msg content stateless validation fails if:

* `FunderAddress` or `VestingAddress` are invalid
* `LockupPeriods` and `VestingPeriods`
  * include a period with a non-positive length or amount
  * do not describe the same total amount

#### `Clawback`[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#clawback-2" id="clawback-2"></a>

```
type MsgClawback struct {
    // funder_address is the address which funded the account
    FunderAddress string `protobuf:"bytes,1,opt,name=funder_address,json=funderAddress,proto3" json:"funder_address,omitempty"`
    // account_address is the address of the ClawbackVestingAccount to claw back from.
    AccountAddress string `protobuf:"bytes,2,opt,name=account_address,json=accountAddress,proto3" json:"account_address,omitempty"`
    // dest_address specifies where the clawed-back tokens should be transferred
    // to. If empty, the tokens will be transferred back to the original funder of
    // the account.
    DestAddress string `protobuf:"bytes,3,opt,name=dest_address,json=destAddress,proto3" json:"dest_address,omitempty"`
}
```

The msg content stateless validation fails if:

* `FunderAddress` or `AccountAddress` are invalid
* `DestAddress` is not empty and invalid

#### `UpdateVestingFunder`[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#updatevestingfunder" id="updatevestingfunder"></a>

```
type MsgUpdateVestingFunder struct {
    // funder_address is the current funder address of the ClawbackVestingAccount
    FunderAddress string `protobuf:"bytes,1,opt,name=funder_address,json=funderAddress,proto3" json:"funder_address,omitempty"`
    // new_funder_address is the new address to replace the existing funder_address
    NewFunderAddress string `protobuf:"bytes,2,opt,name=new_funder_address,json=newFunderAddress,proto3" json:"new_funder_address,omitempty"`
    // vesting_address is the address of the ClawbackVestingAccount being updated
    VestingAddress string `protobuf:"bytes,3,opt,name=vesting_address,json=vestingAddress,proto3" json:"vesting_address,omitempty"`
}
```

The msg content stateless validation fails if:

* `FunderAddress`, `NewFunderAddress` or `VestingAddress` are invalid

#### `ConvertVestingAccount`[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#convertvestingaccount" id="convertvestingaccount"></a>

```
type MsgConvertVestingAccount struct {
    // vesting_address is the address of the ClawbackVestingAccount being updated
    VestingAddress string `protobuf:"bytes,2,opt,name=vesting_address,json=vestingAddress,proto3" json:"vesting_address,omitempty"`
}
```

The msg content stateless validation fails if:

* `VestingAddress` is invalid

### AnteHandlers[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#antehandlers" id="antehandlers"></a>

The `x/vesting` module provides `AnteDecorator`s that are recursively chained together into a single [`Antehandler`](https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-alpha1/docs/architecture/adr-010-modular-antehandler.md). These decorators perform basic validity checks on an Ethereum, such that it could be thrown out of the transaction Mempool.

Note that the `AnteHandler` is called on both `CheckTx` and `DeliverTx`, as CometBFT proposers presently have the ability to include in their proposed block transactions that fail `CheckTx`.

#### Decorators[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#decorators" id="decorators"></a>

The following decorators implement the vesting logic for token delegation and performing EVM transactions.

**`EthVestingTransactionDecorator`**[**​**](broken://pages/yFcy6dQYvCkUqfTOo6Q6)

Validates if a clawback vesting account is permitted to perform Ethereum transactions, based on if it has its vesting schedule has surpassed the vesting cliff and first lockup period. Also, validates if the account has sufficient unlocked tokens to execute the transaction. This AnteHandler decorator will fail if:

* the message is not a `MsgEthereumTx`
* sender account cannot be found
* sender account is not a `ClawbackVestingAccount`
* block time is before surpassing vesting cliff end (with zero vested coins) AND
* block time is before surpassing all lockup periods (with non-zero locked coins)
* sender account has insufficient unlocked tokens to execute the transaction

#### Custom Staking Module[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#custom-staking-module" id="custom-staking-module"></a>

Evomos introduced the concept of EVM extensions to allow smart contract to interact with Cosmos SDK modules like staking and distribution, to provide a better developer experience allowing users to interact with Cosmos native module via the EVM. Since a `ClawbackVestingAccount` is allowed to stake only unlocked & vested coins, or locked & vested, we have to ensure that all other configurations are not permitted to perform a state transition. Instead of having these checks implemented in both the `AnteHandler`s for Cosmos transactions and Ethereum transactions, LagomChain core wraps the Cosmos SDK `x/staking` module to introduce these checks in the `MsgServer` of this module. With this approach we ensure that all staking actions, through direct Cosmos message or through extensions, are validating the account balance in the proper way.

The staking wrapper uses the same functionalities of the original staking module but introduces required checks in the following methods:

* `Delegate`
* `CreateValidator`

### Events[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#events" id="events"></a>

The `x/vesting` module emits the following events:

#### Create Clawback Vesting Account[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#create-clawback-vesting-account-1" id="create-clawback-vesting-account-1"></a>

| Type                              | Attibute Key | Attibute Value         |
| --------------------------------- | ------------ | ---------------------- |
| `create_clawback_vesting_account` | `"funder"`   | `{msg.FunderAddress}`  |
| `create_clawback_vesting_account` | `"sender"`   | `{msg.VestingAddress}` |

#### Fund Vesting Account[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#fund-vesting-account" id="fund-vesting-account"></a>

| Type                   | Attibute Key   | Attibute Value             |
| ---------------------- | -------------- | -------------------------- |
| `fund_vesting_account` | `"funder"`     | `{msg.FunderAddress}`      |
| `fund_vesting_account` | `"coins"`      | `{vestingCoins.String()}`  |
| `fund_vesting_account` | `"start_time"` | `{msg.StartTime.String()}` |
| `fund_vesting_account` | `"account"`    | `{msg.VestingAddress}`     |

#### Clawback[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#clawback-3" id="clawback-3"></a>

| Type       | Attibute Key    | Attibute Value         |
| ---------- | --------------- | ---------------------- |
| `clawback` | `"funder"`      | `{msg.FromAddress}`    |
| `clawback` | `"account"`     | `{msg.AccountAddress}` |
| `clawback` | `"destination"` | `{msg.DestAddress}`    |

#### Update Clawback Vesting Account Funder[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#update-clawback-vesting-account-funder-1" id="update-clawback-vesting-account-funder-1"></a>

| Type                    | Attibute Key   | Attibute Value           |
| ----------------------- | -------------- | ------------------------ |
| `update_vesting_funder` | `"funder"`     | `{msg.FromAddress}`      |
| `update_vesting_funder` | `"account"`    | `{msg.VestingAddress}`   |
| `update_vesting_funder` | `"new_funder"` | `{msg.NewFunderAddress}` |

### Clients[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#clients" id="clients"></a>

A user can query the LagomChain `x/vesting` module using the CLI, gRPC, or REST.

#### CLI[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#cli" id="cli"></a>

Find below a list of `lagomd` commands added with the `x/vesting` module. You can obtain the full list by using the `lagomd -h` command.

**Genesis**[**​**](broken://pages/yFcy6dQYvCkUqfTOo6Q6)

The genesis configuration commands allow users to configure the genesis `vesting` account state.

`add-genesis-account`

Allows users to set up clawback vesting accounts at genesis, funded with an allocation of tokens, subject to clawback. Must provide a lockup periods file (`--lockup`), a vesting periods file (`--vesting`), or both.

If both files are given, they must describe schedules for the same total amount. If one file is omitted, it will default to a schedule that immediately unlocks or vests the entire amount. The described amount of coins will be transferred from the --from address to the vesting account. Unvested coins may be "clawed back" by the funder with the clawback command. Coins may not be transferred out of the account if they are locked or unvested. Only vested coins may be staked. For an example of how to set this see [this link](https://github.com/evmos/evmos/pull/303).

```
lagomd add-genesis-account ADDRESS_OR_KEY_NAME COIN... [flags]
```

**Queries**[**​**](broken://pages/yFcy6dQYvCkUqfTOo6Q6)

The `query` commands allow users to query `vesting` account state.

**`balances`**

Allows users to query the locked, unvested and vested tokens for a given vesting account

```
lagomd query vesting balances ADDRESS [flags]
```

**Transactions**[**​**](broken://pages/yFcy6dQYvCkUqfTOo6Q6)

The `tx` commands allow users to create and clawback `vesting` account state.

**`create-clawback-vesting-account`**

A new clawback vesting account is created for the sender account (`--from`), if it is not already of such type. Only the designated funder will be able to define lockup and vesting schedules and has to do so using the fund-vesting-account subcommand. Clawback via governance is enabled or disabled through the second argument.

```
lagomd tx vesting create-clawback-vesting-account FUNDER_ADDRESS ENABLE_GOV_CLAWBACK --from=VESTING_ADDRESS [flags]
```

**`fund-vesting-account`**

Allows the funder account to update a clawback vesting account with new schedules. Any existing schedules are merged with the newly added schedules. Must provide a lockup periods file (--lockup), a vesting periods file (--vesting), or both.

If both files are given, they must describe schedules for the same total amount. If one file is omitted, it will default to a schedule that immediately unlocks or vests the entire amount. The described amount of coins will be transferred from the --from address to the vesting account. Unvested coins may be "clawed back" by the funder with the clawback command. Coins may not be transferred out of the account if they are locked or unvested. Only vested coins may be staked. For an example of how to set this see this link.

```
lagomd tx vesting fund-vesting-account VESTING_ADDRESS --from=FUNDER_ADDRESS [flags]
```

**`clawback`**

Allows to transfer all unvested unvested tokens out of a ClawbackVestingAccount. Must be requested by the original funder address (--from) and may provide a destination address (--dest), otherwise the coins are returned to the funder. Delegated or unbonding staking tokens will be transferred in the delegated or unbonding state. The recipient is vulnerable to slashing, and must act to unbond the tokens if desired.

```
lagomd tx vesting clawback VESTING_ADDRESS --from=FUNDER_ADDRESS [flags]
```

**`update-vesting-funder`**

Allows users to update the funder of an existent `ClawbackVestingAccount`. Must be requested by the original funder address (`--from`).

```
lagomd tx vesting update-vesting-funder VESTING_ADDRESS NEW_FUNDER_ADDRESS --from=FUNDER_ADDRESS [flags]
```

**`convert`**

Allows users to convert their vesting account to the chain's default account (i.e `EthAccount`). This operation only succeeds if there are no unvested tokens left in the account.

```
lagomd tx vesting convert VESTING_ADDRESS [flags]
```

#### gRPC[​](broken://pages/yFcy6dQYvCkUqfTOo6Q6) <a href="#grpc" id="grpc"></a>

**Queries**[**​**](broken://pages/yFcy6dQYvCkUqfTOo6Q6)

| Verb   | Method                                 | Description                            |
| ------ | -------------------------------------- | -------------------------------------- |
| `gRPC` | `lagom.vesting.v2.Query/Balances`      | Gets locked, unvested and vested coins |
| `GET`  | `/lagom/vesting/v2/balances/{address}` | Gets locked, unvested and vested coins |

**Transactions**[**​**](broken://pages/yFcy6dQYvCkUqfTOo6Q6)

| Verb   | Method                                                 | Description                                     |
| ------ | ------------------------------------------------------ | ----------------------------------------------- |
| `gRPC` | `lagom.vesting.v2.Msg/CreateClawbackVestingAccount`    | Creates clawback vesting account                |
| `gRPC` | `lagom.vesting.v2.Msg/FundVestingAccount`              | Funds a clawback vesting account                |
| `gRPC` | `/lagom.vesting.v2.Msg/Clawback`                       | Performs clawback                               |
| `gRPC` | `/lagom.vesting.v2.Msg/UpdateVestingFunder`            | Updates vesting account funder                  |
| `gRPC` | `/lagom.vesting.v2.Msg/ConvertVestingAccount`          | Converts vesting account back to normal account |
| `GET`  | `/lagom/vesting/v2/tx/create_clawback_vesting_account` | Creates clawback vesting account                |
| `GET`  | `/lagom/vesting/v2/tx/fund_vesting_account`            | Funds a clawback vesting account                |
| `GET`  | `/lagom/vesting/v2/tx/clawback`                        | Performs clawback                               |
| `GET`  | `/lagom/vesting/v2/tx/update_vesting_funder`           | Updates vesting account funder                  |
| `GET`  | `/lagom/vesting/v2/tx/convert_vesting_account`         | Converts vesting account back to normal account |


# Module Accounts

Certain LagomChain modules have dedicated module accounts, which act as wallets controlled exclusively by their respective modules. These accounts are used to manage minting, burning, staking, and IBC transfers.

***

### **Module Accounts & Permissions**

Each module account has specific permissions that define what operations it can perform.

#### Types of Permissions

* Burner – Can burn (destroy) tokens.
* Minter – Can mint (create) new tokens.
* Staking – Can stake tokens on behalf of users.

These permissions ensure that only authorized modules execute key token-related operations, preventing unauthorized minting or burning.

***

### **IBC Module Accounts in LagomChain**

In addition to standard module accounts, IBC transfers use specialized module accounts to escrow tokens when LagomChain is the source chain of a transfer.

#### How IBC Escrow Accounts Work

1. When an IBC transfer is initiated, the tokens are escrowed into a module account.
2. Each IBC connection has a unique escrow account, derived using SHA256 hashing.
3. The account format follows ADR 028, using the first 20 bytes of the SHA256 hash of the account name.

**Example: Generating an IBC Escrow Address**

```go
// The account name is composed of the IBC version, portID, and channelID
accountName := Version + "\0" + portID + "/" + channelID
addr := sha256.Sum256(accountName)[:20]

// Example for channel-0
addr := sha256.Sum256("ics20-1\0transfer/channel-0")[:20]
```

**Note:**\
These IBC escrow accounts do not appear in standard queries using:

```sh
lagomd q auth module-accounts
```

This is because module accounts are pre-defined at compile time, and dynamically generated IBC accounts are not included in the AccountKeeper's address map.


# Bugs

Security is critical when developing a Layer 1 (L1) blockchain. As the foundation of the blockchain ecosystem, any vulnerabilities in an L1 protocol can lead to:

* Financial loss through exploits or malicious attacks.
* Reputation damage that erodes user trust.
* Network instability, potentially compromising the entire ecosystem.

For this reason, LagomChain prioritizes security at every stage of development. Our team follows rigorous security practices, including code audits, formal verifications, and continuous monitoring to mitigate risks.

Check out our [Security Audits](/security-overview/audits) for more details.

***

### Reporting Security Issues

Despite best efforts, security vulnerabilities may still arise. We encourage users to report any bugs or vulnerabilities they discover.

#### For Critical or Sensitive Bugs

* Please submit issues confidentially via LagomChain Security, our third-party security platform.
* This ensures a secure and responsible disclosure process to protect users and mitigate risks before public exposure.

#### For Non-Sensitive Bugs

* Users can file an open ticket on the LagomChain GitHub Repository.
* Our development team will review and resolve reported issues as quickly as possible.


# IBC Channels

IBC channels are a key component of the Inter-blockchain Communication (IBC) protocol used in the Cosmos ecosystem. IBC channels enable communication between different Cosmos chains, allowing the transfer of tokens and data between them. Each IBC channel has a unique identifier known as the channel ID, which is used to specify the source and destination of a transfer. The channel ID can change depending on which relayers are active, so it's important to double-check the channel IDs before making a transfer.

tip

You can also view a full list of IBC Relayers and Channels on Mintscan

<br>


# Security Overview

The Security Policy on LagomChain includes a vulnerability disclosure policy and guidelines for reporting vulnerabilities in the LagomChain ecosystem. It explains the process for reporting and disclosing vulnerabilities through the use of the LagomChain Security and how the LagomChain team handles and resolves reported vulnerabilities. The contents of the policy help avoiding privacy violations and keeping information confidential. Also included are commitments from the LagomChain team, such as not pursuing legal action and working with researchers to disclose issues in a timely manner. The disclosure process includes steps for verifying and confirming reported vulnerabilities, determining their potential impact on the LagomChan platform, and patching and disclosing the vulnerability to the public. The payment process for reported vulnerabilities is also outlined and instructions for contacting the LagomChain Security Team are provided. For more information, visit the Security Policy documentation sites:

* LagomChain Security Policy
* [Ethermint Security Policy](https://github.com/evmos/ethermint/security/policy)

Additionally, LagomChain has a [Simple Arrangement for Funding Upload (SAFU)](/security-overview/simple-arrangement-for-funding-upload-safu). The SAFU is a simple yet extensible way to specify a post-exploit policy for whitehats, particularly rewards and distributions. For more information, visit the [SAFU section](/security-overview/simple-arrangement-for-funding-upload-safu).


# Audits

LagomChain seamlessly connects the Ethereum and Cosmos ecosystems, enabling cross-chain interoperability while maintaining a strong focus on security. However, bridging two major blockchain networks comes with complex security challenges, which is why security remains a top priority for the LagomChain development team.

***

### Security Practices in LagomChain

Every feature in LagomChain undergoes:

* Extensive internal testing before release.
* Thorough internal audits conducted by the development team.
* External security audits by industry-leading firms to ensure the integrity of the protocol.

While internal audits help maintain a high-security standard, external audits provide independent validation—ensuring that both LagomChain’s core protocol and applications deployed on it remain secure and reliable.

***

### Publicly Available Security Audits

Below is a list of third-party security audits conducted on the LagomChain and Ethermint codebases:

* Informal Systems Security Audit
* Oak Security Audit for EVM Extensions
* [Kudelski Security Audit](https://github.com/crypto-org-chain/cronos/blob/main/docs/audit/report_ethermint_1.2_final_public.pdf)

These audits help identify and address potential vulnerabilities, reinforcing LagomChain’s commitment to trust, transparency, and security.


# Simple Arrangement for Funding Upload (SAFU)

The **Simple Arrangement for Funding Upload (SAFU)** defines LagomChain’s post-exploit policy for handling active security vulnerabilities. SAFU is designed to encourage white hat hackers to responsibly return exploited funds while offering a structured bounty system as a reward.

### **Key SAFU Guidelines**

* **Legal Protection for White Hats**
  * Hackers who follow SAFU guidelines will not face legal action.
* **Grace Period for Returning Funds**
  * White hat hackers must return exploited funds to a designated dropbox address within a grace period to qualify for rewards.
* **Bounty Rewards for Secured Funds**
  * A percentage of recovered funds (up to a predefined bounty cap) will be awarded.
  * Rewards are distributed during the next network upgrade.
* **KYC/KYB for High-Value Rewards**
  * If a reward exceeds a certain threshold, the recipient must complete Know Your Client (KYC) / Know Your Business (KYB) verification.
* **Exclusion of Malicious Actors**
  * Hackers who exploit vulnerabilities for malicious purposes are not eligible for rewards.
* **Scope of Eligible Funds**
  * White hat hackers will not receive rewards for funds retrieved from "Out of Scope Projects" (i.e., projects without their own SAFU program).

For full details, visit the LagomChain SAFU Agreement.

### **SAFU Dropbox Address**

The **Dropbox Address** is a secure, protocol-controlled wallet where white hat hackers should deposit recovered funds.

This address is not controlled by any individual or team—it is fully governed by the LagomChain protocol.

#### **LagomChain SAFU Dropbox Address:**

* **Bech32 Format:**\
  `lagom1c6jdy4gy86s69auueqwfjs86vse7kz3grxm9h2`
* **Hex Format:**\
  `0xc6A4d255043ea1A2F79CC81c9940FA6433eb0A28`

### **Address Derivation**

The Dropbox Address is cryptographically derived using the first 20 bytes of the SHA256 hash of the "safu" string, ensuring immutability and security.

```go
goCopyEditaddress = sha256.Sum256([]byte("safu"))[:20]
```

### **How White Hats Can Secure Vulnerable Funds**

1. Identify the exploit and secure the compromised funds.
2. Transfer the funds to the SAFU Dropbox Address within the Grace Period.
3. Follow the SAFU guidelines to remain eligible for a bounty.

### **How to Claim a Bounty Reward**

* Rewards will be distributed during the next network upgrade.
* For high-value rewards, KYC/KYB verification is required.

### **Security Recommendations for dApps on LagomChain**

LagomChain’s SAFU program does not cover funds from individual dApps. Therefore, all dApps are encouraged to implement their own SAFU mechanisms to protect against security threats.

#### **Recommended Implementation:**

* Use [SAFU.sol](https://github.com/JumpCrypto/Safu/) from Jump Crypto as a reference for secure fund recovery.

###


# Metrics

LagomChain nodes can enable [Cosmos SDK telemetry](https://docs.cosmos.network/main/learn/advanced/telemetry) to allow for observing and gathering insights about the LagomChain application. Under the hood, it uses the [`go-metrics`](https://github.com/hashicorp/go-metrics) package and the Prometheus client library to expose different [types of metrics](https://prometheus.io/docs/concepts/metric_types/) like gauges and counters. For best practices on how to use different metrics types, check this [blog article](https://blog.pvincent.io/2017/12/prometheus-blog-series-part-2-metric-types/).

Find below a list of supported LagomChain modules with custom metrics and telemetry. Using the metrics you can e.g. run performance profiles and display them in a [Grafana](https://grafana.com/) dashboard.

### Supported Metrics[​](https://docs.evmos.org/protocol/metrics#supported-metrics) <a href="#supported-metrics" id="supported-metrics"></a>

| Metric                                         | Description                                                                                                  | Unit     | Type      |
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | -------- | --------- |
| `feemarket_base_fee`                           | Amount of base fee per EIP-1559 block                                                                        | token    | gauge     |
| `feemarket_block_gas`                          | Amount of gas used in an EIP-1559 block                                                                      | token    | gauge     |
| `erc20_ibc_on_recv_total`                      | Total amount of times an IBC coin was autoconverted to an ERC20 token in the ibc `onRecvPacket` callback     | transfer | counter   |
| `erc20_ibc_err_total`                          | Total amount of times an IBC coin autoconvertion to ERC20 token failed during an ibc transaction             | transfer | counter   |
| `erc20_ibc_transfer_total`                     | Total amount of times an IBC coin or its ERC20 representation was transferred via ibc (outgoing transaction) | transfer | counter   |
| `tx_msg_convert_coin_amount_total`             | Total amount of converted coins using a `ConvertCoin` msg                                                    | token    | counter   |
| `tx_msg_convert_coin_total`                    | Total number of txs with a `ConvertCoin` msg                                                                 | tx       | counter   |
| `tx_msg_convert_erc20_amount_total`            | Total amount of converted erc20 using a `ConvertERC20` msg                                                   | token    | counter   |
| `tx_msg_convert_erc20_total`                   | Total number of txs with a `ConvertERC20` msg                                                                | tx       | counter   |
| `tx_msg_ethereum_tx_total`                     | Total number of txs processed via the EVM                                                                    | tx       | counter   |
| `tx_msg_ethereum_tx_gas_used_total`            | Total amount of gas used by an ethereum tx                                                                   | gas      | counter   |
| `tx_msg_ethereum_tx_gas_limit_per_gas_used`    | Ratio of gas limit to gas used for an ethereum tx                                                            | ratio    | gauge     |
| `tx_msg_ethereum_tx_incentives_total`          | Total number of txs with an incentivized contract processed via the EVM                                      | tx       | counter   |
| `tx_msg_ethereum_tx_incentives_gas_used_total` | Total amount of gas used by txs with an incentivized contract processed via the EVM                          | gas      | counter   |
| `inflation_allocate_total`                     | Total amount of tokens allocated through inflation                                                           | token    | counter   |
| `inflation_allocate_staking_total`             | Total amount of tokens allocated through inflation to staking                                                | token    | counter   |
| `inflation_allocate_incentives_total`          | Total amount of tokens allocated through inflation to incentives                                             | token    | counter   |
| `inflation_allocate_community_pool_total`      | Total amount of tokens allocated through inflation to community pool                                         | token    | counter   |
| `tx_create_clawback_vesting_account_gas_used`  | Total amount of gas used by a `CreateClawbackVestingAccount` msg                                             | gas      | counter   |
| `tx_fund_vesting_account_gas_used`             | Total amount of gas used by a `FundVestingAccount` msg                                                       | gas      | counter   |
| `tx_clawback_gas_used`                         | Total amount of gas used by a `Clawback` msg                                                                 | gas      | counter   |
| `tx_update_vesting_funder_gas_used`            | Total amount of gas used by a `UpdateVestingFunder` msg                                                      | gas      | counter   |
| `epochs_begin_blocker`                         | Time spent during `BeginBlocker` of the `x/epochs` module                                                    | ms       | histogram |
| `burned_tx_fee_amount`                         | Total amount of fees burned on a tx                                                                          | token    | counter   |


# Frequently Asked Questions

### Concepts[​](https://docs.evmos.org/protocol/faq#concepts) <a href="#concepts" id="concepts"></a>

<details>

<summary>What is the difference between "secp256k1" and "ed25519"?</summary>

secp256k1 and ed25519 are both popular cryptographic algorithms used for digital signatures and key generation, but they have some differences in terms of security, performance, and compatibility with different systems.

secp256k1 is an elliptic curve algorithm that is widely used in Bitcoin and many other cryptocurrencies. It provides 128-bit security, which is considered sufficient for most practical purposes. secp256k1 is relatively fast and efficient, making it a good choice for applications that require high performance. It is widely supported by most cryptographic libraries and software, which makes it a good choice for cross-platform applications.

ed25519 is a newer elliptic curve algorithm that provides 128-bit security, similar to secp256k1. However, ed25519 is generally considered to be more secure than secp256k1, due to its resistance to certain types of attacks such as [side-channel attacks](https://en.wikipedia.org/wiki/Side-channel_attack). It is also faster than many other elliptic curve algorithms, including secp256k1, making it a good choice for applications that require high performance.

In terms of compatibility, secp256k1 is more widely supported by existing systems, while ed25519 is less widely supported. However, ed25519 is gaining popularity, and is supported by many cryptographic libraries and software.

When choosing between secp256k1 and ed25519, you should consider your specific needs in terms of security, performance, and compatibility. If you are building an application that requires high performance and compatibility with existing systems, secp256k1 may be a better choice. However, if you are building an application that requires a higher level of security and performance, and you can afford to sacrifice some compatibility, ed25519 may be a better choice.

</details>

<details>

<summary>Where can I find the Protobuf interfaces for LagomChain?</summary>

Head over to our [Buf](https://buf.build/evmos).

</details>


