TENET

CertiKFiles named in the report

CertiK reviewed Tenet on 23 Apr 2023: 11 findings, 0 critical; 10 marked fixed, 1 open.

No open critical findings
Open the reportOpen Tenet’s security record

Report hosted on skynet.certik.com.

Trustblock does not review code.

Findings11

Statuses are the security firm’s own, from its report.

SeverityOpenAcknowledgedFixed
Critical000
High000
Medium002
Low108
MediumLogic issue on the `Inflation` processFixed

At the beginning of every block, the function `BeginBlocker` is to mint new tokens for the previous block and updates the `minter` params. However, there are two logic issues in this function. **1. There are no coins to be minted.** ````go=28 mintedCoin := minter.BlockProvision(params) mintedCoins := sdk.NewCoins(mintedCoin) ```` The variable `mintedCoin` is the coins that should be minted in the current block but won't actually be minted. **2. There is a comparison between the `balances` and `mintedCoins`, which makes no sense.** ````go=32 balances := k.GetAllBalances(ctx) if !balances.IsAllGTE(mintedCoins) { mintedCoins = sdk.NewCoins(sdk.NewCoin(mintedCoin.Denom, balances.AmountOf(mintedCoin.Denom))) } ```` The `balances` are the amounts of those coins in the current module, and the `mintedCoins` are those coins to be minted in the current block, the two are not comparable.

