xanoutas/solidity-security-findings huggingface dataset:
Non-deterministic gas consumption due to shared StateDB pointer in bank keeper affecting consensus
Audit: 2024-11-nibiru-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-11-nibiru/blob/84054a4f00fdfefaa8e5849c53eb66851a762319/x/evm/keeper/bank_extension.go#L84-L86


# Vulnerability details

## Finding description and impact

An issue exists in Nibiru's implementation of the bank keeper and its interaction with the EVM's StateDB. The `NibiruBankKeeper` maintains a pointer field to `StateDB` that gets updated during read-only EVM operations (like `eth_estimateGas`), which then affects the gas computation of subsequent bank transactions.

The issue arises because the `StateDB` pointer in `NibiruBankKeeper` is modified during read-only operations, and the presence or absence of this pointer affects program flow in bank operations through nil checks:

```go
func (bk *NibiruBankKeeper) SyncStateDBWithAccount(ctx sdk.Context, acc sdk.AccAddress) {
    // If there's no StateDB set, it means we're not in an EthereumTx.
    if bk.StateDB == nil {
        return
    }
    // ... state updates
}
```

This can lead to consensus failures as different nodes may compute different gas amounts for the same transaction (depending on if they previously executed a read only query via RPC), which should never happen.

## Proof of Concept

The vulnerability can be demonstrated through the following sequence:

1. Initial state: Execute a bank send transaction and record gas used
```go
// Initial bank send 
sendMsg := banktypes.NewMsgSend(sender, receiver, coins)
gasUsed1 := executeTx(sendMsg) // Records initial gas usage
```

2. Trigger a read-only operation that modifies the StateDB pointer
```go
// This can modify NibiruBankKeeper.StateDB depending on the tx content
client.EstimateGas(ethTx) 
```

3. Execute the same bank send transaction again
```go
gasUsed2 := executeTx(sendMsg) // Different gas usage than gasUsed1 because bk.StateDB is no longer nil
```

