Skip to content

Instantly share code, notes, and snippets.

@Picodes
Created January 5, 2023 20:05
Show Gist options
  • Save Picodes/d16459938599db69f9ad88c73a2d2990 to your computer and use it in GitHub Desktop.
Save Picodes/d16459938599db69f9ad88c73a2d2990 to your computer and use it in GitHub Desktop.

Report

Gas Optimizations

Issue Instances
GAS-1 Use assembly to check for address(0) 43
GAS-2 Using bools for storage incurs overhead 4
GAS-3 Cache array length outside of loop 12
GAS-4 Use calldata instead of memory for function arguments that do not get mutated 21
GAS-5 Use Custom Errors 15
GAS-6 Don't initialize variables with default value 3
GAS-7 Functions guaranteed to revert when called by normal users can be marked payable 4
GAS-8 ++i costs less gas than i++, especially when it's used in for-loops (--i/i-- too) 5
GAS-9 Using private rather than public for constants, saves gas 1
GAS-10 Use != 0 instead of > 0 for unsigned integer comparison 17
GAS-11 internal functions not called by the contract should be removed 1

[GAS-1] Use assembly to check for address(0)

Saves 6 gas per instance

Instances (43):

File: lib/gpl/src/ERC721.sol

54:       (owner = _loadERC721Slot()._ownerOf[id]) != address(0),

60:     require(owner != address(0), "ZERO_ADDRESS");

115:     require(to != address(0), "INVALID_RECIPIENT");

200:     require(to != address(0), "INVALID_RECIPIENT");

202:     require(s._ownerOf[id] == address(0), "ALREADY_MINTED");

219:     require(owner != address(0), "NOT_MINTED");

Link to code

File: src/AstariaRouter.sol

342:     s.newGuardian = _guardian;

349:     s.newGuardian = address(0);

