As of 3 Nov 2026, Tenet has 1 audit report on Trustblock, by CertiK, dated 23 Apr 2023. That report lists no open critical findings.
Record last updated . It holds audits and findings, contracts and incidents up to Nov 2026. Trustblock does not review code.
Newest first
Statuses are the security firm’s own, from each report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 0 | 0 | 0 |
| Medium | 0 | 0 | 2 |
| Low | 1 | 0 | 8 |
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.
Open the reportWhen 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.
Open the reportWhen 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.
Open the reportThe 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.
Open the reportWe 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`.
Open the reportThe 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) } ````
Open the reportIn 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) ````
Open the reportThe 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`.
Open the reportThe 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.
Open the reportThe 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() { ````
Open the reportThe reports name a repository or files. Open a report to see its scope.
Is this your project? Show this record on your own website. The label states what the record holds, links to this page and updates by itself. It is free and needs no sign-in.
Automatic: the three strongest facts of this project’s own record (its last audit and two more), highlighted. They update with the record. Picking a fact turns Automatic off.
<head><script src="https://widget.trustblock.run/project-widget.min.js" defer></script></head><body><divdata-tb-project-widgetdata-tb-project-slug="tenet"></div></body>
Paste the code where the label should appear. It uses no API credit and updates by itself.
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