OPHIR Endowment Token

CertiKFiles named in the report

CertiK reviewed OphirCrypto (OPHIR Endowment Token) on 22 Jun 2023: 3 findings, 0 critical; 1 acknowledged, 2 open.

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

Report hosted on skynet.certik.com.

Trustblock does not review code.

Findings3

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

SeverityOpenAcknowledgedFixed
Critical000
High010
Medium000
Low200
Low`g_stakedStars` can be updated once instead of twOpen

In the function `endStake()`, `g_stakedStars` needs to have the `stakeTotal` subtracted as it will be minted to the user. This can be done by subtracting `stakeTotal` instead of subtracting `interestAccrued` and then `stake._stakedPrinciple`. In addition, `g_stakedStars` can not be less than the interest or principle as it is the total sum of these variables for all stakes.

LowRedundant CheckOpen

In the function `scrapeStake()`, it is checked if `previousPossibleStars > currentInterest`. However, this is always true as the `previousPossibleStars` is always the principle plus the total amount of accrued interest possible for the stake up to the `endOfStakeDay`. Opposed to the `currentInterest`, which is the amount of accrued interest up to the current day, where the current day must be less than the `endOfStakeDay` because of a `require()` statement earlier in the function. --- In the function `endStake()`, there is the following check: ```solidity=348 if(g_stakedStars >= (stake._possibleStars)){ ``` However, `g_stakedStars` is always updated with `stake._possibleStars`, so that it will always be the sum off all staked possible stars. Thus the check will always pass. --- In the function `endStake()`, there is the following check: ```solidity=353 if(g_stakedPrincipleStars >= stake._stakedPrinciple){ ``` However, `g_stakedPrincipleStars` is always updated with `stake._stakedPrinciple`, so that it will always be the sum off all stakes principle stars. Thus the check will always pass. --- In the function `endStake()`, there is the following check: ```solidity=376 if(g_stakedPrincipleStars >= stake._stakedPrinciple){ ``` However, `g_stakedPrincipleStars` is always updated with the `stake._stakedPrinciple`, so that it will always be the sum off all stakes principle stars. Thus the check will always pass. --- In the function `endStake()`, there is the following check: ```solidity=383 if (stakeTotal != 0) { ``` However, this the `stakeTotal` is either the `principle + accruedInterest` or `principle - penalty`. The maximum `penalty` is only 50 percent of the `principle` and the `principle` is at least `10000` so that the `stakeTotal` can never be `0`. --- In the function `_calculatePenalty()`, there is the following check: ```solidity=738 if (totalStakeDays <= 0) { totalStakeDays = 1 * pctprecision; //sets minimum amt for calculation } ``` However, this is only called in `endStake()` so that the `totalStakeDays` must be at least `MIN_STAKE_DAYS * pctprecision`, thus it is always greater than `0`. --- In the function `_calculatePenalty()`, there is the following check: ```solidity=741 if (calcDays[0] < calcDays[1]) { // should never happen... condition handled in parent } else ``` However, this is only called in `endStake()` in the else block after the if block with the condition that `calcDays[0] < calcDays[1]`. Thus this will never be true. --- In the function `_calculatePenalty()`, there is the following check: ```solidity=762 if (penaltyAmount <= 0) { penaltyAmount = 0; } ``` However, `penaltyAmount` is a `uint256`, thus if it is less than or equal to `0`, then it is already `0` and does not need to be assigned. --- In the function `_calculatePenalty()`, there is the following check: ```solidity=766 if (penaltyAmount > stake._stakedPrinciple) { penaltyAmount = stake._stakedPrinciple; } ``` The `penaltyAmount` is calculated as `(stake._stakedPrinciple * pctleft) / 100`, however the `pctLeft` can only be in the range `[0,50]`. This ensures the maximum `penaltyAmount` is equal to `stake._stakedPrinciple` so that it is impossible for the `penaltyAmount` to be greater than `stake._stakedPrinciple`. --- In the function `calculateStakeTotal()`, there is the following check: ```solidity=802 if (penalty > stake._stakedPrinciple) { // this should never happen but if it does, then set to 50% of the principle appliedPrinciple = stake._stakedPrinciple / 2; } ``` However, the `penalty` amount is always at most 50 percent of the principle so that it can never be greater than `stake._stakedPrinciple`.

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 (2)

  • contracts/OPHIR.sol
  • contracts/StakableEndowmentToken.sol

Part of OphirCrypto’s security record

OphirCrypto
Audits1 audit by 1 firmLast audit Jun 2023, by CertiK.
Critical findingsNo open critical findingsIn 1 report.
Open OphirCrypto’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