MediumLogic Issue on the function `CompleteUndelegationFixed

When handling `UndelegateEvent`, the delegator does not immediately receive the previously delegated assets. Instead, a `QueuedUndelegation` is constructed and processed at the end of each block. In the `CompleteUndelegations()` method, there are two logical issues below, **1. Incorrect balance check** When processing a refund, coins should be transferred from the module address to the delegator's address. Therefore, when checking if the refund balance is sufficient, the balance of the module address instead of the delegator address should be checked to be greater than the refund balance. ````go balances := k.bankKeeper.GetAllBalances(ctx, delAddr) if !balances.IsAllGTE(sdk.NewCoins(undel.Balance)) { k.Logger(ctx).Error("not enough tokens to complete unbonding", "unbonding", undel.Balance, "balances", balances) continue out } ```` **2. Delegator does not actually receive the refund** Typically, regardless of whether it is a native asset, the `undelegation` process should include the logic to return a certain amount of coins from the module address to the delegator address.

LowExplanation of the `Delegate` ProcessFixed

When processing `delegate` events, we can see from the `alliance.sol` contract that there are two types of delegates: **Delegate Native Asset** In this case, the delegator does not transfer any assets in the contract, and the subsequent processing logic uses the relevant processing in Cosmos's staking module, which is logical. **Delegate Alliance Asset** In this case, the delegator transfers a certain amount of tokens to the cosmosBridge address in the contract, and the subsequent event processing uses the corresponding processing in the alliance module of Terry-money. We noticed that in the delegate method, there is another transfer of coins from the delegator's address to the alliance module address. In this case, the delegator pays twice. Does this match your design intentions? According to general logic, when delegating Alliance Assets, the current module should mint the corresponding amount of coins for the delegator and then transfer them to the corresponding module for processing.

LowExplanation on `updateWhitelist`Fixed

The current logic of the function seems to satisfy the intent of comparing two address arrays and checking if they contain the same elements with the same sequence. However, the function's behavior when the arrays contain the same elements but in a different order may not be optimal. Instead of always returning false and updating the whitelist, it may be more efficient to check if the arrays contain the same elements regardless of their order. ````go func testEq(a, b []common.Address) bool { if len(a) != len(b) { return false } for i := range a { if a[i] != b[i] { return false } } return true } ```` One way to achieve this could be to sort both arrays before comparing them. This way, if the arrays have the same elements, regardless of their order, they will be sorted in the same way and will be considered equal. If they are not equal, then the function can return false and update the whitelist.

LowFailure on Starting Local NodeFixed

We noticed that it will be fail when starting the local node by invoke the bash file `local_node.sh`. The error message is in below: ````bash Error: failed to validate genesis state: invalid Bech32 prefix; expected tenet, got evmos ```` We found that this error occurred in the validation of balance messages of the genesis file, the balances contain an address which its prefix is `evmos`, and it can't match the prefix set to be `tenet`. ````bash jq -r --arg amount_to_claim "$amount_to_claim" '.app_state["bank"]["balances"] += [{"address":"evmos15cvq3ljql6utxseh0zau9m8ve2j8erz89m5wkz"," ```` It will start successfully when changing the prefix of the balance address from `evmos` to `tenet`.

LowInappropriate function nameFixed

The function `GetEnableEVMHook` returns true if the EVM hooks are enabled. The name `isEnableEVMHook` should be more appropriate. ````go func (k Keeper) GetEnableEVMHook(ctx sdk.Context) bool { store := ctx.KVStore(k.storeKey) return store.Has(types.ParamStoreKeyEnableEVMHook) } ````

LowIncorrect `if` ConditionFixed

In the following code snippets, if `mintedCoins` is not zero, then return, if it's zero, it will be transferred to `collector` address via the function `AddCollectedFees`. The logic here is unreasonable. ````go if !mintedCoins.IsZero() { return } err := k.AddCollectedFees(ctx, mintedCoins) ````

LowIncorrect commentsFixed

The description of the function `NextInflationRate` below is incorrect. ````go // NextInflationRate returns the new inflation rate for the next hour. func (m Minter) NextInflationRate(params Params, bondedRatio sdk.Dec) sdk.Dec { ```` It should be `for the next block`, not `hour`.

LowLogic issue on the function `SlashUndelegations`Fixed

The function `SlashUndelegations()` is to slash all immature `undelegations`. ````go for _, entry := range undelegations.Entries { tokensToSlash := fraction.MulInt(entry.Balance.Amount).TruncateInt() entry.Balance = sdk.NewCoin(entry.Balance.Denom, entry.Balance.Amount.Sub(tokensToSlash)) } ```` For each entry, it will decrease the balance which should be refunded to the delegator. However, the penalty doesn't transfer to other addresses or get burnt.

LowUnclosed IteratorFixed

The iterator below is not being properly managed and may lead to resource leaks or other issues as it is not being closed. ````go undelegationIterator := k.IterateUndelegationsBySrcValidator(ctx, valAddr) for ; undelegationIterator.Valid(); undelegationIterator.Next() { ````

Contracts in scope

No deployed address is recorded for this audit.

The report names a repository or files. Open the report to see its scope.

Repository and files the report names (39)

  • x/evm_alliance/client/cli/tx.go
  • x/mint/types/genesis.go
  • x/evm_alliance/types/interfaces.go
  • x/mint/client/cli/query.go
  • x/evm_alliance/keeper/hooks.go
  • x/evm_alliance/types/errors.go
  • x/mint/abci.go
  • x/mint/types/events.go
  • x/evm_alliance/types/genesis.go
  • x/evm_alliance/genesis.go
  • x/evm_alliance/keeper/delegations.go
  • x/evm_alliance/keeper/keeper.go
  • x/evm_alliance/types/compiled_contract.go
  • x/evm_alliance/types/params.go
  • x/evm_alliance/keeper/evm_hooks.go
  • x/evm_alliance/types/events.go
  • x/evm_alliance/keeper/grpc_query.go
  • x/evm_alliance/keeper/whitelist.go
  • x/mint/keeper/keeper.go
  • x/evm_alliance/module.go
  • x/mint/module.go
  • x/evm_alliance/keeper/params.go
  • x/mint/types/codec.go
  • x/evm_alliance/abci.go
  • x/evm_alliance/types/utils.go
  • x/mint/types/params.go
  • x/mint/keeper/grpc_query.go
  • x/mint/types/minter.go
  • x/evm_alliance/keeper/evm.go
  • x/mint/keeper/querier.go
  • x/evm_alliance/types/codec.go
  • x/evm_alliance/handler.go
  • x/mint/keeper/genesis.go
  • x/evm_alliance/keeper/slash.go
  • x/evm_alliance/keeper/msg_server.go
  • x/evm_alliance/types/msg.go
  • x/mint/types/keys.go
  • x/evm_alliance/types/keys.go
  • x/evm_alliance/client/cli/query.go

Part of Tenet’s security record

Tenet
Audits1 audit by 1 firmLast audit Apr 2023, by CertiK.
Critical findingsNo open critical findingsIn 1 report.
Open Tenet’s security record

Security firm

CertiK

1,044 projects reviewed · 1,375 reports · latest May 2025

See CertiK’s audits

Something wrong on this page? A missing report, a wrong date, a finding that was fixed since. Tell us and we check it against its source.

Tell us