Open code423n4 opened 2 years ago
contracts should explicitly implement their interface (if available). agreed. addressed here: https://github.com/Swivel-Finance/gost/pull/424
reference to VaultTracker having 2**256-1
is incorrect. Is in Swivel.sol. agree with assessment tho, changed.
casting int returns as booleans is not tautological, particularly in the context of what that method is doing (normalizing returns)
MarketPlace.authRedeem as external
agree - changed
removing TODOS agree: removing
various issues above addressed here: https://github.com/Swivel-Finance/gost/pull/425
adding maybe
in order to discuss adding events for setters
I am not opposed to upgrading and creating a duplicate, but the warden doesn't identify the impact of this correctly which I think is important for an issue to be marked as high severity.
event is now in place for setAdmin
the only one that is needed. the other setters are one-time only by the deploying admin.
QA Report
Table of Contents
Low
Non-critical
2**256 - 1
can be re-writtensummary
Contracts should inherit their interfaces
IMPACT
Contract implementations should inherit their interfaces. Extending an interface ensures that all function signatures are correct, and catches mistakes introduced (e.g. through errant keystrokes)
SEVERITY
Low
PROOF OF CONCEPT
Marketplace.sol
contract MarketPlace {
Does not inherit
IMarketPlace
, defined hereTOOLS USED
Manual Analysis
MITIGATION
Immutable addresses lack zero-address check
IMPACT
constructors should check the address written in an immutable address variable is not the zero address.
Note: while it has been indicated by the sponsor input validation will be on the front-end side to relieve users from unnecessary gas spendings, this issue here concerns constructor functions, ie when the contract is deployed by the team.
SEVERITY
Low
PROOF OF CONCEPT
11 instances include:
Swivel.sol
marketPlace = m
MarketPlace.sol
creator = c
VaultTracker.sol
protocol = p\ maturity = m\ cTokenAddr = c\ swivel = s
ZcToken.sol
protocol = _protocol\ underlying = _underlying\ maturity = _maturity\ cToken = _cToken\ redeemer = IRedeemer(_redeemer)
TOOLS USED
Manual Analysis
MITIGATION
Add a zero address check for the immutable variables aforementioned.
Safe.sol does not check contract existence
PROBLEM
Safe.sol
is used to perform ERC20 transfers in the protocols contracts. It does not check for contract existence, meaning any call to an address with no bytecode (the address zero or an EOA) would not revert uponSafe.transfer
. If there is a market with an underlying token being an empty bytecode address, this means a user can initiate a position without actually transferring any token toSwivel
- as all protocols except Aave do not check for the underlying token. As only an admin can add a market, the risk of this issue affecting the protocols is low.SEVERITY
Low
PROOF OF CONCEPT
In
Safe.transfer
() andSafe.transferFrom
,success
is set to 1 if the call returns1
, which is the case if it made to an address with no bytecode.TOOLS USED
Manual Analysis
MITIGATION
Use
extcodesize()
inSafe.sol
transfer functions to ensure the destination contract has bytecode.Setters should check the input value
PROBLEM
Setters should check the input value - ie make revert if it is the zero address or zero
Note: while it has been indicated by the sponsor input validation will be on the front-end side to relieve users from unnecessary gas spendings, this issue here concerns constructor functions or setters called by authorized admins, not users, and most likely by interacting with the contract directly (for instance using Etherscan or Hardhat) and not with a front-end.
SEVERITY
Low
PROOF OF CONCEPT
5 instances:
Swivel.sol
function setAdmin(address a)
MarketPlace.sol
function setSwivel(address s)\ function setAdmin(address a)
Creator.sol
function setAdmin(address a)\ function setMarketPlace(address m)
TOOLS USED
Manual Analysis
MITIGATION
Add non-zero checks to the setters aforementioned.
Wrong function name
PROBLEM
As per the docs,
MarketPlace
is to act as theIRedeemer
to burn ZcTokens and callSwivel.authRedeem
. The problem is thatSwivel
does not implementauthRedeem
, butauthRedeemZcToken
, meaning the functions call ISwivel(swivel).authRedeem(p, u, market.cTokenAddr, t, a) will always revert. A consequence of this is thatZcToken.withdraw
andZcToken.redeem
will also always revert - that is, ifZcToken.redeemer
isMarketPlace
.SEVERITY
Low
PROOF OF CONCEPT
Swivel.sol
function authRedeemZcToken(uint8 p, address u, address c, address t, uint256 a)
TOOLS USED
Manual Analysis
MITIGATION
Change the function name to
authRedeem
2**256 - 1
can be re-writtenPROBLEM
2**256 - 1
can be re-written astype(uint256).max
SEVERITY
Non-Critical
PROOF OF CONCEPT
VaultTracker.sol
uint256 max = 2**256 - 1
TOOLS USED
Manual Analysis
Constants instead of magic numbers
PROBLEM
It is best practice to use constant variables rather than literal values to make the code easier to understand and maintain.
SEVERITY
Non-Critical
PROOF OF CONCEPT
30 instances:
VaultTracker.sol
yield = ((maturityRate * 1e26) / vlt.exchangeRate) - 1e26\ yield = ((exchangeRate * 1e26) / vlt.exchangeRate) - 1e26\ uint256 interest = (yield * vlt.notional) / 1e26\ yield = ((maturityRate * 1e26) / vlt.exchangeRate) - 1e26\ yield = ((exchangeRate * 1e26) / vlt.exchangeRate) - 1e26\ uint256 interest = (yield * vlt.notional) / 1e26\ yield = ((maturityRate * 1e26) / vlt.exchangeRate) - 1e26\ yield = ((exchangeRate * 1e26) / vlt.exchangeRate) - 1e26\ uint256 interest = (yield * vlt.notional) / 1e26\ yield = ((maturityRate * 1e26) / from.exchangeRate) - 1e26\ yield = ((exchangeRate * 1e26) / from.exchangeRate) - 1e26\ uint256 interest = (yield * from.notional) / 1e26\ yield = ((maturityRate * 1e26) / to.exchangeRate) - 1e26\ yield = ((exchangeRate * 1e26) / to.exchangeRate) - 1e26\ uint256 newVaultInterest = (yield * to.notional) / 1e26\ yield = ((maturityRate * 1e26) / sVault.exchangeRate) - 1e26\ yield = ((exchangeRate * 1e26) / sVault.exchangeRate) - 1e26\ uint256 newVaultInterest = (yield * sVault.notional) / 1e26
TOOLS USED
Manual Analysis
MITIGATION
Define constant variables for the literal values aforementioned.
Events indexing
PROBLEM
Events should use the maximum amount of indexed fields: up to three parameters. This makes it easier to filter for specific values in front-ends.
SEVERITY
Non-Critical
PROOF OF CONCEPT
3 instances:
lending-market/Comptroller.sol
event ScheduleWithdrawal(address indexed token, uint256 hold)\ event ScheduleApproval(address indexed token, uint256 hold)\ event ScheduleFeeChange(uint256 hold)
TOOLS USED
Manual Analysis
MITIGATION
Add indexed fields to these events so that they have the maximum number of indexed fields possible.
Event should be emitted in setters
PROBLEM
Setters should emit an event so that Dapps can detect important changes to storage
SEVERITY
Non-Critical
PROOF OF CONCEPT
5 instances:
Swivel.sol
function setAdmin(address a)
MarketPlace.sol
function setSwivel(address s)\ function setAdmin(address a)
Creator.sol
function setAdmin(address a)\ function setMarketPlace(address m)
TOOLS USED
Manual Analysis
MITIGATION
emit an event in all setters
Function order
PROBLEM
Functions should be ordered following the Solidity conventions
SEVERITY
Non-Critical
PROOF OF CONCEPT
Swivel.sol
authorized
is placed at the end of the contract, while it should be placed before every other function:Type declarations
State variables
Events
Modifiers
Functions
Functions should be grouped according to their visibility and ordered:
constructor
receive function (if exists)
fallback function (if exists)
external
public
internal
private