379:       } else if (what == FileType.TransferProxy) {

384:         revert UnsupportedFile();

396:     impl = _loadRouterSlot().implementations[implType];

402:   function getAuctionWindow(bool includeBuffer) public view returns (uint256) {

418:         mstore(0, OUTOFBOUND_ERROR_SELECTOR)

459:       revert InvalidCommitmentState(CommitmentState.INVALID_RATE);

476:     if (timeToSecondEpochEnd > 0 && details.duration > timeToSecondEpochEnd) {

Link to code

File: src/CollateralToken.sol

134:       revert InvalidCollateralState(InvalidCollateralStates.AUCTION_ACTIVE);

134:       revert InvalidCollateralState(InvalidCollateralStates.AUCTION_ACTIVE);

243:         address(s.CONDUIT),

274:   ) external onlyOwner(collateralId) {

278:     (addr, tokenId) = getUnderlying(collateralId);

311:     ) {

336:     CollateralStorage storage s = _loadCollateralSlot();

541:   function _settleAuction(CollateralStorage storage s, uint256 collateralId)

576:         s.clearingHouse[collateralId] = clearingHouse;

581:         tokenId_

Link to code

File: src/LienToken.sol

286:       auctionWindow,

294:     uint256 collateralId,

342:     auctionData.endAmount = uint88(1000 wei);

404:     newStack = _appendStack(s, params.stack, newStackSlot);

564:     if (!_exists(lienId)) {

920: 

Link to code

File: src/PublicVault.sol

235:     override(ERC4626Cloned)

312:       uint256 proxySupply = currentWithdrawProxy.totalSupply();

325:             .safeCastTo88();

376:         withdrawBalance = s.withdrawReserve;

385:       WithdrawProxy(currentWithdrawProxy).increaseWithdrawReserveReceived(

413:   function _beforeCommitToLien(IAstariaRouter.Commitment calldata params)

444:     VaultData storage s = _loadStorageSlot();

619:     VaultData storage s = _loadStorageSlot();

Link to code

File: src/VaultImplementation.sol

213:     s.delegate = delegate_;

281:    * Origination consists of a few phases: pre-commitment validation, lien token issuance, strategist reward, and after commitment actions

411: 

Link to code

File: src/WithdrawProxy.sol

289:   function drain(uint256 amount, address withdrawProxy)

Link to code

[GAS-2] Using bools for storage incurs overhead

Use uint256(1) and uint256(2) for true/false to avoid a Gwarmaccess (100 gas), and to avoid Gsset (20000 gas) when changing from ‘false’ to ‘true’, after having been ‘true’ in the past. See source.

Instances (4):

File: lib/gpl/src/ERC721.sol

23:     mapping(address => mapping(address => bool)) isApprovedForAll;

Link to code

File: src/interfaces/IAstariaRouter.sol

84:     mapping(address => bool) vaults;

Link to code

File: src/interfaces/ICollateralToken.sol

60:     mapping(address => bool) flashEnabled;

Link to code

File: src/interfaces/IVaultImplementation.sol

49:     mapping(address => bool) allowList;

Link to code

[GAS-3] Cache array length outside of loop

If not cached, the solidity compiler will always read the length of the array during each iteration. That is, if it is a storage array, this is an extra sload operation (100 additional extra gas for each iteration except for the first) and if it is a memory array, this is an extra mload operation (3 additional gas for each iteration except for the first).

Instances (12):

File: src/AstariaRouter.sol

265:     for (; i < files.length; ) {

364:     for (; i < file.length; ) {

506:     for (; i < commitments.length; ) {

Link to code

File: src/ClearingHouse.sol

96:     for (uint256 i; i < accounts.length; ) {

Link to code

File: src/CollateralToken.sol

198:     for (; i < files.length; ) {

Link to code

File: src/LienToken.sol

153:     for (uint256 i = params.encumber.stack.length; i > 0; ) {

304:     for (; i < stack.length; ) {

472:     for (uint256 i = stack.length; i > 0; ) {

520:     for (; i < stack.length;) {

669:     for (uint256 i; i < newStack.length; ) {

734:     for (; i < stack.length; ) {

Link to code

File: src/VaultImplementation.sol

201:       for (; i < params.allowList.length; ) {

Link to code

[GAS-4] Use calldata instead of memory for function arguments that do not get mutated

Mark data types as calldata instead of memory where possible. This makes it so that the data is not automatically loaded into memory. If the data passed into the function does not need to be changed (like updating values in an array), it can be passed in as calldata. The one exception to this is if the argument must later be passed into another function that takes an argument that specifies memory storage.

Instances (21):

File: src/AstariaRouter.sol

510:       uint256 payout;

629:     RouterStorage storage s = _loadRouterSlot();

638:     emit Liquidation(stack[position].lien.collateralId, position);

Link to code

File: src/ClearingHouse.sol

211:     address tokenContract,

Link to code

File: src/CollateralToken.sol

124:       s.collateralIdToAuction[collateralId] != keccak256(abi.encode(params))

Link to code

File: src/LienToken.sol

406:       abi.encode(newStack)

520:     for (; i < stack.length;) {

582:     return _getBuyout(_loadLienStorageSlot(), stack);

718:   ) internal pure returns (uint256 maxPotentialDebt) {

727:   function getMaxPotentialDebtForCollateral(Stack[] memory stack, uint256 end)

749:     view

761:   function _getOwed(Stack memory stack, uint256 timestamp)

766:     return stack.point.amount + _getInterest(stack, timestamp).safeCastTo88();

Link to code

File: src/interfaces/IAstariaRouter.sol

199:   function LIEN_TOKEN() external view returns (ILienToken);

Link to code

File: src/interfaces/ICollateralToken.sol

186:   error FlashActionNFTNotReturned();

Link to code

File: src/interfaces/ILienToken.sol

200:    * @notice Called by the ClearingHouse (through Seaport) to pay back debt with auction funds.

212:    * @notice Make a payment for the debt against a CollateralToken.

227:   ) external returns (Stack[] memory newStack);

245:    * @notice Retrieves the AuctionData for a CollateralToken (The liquidator address and the AuctionStack).

282:    * @notice Retrieve the payee (address that receives payments and auction funds) for a specified Lien.

292:   function file(File calldata file) external;

Link to code

[GAS-5] Use Custom Errors

Source Instead of using error strings, to reduce deployment and runtime cost, you should use Custom Errors. This would save both deployment and runtime cost.

Instances (15):

File: lib/gpl/src/ERC4626-Cloned.sol

25:     require((shares = previewDeposit(assets)) != 0, "ZERO_SHARES");

27:     require(shares > minDepositAmount(), "VALUE_TOO_SMALL");

43:     require(assets > minDepositAmount(), "VALUE_TOO_SMALL");

94:     require((assets = previewRedeem(shares)) != 0, "ZERO_ASSETS");

Link to code

File: lib/gpl/src/ERC721.sol

60:     require(owner != address(0), "ZERO_ADDRESS");

113:     require(from == s._ownerOf[id], "WRONG_FROM");

115:     require(to != address(0), "INVALID_RECIPIENT");

200:     require(to != address(0), "INVALID_RECIPIENT");

202:     require(s._ownerOf[id] == address(0), "ALREADY_MINTED");

219:     require(owner != address(0), "NOT_MINTED");

Link to code

File: src/AstariaRouter.sol

398:       revert("unsupported/impl");

Link to code

File: src/ClearingHouse.sol

134:     require(payment >= currentOfferPrice, "not enough funds received");

Link to code

File: src/PublicVault.sol

170:     require((assets = previewRedeem(shares)) != 0, "ZERO_ASSETS");

Link to code

File: src/WithdrawProxy.sol

138:     require(msg.sender == VAULT(), "only vault can mint");

231:     require(msg.sender == VAULT(), "only vault can call");

Link to code

[GAS-6] Don't initialize variables with default value

Instances (3):

File: src/LienToken.sol

152:     uint256 potentialDebt = 0;

636:     uint256 remaining = 0;

Link to code

File: src/WithdrawProxy.sol

254:     uint256 transferAmount = 0;

Link to code

[GAS-7] Functions guaranteed to revert when called by normal users can be marked payable

If a function modifier such as onlyOwner is used, the function will revert if a normal user tries to pay the function. Marking the function as payable will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided.

Instances (4):

File: src/PublicVault.sol

534:   function decreaseEpochLienCount(uint64 epoch) public onlyLienToken {

562:   function afterPayment(uint256 computedSlope) public onlyLienToken {

Link to code

File: src/WithdrawProxy.sol

235:   function increaseWithdrawReserveReceived(uint256 amount) external onlyVault {

302:   function setWithdrawRatio(uint256 liquidationWithdrawRatio) public onlyVault {

Link to code

[GAS-8] ++i costs less gas than i++, especially when it's used in for-loops (--i/i-- too)

Saves 5 gas per loop

Instances (5):

File: lib/gpl/src/ERC721.sol

138:       s._balanceOf[to]++;

206:       s._balanceOf[to]++;

Link to code

File: src/PublicVault.sol

341:       s.currentEpoch++;

558:       s.epochData[epoch].liensOpenForEpoch++;

Link to code

File: src/VaultImplementation.sol

69:     s.strategistNonce++;

Link to code

[GAS-9] Using private rather than public for constants, saves gas

If needed, the values can be read from the verified contract source code, or if there are multiple values there can be a single getter function that returns a tuple of the values of all currently-public constants. Saves 3406-3606 gas in deployment gas due to the compiler not having to create non-payable getter functions for deployment calldata, not having to store the bytes of the value outside of where it's used, and not adding another entry to the method ID table

Instances (1):

File: src/VaultImplementation.sol

44:   bytes32 public constant STRATEGY_TYPEHASH =

Link to code

[GAS-10] Use != 0 instead of > 0 for unsigned integer comparison

Instances (17):

File: lib/gpl/src/ERC4626-Cloned.sol

2: pragma solidity >=0.8.16;

Link to code

File: lib/gpl/src/interfaces/IMulticall.sol

4: pragma solidity >=0.7.5;

Link to code

File: lib/gpl/src/interfaces/IUniswapV3Factory.sol

2: pragma solidity >=0.5.0;

Link to code

File: lib/gpl/src/interfaces/IUniswapV3PoolState.sol

2: pragma solidity >=0.5.0;

Link to code

File: src/AstariaRouter.sol

476:     if (timeToSecondEpochEnd > 0 && details.duration > timeToSecondEpochEnd) {

Link to code

File: src/ClearingHouse.sol

160:     if (ERC20(paymentToken).balanceOf(address(this)) > 0) {

Link to code

File: src/LienToken.sol

153:     for (uint256 i = params.encumber.stack.length; i > 0; ) {

438:     if (params.stack.length > 0) {

472:     for (uint256 i = stack.length; i > 0; ) {

491:       stack.length > 0 && potentialDebt > newSlot.lien.details.maxPotentialDebt

642:     if (payment > 0)

Link to code

File: src/PublicVault.sol

277:     if (timeToEpochEnd() > 0) {

282:     if (s.withdrawReserve > 0) {

303:     if (s.epochData[s.currentEpoch].liensOpenForEpoch > 0) {

393:       s.withdrawReserve > 0 &&

636:     if (params.remaining > 0)

Link to code

File: src/WithdrawProxy.sol

280:       if (balance > 0) {

Link to code

[GAS-11] internal functions not called by the contract should be removed

If the functions are required by an interface, the contract should inherit from that interface and use the override keyword

Instances (1):

File: lib/gpl/src/ERC721.sol

69:   function __initERC721(string memory _name, string memory _symbol) internal {

Link to code

Non Critical Issues

Issue Instances
NC-1 require() / revert() statements should have descriptive reason strings 32
NC-2 Return values of approve() not checked 1
NC-3 Event is missing indexed fields 30
NC-4 Constants should be defined rather than using magic numbers 19
NC-5 Functions not used internally could be marked external 83

[NC-1] require() / revert() statements should have descriptive reason strings

Instances (32):

File: src/AstariaRouter.sol

360:     RouterStorage storage s = _loadRouterSlot();

365:       FileType what = file[i].what;

369:         if (addr == address(0)) revert InvalidFileData();

373:         if (addr == address(0)) revert InvalidFileData();

579:     address receiver

587:       uint256

Link to code

File: src/ClearingHouse.sol

93:     returns (uint256[] memory output)

215:     IAstariaRouter ASTARIA_ROUTER = IAstariaRouter(_getArgAddress(0));

230:     );

233: 

Link to code

File: src/CollateralToken.sol

285:       s.LIEN_TOKEN.getCollateralState(collateralId) == bytes32("ACTIVE_AUCTION")

553:   function onERC721Received(

578:       ERC721(msg.sender).safeTransferFrom(

Link to code

File: src/LienToken.sol

523:         spent = _paymentAH(s, token, stack, i, payment, payer);

884:     internal

Link to code

File: src/PublicVault.sol

262:     uint256 assets = totalAssets();

280:     VaultData storage s = _loadStorageSlot();

526:     _handleStrategistInterestReward(s, params.interestOwed, params.amount);

691:     _setYIntercept(s, s.yIntercept - amount);

696:     emit YInterceptChanged(s.yIntercept);

703:   function timeToEpochEnd(uint256 epoch) public view returns (uint256) {

Link to code

File: src/Vault.sol

80:   function enableAllowList() external pure override(VaultImplementation) {

85:   function modifyAllowList(address, bool)

Link to code

File: src/VaultImplementation.sol

96:     require(msg.sender == owner()); //owner is "strategist"

114:     require(msg.sender == owner()); //owner is "strategist"

124:     address, // from_

133:       revert InvalidRequest(InvalidRequestReason.PAUSED);

168:    * @param amount The amount of the token

211:     require(msg.sender == owner()); //owner is "strategist"

222:    * if a user, then ensure that the user is approved to borrow and is also receiving the funds.

282:    * Starts by depositing collateral and take optimized-out a lien against it. Next, verifies the merkle proof for a loan commitment. Vault owners are then rewarded fees for successful loan origination.

344:               commitment: incomingTerms,

Link to code

[NC-2] Return values of approve() not checked

Not all IERC20 implementations revert() when there's a failure in approve(). The function signature has a boolean return value and they indicate errors that way instead. By not checking the return value, operations that should have marked as failed, may potentially go through without actually approving anything

Instances (1):

File: src/ClearingHouse.sol

203:     ERC721(order.parameters.offer[0].token).approve(

Link to code

[NC-3] Event is missing indexed fields

Index event fields make the field more quickly accessible to off-chain tools that parse events. However, note that each index field costs extra gas during emission, so it's not necessarily best to index the maximum allowed per event (three fields). Each event should use three indexed fields if there are three or more fields, and gas usage is not particularly of concern for the events in question. If there are fewer than three fields, all of the fields should be indexed.

Instances (30):

File: src/PublicVault.sol

477:    * @return The implied value for this PublicVault.

Link to code

File: src/WithdrawProxy.sol

54:     uint88 expected; // The sum of the remaining debt (amountOwed) accrued against the NFT at the timestamp when it is liquidated. yIntercept (virtual assets) of a PublicVault are not modified on liquidation, only once an auction is completed.

Link to code

File: src/interfaces/IAstariaRouter.sol

72:     address BEACON_PROXY_IMPLEMENTATION; //20

310:   error InvalidCollateralState(CollateralStates);

312:   error InvalidStrategy(uint16);

Link to code

File: src/interfaces/ICollateralToken.sol

54:     IAstariaRouter ASTARIA_ROUTER;

55:     ConsiderationInterface SEAPORT;

60:     mapping(address => bool) flashEnabled;

Link to code

File: src/interfaces/IERC1155.sol

42:   event ApprovalForAll(

55:   event URI(string value, uint256 indexed id);

Link to code

File: src/interfaces/IERC4626.sol

15:   event Deposit(

Link to code

File: src/interfaces/IERC721.sol

14:   event ApprovalForAll(

Link to code

File: src/interfaces/ILienToken.sol

55:     uint256 duration;

315:   event PayeeChanged(uint256 indexed lienId, address indexed payee);

320:   error InvalidTerms();

328:     NOT_ENOUGH_FUNDS,

330:     COLLATERAL_AUCTION,

Link to code

File: src/interfaces/IPublicVault.sol

174: 

174: 

174: 

174: 

174: 

Link to code

File: src/interfaces/IV3PositionManager.sol

10:   event IncreaseLiquidity(

21:   event DecreaseLiquidity(

33:   event Collect(

Link to code

File: src/interfaces/IVaultImplementation.sol

78:       uint256 payout

81:   function buyoutLien(

82:     ILienToken.Stack[] calldata stack,

84:     IAstariaRouter.Commitment calldata incomingTerms

84:     IAstariaRouter.Commitment calldata incomingTerms

Link to code

[NC-4] Constants should be defined rather than using magic numbers

Instances (19):

File: src/AstariaRouter.sol

110:     s.liquidationFeeNumerator = uint32(130);

112:     s.minInterestBPS = uint32((uint256(1e15) * 5) / (365 days));

114:     s.maxEpochLength = uint32(45 days);

115:     s.maxInterestRate = ((uint256(1e16) * 200) / (365 days)).safeCastTo88();

Link to code

File: src/AstariaVaultBase.sol

33:     return _getArgUint8(20); //ends at 21

37:     return _getArgAddress(21); //ends at 44

47:     return _getArgAddress(41); //ends at 64

51:     return _getArgUint256(61);

55:     return _getArgUint256(93); //ends at 116

59:     return _getArgUint256(125);

Link to code

File: src/BeaconProxy.sol

62:     _delegate(_getBeacon().getImpl(_getArgUint8(20)));

Link to code

File: src/ClearingHouse.sol

48:     return _getArgUint256(21);

52:     return _getArgUint8(20);

136:     uint256 collateralId = _getArgUint256(21);

Link to code

File: src/PublicVault.sol

103:     if (ERC20(asset()).decimals() == uint8(18)) {

Link to code

File: src/WithdrawVaultBase.sol

31:     return _getArgUint8(20);

35:     return _getArgAddress(21);

39:     return _getArgAddress(41);

43:     return _getArgUint64(61);

Link to code

[NC-5] Functions not used internally could be marked external

Instances (83):

File: lib/gpl/src/ERC4626Router.sol

35:   function depositMax(

49:   function redeemMax(

Link to code

File: lib/gpl/src/ERC721.sol

26:   function getApproved(uint256 tokenId) public view returns (address) {

30:   function isApprovedForAll(address owner, address operator)

79:   function name() public view returns (string memory) {

83:   function symbol() public view returns (string memory) {

Link to code

File: src/AstariaRouter.sol

225:     RouterStorage storage s = _loadRouterSlot();

240:     RouterStorage storage s = _loadRouterSlot();

245:     RouterStorage storage s = _loadRouterSlot();

251:    */

257:    * @dev Disables _pause, un-freezing functions with the whenNotPaused modifier.

263:   function fileBatch(File[] calldata files) external requiresAuth {

288:     } else if (what == FileType.LiquidationFee) {

422:       x := mload(add(bs, end))

439:     if (block.timestamp > commitment.lienRequest.strategy.deadline) {

508:         commitments[i].lienRequest.stack = stack;

561:         IPublicVault.InvalidStates.EPOCH_TOO_HIGH

638:     emit Liquidation(stack[position].lien.collateralId, position);

698:         newLien.details.duration + block.timestamp >=

Link to code

File: src/AstariaVaultBase.sol

55:     return _getArgUint256(93); //ends at 116

59:     return _getArgUint256(125);

66: 

66: 

66: 

66: 

Link to code

File: src/ClearingHouse.sol

66:   function setAuctionData(ILienToken.AuctionData calldata auctionData)

72:     require(msg.sender == address(ASTARIA_ROUTER.LIEN_TOKEN()));

191:     uint256 tokenId_,

199:     require(msg.sender == address(ASTARIA_ROUTER.COLLATERAL_TOKEN()));

Link to code

File: src/CollateralToken.sol

93:     bytes32 CONDUIT_KEY = Bytes32AddressLib.fillLast12Bytes(address(this));

119:     ) {

210:   function _file(File calldata incoming) internal {

219:       (address target, address hook) = abi.decode(data, (address, address));

346:   }

385:   function getUnderlying(uint256 collateralId)

390:     Asset memory underlying = _loadCollateralSlot().idToUnderlying[

431:   ) internal returns (OrderParameters memory orderParameters) {

537:     delete s.idToUnderlying[collateralId];

Link to code

File: src/LienToken.sol

82:   function file(File calldata incoming) external requiresAuth {

113:       revert InvalidState(InvalidStates.EXPIRED_LIEN);

262:     return (delta_t * stack.lien.details.rate).mulWadDown(stack.point.amount);

370:       revert InvalidState(InvalidStates.COLLATERAL_AUCTION);

377:   function ASTARIA_ROUTER() public view returns (IAstariaRouter) {

392:     validateStack(params.lien.collateralId, params.stack)

399:     LienStorage storage s = _loadLienStorageSlot();

569:   function getCollateralState(uint256 collateralId)

599:     uint256 amount

619:     (newStack, ) = _payment(s, stack, position, amount, msg.sender);

721:       unchecked {

747:   function getOwed(Stack memory stack, uint256 timestamp)

914:     address newPayee

Link to code

File: src/PublicVault.sol

208:   function getLiquidationWithdrawRatio() public view returns (uint256) {

212:   function getYIntercept() public view returns (uint256) {

216:   function _deployWithdrawProxyIfNotDeployed(VaultData storage s, uint64 epoch)

219:     if (s.epochData[epoch].withdrawProxy == address(0)) {

221:         IAstariaRouter(ROUTER()).BEACON_PROXY_IMPLEMENTATION(),

224:           uint8(IAstariaRouter.ImplementationType.WithdrawProxy),

252:     public

272:     return super.domainSeparator();

363:       return;

477:    * @return The implied value for this PublicVault.

549:         .safeCastTo64();

571:    * @notice After-deposit hook to update the yIntercept of the PublicVault to reflect a capital contribution.

575:   function afterDeposit(uint256 assets, uint256 shares)

632:   function updateAfterLiquidationPayment(

657:     uint256 timeToEnd = timeToEpochEnd(lienEpoch);

686:     uint64 currentEpoch = s.currentEpoch;

699:   function timeToEpochEnd() public view returns (uint256) {

726: 

Link to code

File: src/WithdrawProxy.sol

103:   function name()

114:    * @notice Public view function to return the symbol of this WithdrawProxy.

124:       string(abi.encodePacked("AST-W", VAULT(), "-", ERC20(asset()).symbol()));

135:     override(ERC4626Cloned, IERC4626)

235:   function increaseWithdrawReserveReceived(uint256 amount) external onlyVault {

240:   function claim() public {

244:       revert InvalidState(InvalidStates.CANT_CLAIM);

256:       s.withdrawReserveReceived; // will never underflow because withdrawReserveReceived is always increased by the transfer amount from the PublicVault

307:     uint256 newLienExpectedValue,

315:       if (auctionEnd > s.finalAuctionEnd) s.finalAuctionEnd = auctionEnd;

319: 

Link to code

File: src/WithdrawVaultBase.sol

46: 

46: 

46: 

Link to code

Low Issues

Issue Instances
L-1 Do not use deprecated library functions 6
L-2 Unsafe ERC20 operation(s) 2
L-3 Unspecific compiler version pragma 4

[L-1] Do not use deprecated library functions

Instances (6):

File: lib/gpl/src/ERC4626RouterBase.sol

21:     ERC20(vault.asset()).safeApprove(address(vault), shares);

34:     ERC20(vault.asset()).safeApprove(address(vault), amount);

48:     ERC20(address(vault)).safeApprove(address(vault), amount);

62:     ERC20(address(vault)).safeApprove(address(vault), shares);

Link to code

File: src/ClearingHouse.sol

148:     ERC20(paymentToken).safeApprove(

Link to code

File: src/VaultImplementation.sol

334:     ERC20(asset()).safeApprove(address(ROUTER().TRANSFER_PROXY()), buyout);

Link to code

[L-2] Unsafe ERC20 operation(s)

Instances (2):

File: src/ClearingHouse.sol

203:     ERC721(order.parameters.offer[0].token).approve(

Link to code

File: src/LienToken.sol

374:     super.transferFrom(from, to, id);

Link to code

[L-3] Unspecific compiler version pragma

Instances (4):

File: lib/gpl/src/ERC4626-Cloned.sol

2: pragma solidity >=0.8.16;

Link to code

File: lib/gpl/src/interfaces/IMulticall.sol

4: pragma solidity >=0.7.5;

Link to code

File: lib/gpl/src/interfaces/IUniswapV3Factory.sol

2: pragma solidity >=0.5.0;

Link to code

File: lib/gpl/src/interfaces/IUniswapV3PoolState.sol

2: pragma solidity >=0.5.0;

Link to code

Medium Issues

Issue Instances
M-1 Centralization Risk for trusted owners 16

[M-1] Centralization Risk for trusted owners

Impact:

Contracts have owners with privileged rights to perform admin tasks and need to be trusted to not perform malicious updates or drain funds.

Instances (16):

File: src/AstariaRouter.sol

94:     __initAuth(msg.sender, address(_AUTHORITY));

252:   function __emergencyPause() external requiresAuth whenNotPaused {

259:   function __emergencyUnpause() external requiresAuth whenPaused {

263:   function fileBatch(File[] calldata files) external requiresAuth {

273:   function file(File calldata incoming) public requiresAuth {

Link to code

File: src/CollateralToken.sol

86:     __initAuth(msg.sender, address(AUTHORITY_));

196:   function fileBatch(File[] calldata files) external requiresAuth {

206:   function file(File calldata incoming) public requiresAuth {

Link to code

File: src/LienToken.sol

18: import {Auth, Authority} from "solmate/auth/Auth.sol";

63:     __initAuth(msg.sender, address(_AUTHORITY));

82:   function file(File calldata incoming) external requiresAuth {

282:   ) external validateStack(collateralId, stack) requiresAuth {

Link to code

File: src/TransferProxy.sol

16: import {Auth, Authority} from "solmate/auth/Auth.sol";

21: contract TransferProxy is Auth, ITransferProxy {

24:   constructor(Authority _AUTHORITY) Auth(msg.sender, _AUTHORITY) {

33:   ) external requiresAuth {

Link to code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment