Pension Token

CertiKFiles named in the report

CertiK reviewed Pension (Pension Token) on 20 Oct 2022: 18 findings, 0 critical; none marked fixed.

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

Report hosted on skynet.certik.com.

Trustblock does not review code.

Findings18

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

SeverityOpenAcknowledgedFixed
Critical000
High300
Medium100
Low1400
HighCentralization Risks in Pension.solOpen

In the contract `Ownable` the role `_owner` has authority over the functions shown in the diagram below. Any compromise to the `_owner` account may allow the hacker to take advantage of this authority and - transfer ownership through `transferOwnership()` - permanently renounce ownership through `renounceOwnership()` ![](https://accelerator-tasks-prod.acc.corp.certik.com/d554a9edb0b44ab59f3d63b64f380b3d/diagrams/centralization_Pension-Ownable-_owner.svg) In the contract `PensionProtocolToken` the role `_owner` has authority over the functions shown in the diagram below. Any compromise to the `_owner` account may allow the hacker to take advantage of this authority and - set `liquidityAddress`, `marketingAddress` and `developmentAddress` through `setFeeReceivers()` - set the fees up to fifteen in total through `setFees()` - exempt or include an address from/in fees through `setFeeExempt()` - transfer tokens on this contract to any address through `rescueToken()` - transfer ether on this contract to any address through `clearStruckBalance()` - set the next timestamp for rebasing through `setNextRebase()` - add or remove automated market maker pair through `setAutomatedMarketMakerPair()` - set the rebasing time delay up to eighteen hundred seconds through `setRebaseFrequency()` - set the reward rate and denominator through `setRewardYield()` ![](https://accelerator-tasks-prod.acc.corp.certik.com/d554a9edb0b44ab59f3d63b64f380b3d/diagrams/centralization_Pension-PensionProtocolToken-_owner.svg) In the contract `PensionProtocolToken` the role `_owner` has authority over the functions shown below. Any compromise to the `_owner` account may allow the hacker to take advantage of this authority and - add liquidity through `swapBack()` - mint uncapped "gon" tokens on any account through `mint()` - burn from any account through `burn()` - rebase the supply of the token through `manualRebase()` In the contract `TokenHandler` the role `_owner` has authority over the functions shown in the diagram below. Any compromise to the `_owner` account may allow the hacker to take advantage of this authority and - take all tokens on this contract through `sendTokenToOwner()` ![](https://accelerator-tasks-prod.acc.corp.certik.com/d554a9edb0b44ab59f3d63b64f380b3d/diagrams/centralization_Pension-TokenHandler-_owner.svg) In the contract `WhitelistedRole` the role `_owner` has authority over the functions shown in the diagram below. Any compromise to the `_owner` account may allow the hacker to take advantage of this authority and - add an account to the whitelist through `addWhitelisted()` - remove an account from the whitelist through `removeWhitelisted()` ![](https://accelerator-tasks-prod.acc.corp.certik.com/d554a9edb0b44ab59f3d63b64f380b3d/diagrams/centralization_Pension-WhitelistedRole-_owner.svg)

HighCentralization Risks in PensionBank.solOpen

In the contract `Ownable` the role `_owner` has authority over the functions shown in the diagram below. Any compromise to the `_owner` account may allow the hacker to take advantage of this authority and - transfer ownership through `transferOwnership()` - permanently renounce ownership through `renounceOwnership()` ![](https://accelerator-tasks-prod.acc.corp.certik.com/d554a9edb0b44ab59f3d63b64f380b3d/diagrams/centralization_PensionBank-Ownable-_owner.svg) In the contract `PensionBank` the role `_owner` has authority over the functions shown in the diagram below. Any compromise to the `_owner` account may allow the hacker to take advantage of this authority and - set the pension token address through `setPensionToken()` - update the pension tax up to eighty percent through `updatePensionTax()` ![](https://accelerator-tasks-prod.acc.corp.certik.com/d554a9edb0b44ab59f3d63b64f380b3d/diagrams/centralization_PensionBank-PensionBank-_owner.svg) In the contract `PensionBank` the role `_whitelisted` has authority over the functions shown below. Any compromise to the `_whitelisted` account may allow the hacker to take advantage of this authority and - rebase the pension token and take dividends through `rebase()` In the contract `WhitelistedRole` the role `_owner` has authority over the functions shown in the diagram below. Any compromise to the `_owner` account may allow the hacker to take advantage of this authority and - add an account to the whitelist through `addWhitelisted()` - remove an account from the whitelist through `removeWhitelisted()` ![](https://accelerator-tasks-prod.acc.corp.certik.com/d554a9edb0b44ab59f3d63b64f380b3d/diagrams/centralization_PensionBank-WhitelistedRole-_owner.svg)

HighInitial Token DistributionOpen

Tokens are sent to the deployer when deploying the contract. This could be a centralization risk as the deployer can distribute tokens without obtaining the consensus of the community.

Medium`liquidityBalance` Not AddedOpen

Balance is not added to `liquidityBalance` which will always be zero.

Low`supplyDelta` Is Always Non-negativeOpen

The calculated `supplyDelta` would always be non-negative given that `rewardYield` and `circulatingSupply` are non-negative. Yet the rebasing logic assume that it could be negative.

LowFunction Visibility OptimizationOpen

The mentioned functions are declared as `public`, contain array function arguments, and are not invoked in any of the contracts contained within the project's scope. The functions that are never called internally within the contract should have external visibility.

LowMissing Emit EventsOpen

The function that affects the status of sensitive variables should be able to emit events as notifications to users.

LowMissing Input ValidationOpen

The given input is missing the check for the non-zero address.

LowRedundant CodeOpen

The aforementioned code is not used and seems redundant.

LowSelling PensionOpen

The `_transferFrom` method restricts token transfer to only `excludedAccount`. While listed `automatedMarketMakerPairs` are allowed to send but not allowed to receive pension tokens, this means the user cannot freely sell or transfer their pension tokens. To sell they would have to call `sell()` in the `PensionBank` contract, yet it would incur a high 50% of pension tax.

Show 8 more
LowThird Party DependenciesOpen

The contract is serving as the underlying entity to interact with third-party protocols. The scope of the audit treats 3rd party entities as black boxes and assumes their functional correctness.

LowUnchecked ERC-20 `transfer()`/`transferFrom()` CaOpen

The return value of the transfer()/transferFrom() call is not checked. ```solidity=202 IERC20(token).transfer(owner(), IERC20(token).balanceOf(address(this))); ``` --- ```solidity=445 IERC20(BUSD).transfer(marketingAddress, busdForMarketing); ``` --- ```solidity=449 IERC20(BUSD).transfer(developmentAddress, busdForDevelopment); ``` --- ```solidity=453 IERC20(BUSD).transfer(teamAddress, busdForTeam); ``` --- ```solidity=561 try IERC20(address(pensionToken)).transferFrom(msg.sender, address(this), userPensionBalance) {} catch {revert("transfer from caller failed");} ``` --- ```solidity=565 IERC20(BUSD).transfer(msg.sender, busdBalance * (100-pensionTax) / 100); ```

LowUninitialized State VariableOpen

`excludedFromDividends` is not being initialized in the constructor and cannot be written by any methods.

LowUnnecessary Memory DeclarationOpen

The linked statement make an assignment of a global variable.

LowUnused FunctionsOpen

The functions `get()`, `getIndexOfKey()`, `getKeyAtIndex()` and `size()` are declared but never used in the contract.

LowUnused Return ValueOpen

The return value of an external call is not stored in a local or state variable. ```solidity=479 IERC20(BUSD).approve(address(router), busdAmount); ``` --- ```solidity=482 router.addLiquidity(address(this), address(BUSD), tokenAmount, busdAmount, 0, 0, address(liquidityAddress), block.timestamp); ``` --- ```solidity=337 BUSD.approve(address(dexRouter), busdBalance); ``` --- ```solidity=340 dexRouter.swapExactTokensForETH( busdBalance, 0, // accept any amount of Ethereum path, address(this), block.timestamp ); ``` --- ```solidity=578 IERC20(address(pensionToken)).approve(address(dexRouter), tokenAmount); ``` --- ```solidity=594 IERC20(BUSD).approve(address(dexRouter), amountInBusd); ```

LowUse of Rebase in Token and BankOpen

Calling `manualRebase()` in the token contract deflates the token somewhat and the user's balance is increased proportionally while calling `rebase()` in the bank contract additionally mint extra token and then sell them for dividends. Generally, the bank user should receive as many dividends as token holders' balance increases but this may not be the case if `manualRebase` is called by external other than the bank.

LowVariables That Could Be Declared as `constant`Open

The linked variables could be declared as `constant` since these state variables are never modified.

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/PensionBank.sol
  • contracts/Pension.sol

Part of Pension’s security record

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