The key problematic code is in [bank_extension.go](https://github.com/code-423n4/2024-11-nibiru/blob/main/x/evm/keeper/bank_extension.go):

```go
type NibiruBankKeeper struct {
    bankkeeper.BaseKeeper
    StateDB *statedb.StateDB  // This shared pointer causes the issue
}

func (evmKeeper *Keeper) NewStateDB(
    ctx sdk.Context, txConfig statedb.TxConfig,
) *statedb.StateDB {
    stateDB := statedb.New(ctx, evmKeeper, txConfig)
    evmKeeper.Bank.StateDB = stateDB // Modifies shared state
    return stateDB
}
```

## Recommended mitigation steps

There are several ways to fix this issue:

1. Clone the StateDB for read-only operations:
```go
func (k Keeper) EstimateGas(ctx sdk.Context, msg core.Message) (uint64, error) {
    originalStateDB := k.Bank.StateDB
    k.Bank.StateDB = originalStateDB.Copy()
    defer func() {
        k.Bank.StateDB = originalStateDB
    }()
    // ... estimation logic
}
```

2. Use context to pass StateDB instead of keeping it as a field:
```go
type NibiruBankKeeper struct {
    bankkeeper.BaseKeeper
}

func (bk *NibiruBankKeeper) SyncStateDBWithAccount(
    ctx sdk.Context, 
    stateDB *statedb.Stat
Irreversible state changes due to missing rollback mechanism in coin-to-EVM conversion leading to permanent fund loss
Audit: 2024-11-nibiru-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-11-nibiru/blob/84054a4f00fdfefaa8e5849c53eb66851a762319/x/evm/keeper/msg_server.go#L594


# Vulnerability details

## Finding description and impact

In the `convertCoinToEvmBornCoin` and `convertCoinToEvmBornERC20` functions, bank coins are transferred to the EVM module account before attempting ERC20 operations. If these ERC20 operations fail (e.g., due to a paused token or failed transfer), the initial bank coin transfer is not reversed, leading to permanent loss of user funds.

This is particularly severe for `convertCoinToEvmBornERC20` as it deals with arbitrary ERC20 tokens that may (according to the contest description):
- Be pausable 
- Have transfer restrictions
- Implement fee-on-transfer
- Have upgradeable logic
- Be blacklisted

The impact is:
1. Direct loss of user funds when ERC20 operations fail
2. No way to recover funds once they're stuck in the EVM module
3. Susceptibility to malicious ERC20 implementations that could trap funds

## Proof of Concept

In [msg_server.go](https://github.com/code-423n4/2024-11-nibiru/blob/84054a4f00fdfefaa8e5849c53eb66851a762319/x/evm/keeper/msg_server.go#L594):

```go
// 1 | Caller transfers Bank Coins to be converted to ERC20 tokens.
if err := k.Bank.SendCoinsFromAccountToModule(
    ctx,
    sender,
    evm.ModuleName,
    sdk.NewCoins(coin),
); err != nil {
    return nil, errors.Wrap(err, "error sending Bank Coins to the EVM")
}

// 2 | EVM sends ERC20 tokens to the "to" account.
actualSentAmount, _, err := k.ERC20().Transfer(
    erc20Addr,
    evm.EVM_MODULE_ADDRESS,
    recipient,
    coin.Amount.BigInt(),
    ctx,
)
if err != nil {
    return nil, errors.Wrap(err, "failed to transfer ERC-20 tokens") // Coins lost!
}
```

Similar issues exist in `convertCoinToEvmBornCoin`:
```go
err := k.Bank.SendCoinsFromAccountToModule(ctx, sender, evm.ModuleName, sdk.NewCoins(coin))
if err != nil {
    return nil, errors.Wrap(err, "failed to send coins to module account")
}

evmResp, err := k.CallContract(
    ctx,
    embeds.SmartContract_ERC20Minter.ABI,
    evm.EVM_MODULE_ADDRESS,
    &erc20Addr,
    true,
    Erc20GasLimitExecute,
    "mint",
    recipient,
    coin.Amount.BigInt(),
)
if err != nil {
    return nil, err  // Coins lost!
}
```

## Recommended mitigation steps

1. Implement a transaction-like pattern that only commits state changes if all operations succeed:

```go
func (k Keeper) convertCoinToEvmBornERC20(ctx sdk.Context, ...) (*MsgResponse, error) {
    // Cache context to allow rollback
    tmpCtx, commit := ctx.CacheContext()
    
    // Perform bank transfer
    if err := k.Bank.SendCoinsFromAccountToModule(tmpCtx, sender, evm.ModuleName, coins); err != nil {
        return nil, err
    }
    
    // Attempt ERC20 transfer
    actualSentAmount, _, err := k.ERC20().Transfer(erc20Addr, evm.EVM_MODULE_ADDRESS, recipient, amount, tmpCtx)
    if err != nil {
        // No need to rollback - changes were only in cached context
        re
Missing Validity Check for the admin Parameter in the instantiate Function of x/evm/precompile/wasm.go
Audit: 2024-11-nibiru-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-11-nibiru/blob/main/x/evm/precompile/wasm.go#L237


# Vulnerability details

The `instantiate` function creates a new instance of a Wasm smart contract for a given code ID. This function is designed to interact with a Wasm contract through the Ethereum Virtual Machine (EVM). It processes the `admin` parameter, but there is a missing validity check for this parameter.

```go
// instantiate creates a new instance of a Wasm smart contract for some code id.
//
// Implements "instantiate" from evm/embeds/contracts/Wasm.sol:
//
//	```solidity
//	/// @notice InstantiateContract creates a new smart contract instance for the given code id.
//	/// @param admin The address of the contract admin (optional, can be empty string)
//	/// @param codeID The ID of the code to instantiate
//	/// @param msgArgs JSON encoded instantiation message
//	/// @param label A human-readable label for the contract
//	/// @param funds Optional funds to send to the contract upon instantiation
//	function instantiate(
//	  string memory admin,
//	  uint64 codeID,
//	  bytes memory msgArgs,
//	  string memory label,
//	  BankCoin[] memory funds
//	) payable external returns (string memory contractAddr, bytes memory data);
//	```
func (p precompileWasm) instantiate(
	start OnRunStartResult,
	caller gethcommon.Address,
	readOnly bool,
) (bz []byte, err error) {
	method, args, ctx := start.Method, start.Args, start.CacheCtx
	defer func() {
		if err != nil {
			err = ErrMethodCalled(method, err)
		}
	}()
	if err := assertNotReadonlyTx(readOnly, method); err != nil {
		return nil, err
	}

	callerBech32 := eth.EthAddrToNibiruAddr(caller)
	txMsg, err := p.parseArgsWasmInstantiate(args, callerBech32.String())
	if err != nil {
		err = ErrInvalidArgs(err)
		return
	}

	var adminAddr sdk.AccAddress
	if len(txMsg.Admin) > 0 {
		adminAddr = sdk.MustAccAddressFromBech32(txMsg.Admin) // validated in parse
	}
	contractAddr, data, err := p.Wasm.Instantiate(
		ctx, txMsg.CodeID, callerBech32, adminAddr, txMsg.Msg, txMsg.Label, txMsg.Funds,
	)
	if err != nil {
		return
	}

	return method.Outputs.Pack(contractAddr.String(), data)
}
```

The comment in the code indicates that the `Admin` parameter is validated in the `parse` function:

```go
	var adminAddr sdk.AccAddress
	if len(txMsg.Admin) > 0 {
		adminAddr = sdk.MustAccAddressFromBech32(txMsg.Admin) // validated in parse
	}
```

Let's look at the `parse` function, where it performs `ValidateBasic` checks for the validity of all the parameters.

```go
func (p precompileWasm) parseArgsWasmInstantiate(args []any, sender string) (
	txMsg wasm.MsgInstantiateContract,
	err error,
) {
	if e := assertNumArgs(args, 5); e != nil {
		err = e
		return
	}

	argIdx := 0
	admin, ok := args[argIdx].(string)
	if !ok {
		err = ErrArgTypeValidation("string admin", args[argIdx])
		return
	}

	argIdx++
	codeID, ok := args[argIdx].(uint64)
	if !ok {
		err = ErrArgTypeValidation("uint64 codeID", args[argIdx])
		return
Incorrect Handling of weiInt in the ParseWeiAsMultipleOfMicronibi Function in x/evm/keeper/msg_server.go
Audit: 2024-11-nibiru-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-11-nibiru/blob/main/x/evm/keeper/msg_server.go#L402
https://github.com/code-423n4/2024-11-nibiru/blob/main/x/evm/keeper/msg_server.go#L249


# Vulnerability details

The `ApplyEvmMsg` function is used to apply a message in the Ethereum Virtual Machine (EVM) and compute the new blockchain state.

Within `ApplyEvmMsg`, the `ParseWeiAsMultipleOfMicronibi` function is called to parse the `Wei` value (the smallest unit of Ether) from the message into Micronibi.

[Source Code](https://github.com/code-423n4/2024-11-nibiru/blob/main/x/evm/keeper/msg_server.go#L249)

```go
func (k *Keeper) ApplyEvmMsg(ctx sdk.Context,
	msg core.Message,
	tracer vm.EVMLogger,
	commit bool,
	evmConfig *statedb.EVMConfig,
	txConfig statedb.TxConfig,
	fullRefundLeftoverGas bool,
) (resp *evm.MsgEthereumTxResponse, evmObj *vm.EVM, err error) {
	...

	msgWei, err := ParseWeiAsMultipleOfMicronibi(msg.Value()) // <--------
	if err != nil {
		return nil, evmObj, errors.Wrapf(err, "ApplyEvmMsg: invalid wei amount %s", msg.Value())
	}

	...
}
```

However, in the `ParseWeiAsMultipleOfMicronibi` function, when `weiInt` is negative, the function incorrectly returns the value as-is without converting it to Micronibi. One Micronibi equals 10^12 Wei. This behavior leads to subsequent misinterpretation of the negative Wei value as Micronibi.

[Source Code](https://github.com/code-423n4/2024-11-nibiru/blob/main/x/evm/keeper/msg_server.go#L402)

```go
func ParseWeiAsMultipleOfMicronibi(weiInt *big.Int) (newWeiInt *big.Int, err error) {
	// If "weiInt" is nil, 0, or negative, early return
	if weiInt == nil || !(weiInt.Cmp(big.NewInt(0)) > 0) { // <----------
		return weiInt, nil
	}

	// Error if weiInt is too small
	tenPow12 := new(big.Int).Exp(big.NewInt(10), big.NewInt(12), nil)
	if weiInt.Cmp(tenPow12) < 0 {
		return weiInt, fmt.Errorf(
			"wei amount is too small (%s), cannot transfer less than 1 micronibi. 1 NIBI == 10^6 micronibi == 10^18 wei", weiInt)
	}

	// Truncate to highest micronibi amount
	newWeiInt = evm.NativeToWei(evm.WeiToNative(weiInt))
	return newWeiInt, nil
}
```

This issue results in negative transfers during subsequent calls to `evmObj.Create` or `evmObj.Call`.

### Example of Issue Propagation

In `ApplyEvmMsg`, if a negative `msgWei` value is passed to `evmObj.Call`, the following occurs:

```go
func (k *Keeper) ApplyEvmMsg(ctx sdk.Context,
	msg core.Message,
	tracer vm.EVMLogger,
	commit bool,
	evmConfig *statedb.EVMConfig,
	txConfig statedb.TxConfig,
	fullRefundLeftoverGas bool,
) (resp *evm.MsgEthereumTxResponse, evmObj *vm.EVM, err error) {
	...

	msgWei, err := ParseWeiAsMultipleOfMicronibi(msg.Value())
	if err != nil {
		return nil, evmObj, errors.Wrapf(err, "ApplyEvmMsg: invalid wei amount %s", msg.Value())
	}

	if contractCreation {
		ret, _, leftoverGas, vmErr = evmObj.Create( // <---------
			sender,
			msg.Data(),
			leftoverGas,
			msgWei,
		)
	} else {
		ret, leftoverGas, vmErr = evmObj.Call( // <-----
Inadequate validation for EVM messages could lead to unauthorized EVM execution and potential DoS
Audit: 2024-11-nibiru-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-11-nibiru/blob/8ed91a036f664b421182e183f19f6cef1a4e28ea/app/ante/auth_grard_test.go#L25-L37


# Vulnerability details

## Finding description and impact
Inadequate Validation for EVM Messages in Authorization (Authz)
Root Cause:
- The AnteDecoratorAuthzGuard does not sufficiently validate the types of messages being authorized through the Cosmos SDK authz module. This creates a risk where malicious EVM-specific messages can bypass intended checks.
- Generic grants for EVM-related messages (evm.MsgEthereumTx) are restricted, but certain combinations, like MsgExec wrapping both EVM and non-EVM messages, might slip through the logic inconsistencies.

Impact:
Unauthorized access or misuse of the authz module could lead to:
- Malicious or unintended execution of EVM transactions, potentially consuming resources or causing denial-of-service (DoS) conditions.
- Exploiting vulnerabilities within authorized contracts through replay attacks or malicious payloads.

## Proof of Concept
// Crafting a generic grant for an unauthorized EVM message
someTime := time.Now()
expiryTime := someTime.Add(time.Hour)
genericGrant, err := authz.NewGrant(
    someTime,
    authz.NewGenericAuthorization(sdk.MsgTypeURL(&evm.MsgEthereumTx{})),
    &expiryTime,
)
if err != nil {
    log.Fatalf("Grant creation failed: %v", err)
}
msgGrant := &authz.MsgGrant{Grant: genericGrant}

// Bypassing intended checks by wrapping in MsgExec
msgExec := authz.NewMsgExec(
    sdk.AccAddress("malicioususer"),
    []sdk.Msg{
        msgGrant,
    },
)

## Recommended mitigation steps
1. Implement stricter validation in AnteDecoratorAuthzGuard for composite messages.
2. Add checks to ensure no unauthorized EVM-specific messages are present in any level of wrapping (MsgGrant, MsgExec).
3. Apply an allowlist approach for message types explicitly supported in authz.
Missing replay protection could lead to Double-spending and unauthorized re-execution
Audit: 2024-11-nibiru-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-11-nibiru/blob/8ed91a036f664b421182e183f19f6cef1a4e28ea/app/ante/auth_grard_test.go#L75-L86


# Vulnerability details

## Finding description and impact
Missing Replay Protection for Wrapped Messages
Root Cause: AnteDecoratorAuthzGuard does not appear to validate replay protections for MsgExec or MsgGrant. Malicious actors could replay previously authorized transactions, exploiting the authz functionality.

Impact:
- Enables double-execution of transactions, leading to potential resource drains or unauthorized state changes.
- Vulnerable to nonce-replay attacks, especially in composite transactions involving authz.

## Proof of Concept
// Re-executing a previously authorized message without nonce checks
msgExec := authz.NewMsgExec(
    sdk.AccAddress("nibiuser"),
    []sdk.Msg{
        &evm.MsgEthereumTx{}, // Previously authorized message
    },
)
err = anteDec.AnteHandle(
    deps.Ctx, txBuilder.GetTx(), false, evmtest.NextNoOpAnteHandler,
)
if err == nil {
    log.Println("Replay attack successful")
}

## Recommended mitigation steps
1. Introduce nonce-based replay protection for all MsgExec and MsgGrant invocations.
2. Maintain a cache of executed transaction IDs to prevent reprocessing.
Non-Deterministic Iteration in ForEachStorage
Audit: 2024-11-nibiru-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-11-nibiru/blob/main/x/evm/statedb/statedb.go#L324
https://github.com/code-423n4/2024-11-nibiru/blob/main/x/evm/statedb/state_object.go#L82


# Vulnerability details

### PoC

The `ForEachStorage` method iterates over the storage data of a contract at a given address, invoking a callback function `cb` for each key-value pair. This method checks both the dirty storage in the local state object and the global storage for keys.

https://github.com/code-423n4/2024-11-nibiru/blob/main/x/evm/statedb/statedb.go#L324

```go
// ForEachStorage iterate the contract storage, the iteration order is not defined.
func (s *StateDB) ForEachStorage(addr common.Address, cb func(key, value common.Hash) bool) error {
    so := s.getStateObject(addr)
    if so == nil {
        return nil
    }
    s.keeper.ForEachStorage(s.evmTxCtx, addr, func(key, value common.Hash) bool {
        if value, dirty := so.DirtyStorage[key]; dirty {
            return cb(key, value)
        }
        if len(value) > 0 {
            return cb(key, value)
        }
        return true
    })
    return nil
}
```

However, `DirtyStorage` is implemented using **Go's `map`**, and iteration over a `map` in Go is inherently non-deterministic.

https://github.com/code-423n4/2024-11-nibiru/blob/main/x/evm/statedb/state_object.go#L82

```go
// Storage represents in-memory cache/buffer of contract storage.
type Storage map[common.Hash]common.Hash
```

Any computation performed on-chain must be deterministic and reproducible by every validator to ensure the network’s state remains consistent.

This non-deterministic iteration can lead to severe inconsistencies, where different nodes may produce varying results due to differing iteration orders, ultimately causing consensus issues.

---

### Suggested Fix

All keys should be sorted to ensure a consistent iteration order:

```go
func (s *StateDB) ForEachStorage(addr common.Address, cb func(key, value common.Hash) bool) error {
    so := s.getStateObject(addr)
    if so == nil {
        return nil
    }

    // Collect all key-value pairs
    storage := map[common.Hash]common.Hash{}
    for key, value := range so.DirtyStorage {
        storage[key] = value
    }
    s.keeper.ForEachStorage(s.evmTxCtx, addr, func(key, value common.Hash) bool {
        if _, dirty := so.DirtyStorage[key]; !dirty && len(value) > 0 {
            storage[key] = value
        }
        return true
    })

    // Sort the keys
    keys := make([]common.Hash, 0, len(storage))
    for key := range storage {
        keys = append(keys, key)
    }
    sort.Slice(keys, func(i, j int) bool {
        return bytes.Compare(keys[i].Bytes(), keys[j].Bytes()) < 0
    })

    // Invoke the callback in order
    for _, key := range keys {
        if !cb(key, storage[key]) {
            break
        }
    }
    return nil
}
```

---

### Impact

This issue primarily affects consensus. Non-deterministic iteration of contract storage can res
StateDB Persistence in Read-Only Operations within Bank Module State Can Lead to Consensus Failures
Audit: 2024-11-nibiru-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-11-nibiru/blob/8ed91a036f664b421182e183f19f6cef1a4e28ea/x/evm/keeper/msg_server.go#L262


# Vulnerability details

## Finding description and impact

ApplyEvmMsg is used for both state-modifying transactions and read-only operations (call/estimateGas). This implementation creates and assigns a new StateDB via NewStateDB to the Bank module's StateDB pointer:

```
// In ApplyEvmMsg both read-only and state-modifying operations call:
stateDB := k.NewStateDB(ctx, txConfig)
// Which sets Bank.StateDB pointer:
evmKeeper.Bank.StateDB = stateDB
```

The StateDB is not restored to the previous state which should be done for read-only operations.

Impact:


This violates a core principle - read-only operations must not produce state changes. The persistence of StateDB from read-only queries to the Bank module causes:

1. State changes from operations intended to be read-only
2. Unexpected failures and non-deterministic behavior due to altered Bank module state

For example, currently the bank.stateDB != nil is used to decide if the state needs to be synced in `SyncStateDBWithAccount` and will execute different branches if preceded by a read only estimateGas and inconsistent gas usage.

Such non-deterministic behavior will lead to consensus failure and is a critical issue.

The lack of state isolation between read-only queries and the Bank module represents a fundamental design issue that should be addressed.
Bypassing Validation for Nested MsgEthereumTx in MsgExec
Audit: 2024-11-nibiru-findings
Severity: HIGH

In the file [authz_guard.go](https://github.com/code-423n4/2024-11-nibiru/blob/main/app/ante/authz_guard.go#L56), the AnteHandle function prohibits MsgEthereumTx messages within the execution messages of authz.MsgExec.

However, the current implementation only iterates over the top-level messages in msgExec and checks their types for MsgEthereumTx. It does not recursively inspect nested MsgExec structures, such as a msgExec containing another msgExec that encapsulates MsgEthereumTx.

```go
// Also rejects authz exec tx.json with any MsgEthereumTx inside
func (rmd AnteDecoratorAuthzGuard) AnteHandle(
	ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler,
) (newCtx sdk.Context, err error) {
	for _, msg := range tx.GetMsgs() {
		...
		// Also reject MsgEthereumTx in exec
		if msgExec, ok := msg.(*authz.MsgExec); ok {
			msgsInExec, err := msgExec.GetMessages()
			if err != nil {
				return ctx, errors.Wrapf(
					errortypes.ErrInvalidType,
					"failed getting exec messages %s", err,
				)
			}
			for _, msgInExec := range msgsInExec {
				if _, ok := msgInExec.(*evm.MsgEthereumTx); ok {
					return ctx, errors.Wrapf(
						errortypes.ErrInvalidType,
						"MsgEthereumTx needs to be contained within a tx with 'ExtensionOptionsEthereumTx' option",
					)
				}
			}
		}
	}
	return next(ctx, tx, simulate)
}
```

### Proof of Concept

The current implementation only checks the first level of messages in authz.MsgExec. If an attacker creates a nested structure, it can bypass validation for MsgEthereumTx:

```go
Outer MsgExec:
  - Inner MsgExec:
      - MsgEthereumTx
```

By constructing such a structure, the AnteHandle validation can be bypassed, allowing a malicious MsgEthereumTx to pass undetected.

**Start the Node:**

**Initialize the Blockchain Node**

- Initialize the blockchain node and create necessary configuration files (e.g., config.toml, genesis.json) for the new blockchain.
- Set the validator's node name (gxh191) and the chain ID (nibiru-1).

Initialize the environment and specify the identity of the node and the blockchain it participates in.

```go
nibid init gxh191 --chain-id nibiru-1
```

**Create Validator Account**

- Create a local key pair to manage the validator's account.
- Generate a mnemonic and address to register the account on the blockchain.

Configure the validator's account to enable signing transactions and operations.

```go
nibid keys add validator
```

```go
- address: nibi16jvwx57mhn6yv96egyd7g2mjw2wu4s93tmkg3k
  name: validator
  pubkey: '{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AsnVfrZbG3Hr+wDgtcjDOuBFqJpVJ/9q3bAH1CThECM4"}'
  type: local
```

**Set Validator Account as Super Admin**

- Set the validator account as a sudo root account to manage blockchain permissions.

```go
nibid genesis add-sudo-root-account nibi16jvwx57mhn6yv96egyd7g2mjw2wu4s93tmkg3k
```

**Allocate Initial Funds to Validator Account**

- Al