diff --git a/src/BondDepository.sol b/src/BondDepository.sol index 3b108d0..2ff0b3d 100644 --- a/src/BondDepository.sol +++ b/src/BondDepository.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import "@openzeppelin-contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; -import "@openzeppelin-contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {IERC20} from "@openzeppelin-contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20Metadata} from "@openzeppelin-contracts/token/ERC20/extensions/IERC20Metadata.sol"; -import "./types/NoteKeeper.sol"; -import "./interfaces/IBondDepository.sol"; +import {NoteKeeper} from "./types/NoteKeeper.sol"; +import {IBondDepository} from "./interfaces/IBondDepository.sol"; contract GhostBondDepository is IBondDepository, NoteKeeper { using SafeERC20 for IERC20; @@ -59,12 +59,12 @@ contract GhostBondDepository is IBondDepository, NoteKeeper { market.capacity -= market.capacityInQuote ? amount : payout; market.purchased += amount; - market.sold += uint64(payout); - market.totalDebt += uint64(payout); + market.sold += uint64(payout); // forge-lint: disable-line(unsafe-typecast) + market.totalDebt += uint64(payout); // forge-lint: disable-line(unsafe-typecast) emit Bond(id, amount, price); - index = addNote(user, payout, uint48(expiry), uint48(id), referral); + index = addNote(user, payout, uint48(expiry), uint48(id), referral); // forge-lint: disable-line(unsafe-typecast) IERC20(market.quoteToken).safeTransferFrom(msg.sender, address(_treasury), amount); if (term.maxDebt < market.totalDebt) { @@ -108,8 +108,10 @@ contract GhostBondDepository is IBondDepository, NoteKeeper { ? ((market.capacity * 1e18) / price) / (10**meta.quoteDecimals) : market.capacity; + // forge-lint: disable-next-line(unsafe-typecast) markets[id].maxPayout = uint64((capacity * meta.depositInterval) / timeRemaining); uint256 targetDebt = (capacity * meta.length) / timeRemaining; + // forge-lint: disable-next-line(unsafe-typecast) uint64 newControlVariable = uint64((price * _treasury.baseSupply()) / targetDebt); emit Tuned(id, terms[id].controlVariable, newControlVariable); @@ -118,7 +120,12 @@ contract GhostBondDepository is IBondDepository, NoteKeeper { terms[id].controlVariable = newControlVariable; } else { uint64 change = terms[id].controlVariable - newControlVariable; - adjustments[id] = Adjustment(change, time, meta.tuneInterval, true); + adjustments[id] = Adjustment({ + change: change, + lastAdjustment: time, + timeToAdjusted: meta.tuneInterval, + active: true + }); } metadatas[id].lastTune = time; } @@ -141,6 +148,8 @@ contract GhostBondDepository is IBondDepository, NoteKeeper { uint64 targetDebt = uint64(_booleans[0] ? ((_market[0] * 1e18) / _market[1]) / 10**decimals : _market[0]); + + // forge-lint: disable-next-line(unsafe-typecast) uint64 maxPayout = uint64((targetDebt * _intervals[0]) / secondsToConclusion); uint256 maxDebt = targetDebt + ((targetDebt * _market[2]) / 1e5); uint256 controlVariable = (_market[1] * _treasury.baseSupply()) / targetDebt; @@ -162,10 +171,10 @@ contract GhostBondDepository is IBondDepository, NoteKeeper { terms.push( Term({ fixedTerm: _booleans[1], - controlVariable: uint64(controlVariable), - vesting: uint48(_terms[0]), - conclusion: uint48(_terms[1]), - maxDebt: uint64(maxDebt) + controlVariable: uint64(controlVariable), // forge-lint: disable-line(unsafe-typecast) + vesting: uint48(_terms[0]), // forge-lint: disable-line(unsafe-typecast) + conclusion: uint48(_terms[1]), // forge-lint: disable-line(unsafe-typecast) + maxDebt: uint64(maxDebt) // forge-lint: disable-line(unsafe-typecast) }) ); @@ -173,9 +182,11 @@ contract GhostBondDepository is IBondDepository, NoteKeeper { Metadata({ lastTune: uint48(block.timestamp), lastDecay: uint48(block.timestamp), + // forge-lint: disable-next-line(unsafe-typecast) length: uint48(secondsToConclusion), depositInterval: _intervals[0], tuneInterval: _intervals[1], + // forge-lint: disable-next-line(unsafe-typecast) quoteDecimals: uint8(decimals) }) ); diff --git a/src/FatsoERC20.sol b/src/FatsoERC20.sol index d3d6743..ec6a2fd 100644 --- a/src/FatsoERC20.sol +++ b/src/FatsoERC20.sol @@ -1,10 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import "@openzeppelin-contracts/token/ERC20/extensions/ERC20Permit.sol"; +import {ERC20Permit} from "@openzeppelin-contracts/token/ERC20/extensions/ERC20Permit.sol"; +import {ERC20} from "@openzeppelin-contracts/token/ERC20/ERC20.sol"; -import "./interfaces/IFTSO.sol"; -import "./types/GhostAccessControlled.sol"; +import {IFTSO} from "./interfaces/IFTSO.sol"; +import {IGhostAuthority} from "./interfaces/IGhostAuthority.sol"; +import {GhostAccessControlled} from "./types/GhostAccessControlled.sol"; contract Fatso is ERC20Permit, IFTSO, GhostAccessControlled { constructor(address _authority, string memory name, string memory symbol) diff --git a/src/Gatekeeper.sol b/src/Gatekeeper.sol index da57cc8..e32fb63 100644 --- a/src/Gatekeeper.sol +++ b/src/Gatekeeper.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import "./interfaces/IGatekeeper.sol"; +import {IGatekeeper} from "./interfaces/IGatekeeper.sol"; contract Gatekeeper is IGatekeeper { uint256 public override ghostedSupply; - address public immutable staking; + address public immutable staking; // forge-lint: disable-line(screaming-snake-case-immutable) uint256 private _aggregatedPublicKey; mapping(uint256 => mapping(uint256 => bool)) private _executedTransaction; @@ -32,7 +32,16 @@ contract Gatekeeper is IGatekeeper { ) external override { if (msg.sender != staking) revert NotStaking(); _checkTransactionExistence(rx, s); - bytes32 message = keccak256(abi.encodePacked("materialize", receiver, amount)); + + bytes4 selector = bytes4(keccak256("materialize(address,uint256)")); + bytes32 message; + assembly { + let ptr := mload(0x40) + mstore(ptr, selector) + mstore(add(ptr, 4), receiver) + mstore(add(ptr, 36), amount) + message := keccak256(ptr, 68) + } if (_incorrectSignature(rx, s, message)) revert WrongSignature(); ghostedSupply -= amount; @@ -45,7 +54,15 @@ contract Gatekeeper is IGatekeeper { uint256 s ) external override { _checkTransactionExistence(rx, s); - bytes32 message = keccak256(abi.encodePacked("rotate", aggregatedPublicKey)); + + bytes4 selector = bytes4(keccak256("rotate(uint256)")); + bytes32 message; + assembly { + let ptr := mload(0x40) + mstore(ptr, selector) + mstore(add(ptr, 4), aggregatedPublicKey) + message := keccak256(ptr, 36) + } if (_incorrectSignature(rx, s, message)) revert WrongSignature(); _aggregatedPublicKey = aggregatedPublicKey; diff --git a/src/GhostAuthority.sol b/src/GhostAuthority.sol index 500beba..8263e39 100644 --- a/src/GhostAuthority.sol +++ b/src/GhostAuthority.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import "./interfaces/IGhostAuthority.sol"; -import "./types/GhostAccessControlled.sol"; +import {IGhostAuthority} from "./interfaces/IGhostAuthority.sol"; +import {GhostAccessControlled} from "./types/GhostAccessControlled.sol"; contract GhostAuthority is IGhostAuthority, GhostAccessControlled { address public override governor; diff --git a/src/GhstERC20.sol b/src/GhstERC20.sol index 2b922ba..e1a5720 100644 --- a/src/GhstERC20.sol +++ b/src/GhstERC20.sol @@ -1,12 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import "@openzeppelin-contracts/token/ERC20/ERC20.sol"; -import "@openzeppelin-contracts/token/ERC20/extensions/ERC20Permit.sol"; -import "@openzeppelin-contracts/token/ERC20/extensions/ERC20Votes.sol"; +import {ERC20} from "@openzeppelin-contracts/token/ERC20/ERC20.sol"; +import {ERC20Permit} from "@openzeppelin-contracts/token/ERC20/extensions/ERC20Permit.sol"; +import {ERC20Votes} from "@openzeppelin-contracts/token/ERC20/extensions/ERC20Votes.sol"; +import {Nonces} from "@openzeppelin-contracts/utils/Nonces.sol"; -import "./interfaces/ISTNK.sol"; -import "./interfaces/IGHST.sol"; +import {ISTNK} from "./interfaces/ISTNK.sol"; +import {IGHST} from "./interfaces/IGHST.sol"; contract Ghost is IGHST, ERC20, ERC20Permit, ERC20Votes { address public override staking; diff --git a/src/Staking.sol b/src/Staking.sol index 4a1ff69..90e5ecd 100644 --- a/src/Staking.sol +++ b/src/Staking.sol @@ -1,25 +1,26 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; -import "@openzeppelin-contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "@openzeppelin-contracts/token/ERC20/IERC20.sol"; -import "./types/GhostAccessControlled.sol"; +import {GhostAccessControlled} from "./types/GhostAccessControlled.sol"; -import "./interfaces/ISTNK.sol"; -import "./interfaces/IGHST.sol"; -import "./interfaces/IDistributor.sol"; -import "./interfaces/IStaking.sol"; -import "./interfaces/IGatekeeper.sol"; +import {ISTNK} from "./interfaces/ISTNK.sol"; +import {IGHST} from "./interfaces/IGHST.sol"; +import {IDistributor} from "./interfaces/IDistributor.sol"; +import {IStaking} from "./interfaces/IStaking.sol"; +import {IGatekeeper} from "./interfaces/IGatekeeper.sol"; +import {IGhostAuthority} from "./interfaces/IGhostAuthority.sol"; contract GhostStaking is IStaking, GhostAccessControlled { using SafeERC20 for IERC20; using SafeERC20 for ISTNK; using SafeERC20 for IGHST; - address public immutable ftso; - address public immutable stnk; - address public immutable ghst; + address public immutable ftso; // forge-lint: disable-line(screaming-snake-case-immutable) + address public immutable stnk; // forge-lint: disable-line(screaming-snake-case-immutable) + address public immutable ghst; // forge-lint: disable-line(screaming-snake-case-immutable) uint48 public warmupPeriod; @@ -180,6 +181,7 @@ contract GhostStaking is IStaking, GhostAccessControlled { } function setWarmupPeriod(uint256 _warmupPeriod) external onlyGovernor { + // forge-lint: disable-next-line(unsafe-typecast) warmupPeriod = uint48(_warmupPeriod); emit WarmupSet(_warmupPeriod); } diff --git a/src/StakingDistributor.sol b/src/StakingDistributor.sol index e36e09f..9157c2c 100644 --- a/src/StakingDistributor.sol +++ b/src/StakingDistributor.sol @@ -1,21 +1,21 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import "@openzeppelin-contracts/token/ERC20/IERC20.sol"; -import "@uniswap-v2-core/interfaces/IUniswapV2Pair.sol"; +import {IERC20} from "@openzeppelin-contracts/token/ERC20/IERC20.sol"; +import {IUniswapV2Pair} from "@uniswap-v2-core/interfaces/IUniswapV2Pair.sol"; -import "./types/GhostAccessControlled.sol"; +import {GhostAccessControlled} from "./types/GhostAccessControlled.sol"; -import "./interfaces/ITreasury.sol"; -import "./interfaces/IStaking.sol"; -import "./interfaces/IDistributor.sol"; +import {ITreasury} from "./interfaces/ITreasury.sol"; +import {IDistributor} from "./interfaces/IDistributor.sol"; +import {IGhostAuthority} from "./interfaces/IGhostAuthority.sol"; contract GhostDistributor is IDistributor, GhostAccessControlled { uint256 private constant DENOMINATOR = 1e6; - address private immutable ftso; - address private immutable treasury; - address private immutable staking; + address private immutable ftso; // forge-lint: disable-line(screaming-snake-case-immutable) + address private immutable treasury; // forge-lint: disable-line(screaming-snake-case-immutable) + address private immutable staking; // forge-lint: disable-line(screaming-snake-case-immutable) uint256 public rewardRate; uint256 public bounty; @@ -115,8 +115,8 @@ contract GhostDistributor is IDistributor, GhostAccessControlled { adjustment = Adjust({ add: add, - rate: uint120(rate), - target: uint120(target) + rate: uint120(rate), // forge-lint: disable-line(unsafe-typecast) + target: uint120(target) // forge-lint: disable-line(unsafe-typecast) }); } } diff --git a/src/StandardBondingCalculator.sol b/src/StandardBondingCalculator.sol index b83209b..7a1a1f8 100644 --- a/src/StandardBondingCalculator.sol +++ b/src/StandardBondingCalculator.sol @@ -1,23 +1,18 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import "./libraries/FixedPoint.sol"; +import {FixedPoint} from "./libraries/FixedPoint.sol"; -import "@openzeppelin-contracts/utils/Address.sol"; -import "@openzeppelin-contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; -import "@openzeppelin-contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {IERC20Metadata} from "@openzeppelin-contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {IUniswapV2Pair} from "@uniswap-v2-core/interfaces/IUniswapV2Pair.sol"; -import "@uniswap-v2-core/interfaces/IUniswapV2ERC20.sol"; -import "@uniswap-v2-core/interfaces/IUniswapV2Pair.sol"; - -import "./interfaces/IBondingCalculator.sol"; +import {IBondingCalculator} from "./interfaces/IBondingCalculator.sol"; contract GhostBondingCalculator is IBondingCalculator { using FixedPoint for *; - uint256 public override immutable fraction; - address internal immutable ftso; + uint256 public override immutable fraction; // forge-lint: disable-line(screaming-snake-case-immutable) + address internal immutable ftso; // forge-lint: disable-line(screaming-snake-case-immutable) constructor(address _ftso, uint256 _numerator, uint256 _denominator) { ftso = _ftso; diff --git a/src/StinkyERC20.sol b/src/StinkyERC20.sol index 49ba7a9..83bdb17 100644 --- a/src/StinkyERC20.sol +++ b/src/StinkyERC20.sol @@ -1,19 +1,20 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import "@openzeppelin-contracts/utils/Address.sol"; -import "@openzeppelin-contracts/token/ERC20/extensions/ERC20Permit.sol"; +import {ERC20Permit} from "@openzeppelin-contracts/token/ERC20/extensions/ERC20Permit.sol"; +import {ERC20} from "@openzeppelin-contracts/token/ERC20/ERC20.sol"; +import {IERC20} from "@openzeppelin-contracts/token/ERC20/IERC20.sol"; -import "./interfaces/IGHST.sol"; -import "./interfaces/ISTNK.sol"; -import "./interfaces/IStaking.sol"; +import {IGHST} from "./interfaces/IGHST.sol"; +import {ISTNK} from "./interfaces/ISTNK.sol"; +import {IStaking} from "./interfaces/IStaking.sol"; contract Stinky is ISTNK, ERC20Permit { uint256 private constant INITIAL_SHARES_SUPPLY = 5 * 10**15; uint256 private constant TOTAL_SHARES = type(uint256).max - (type(uint256).max % INITIAL_SHARES_SUPPLY); uint256 private constant MAX_SUPPLY = type(uint128).max; - uint256 internal immutable _internalIndex; + uint256 internal immutable _INTERNAL_INDEX; address internal _initializer; uint256 private _sharesPerUnit; @@ -32,7 +33,7 @@ contract Stinky is ISTNK, ERC20Permit { ERC20Permit(name) { _initializer = msg.sender; - _internalIndex = usedIndex; + _INTERNAL_INDEX = usedIndex; _totalSupply = INITIAL_SHARES_SUPPLY; _sharesPerUnit = TOTAL_SHARES / INITIAL_SHARES_SUPPLY; } @@ -174,7 +175,7 @@ contract Stinky is ISTNK, ERC20Permit { } function index() public view override returns (uint256) { - return balanceForShares(_internalIndex); + return balanceForShares(_INTERNAL_INDEX); } function changeDebt( diff --git a/src/Treasury.sol b/src/Treasury.sol index b6b536d..4e88db3 100644 --- a/src/Treasury.sol +++ b/src/Treasury.sol @@ -1,28 +1,29 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import "@openzeppelin-contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin-contracts/token/ERC20/extensions/IERC20Metadata.sol"; -import "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "@openzeppelin-contracts/token/ERC20/IERC20.sol"; +import {IERC20Metadata} from "@openzeppelin-contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {SafeERC20} from "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; -import "@uniswap-v2-core-1.0.1/interfaces/IUniswapV2Factory.sol"; -import "@uniswap-v2-core-1.0.1/interfaces/IUniswapV2Pair.sol"; -import "@uniswap-v2-periphery-1.1.0-beta.0/interfaces/IUniswapV2Router02.sol"; -import "@uniswap-v2-periphery-1.1.0-beta.0/interfaces/IUniswapV2Router01.sol"; +import {IUniswapV2Factory} from "@uniswap-v2-core-1.0.1/interfaces/IUniswapV2Factory.sol"; +import {IUniswapV2Pair} from "@uniswap-v2-core-1.0.1/interfaces/IUniswapV2Pair.sol"; +import {IUniswapV2Router02} from "@uniswap-v2-periphery-1.1.0-beta.0/interfaces/IUniswapV2Router02.sol"; +import {IUniswapV2Router01} from "@uniswap-v2-periphery-1.1.0-beta.0/interfaces/IUniswapV2Router01.sol"; -import "./types/GhostAccessControlled.sol"; -import "./libraries/FixedPoint.sol"; +import {GhostAccessControlled} from "./types/GhostAccessControlled.sol"; +import {Babylonian} from "./libraries/FixedPoint.sol"; -import "./interfaces/IFTSO.sol"; -import "./interfaces/ISTNK.sol"; -import "./interfaces/IBondingCalculator.sol"; -import "./interfaces/ITreasury.sol"; +import {IFTSO} from "./interfaces/IFTSO.sol"; +import {ISTNK} from "./interfaces/ISTNK.sol"; +import {IBondingCalculator} from "./interfaces/IBondingCalculator.sol"; +import {ITreasury} from "./interfaces/ITreasury.sol"; +import {IGhostAuthority} from "./interfaces/IGhostAuthority.sol"; contract GhostTreasury is GhostAccessControlled, ITreasury { using SafeERC20 for IERC20; - address public immutable ftso; - uint256 public immutable blocksNeededForQueue; + address public immutable ftso; // forge-lint: disable-line(screaming-snake-case-immutable) + uint256 public immutable blocksNeededForQueue; // forge-lint: disable-line(screaming-snake-case-immutable) uint256 public totalReserves; uint256 public totalDebt; @@ -234,7 +235,7 @@ contract GhostTreasury is GhostAccessControlled, ITreasury { address weth = IUniswapV2Router01(router).WETH(); address pair = IUniswapV2Factory(IUniswapV2Router01(router).factory()).getPair(ftso, weth); - IUniswapV2Pair(pair).transfer(pair, liquidity); + IERC20(pair).safeTransfer(pair, liquidity); (uint256 amount0, uint256 amount1) = IUniswapV2Pair(pair).burn(address(this)); if (destroyerMode) { @@ -286,8 +287,8 @@ contract GhostTreasury is GhostAccessControlled, ITreasury { amountIn = amount - amountIn; - IERC20(weth).transfer(pair, amountIn); - IERC20(ftso).transfer(pair, amounts[1]); + IERC20(weth).safeTransfer(pair, amountIn); + IERC20(ftso).safeTransfer(pair, amounts[1]); IUniswapV2Pair(pair).mint(address(this)); } diff --git a/src/TreasuryExtender.sol b/src/TreasuryExtender.sol index c5850f3..cb1f2d9 100644 --- a/src/TreasuryExtender.sol +++ b/src/TreasuryExtender.sol @@ -1,19 +1,20 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import "@openzeppelin-contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "@openzeppelin-contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; -import "./types/GhostAccessControlled.sol"; +import {GhostAccessControlled} from "./types/GhostAccessControlled.sol"; -import "./interfaces/ITreasury.sol"; -import "./interfaces/IAllocator.sol"; -import "./interfaces/ITreasuryExtender.sol"; +import {ITreasury} from "./interfaces/ITreasury.sol"; +import {IAllocator} from "./interfaces/IAllocator.sol"; +import {ITreasuryExtender} from "./interfaces/ITreasuryExtender.sol"; +import {IGhostAuthority} from "./interfaces/IGhostAuthority.sol"; contract TreasuryExtender is GhostAccessControlled, ITreasuryExtender { using SafeERC20 for IERC20; - ITreasury public immutable treasury; + ITreasury public immutable treasury; // forge-lint: disable-line(screaming-snake-case-immutable) IAllocator[] public allocators; mapping(IAllocator => mapping(uint256 => AllocatorData)) public allocatorData; @@ -134,6 +135,7 @@ contract TreasuryExtender is GhostAccessControlled, ITreasuryExtender { amount = allocated + gain; gain = 0; } else { + // forge-lint: disable-next-line(unsafe-typecast) gain -= uint128(amount); amount += allocated; } diff --git a/src/governance/GhostGovernor.sol b/src/governance/GhostGovernor.sol index 48a0c27..ca031be 100644 --- a/src/governance/GhostGovernor.sol +++ b/src/governance/GhostGovernor.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import {IGovernor, Governor} from "@openzeppelin-contracts/governance/Governor.sol"; +import {Governor} from "@openzeppelin-contracts/governance/Governor.sol"; import {GovernorPreventLateQuorum} from "@openzeppelin-contracts/governance/extensions/GovernorPreventLateQuorum.sol"; import {GovernorSettings} from "@openzeppelin-contracts/governance/extensions/GovernorSettings.sol"; import {GovernorStorage} from "@openzeppelin-contracts/governance/extensions/GovernorStorage.sol"; @@ -10,8 +10,8 @@ import {GovernorVotesQuorumFraction} from "@openzeppelin-contracts/governance/ex import {IVotes} from "@openzeppelin-contracts/governance/utils/IVotes.sol"; import {ReentrancyGuard} from "@openzeppelin-contracts/utils/ReentrancyGuard.sol"; -import "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; -import "@openzeppelin-contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "@openzeppelin-contracts/token/ERC20/IERC20.sol"; import {GovernorGhostCounting} from "./GovernorGhostCounting.sol"; import {Babylonian} from "../libraries/FixedPoint.sol"; @@ -80,7 +80,7 @@ contract GhostGovernor is if (releaseAmount > 0 && (currentProposalState & activePendingMask == 0)) { lockedAmounts[proposalId] = 0; - IERC20(address(token())).transfer(proposer, releaseAmount); + IERC20(address(token())).safeTransfer(proposer, releaseAmount); return releaseAmount; } diff --git a/src/governance/GovernorGhostCounting.sol b/src/governance/GovernorGhostCounting.sol index 1fe9508..780351b 100644 --- a/src/governance/GovernorGhostCounting.sol +++ b/src/governance/GovernorGhostCounting.sol @@ -20,7 +20,8 @@ abstract contract GovernorGhostCounting is Governor { mapping(uint256 proposalId => ProposalVote) private _proposalVotes; - // solhint-disable-next-line func-name-mixedcase + // forge-lint: disable-next-item(mixed-case-function) + // solhint-disable-next-line mixed-case-function function COUNTING_MODE() public pure virtual override returns (string memory) { return "support=bravo&quorum=for"; } diff --git a/src/interfaces/IAllocator.sol b/src/interfaces/IAllocator.sol index 8a249a5..307c4bf 100644 --- a/src/interfaces/IAllocator.sol +++ b/src/interfaces/IAllocator.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import "@openzeppelin-contracts/token/ERC20/IERC20.sol"; -import "./ITreasuryExtender.sol"; -import "./IGhostAuthority.sol"; +import {IERC20} from "@openzeppelin-contracts/token/ERC20/IERC20.sol"; +import {ITreasuryExtender} from "./ITreasuryExtender.sol"; +import {IGhostAuthority} from "./IGhostAuthority.sol"; interface IAllocator { error OnlyExtender(address sender); diff --git a/src/interfaces/IBondDepository.sol b/src/interfaces/IBondDepository.sol index d8dba1e..bef8694 100644 --- a/src/interfaces/IBondDepository.sol +++ b/src/interfaces/IBondDepository.sol @@ -1,8 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import "@openzeppelin-contracts/token/ERC20/IERC20.sol"; - interface IBondDepository { error DepositoryConcluded(uint48 concludedTime); error DepositoryMaxPrice(uint256 price, uint256 maxPrice); diff --git a/src/interfaces/IFTSO.sol b/src/interfaces/IFTSO.sol index 5900f7f..67f4c15 100644 --- a/src/interfaces/IFTSO.sol +++ b/src/interfaces/IFTSO.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import "@openzeppelin-contracts/token/ERC20/IERC20.sol"; +import {IERC20} from "@openzeppelin-contracts/token/ERC20/IERC20.sol"; interface IFTSO is IERC20 { function mint(address account, uint256 amount) external; diff --git a/src/interfaces/IGHST.sol b/src/interfaces/IGHST.sol index 0154427..1601a34 100644 --- a/src/interfaces/IGHST.sol +++ b/src/interfaces/IGHST.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import "@openzeppelin-contracts/token/ERC20/IERC20.sol"; +import {IERC20} from "@openzeppelin-contracts/token/ERC20/IERC20.sol"; interface IGHST is IERC20 { error NotStakingContract(); diff --git a/src/interfaces/ISTNK.sol b/src/interfaces/ISTNK.sol index f693195..5571b08 100644 --- a/src/interfaces/ISTNK.sol +++ b/src/interfaces/ISTNK.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import "@openzeppelin-contracts/token/ERC20/IERC20.sol"; +import {IERC20} from "@openzeppelin-contracts/token/ERC20/IERC20.sol"; interface ISTNK is IERC20 { error NotStakingContract(); diff --git a/src/libraries/FixedPoint.sol b/src/libraries/FixedPoint.sol index 1fe38e6..a3cc758 100644 --- a/src/libraries/FixedPoint.sol +++ b/src/libraries/FixedPoint.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import "./FullMath.sol"; +import {FullMath} from "./FullMath.sol"; library Babylonian { function sqrt(uint256 x) internal pure returns (uint256) { @@ -85,11 +85,11 @@ library BitMath { } library FixedPoint { - struct uq112x112 { + struct Uq112x112 { uint224 _x; } - struct uq144x112 { + struct Uq144x112 { uint256 _x; } @@ -98,38 +98,42 @@ library FixedPoint { uint256 private constant Q224 = 0x100000000000000000000000000000000000000000000000000000000; uint256 private constant LOWER_MASK = 0xffffffffffffffffffffffffffff; // decimal of UQ*x112 (lower 112 bits) - function decode(uq112x112 memory self) internal pure returns (uint112) { + function decode(Uq112x112 memory self) internal pure returns (uint112) { return uint112(self._x >> RESOLUTION); } - function decode112with18(uq112x112 memory self) internal pure returns (uint256) { + function decode112with18(Uq112x112 memory self) internal pure returns (uint256) { return uint256(self._x) / 5192296858534827; } - function fraction(uint256 numerator, uint256 denominator) internal pure returns (uq112x112 memory) { + function fraction(uint256 numerator, uint256 denominator) internal pure returns (Uq112x112 memory) { require(denominator > 0, "FixedPoint::fraction: division by zero"); - if (numerator == 0) return FixedPoint.uq112x112(0); + if (numerator == 0) return FixedPoint.Uq112x112(0); if (numerator <= type(uint144).max) { uint256 result = (numerator << RESOLUTION) / denominator; require(result <= type(uint224).max, "FixedPoint::fraction: overflow"); - return uq112x112(uint224(result)); + // forge-lint: disable-next-line(unsafe-typecast) + return Uq112x112({ _x: uint224(result) }); } else { uint256 result = FullMath.mulDiv(numerator, Q112, denominator); require(result <= type(uint224).max, "FixedPoint::fraction: overflow"); - return uq112x112(uint224(result)); + // forge-lint: disable-next-line(unsafe-typecast) + return Uq112x112({ _x: uint224(result) }); } } // square root of a UQ112x112 // lossy between 0/1 and 40 bits - function sqrt(uq112x112 memory self) internal pure returns (uq112x112 memory) { + function sqrt(Uq112x112 memory self) internal pure returns (Uq112x112 memory) { if (self._x <= type(uint144).max) { - return uq112x112(uint224(Babylonian.sqrt(uint256(self._x) << 112))); + // forge-lint: disable-next-line(unsafe-typecast) + return Uq112x112({ _x: uint224(Babylonian.sqrt(uint256(self._x) << 112)) }); } uint8 safeShiftBits = 255 - BitMath.mostSignificantBit(self._x); safeShiftBits -= safeShiftBits % 2; - return uq112x112(uint224(Babylonian.sqrt(uint256(self._x) << safeShiftBits) << ((112 - safeShiftBits) / 2))); + // forge-lint: disable-next-line(unsafe-typecast) + return Uq112x112({ _x: uint224(Babylonian.sqrt(uint256(self._x) << safeShiftBits) << ((112 - safeShiftBits) / 2)) }); } } diff --git a/src/mocks/ERC20Mock.sol b/src/mocks/ERC20Mock.sol index 287c183..6952b1a 100644 --- a/src/mocks/ERC20Mock.sol +++ b/src/mocks/ERC20Mock.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import "@openzeppelin-contracts/token/ERC20/ERC20.sol"; +import {ERC20} from "@openzeppelin-contracts/token/ERC20/ERC20.sol"; contract ERC20Mock is ERC20 { constructor(string memory name, string memory symbol) ERC20(name, symbol) {} diff --git a/src/mocks/Reserve.sol b/src/mocks/Reserve.sol index 6571679..7cad46a 100644 --- a/src/mocks/Reserve.sol +++ b/src/mocks/Reserve.sol @@ -1,10 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import "@openzeppelin-contracts/token/ERC20/extensions/ERC20Permit.sol"; +import {ERC20} from "@openzeppelin-contracts/token/ERC20/ERC20.sol"; +import {ERC20Permit} from "@openzeppelin-contracts/token/ERC20/extensions/ERC20Permit.sol"; contract Reserve is ERC20Permit { - address private immutable _owner; + address private immutable _owner; // forge-lint: disable-line(screaming-snake-case-immutable) uint256 public accumulatedDonation; uint256 public conversionRate; uint256 public donationRate; diff --git a/src/mocks/SigUtils.sol b/src/mocks/SigUtils.sol index 33183b6..2c4eb97 100644 --- a/src/mocks/SigUtils.sol +++ b/src/mocks/SigUtils.sol @@ -1,10 +1,10 @@ pragma solidity 0.8.20; contract SigUtils { - bytes32 internal DOMAIN_SEPARATOR; + bytes32 internal immutable DOMAIN_SEPARATOR; - constructor(bytes32 _DOMAIN_SEPARATOR) { - DOMAIN_SEPARATOR = _DOMAIN_SEPARATOR; + constructor(bytes32 domainSeparator) { + DOMAIN_SEPARATOR = domainSeparator; } // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); @@ -23,34 +23,38 @@ contract SigUtils { function getStructHash(Permit memory _permit) internal pure - returns (bytes32) + returns (bytes32 structHash) { - return - keccak256( - abi.encode( - PERMIT_TYPEHASH, - _permit.owner, - _permit.spender, - _permit.value, - _permit.nonce, - _permit.deadline - ) - ); + assembly { + let ptr := mload(0x40) + + mstore(ptr, PERMIT_TYPEHASH) // PERMIT_TYPEHASH + mstore(add(ptr, 32), mload(_permit)) // owner + mstore(add(ptr, 64), mload(add(_permit, 32))) // spender + mstore(add(ptr, 96), mload(add(_permit, 64))) // value + mstore(add(ptr, 128), mload(add(_permit, 96))) // nonce + mstore(add(ptr, 160), mload(add(_permit, 128))) // deadline + + structHash := keccak256(ptr, 192) + } } // computes the hash of the fully encoded EIP-712 message for the domain, which can be used to recover the signer function getTypedDataHash(Permit memory _permit) public view - returns (bytes32) + returns (bytes32 digest) { - return - keccak256( - abi.encodePacked( - "\x19\x01", - DOMAIN_SEPARATOR, - getStructHash(_permit) - ) - ); + bytes32 structHash = getStructHash(_permit); + bytes32 domainSeparator = DOMAIN_SEPARATOR; + assembly { + let ptr := mload(0x40) + + mstore(ptr, 0x1901000000000000000000000000000000000000000000000000000000000000) // \x19\x01 + mstore(add(ptr, 2), domainSeparator) + mstore(add(ptr, 34), structHash) + + digest := keccak256(ptr, 66) + } } } diff --git a/src/types/BaseAllocator.sol b/src/types/BaseAllocator.sol index f05dd65..2ffab54 100644 --- a/src/types/BaseAllocator.sol +++ b/src/types/BaseAllocator.sol @@ -1,16 +1,17 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "@openzeppelin-contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; -import "./GhostAccessControlled.sol"; -import "../interfaces/IAllocator.sol"; -import "../interfaces/ITreasury.sol"; +import {GhostAccessControlled} from "./GhostAccessControlled.sol"; +import {IAllocator} from "../interfaces/IAllocator.sol"; +import {ITreasuryExtender} from "../interfaces/ITreasuryExtender.sol"; abstract contract BaseAllocator is GhostAccessControlled, IAllocator { using SafeERC20 for IERC20; - ITreasuryExtender public immutable extender; + ITreasuryExtender public immutable extender; // forge-lint: disable-line(screaming-snake-case-immutable) AllocatorStatus public status; uint256[] internal _ids; diff --git a/src/types/FrontEndRewarder.sol b/src/types/FrontEndRewarder.sol index 2704f1d..10e1eab 100644 --- a/src/types/FrontEndRewarder.sol +++ b/src/types/FrontEndRewarder.sol @@ -1,17 +1,21 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import "./GhostAccessControlled.sol"; -import "@openzeppelin-contracts/token/ERC20/IERC20.sol"; +import {GhostAccessControlled} from "./GhostAccessControlled.sol"; +import {IGhostAuthority} from "../interfaces/IGhostAuthority.sol"; +import {IERC20} from "@openzeppelin-contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; abstract contract FrontEndRewarder is GhostAccessControlled { + using SafeERC20 for IERC20; + uint256 public daoReward; uint256 public refReward; mapping(address => uint256) public rewards; mapping(address => bool) public whitelisted; - IERC20 internal immutable _ftso; + IERC20 internal immutable _ftso; // forge-lint: disable-line(screaming-snake-case-immutable) constructor(address _authorityAddress, address _ftsoAddress) GhostAccessControlled(IGhostAuthority(_authorityAddress)) @@ -22,7 +26,7 @@ abstract contract FrontEndRewarder is GhostAccessControlled { function getReward() external { uint256 reward = rewards[msg.sender]; rewards[msg.sender] = 0; - _ftso.transfer(msg.sender, reward); + _ftso.safeTransfer(msg.sender, reward); } function _giveRewards( diff --git a/src/types/GhostAccessControlled.sol b/src/types/GhostAccessControlled.sol index 1d0e90b..a7ec9c6 100644 --- a/src/types/GhostAccessControlled.sol +++ b/src/types/GhostAccessControlled.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import "../interfaces/IGhostAuthority.sol"; +import {IGhostAuthority} from "../interfaces/IGhostAuthority.sol"; abstract contract GhostAccessControlled { error Unauthorized(); diff --git a/src/types/NoteKeeper.sol b/src/types/NoteKeeper.sol index 516f6b5..48c961a 100644 --- a/src/types/NoteKeeper.sol +++ b/src/types/NoteKeeper.sol @@ -1,24 +1,26 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import "./FrontEndRewarder.sol"; +import {FrontEndRewarder} from "./FrontEndRewarder.sol"; -import "../interfaces/IGHST.sol"; -import "../interfaces/IStaking.sol"; -import "../interfaces/ITreasury.sol"; -import "../interfaces/INoteKeeper.sol"; +import {IGHST} from "../interfaces/IGHST.sol"; +import {IStaking} from "../interfaces/IStaking.sol"; +import {ITreasury} from "../interfaces/ITreasury.sol"; +import {INoteKeeper} from "../interfaces/INoteKeeper.sol"; -import "@openzeppelin-contracts/utils/structs/EnumerableSet.sol"; +import {EnumerableSet} from "@openzeppelin-contracts/utils/structs/EnumerableSet.sol"; +import {SafeERC20} from "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; abstract contract NoteKeeper is INoteKeeper, FrontEndRewarder { using EnumerableSet for EnumerableSet.UintSet; + using SafeERC20 for IGHST; mapping(address => Note[]) public notes; mapping(address => mapping(uint256 => address)) private _noteTransfers; mapping(address => EnumerableSet.UintSet) private _pendingIndexes; - IGHST internal immutable _ghst; - IStaking internal immutable _staking; + IGHST internal immutable _GHST; + IStaking internal immutable _STAKING; ITreasury internal _treasury; constructor( @@ -28,10 +30,10 @@ abstract contract NoteKeeper is INoteKeeper, FrontEndRewarder { address _stakingAddress, address _treasuryAddress ) FrontEndRewarder(_authority, _ftsoAddress) { - _ghst = IGHST(_ghstAddress); - _staking = IStaking(_stakingAddress); + _GHST = IGHST(_ghstAddress); + _STAKING = IStaking(_stakingAddress); _treasury = ITreasury(_treasuryAddress); - _staking.toggleLock(); + _STAKING.toggleLock(); } function updateTreasury() external { @@ -54,7 +56,7 @@ abstract contract NoteKeeper is INoteKeeper, FrontEndRewarder { _pendingIndexes[user].add(index); notes[user].push( Note({ - payout: _ghst.balanceTo(payout), + payout: _GHST.balanceTo(payout), created: uint48(block.timestamp), matured: expiry, redeemed: 0, @@ -64,7 +66,7 @@ abstract contract NoteKeeper is INoteKeeper, FrontEndRewarder { uint256 rewards = _giveRewards(payout, referral); _treasury.mint(address(this), payout + rewards); - _staking.stake(payout, address(this), false, true); + _STAKING.stake(payout, address(this), false, true); } function redeem( @@ -72,7 +74,7 @@ abstract contract NoteKeeper is INoteKeeper, FrontEndRewarder { bool sendGhst, uint256[] memory indexes ) public override returns (uint256 payout) { - _staking.claim(address(this), false); + _STAKING.claim(address(this), false); uint48 time = uint48(block.timestamp); uint256 i; @@ -87,8 +89,8 @@ abstract contract NoteKeeper is INoteKeeper, FrontEndRewarder { unchecked { ++i; } } - if (sendGhst) _ghst.transfer(user, payout); - else _staking.unwrap(user, payout); + if (sendGhst) _GHST.safeTransfer(user, payout); + else _STAKING.unwrap(user, payout); } function redeemAll( diff --git a/src/vesting/Genesis.sol b/src/vesting/Genesis.sol index 1fd25f5..c86a40c 100644 --- a/src/vesting/Genesis.sol +++ b/src/vesting/Genesis.sol @@ -1,14 +1,15 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; -import "@openzeppelin-contracts/access/Ownable2Step.sol"; +import {IERC20} from "@openzeppelin-contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; +import {Ownable2Step} from "@openzeppelin-contracts/access/Ownable2Step.sol"; +import {Ownable} from "@openzeppelin-contracts/access/Ownable.sol"; -import "../interfaces/ITreasury.sol"; -import "../interfaces/ISTNK.sol"; -import "../interfaces/IGHST.sol"; -import "../interfaces/IStaking.sol"; -import "../interfaces/IClaim.sol"; +import {ITreasury} from "../interfaces/ITreasury.sol"; +import {IGHST} from "../interfaces/IGHST.sol"; +import {IStaking} from "../interfaces/IStaking.sol"; +import {IClaim} from "../interfaces/IClaim.sol"; contract GenesisClaim is IClaim, Ownable2Step { using SafeERC20 for IERC20; @@ -18,12 +19,12 @@ contract GenesisClaim is IClaim, Ownable2Step { uint256 public totalAllocated; uint256 public maximumAllocated; - IERC20 internal immutable _ftso; - IERC20 internal immutable _reserve; - IGHST internal immutable _ghst; - ITreasury internal immutable _treasury; - IStaking internal immutable _staking; - address internal immutable _dao; + IERC20 internal immutable _FTSO; + IERC20 internal immutable _RESERVE; + IGHST internal immutable _GHST; + ITreasury internal immutable _TREASURY; + IStaking internal immutable _STAKING; + address internal immutable _DAO; mapping(address => Term) private _terms; mapping(address => address) public walletChange; @@ -40,16 +41,16 @@ contract GenesisClaim is IClaim, Ownable2Step { maximumAllocated = _maximumAllocated; useStatic = true; - _ftso = IERC20(_ftsoAddress); - _reserve = IERC20(_reserveAddress); - _treasury = ITreasury(_treasuryAddress); - _ghst = IGHST(_ghstAddress); - _staking = IStaking(_stakingAddress); - _dao = _daoAddress; + _FTSO = IERC20(_ftsoAddress); + _RESERVE = IERC20(_reserveAddress); + _TREASURY = ITreasury(_treasuryAddress); + _GHST = IGHST(_ghstAddress); + _STAKING = IStaking(_stakingAddress); + _DAO = _daoAddress; } function claim(uint256 amount) external { - _ftso.safeTransfer(msg.sender, _claim(amount)); + _FTSO.safeTransfer(msg.sender, _claim(amount)); } function stake( @@ -60,28 +61,28 @@ contract GenesisClaim is IClaim, Ownable2Step { ) external { uint256 toStake = _claim(amount); // - // _ftso.approve(address(_staking), toStake); - // _staking.stake(toStake, msg.sender); + // _FTSO.approve(address(_STAKING), toStake); + // _STAKING.stake(toStake, msg.sender); // - // if (isFtso) _staking.claim(msg.sender); - _staking.stake(toStake, to, isRebasing, isClaim); + // if (isFtso) _STAKING.claim(msg.sender); + _STAKING.stake(toStake, to, isRebasing, isClaim); } function _claim(uint256 amount) internal returns (uint256 toSend) { Term memory info = _terms[msg.sender]; - _reserve.safeTransferFrom(msg.sender, address(this), amount); - _reserve.approve(address(_treasury), amount); - toSend = _treasury.deposit(address(_reserve), amount, 0); + _RESERVE.safeTransferFrom(msg.sender, address(this), amount); + _RESERVE.approve(address(_TREASURY), amount); + toSend = _TREASURY.deposit(address(_RESERVE), amount, 0); if (redeemableFor(msg.sender) / 1e9 < toSend) revert NotEnoughVested(); if (info.max - claimed(msg.sender) < toSend) revert ClaimedOverMax(); if (useStatic) { - _terms[msg.sender].gClaimed = info.gClaimed + _ghst.balanceTo(toSend * 9 / 10); + _terms[msg.sender].gClaimed = info.gClaimed + _GHST.balanceTo(toSend * 9 / 10); _terms[msg.sender].claimed = info.claimed + (toSend / 10); } else { - _terms[msg.sender].gClaimed = info.gClaimed + _ghst.balanceTo(toSend); + _terms[msg.sender].gClaimed = info.gClaimed + _GHST.balanceTo(toSend); } } @@ -107,12 +108,12 @@ contract GenesisClaim is IClaim, Ownable2Step { } function claimed(address someAddress) public view returns (uint256) { - return _ghst.balanceFrom(_terms[someAddress].gClaimed) + return _GHST.balanceFrom(_terms[someAddress].gClaimed) + _terms[someAddress].claimed; } function circulatingSupply() public view returns ( uint ) { - return _treasury.baseSupply() - _ftso.balanceOf(_dao); + return _TREASURY.baseSupply() - _FTSO.balanceOf(_DAO); } function setTerms( @@ -134,7 +135,7 @@ contract GenesisClaim is IClaim, Ownable2Step { } function treatAllAsStaked() external { - if (msg.sender != _dao) revert NotADao(); + if (msg.sender != _DAO) revert NotADao(); useStatic = false; } } diff --git a/test/bonding/BondDepositorty.t.sol b/test/bonding/BondDepositorty.t.sol index b44c1d0..88eb177 100644 --- a/test/bonding/BondDepositorty.t.sol +++ b/test/bonding/BondDepositorty.t.sol @@ -2,16 +2,17 @@ pragma solidity 0.8.20; import {Test} from "forge-std/Test.sol"; -import "../../src/FatsoERC20.sol"; -import "../../src/StinkyERC20.sol"; -import "../../src/GhstERC20.sol"; -import "../../src/GhostAuthority.sol"; -import "../../src/StakingDistributor.sol"; -import "../../src/Treasury.sol"; -import "../../src/Staking.sol"; -import "../../src/BondDepository.sol"; -import "../../src/mocks/ERC20Mock.sol"; -import "../../src/StandardBondingCalculator.sol"; +import {Fatso} from "../../src/FatsoERC20.sol"; +import {Stinky} from "../../src/StinkyERC20.sol"; +import {Ghost} from "../../src/GhstERC20.sol"; +import {GhostAuthority} from "../../src/GhostAuthority.sol"; +import {GhostTreasury} from "../../src/Treasury.sol"; +import {GhostStaking} from "../../src/Staking.sol"; +import {GhostBondDepository} from "../../src/BondDepository.sol"; +import {ERC20Mock} from "../../src/mocks/ERC20Mock.sol"; +import {GhostBondingCalculator} from "../../src/StandardBondingCalculator.sol"; + +import {ITreasury} from "../../src/interfaces/ITreasury.sol"; contract GhostBondDepositoryTest is Test { uint256 public constant TOTAL_INITIAL_SUPPLY = 5000000000000000; @@ -21,24 +22,22 @@ contract GhostBondDepositoryTest is Test { uint48 public constant EPOCH_NUMBER = 1; uint48 public constant EPOCH_END_TIME = 1337; - uint256 public constant initialMint = 1000000000000000000000000; - uint256 public constant initialDeposit = 100000000000000000000000; - uint256 public constant capacity = 10000e9; - uint256 public constant initialPrice = 400e9; - uint256 public constant buffer = 2e5; + uint256 public constant INITIAL_MINT = 1000000000000000000000000; + uint256 public constant CAPACITY = 10000e9; + uint256 public constant INITIAL_PRICE = 400e9; + uint256 public constant BUFFER = 2e5; - address constant initializer = 0x0000000000000000000000000000000000000001; - address constant governor = 0x0000000000000000000000000000000000000003; - address constant guardian = 0x0000000000000000000000000000000000000004; - address constant policy = 0x0000000000000000000000000000000000000005; - address constant vault = 0x0000000000000000000000000000000000000006; - address constant alice = 0x0000000000000000000000000000000000000007; - address constant bob = 0x0000000000000000000000000000000000000008; + address constant INITIALIZER = 0x0000000000000000000000000000000000000001; + address constant GOVERNOR = 0x0000000000000000000000000000000000000003; + address constant GUARDIAN = 0x0000000000000000000000000000000000000004; + address constant POLICY = 0x0000000000000000000000000000000000000005; + address constant VAULT = 0x0000000000000000000000000000000000000006; + address constant ALICE = 0x0000000000000000000000000000000000000007; - uint256 public constant vesting = 100; - uint256 public constant timeToConclusion = 60 * 60 * 24; - uint256 public constant depositInterval = 60 * 60 * 4; - uint256 public constant tuneInterval = 60 * 60; + uint256 public constant VESTING = 100; + uint256 public constant TIME_TO_CONCLUSION = 60 * 60 * 24; + uint256 public constant DEPOSIT_INTERVAL = 60 * 60 * 4; + uint256 public constant TUNE_INTERVAL = 60 * 60; uint256 public conclusion; @@ -53,12 +52,12 @@ contract GhostBondDepositoryTest is Test { GhostBondingCalculator calculator; function setUp() public { - vm.startPrank(initializer); + vm.startPrank(INITIALIZER); authority = new GhostAuthority( - governor, - guardian, - policy, - vault + GOVERNOR, + GUARDIAN, + POLICY, + VAULT ); reserve = new ERC20Mock("Reserve Token", "RET"); ftso = new Fatso(address(authority), "Fatso", "FTSO"); @@ -89,31 +88,31 @@ contract GhostBondDepositoryTest is Test { } function _createFirstBond() internal { - vm.startPrank(governor); + vm.startPrank(GOVERNOR); authority.pushVault(address(treasury)); treasury.enable(ITreasury.STATUS.REWARDMANAGER, address(depository), address(0)); - treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, alice, address(0)); + treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, ALICE, address(0)); treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator)); vm.stopPrank(); - vm.startPrank(alice); - reserve.mint(alice, initialMint); + vm.startPrank(ALICE); + reserve.mint(ALICE, INITIAL_MINT); reserve.approve(address(treasury), type(uint256).max); - treasury.deposit(address(reserve), initialMint, treasury.tokenValue(address(reserve), initialMint) / 2); + treasury.deposit(address(reserve), INITIAL_MINT, treasury.tokenValue(address(reserve), INITIAL_MINT) / 2); assertEq(ftso.totalSupply(), treasury.baseSupply()); - reserve.mint(alice, initialMint); + reserve.mint(ALICE, INITIAL_MINT); reserve.approve(address(depository), type(uint256).max); vm.stopPrank(); - conclusion = block.timestamp + timeToConclusion; + conclusion = block.timestamp + TIME_TO_CONCLUSION; - vm.prank(policy); + vm.prank(POLICY); depository.create( - [capacity, initialPrice, buffer], - [vesting, conclusion], + [CAPACITY, INITIAL_PRICE, BUFFER], + [VESTING, conclusion], address(reserve), - [uint32(depositInterval), uint32(tuneInterval)], + [uint32(DEPOSIT_INTERVAL), uint32(TUNE_INTERVAL)], // forge-lint: disable-line(unsafe-typecast) [false, true] ); } @@ -124,23 +123,23 @@ contract GhostBondDepositoryTest is Test { function test_shouldConcludeInCorrectAmountOfTime() public view { (, , , uint48 concludes,) = depository.terms(0); - assertEq(concludes, uint48(conclusion)); + assertEq(concludes, uint48(conclusion)); // forge-lint: disable-line(unsafe-typecast) (, , uint48 length, , ,) = depository.metadatas(0); - assertEq(length, timeToConclusion); + assertEq(length, TIME_TO_CONCLUSION); } function test_shouldSetMaxPayoutToCorrectPercentageOfCapacity() public view { (, , , , uint256 maxPayout, ,) = depository.markets(0); - assertEq(maxPayout, capacity / 6); + assertEq(maxPayout, CAPACITY / 6); } function test_shouldReturnIdsOfAllMarkets() public { - vm.prank(policy); + vm.prank(POLICY); depository.create( - [capacity, initialPrice, buffer], - [vesting, conclusion], + [CAPACITY, INITIAL_PRICE, BUFFER], + [VESTING, conclusion], address(reserve), - [uint32(depositInterval), uint32(tuneInterval)], + [uint32(DEPOSIT_INTERVAL), uint32(TUNE_INTERVAL)], // forge-lint: disable-line(unsafe-typecast) [false, true] ); @@ -151,12 +150,12 @@ contract GhostBondDepositoryTest is Test { } function test_shouldUpdateIdsOfMarkets() public { - vm.startPrank(policy); + vm.startPrank(POLICY); depository.create( - [capacity, initialPrice, buffer], - [vesting, conclusion], + [CAPACITY, INITIAL_PRICE, BUFFER], + [VESTING, conclusion], address(reserve), - [uint32(depositInterval), uint32(tuneInterval)], + [uint32(DEPOSIT_INTERVAL), uint32(TUNE_INTERVAL)], // forge-lint: disable-line(unsafe-typecast) [false, true] ); depository.close(0); @@ -174,7 +173,7 @@ contract GhostBondDepositoryTest is Test { } function test_shouldStartWithPriceAtInitialPrice() public view { - assertEq(depository.marketPrice(0), initialPrice); + assertEq(depository.marketPrice(0), INITIAL_PRICE); } function test_shouldGiveAccuratePayoutForPrice() public view { @@ -187,20 +186,20 @@ contract GhostBondDepositoryTest is Test { function test_shouldDecayDebt() public { (, , , uint256 totalDebt, , ,) = depository.markets(0); - skip(depositInterval); - vm.prank(alice); - depository.deposit(0, 0, initialPrice, alice, alice); + skip(DEPOSIT_INTERVAL); + vm.prank(ALICE); + depository.deposit(0, 0, INITIAL_PRICE, ALICE, ALICE); (, , , uint256 newTotalDebt, , ,) = depository.markets(0); assertEq(totalDebt > newTotalDebt, true); } function test_shouldStartAdjustmentIfBehindSchedule() public { - skip(depositInterval); + skip(DEPOSIT_INTERVAL); uint256 amount = 10_000 * 1e18; - vm.prank(alice); - depository.deposit(0, amount, initialPrice, alice, alice); + vm.prank(ALICE); + depository.deposit(0, amount, INITIAL_PRICE, ALICE, ALICE); (, , , bool active) = depository.adjustments(0); assertEq(active, true); @@ -210,11 +209,11 @@ contract GhostBondDepositoryTest is Test { (, uint64 ctrlVariable, , ,) = depository.terms(0); uint256 amount = 10_000 * 1e18; - vm.startPrank(alice); - depository.deposit(0, amount, initialPrice, alice, alice); - skip(depositInterval); + vm.startPrank(ALICE); + depository.deposit(0, amount, INITIAL_PRICE, ALICE, ALICE); + skip(DEPOSIT_INTERVAL); (uint64 change, , ,) = depository.adjustments(0); - depository.deposit(0, amount, initialPrice, alice, alice); + depository.deposit(0, amount, INITIAL_PRICE, ALICE, ALICE); vm.stopPrank(); (, uint64 newCtrlVariable, , ,) = depository.terms(0); @@ -222,16 +221,16 @@ contract GhostBondDepositoryTest is Test { } function test_adjustmentShouldLowerControlVariableByHalfOfTuneInterval() public { - skip(depositInterval); + skip(DEPOSIT_INTERVAL); (, uint64 ctrlVariable, , ,) = depository.terms(0); uint256 amount = 10_000 * 1e18; - vm.startPrank(alice); - depository.deposit(0, amount, initialPrice, alice, alice); + vm.startPrank(ALICE); + depository.deposit(0, amount, INITIAL_PRICE, ALICE, ALICE); (uint64 change, , ,) = depository.adjustments(0); - skip(tuneInterval / 2); + skip(TUNE_INTERVAL / 2); - depository.deposit(0, amount, initialPrice, alice, alice); + depository.deposit(0, amount, INITIAL_PRICE, ALICE, ALICE); (, uint64 newCtrlVariable, , ,) = depository.terms(0); vm.stopPrank(); @@ -244,13 +243,13 @@ contract GhostBondDepositoryTest is Test { (, uint64 ctrlVariable, , ,) = depository.terms(0); uint256 amount = 10_000 * 1e18; - vm.startPrank(alice); - depository.deposit(0, amount, initialPrice, alice, alice); + vm.startPrank(ALICE); + depository.deposit(0, amount, INITIAL_PRICE, ALICE, ALICE); (uint64 change, , ,) = depository.adjustments(0); - skip(tuneInterval / 2); - depository.deposit(0, amount, initialPrice, alice, alice); - skip(tuneInterval / 2); - depository.deposit(0, amount, initialPrice, alice, alice); + skip(TUNE_INTERVAL / 2); + depository.deposit(0, amount, INITIAL_PRICE, ALICE, ALICE); + skip(TUNE_INTERVAL / 2); + depository.deposit(0, amount, INITIAL_PRICE, ALICE, ALICE); vm.stopPrank(); (, uint64 newCtrlVariable, , ,) = depository.terms(0); @@ -259,53 +258,53 @@ contract GhostBondDepositoryTest is Test { function test_shouldAllowDeposit() public { uint256 amount = 10_000 * 1e18; - vm.prank(alice); - depository.deposit(0, amount, initialPrice, alice, alice); + vm.prank(ALICE); + depository.deposit(0, amount, INITIAL_PRICE, ALICE, ALICE); - uint256[] memory arr = depository.indexesFor(alice); + uint256[] memory arr = depository.indexesFor(ALICE); assertEq(arr.length, 1); } function test_shouldNotAllowDepositGreaterThanMaxPayout() public { uint256 amount = 6_700_000 * 1e18; vm.expectRevert(); - vm.prank(alice); - depository.deposit(0, amount, initialPrice, alice, alice); + vm.prank(ALICE); + depository.deposit(0, amount, INITIAL_PRICE, ALICE, ALICE); } function test_shouldNotRedeemAfterVested() public { - uint256 balance = ftso.balanceOf(alice); + uint256 balance = ftso.balanceOf(ALICE); uint256 amount = 10_000 * 1e18; // 10,000 - vm.startPrank(alice); - depository.deposit(0, amount, initialPrice, alice, alice); - depository.redeemAll(alice, true); + vm.startPrank(ALICE); + depository.deposit(0, amount, INITIAL_PRICE, ALICE, ALICE); + depository.redeemAll(ALICE, true); vm.stopPrank(); - assertEq(ftso.balanceOf(alice), balance); + assertEq(ftso.balanceOf(ALICE), balance); } function test_shouldRedeemAfterVested() public { uint256 amount = 10_000 * 1e18; // 10,000 - vm.startPrank(alice); - (uint256 expectedPayout, ,) = depository.deposit(0, amount, initialPrice, alice, alice); + vm.startPrank(ALICE); + (uint256 expectedPayout, ,) = depository.deposit(0, amount, INITIAL_PRICE, ALICE, ALICE); - skip(depositInterval); - depository.redeemAll(alice, true); + skip(DEPOSIT_INTERVAL); + depository.redeemAll(ALICE, true); vm.stopPrank(); - uint256 aliceBalance = ghst.balanceOf(alice); + uint256 aliceBalance = ghst.balanceOf(ALICE); assertEq(aliceBalance >= ghst.balanceTo(expectedPayout), true); assertEq(aliceBalance < ghst.balanceTo(expectedPayout * 10001 / 10000), true); } function test_shouldCorrectlyRedeemPartially() public { uint256 amount = 1 * 1e18; - vm.startPrank(alice); - depository.deposit(0, amount, initialPrice * 2, alice, alice); - depository.deposit(0, amount, initialPrice * 2, alice, alice); - depository.deposit(0, amount, initialPrice * 2, alice, alice); - depository.deposit(0, amount, initialPrice * 2, alice, alice); + vm.startPrank(ALICE); + depository.deposit(0, amount, INITIAL_PRICE * 2, ALICE, ALICE); + depository.deposit(0, amount, INITIAL_PRICE * 2, ALICE, ALICE); + depository.deposit(0, amount, INITIAL_PRICE * 2, ALICE, ALICE); + depository.deposit(0, amount, INITIAL_PRICE * 2, ALICE, ALICE); - skip(depositInterval); + skip(DEPOSIT_INTERVAL); uint256[] memory indexesToRemove = new uint256[](1); indexesToRemove[0] = 1; @@ -313,22 +312,22 @@ contract GhostBondDepositoryTest is Test { uint256[] memory nextIndexToRemove = new uint256[](1); nextIndexToRemove[0] = 3; - uint256[] memory allIndexes = depository.indexesFor(alice); + uint256[] memory allIndexes = depository.indexesFor(ALICE); assertEq(allIndexes.length, 4); assertEq(allIndexes[0], 0); assertEq(allIndexes[1], 1); assertEq(allIndexes[2], 2); assertEq(allIndexes[3], 3); - depository.redeem(alice, true, indexesToRemove); - uint256[] memory allIndexesOneRemoved = depository.indexesFor(alice); + depository.redeem(ALICE, true, indexesToRemove); + uint256[] memory allIndexesOneRemoved = depository.indexesFor(ALICE); assertEq(allIndexesOneRemoved.length, 3); assertEq(allIndexesOneRemoved[0], 0); assertEq(allIndexesOneRemoved[1], 3); assertEq(allIndexesOneRemoved[2], 2); - depository.redeem(alice, true, nextIndexToRemove); - uint256[] memory allIndexesTwoRemoved = depository.indexesFor(alice); + depository.redeem(ALICE, true, nextIndexToRemove); + uint256[] memory allIndexesTwoRemoved = depository.indexesFor(ALICE); assertEq(allIndexesTwoRemoved.length, 2); assertEq(allIndexesTwoRemoved[0], 0); assertEq(allIndexesTwoRemoved[1], 2); @@ -339,20 +338,20 @@ contract GhostBondDepositoryTest is Test { function test_afterSuccesfullWarmupAutoClaimExecuted() public { uint256 amount = 10_000 * 1e18; // 10,000 - vm.prank(governor); + vm.prank(GOVERNOR); staking.setWarmupPeriod(1); - vm.startPrank(alice); + vm.startPrank(ALICE); - assertEq(ghst.balanceOf(alice), 0); - (uint256 expectedPayout, ,) = depository.deposit(0, amount, initialPrice, alice, alice); + assertEq(ghst.balanceOf(ALICE), 0); + (uint256 expectedPayout, ,) = depository.deposit(0, amount, INITIAL_PRICE, ALICE, ALICE); assertEq(ghst.balanceOf(address(depository)), 0); - skip(depositInterval); + skip(DEPOSIT_INTERVAL); staking.rebase(); - depository.redeemAll(alice, true); - uint256 aliceBalance = ghst.balanceOf(alice); + depository.redeemAll(ALICE, true); + uint256 aliceBalance = ghst.balanceOf(ALICE); assertEq(aliceBalance >= ghst.balanceTo(expectedPayout), true); assertEq(aliceBalance < ghst.balanceTo(expectedPayout * 10001 / 10000), true); @@ -360,7 +359,7 @@ contract GhostBondDepositoryTest is Test { } function test_externalAccountCouldNotClaimFromWarmup() public { - vm.startPrank(alice); + vm.startPrank(ALICE); vm.expectRevert(); staking.claim(address(depository), false); @@ -375,17 +374,17 @@ contract GhostBondDepositoryTest is Test { (, , , , uint64 maxPayout, ,) = depository.markets(0); uint256 price = depository.marketPrice(0); uint256 amount = maxPayout * price; - vm.prank(alice); - depository.deposit(0, amount, initialPrice, alice, alice); - skip(depositInterval); + vm.prank(ALICE); + depository.deposit(0, amount, INITIAL_PRICE, ALICE, ALICE); + skip(DEPOSIT_INTERVAL); uint256 newPrice = depository.marketPrice(0); - assertEq(newPrice < initialPrice, true); + assertEq(newPrice < INITIAL_PRICE, true); } function test_shouldCloseMarket() public { (uint256 cap, , , , , ,) = depository.markets(0); assertEq(cap > 0, true); - vm.prank(policy); + vm.prank(POLICY); depository.close(0); (uint256 newCap, , , , , ,) = depository.markets(0); assertEq(newCap, 0); diff --git a/test/gatekeeper/Gatekeeper.t.sol b/test/gatekeeper/Gatekeeper.t.sol index 57f3b87..7682cb5 100644 --- a/test/gatekeeper/Gatekeeper.t.sol +++ b/test/gatekeeper/Gatekeeper.t.sol @@ -2,42 +2,42 @@ pragma solidity 0.8.20; import {Test} from "forge-std/Test.sol"; -import "../../src/Gatekeeper.sol"; +import {Gatekeeper} from "../../src/Gatekeeper.sol"; contract GatekeeperTest is Test { - address constant alice = 0x0000000000000000000000000000000000000001; - address constant bob = 0x0000000000000000000000000000000000000002; - uint256 constant initAmount = 69 * 1e18; + address constant ALICE = 0x0000000000000000000000000000000000000001; + address constant BOB = 0x0000000000000000000000000000000000000002; + uint256 constant INIT_AMOUNT = 69 * 1e18; Gatekeeper gatekeeper; event Ghosted(bytes32 indexed receiver, uint256 indexed amount); function setUp() public { - gatekeeper = new Gatekeeper(alice, 0); + gatekeeper = new Gatekeeper(ALICE, 0); } function test_correctInitialization() public { - assertEq(gatekeeper.staking(), alice); + assertEq(gatekeeper.staking(), ALICE); assertEq(gatekeeper.ghostedSupply(), 0); - Gatekeeper anotherGatekeeper = new Gatekeeper(bob, initAmount); - assertEq(anotherGatekeeper.staking(), bob); - assertEq(anotherGatekeeper.ghostedSupply(), initAmount); + Gatekeeper anotherGatekeeper = new Gatekeeper(BOB, INIT_AMOUNT); + assertEq(anotherGatekeeper.staking(), BOB); + assertEq(anotherGatekeeper.ghostedSupply(), INIT_AMOUNT); } function test_ghostTokensWork(uint256 ghostAmount) public { vm.assume(ghostAmount > 0); - bytes32 receiver = bytes32(abi.encodePacked(alice)); + bytes32 receiver = bytes32(abi.encodePacked(ALICE)); uint256 ghostedSupply = gatekeeper.ghostedSupply(); - vm.prank(alice); + vm.prank(ALICE); gatekeeper.ghost(receiver, ghostAmount); assertEq(gatekeeper.ghostedSupply(), ghostedSupply + ghostAmount); } function test_couldNotGhostTokensFromArbitraryAddress(address someone) public { - vm.assume(someone != alice); - bytes32 receiver = bytes32(abi.encodePacked(alice)); + vm.assume(someone != ALICE); + bytes32 receiver = bytes32(abi.encodePacked(ALICE)); vm.expectRevert(); vm.prank(someone); @@ -47,17 +47,17 @@ contract GatekeeperTest is Test { function test_ghostTokensEmitsEvent(uint256 ghostAmount) public { vm.assume(ghostAmount > 0); - bytes32 receiver = bytes32(abi.encodePacked(alice)); + bytes32 receiver = bytes32(abi.encodePacked(ALICE)); vm.expectEmit(true, true, true, false, address(gatekeeper)); emit Ghosted(receiver, ghostAmount); - vm.prank(alice); + vm.prank(ALICE); gatekeeper.ghost(receiver, ghostAmount); } function test_materializeWork(uint256 ghostAmount) public { vm.expectRevert(); - gatekeeper.materialize(alice, ghostAmount, 0, 0); + gatekeeper.materialize(ALICE, ghostAmount, 0, 0); } function test_rotateWork(uint256 aggregatedPublicKey) public { diff --git a/test/governance/GhostGovernor.t.sol b/test/governance/GhostGovernor.t.sol index 978528f..c21956e 100644 --- a/test/governance/GhostGovernor.t.sol +++ b/test/governance/GhostGovernor.t.sol @@ -3,9 +3,13 @@ pragma solidity 0.8.20; import {Test} from "forge-std/Test.sol"; import {Strings} from "@openzeppelin-contracts/utils/Strings.sol"; -import "../../src/governance/GhostGovernor.sol"; -import "../../src/GhstERC20.sol"; -import "../../src/StinkyERC20.sol"; +import {Ghost} from "../../src/GhstERC20.sol"; +import {Stinky} from "../../src/StinkyERC20.sol"; +import {GhostGovernor} from "../../src/governance/GhostGovernor.sol"; + +import {IGovernor} from "@openzeppelin-contracts/governance/IGovernor.sol"; +import {IVotes} from "@openzeppelin-contracts/governance/utils/IVotes.sol"; +import {SafeERC20} from "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; contract GhostGovernorExposed is GhostGovernor { constructor( @@ -42,6 +46,7 @@ contract GhostGovernorExposed is GhostGovernor { contract GhostGovernorTest is Test { using Strings for address; + using SafeERC20 for Ghost; uint48 public constant VOTE_EXTENSION = 69; uint48 public constant VOTING_DELAY = 420; @@ -49,22 +54,22 @@ contract GhostGovernorTest is Test { uint256 public constant PROPOSAL_THRESHOLD = 69 * 1e18; uint256 public constant QUORUM_FRACTION = 20; // percent - address constant init = 0x0000000000000000000000000000000000000001; - address constant alice = 0x0000000000000000000000000000000000000002; - address constant bob = 0x0000000000000000000000000000000000000003; - address constant carol = 0x0000000000000000000000000000000000000004; - address constant dave = 0x0000000000000000000000000000000000000005; - address constant eve = 0x0000000000000000000000000000000000000006; + address constant INIT = 0x0000000000000000000000000000000000000001; + address constant ALICE = 0x0000000000000000000000000000000000000002; + address constant BOB = 0x0000000000000000000000000000000000000003; + address constant CAROL = 0x0000000000000000000000000000000000000004; + address constant DAVE = 0x0000000000000000000000000000000000000005; + address constant EVE = 0x0000000000000000000000000000000000000006; GhostGovernorExposed public governor; Stinky public stnk; Ghost public ghst; function setUp() public { - vm.startPrank(init); + vm.startPrank(INIT); stnk = new Stinky(10819917194513808e56, "Stinky Test Name", "STNKTST"); ghst = new Ghost(address(stnk), "Ghost Test Name", "GHSTTST"); - ghst.initialize(init); + ghst.initialize(INIT); governor = new GhostGovernorExposed( ghst, VOTE_EXTENSION, @@ -75,13 +80,13 @@ contract GhostGovernorTest is Test { ); vm.stopPrank(); - vm.prank(alice); + vm.prank(ALICE); ghst.approve(address(governor), type(uint256).max); - vm.prank(bob); + vm.prank(BOB); ghst.approve(address(governor), type(uint256).max); - vm.prank(carol); + vm.prank(CAROL); ghst.approve(address(governor), type(uint256).max); } @@ -154,129 +159,129 @@ contract GhostGovernorTest is Test { } function test_succeededOnAbsoluteMajority() public { - vm.startPrank(init); - ghst.mint(alice, PROPOSAL_THRESHOLD); - ghst.mint(bob, 555 * 1e17); - ghst.mint(carol, 345 * 1e17 + 1); - ghst.mint(dave, 21 * 1e18); + vm.startPrank(INIT); + ghst.mint(ALICE, PROPOSAL_THRESHOLD); + ghst.mint(BOB, 555 * 1e17); + ghst.mint(CAROL, 345 * 1e17 + 1); + ghst.mint(DAVE, 21 * 1e18); vm.stopPrank(); vm.roll(block.number + 1); - (uint256 proposalId,,,,) = _proposeDummy(alice, 69); + (uint256 proposalId,,,,) = _proposeDummy(ALICE, 69); _waitForActive(proposalId); assertEq(uint8(governor.state(proposalId)), uint8(IGovernor.ProposalState.Active)); - _castVoteWrapper(proposalId, bob, 1, true, true); + _castVoteWrapper(proposalId, BOB, 1, true, true); assertEq(uint8(governor.state(proposalId)), uint8(IGovernor.ProposalState.Succeeded)); vm.expectRevert(); - vm.prank(carol); + vm.prank(CAROL); governor.castVote(proposalId, 0); vm.expectRevert(); - vm.prank(dave); + vm.prank(DAVE); governor.castVote(proposalId, 0); } function test_defeatedOnAbsoluteMajority() public { - vm.startPrank(init); - ghst.mint(alice, PROPOSAL_THRESHOLD); - ghst.mint(bob, 555 * 1e17); - ghst.mint(carol, 345 * 1e17 + 1); - ghst.mint(dave, 21 * 1e18); + vm.startPrank(INIT); + ghst.mint(ALICE, PROPOSAL_THRESHOLD); + ghst.mint(BOB, 555 * 1e17); + ghst.mint(CAROL, 345 * 1e17 + 1); + ghst.mint(DAVE, 21 * 1e18); vm.stopPrank(); vm.roll(block.number + 1); - (uint256 proposalId,,,,) = _proposeDummy(alice, 69); + (uint256 proposalId,,,,) = _proposeDummy(ALICE, 69); _waitForActive(proposalId); assertEq(uint8(governor.state(proposalId)), uint8(IGovernor.ProposalState.Active)); - _castVoteWrapper(proposalId, bob, 0, true, false); + _castVoteWrapper(proposalId, BOB, 0, true, false); assertEq(uint8(governor.state(proposalId)), uint8(IGovernor.ProposalState.Active)); - _castVoteWrapper(proposalId, carol, 0, true, false); + _castVoteWrapper(proposalId, CAROL, 0, true, false); assertEq(uint8(governor.state(proposalId)), uint8(IGovernor.ProposalState.Defeated)); vm.expectRevert(); - vm.prank(dave); + vm.prank(DAVE); governor.castVote(proposalId, 1); } function test_onlyOneActiveProposal() public { uint256 amount = PROPOSAL_THRESHOLD; - vm.startPrank(init); - ghst.mint(alice, amount); - ghst.mint(bob, 2 * amount); - ghst.mint(carol, 3 * amount); + vm.startPrank(INIT); + ghst.mint(ALICE, amount); + ghst.mint(BOB, 2 * amount); + ghst.mint(CAROL, 3 * amount); vm.stopPrank(); vm.roll(block.number + 1); - (uint256 proposalId,,,,) = _proposeDummy(alice, 69); + (uint256 proposalId,,,,) = _proposeDummy(ALICE, 69); _waitForActive(proposalId); - vm.prank(alice); + vm.prank(ALICE); assertEq(governor.releaseLocked(proposalId), 0); assertEq(governor.lockedAmounts(proposalId), amount); - assertEq(ghst.balanceOf(alice), 0); + assertEq(ghst.balanceOf(ALICE), 0); (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes) = governor.proposalVotes(proposalId); assertEq(againstVotes, 0); assertEq(forVotes, amount); assertEq(abstainVotes, 0); - _castVoteWrapper(proposalId, bob, 1, true, true); + _castVoteWrapper(proposalId, BOB, 1, true, true); (againstVotes, forVotes, abstainVotes) = governor.proposalVotes(proposalId); assertEq(againstVotes, 0); assertEq(forVotes, 3 * amount); assertEq(abstainVotes, 0); - assertEq(ghst.balanceOf(alice), 0); - assertEq(ghst.balanceOf(bob), 2 * amount); - assertEq(ghst.balanceOf(carol), 3 * amount); + assertEq(ghst.balanceOf(ALICE), 0); + assertEq(ghst.balanceOf(BOB), 2 * amount); + assertEq(ghst.balanceOf(CAROL), 3 * amount); _waitForSucceed(proposalId); - vm.prank(alice); + vm.prank(ALICE); assertEq(governor.releaseLocked(proposalId), amount); assertEq(governor.lockedAmounts(proposalId), 0); - assertEq(ghst.balanceOf(alice), amount); + assertEq(ghst.balanceOf(ALICE), amount); - vm.prank(alice); + vm.prank(ALICE); assertEq(governor.releaseLocked(proposalId), 0); assertEq(governor.lockedAmounts(proposalId), 0); - assertEq(ghst.balanceOf(alice), amount); + assertEq(ghst.balanceOf(ALICE), amount); - assertEq(ghst.balanceOf(alice), amount); - assertEq(ghst.balanceOf(bob), 2 * amount); - assertEq(ghst.balanceOf(carol), 3 * amount); + assertEq(ghst.balanceOf(ALICE), amount); + assertEq(ghst.balanceOf(BOB), 2 * amount); + assertEq(ghst.balanceOf(CAROL), 3 * amount); - (proposalId,,,,) = _proposeDummy(bob, 420); + (proposalId,,,,) = _proposeDummy(BOB, 420); _waitForActive(proposalId); - _castVoteWrapper(proposalId, alice, 1, true, true); - _castVoteWrapper(proposalId, carol, 1, true, true); + _castVoteWrapper(proposalId, ALICE, 1, true, true); + _castVoteWrapper(proposalId, CAROL, 1, true, true); vm.roll(block.number + 3); - (uint256 newProposalId,,,,) = _proposeDummy(carol, 1337); + (uint256 newProposalId,,,,) = _proposeDummy(CAROL, 1337); assertEq(uint8(governor.state(proposalId)), uint8(IGovernor.ProposalState.Succeeded)); assertEq(uint8(governor.state(newProposalId)), uint8(IGovernor.ProposalState.Pending)); - assertEq(ghst.balanceOf(alice), amount); - assertEq(ghst.balanceOf(bob), 0); - assertEq(ghst.balanceOf(carol), 0); + assertEq(ghst.balanceOf(ALICE), amount); + assertEq(ghst.balanceOf(BOB), 0); + assertEq(ghst.balanceOf(CAROL), 0); - vm.prank(bob); + vm.prank(BOB); assertEq(governor.releaseLocked(proposalId), 2 * amount); assertEq(governor.lockedAmounts(proposalId), 0); - assertEq(ghst.balanceOf(bob), 2 * amount); + assertEq(ghst.balanceOf(BOB), 2 * amount); - vm.prank(carol); + vm.prank(CAROL); assertEq(governor.releaseLocked(newProposalId), 0); assertEq(governor.lockedAmounts(newProposalId), 3 * amount); - assertEq(ghst.balanceOf(carol), 0); + assertEq(ghst.balanceOf(CAROL), 0); } function test_proposalCountWorks() public { @@ -291,8 +296,8 @@ contract GhostGovernorTest is Test { break; } - vm.prank(init); - ghst.mint(alice, amount); + vm.prank(INIT); + ghst.mint(ALICE, amount); vm.roll(block.number + 1); } @@ -302,7 +307,7 @@ contract GhostGovernorTest is Test { uint256[] memory values, bytes[] memory calldatas, string memory description - ) = _proposeDummy(alice, i); + ) = _proposeDummy(ALICE, i); { ( @@ -348,43 +353,43 @@ contract GhostGovernorTest is Test { } function test_preventLateQuorumWorks() public { - vm.startPrank(init); - ghst.mint(alice, PROPOSAL_THRESHOLD); - ghst.mint(bob, 50 * 1e18); - ghst.mint(carol, 100 * 1e18); - ghst.mint(dave, 100 * 1e18); - ghst.mint(eve, 500 * 1e18); + vm.startPrank(INIT); + ghst.mint(ALICE, PROPOSAL_THRESHOLD); + ghst.mint(BOB, 50 * 1e18); + ghst.mint(CAROL, 100 * 1e18); + ghst.mint(DAVE, 100 * 1e18); + ghst.mint(EVE, 500 * 1e18); vm.stopPrank(); vm.roll(block.number + 1); - (uint256 proposalId,,,,) = _proposeDummy(alice, 69); + (uint256 proposalId,,,,) = _proposeDummy(ALICE, 69); assertEq(uint8(governor.state(proposalId)), uint8(IGovernor.ProposalState.Pending)); vm.roll(block.number + VOTING_DELAY + 1); assertEq(uint8(governor.state(proposalId)), uint8(IGovernor.ProposalState.Active)); - assertEq(governor.voteOf(proposalId, bob), 0); - assertEq(governor.voteOf(proposalId, carol), 0); - assertEq(governor.voteOf(proposalId, dave), 0); - assertEq(governor.voteOf(proposalId, eve), 0); + assertEq(governor.voteOf(proposalId, BOB), 0); + assertEq(governor.voteOf(proposalId, CAROL), 0); + assertEq(governor.voteOf(proposalId, DAVE), 0); + assertEq(governor.voteOf(proposalId, EVE), 0); vm.roll(governor.proposalDeadline(proposalId)); - _castVoteWrapper(proposalId, bob, 1, false, true); + _castVoteWrapper(proposalId, BOB, 1, false, true); vm.roll(governor.proposalDeadline(proposalId)); - _castVoteWrapper(proposalId, carol, 0, true, false); + _castVoteWrapper(proposalId, CAROL, 0, true, false); vm.roll(governor.proposalDeadline(proposalId)); - _castVoteWrapper(proposalId, dave, 1, true, false); + _castVoteWrapper(proposalId, DAVE, 1, true, false); vm.roll(governor.proposalDeadline(proposalId)); - _castVoteWrapper(proposalId, eve, 1, true, true); + _castVoteWrapper(proposalId, EVE, 1, true, true); - vm.prank(alice); + vm.prank(ALICE); governor.execute(proposalId); assertEq(uint8(governor.state(proposalId)), uint8(IGovernor.ProposalState.Executed)); - assertEq(governor.voteOf(proposalId, bob), 2); - assertEq(governor.voteOf(proposalId, carol), 1); - assertEq(governor.voteOf(proposalId, dave), 2); - assertEq(governor.voteOf(proposalId, eve), 2); + assertEq(governor.voteOf(proposalId, BOB), 2); + assertEq(governor.voteOf(proposalId, CAROL), 1); + assertEq(governor.voteOf(proposalId, DAVE), 2); + assertEq(governor.voteOf(proposalId, EVE), 2); } function test_quorumNumeratorWorks() public { @@ -392,12 +397,12 @@ contract GhostGovernorTest is Test { uint256 denominator = governor.quorumDenominator(); uint256 currentBlock = block.number; - vm.startPrank(init); - ghst.mint(alice, 1 * 1e18); - ghst.mint(bob, 69 * 1e18); - ghst.mint(carol, 420 * 1e18); - ghst.mint(dave, 1337 * 1e18); - ghst.mint(eve, 69420 * 1e18); + vm.startPrank(INIT); + ghst.mint(ALICE, 1 * 1e18); + ghst.mint(BOB, 69 * 1e18); + ghst.mint(CAROL, 420 * 1e18); + ghst.mint(DAVE, 1337 * 1e18); + ghst.mint(EVE, 69420 * 1e18); vm.stopPrank(); vm.roll(currentBlock + 2); @@ -405,79 +410,79 @@ contract GhostGovernorTest is Test { } function test_votingPowerTransfer() public { - vm.startPrank(init); - ghst.mint(alice, 35 * 1e18); - ghst.mint(bob, 34 * 1e18); + vm.startPrank(INIT); + ghst.mint(ALICE, 35 * 1e18); + ghst.mint(BOB, 34 * 1e18); vm.stopPrank(); vm.roll(block.number + 1); vm.expectRevert(); - vm.prank(alice); - ghst.delegate(alice); + vm.prank(ALICE); + ghst.delegate(ALICE); vm.expectRevert(); - vm.prank(bob); - ghst.delegate(bob); + vm.prank(BOB); + ghst.delegate(BOB); _assertVotesEqualToBalance(); - vm.prank(alice); - ghst.transfer(bob, 420); + vm.prank(ALICE); + ghst.safeTransfer(BOB, 420); _assertVotesEqualToBalance(); - uint256 aliceBalance = ghst.balanceOf(alice); - vm.prank(alice); - ghst.transfer(bob, aliceBalance); + uint256 aliceBalance = ghst.balanceOf(ALICE); + vm.prank(ALICE); + ghst.safeTransfer(BOB, aliceBalance); _assertVotesEqualToBalance(); - vm.prank(bob); - ghst.transfer(carol, 1337); + vm.prank(BOB); + ghst.safeTransfer(CAROL, 1337); _assertVotesEqualToBalance(); - uint256 bobBalance = ghst.balanceOf(bob); - vm.prank(bob); - ghst.transfer(carol, bobBalance); + uint256 bobBalance = ghst.balanceOf(BOB); + vm.prank(BOB); + ghst.safeTransfer(CAROL, bobBalance); _assertVotesEqualToBalance(); vm.expectRevert(); - vm.prank(carol); - ghst.delegate(carol); + vm.prank(CAROL); + ghst.delegate(CAROL); - assertEq(ghst.getVotes(alice), 0); - assertEq(ghst.getVotes(bob), 0); - assertEq(ghst.getVotes(carol), 69 * 1e18); + assertEq(ghst.getVotes(ALICE), 0); + assertEq(ghst.getVotes(BOB), 0); + assertEq(ghst.getVotes(CAROL), 69 * 1e18); - assertEq(ghst.balanceOf(alice), 0); - assertEq(ghst.balanceOf(bob), 0); - assertEq(ghst.balanceOf(carol), 69 * 1e18); + assertEq(ghst.balanceOf(ALICE), 0); + assertEq(ghst.balanceOf(BOB), 0); + assertEq(ghst.balanceOf(CAROL), 69 * 1e18); - vm.prank(init); - ghst.burn(carol, 69 * 1e18); + vm.prank(INIT); + ghst.burn(CAROL, 69 * 1e18); - assertEq(ghst.getVotes(carol), 0); - assertEq(ghst.balanceOf(carol), 0); + assertEq(ghst.getVotes(CAROL), 0); + assertEq(ghst.balanceOf(CAROL), 0); assertEq(ghst.totalSupply(), 0); } function test_changesOfTotalSupplyHasNoAffectOnPastTotalSupply() public { - vm.prank(init); - ghst.mint(alice, 100); + vm.prank(INIT); + ghst.mint(ALICE, 100); vm.roll(block.number + 1); assertEq(ghst.getPastTotalSupply(block.number - 1), 100); assertEq(ghst.totalSupply(), 100); - vm.prank(init); - ghst.burn(alice, 50); + vm.prank(INIT); + ghst.burn(ALICE, 50); vm.roll(block.number + 1); assertEq(ghst.getPastTotalSupply(block.number - 2), 100); assertEq(ghst.getPastTotalSupply(block.number - 1), 50); assertEq(ghst.totalSupply(), 50); - vm.prank(init); - ghst.mint(bob, 150); + vm.prank(INIT); + ghst.mint(BOB, 150); vm.roll(block.number + 1); assertEq(ghst.getPastTotalSupply(block.number - 3), 100); @@ -487,12 +492,12 @@ contract GhostGovernorTest is Test { } function test_proposeAutoForVote() public { - vm.startPrank(init); - ghst.mint(alice, PROPOSAL_THRESHOLD); + vm.startPrank(INIT); + ghst.mint(ALICE, PROPOSAL_THRESHOLD); vm.stopPrank(); vm.roll(block.number + 1); - (uint256 proposalId,,,,) = _proposeDummy(alice, 69); + (uint256 proposalId,,,,) = _proposeDummy(ALICE, 69); (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes) = governor.proposalVotes(proposalId); assertEq(forVotes, PROPOSAL_THRESHOLD); @@ -502,68 +507,68 @@ contract GhostGovernorTest is Test { vm.roll(block.number + 1); vm.expectRevert(); - vm.prank(alice); + vm.prank(ALICE); governor.castVote(proposalId, 1); } function test_releaseAfterDefeated() public { - vm.startPrank(init); - ghst.mint(alice, PROPOSAL_THRESHOLD); - ghst.mint(bob, PROPOSAL_THRESHOLD); - ghst.mint(carol, PROPOSAL_THRESHOLD); + vm.startPrank(INIT); + ghst.mint(ALICE, PROPOSAL_THRESHOLD); + ghst.mint(BOB, PROPOSAL_THRESHOLD); + ghst.mint(CAROL, PROPOSAL_THRESHOLD); vm.stopPrank(); vm.roll(block.number + 1); - (uint256 proposalId,,,,) = _proposeDummy(alice, 69); + (uint256 proposalId,,,,) = _proposeDummy(ALICE, 69); assertEq(governor.releaseLocked(proposalId), 0); - assertEq(ghst.balanceOf(alice), 0); + assertEq(ghst.balanceOf(ALICE), 0); assertEq(ghst.balanceOf(address(governor)), PROPOSAL_THRESHOLD); _waitForActive(proposalId); - _castVoteWrapper(proposalId, bob, 0, true, false); - _castVoteWrapper(proposalId, carol, 0, true, false); + _castVoteWrapper(proposalId, BOB, 0, true, false); + _castVoteWrapper(proposalId, CAROL, 0, true, false); assertEq(uint8(governor.state(proposalId)), uint8(IGovernor.ProposalState.Defeated)); assertEq(governor.releaseLocked(proposalId), PROPOSAL_THRESHOLD); - assertEq(ghst.balanceOf(alice), PROPOSAL_THRESHOLD); + assertEq(ghst.balanceOf(ALICE), PROPOSAL_THRESHOLD); assertEq(ghst.balanceOf(address(governor)), 0); } function test_releaseAfterSucceeded() public { - vm.startPrank(init); - ghst.mint(alice, PROPOSAL_THRESHOLD); - ghst.mint(bob, PROPOSAL_THRESHOLD); - ghst.mint(carol, PROPOSAL_THRESHOLD); + vm.startPrank(INIT); + ghst.mint(ALICE, PROPOSAL_THRESHOLD); + ghst.mint(BOB, PROPOSAL_THRESHOLD); + ghst.mint(CAROL, PROPOSAL_THRESHOLD); vm.stopPrank(); vm.roll(block.number + 1); - (uint256 proposalId,,,,) = _proposeDummy(alice, 69); + (uint256 proposalId,,,,) = _proposeDummy(ALICE, 69); assertEq(governor.releaseLocked(proposalId), 0); - assertEq(ghst.balanceOf(alice), 0); + assertEq(ghst.balanceOf(ALICE), 0); assertEq(ghst.balanceOf(address(governor)), PROPOSAL_THRESHOLD); _waitForActive(proposalId); - _castVoteWrapper(proposalId, bob, 1, true, true); + _castVoteWrapper(proposalId, BOB, 1, true, true); assertEq(uint8(governor.state(proposalId)), uint8(IGovernor.ProposalState.Succeeded)); assertEq(governor.releaseLocked(proposalId), PROPOSAL_THRESHOLD); - assertEq(ghst.balanceOf(alice), PROPOSAL_THRESHOLD); + assertEq(ghst.balanceOf(ALICE), PROPOSAL_THRESHOLD); assertEq(ghst.balanceOf(address(governor)), 0); } function test_releaseAfterDeadline() public { - vm.startPrank(init); - ghst.mint(alice, PROPOSAL_THRESHOLD); - ghst.mint(bob, 420 * PROPOSAL_THRESHOLD); + vm.startPrank(INIT); + ghst.mint(ALICE, PROPOSAL_THRESHOLD); + ghst.mint(BOB, 420 * PROPOSAL_THRESHOLD); vm.stopPrank(); vm.roll(block.number + 1); - (uint256 proposalId,,,,) = _proposeDummy(alice, 69); + (uint256 proposalId,,,,) = _proposeDummy(ALICE, 69); assertEq(governor.releaseLocked(proposalId), 0); - assertEq(ghst.balanceOf(alice), 0); + assertEq(ghst.balanceOf(ALICE), 0); assertEq(ghst.balanceOf(address(governor)), PROPOSAL_THRESHOLD); _waitForActive(proposalId); @@ -571,7 +576,7 @@ contract GhostGovernorTest is Test { assertEq(uint8(governor.state(proposalId)), uint8(IGovernor.ProposalState.Defeated)); assertEq(governor.releaseLocked(proposalId), PROPOSAL_THRESHOLD); - assertEq(ghst.balanceOf(alice), PROPOSAL_THRESHOLD); + assertEq(ghst.balanceOf(ALICE), PROPOSAL_THRESHOLD); assertEq(ghst.balanceOf(address(governor)), 0); } @@ -586,7 +591,7 @@ contract GhostGovernorTest is Test { ) { targets = new address[](1); - targets[0] = address(uint160(index + 1)); + targets[0] = address(uint160(index + 1)); // forge-lint: disable-line(unsafe-typecast) values = new uint256[](1); values[0] = 0; @@ -623,9 +628,9 @@ contract GhostGovernorTest is Test { } function _assertVotesEqualToBalance() private view { - assertEq(ghst.getVotes(alice), ghst.balanceOf(alice)); - assertEq(ghst.getVotes(bob), ghst.balanceOf(bob)); - assertEq(ghst.getVotes(carol), ghst.balanceOf(carol)); + assertEq(ghst.getVotes(ALICE), ghst.balanceOf(ALICE)); + assertEq(ghst.getVotes(BOB), ghst.balanceOf(BOB)); + assertEq(ghst.getVotes(CAROL), ghst.balanceOf(CAROL)); } function _waitForActive(uint256 proposalId) private { diff --git a/test/staking/Staking.t.sol b/test/staking/Staking.t.sol index e89db2f..810a795 100644 --- a/test/staking/Staking.t.sol +++ b/test/staking/Staking.t.sol @@ -2,25 +2,30 @@ pragma solidity 0.8.20; import {Test} from "forge-std/Test.sol"; -import "../../src/FatsoERC20.sol"; -import "../../src/StinkyERC20.sol"; -import "../../src/GhstERC20.sol"; -import "../../src/GhostAuthority.sol"; -import "../../src/StakingDistributor.sol"; -import "../../src/Treasury.sol"; -import "../../src/Staking.sol"; -import "../../src/mocks/ERC20Mock.sol"; -import "../../src/Gatekeeper.sol"; -import "../../src/StandardBondingCalculator.sol"; +import {Fatso} from "../../src/FatsoERC20.sol"; +import {Stinky} from "../../src/StinkyERC20.sol"; +import {Ghost} from "../../src/GhstERC20.sol"; +import {GhostAuthority} from "../../src/GhostAuthority.sol"; +import {GhostDistributor} from "../../src/StakingDistributor.sol"; +import {GhostTreasury} from "../../src/Treasury.sol"; +import {GhostStaking} from "../../src/Staking.sol"; +import {ERC20Mock} from "../../src/mocks/ERC20Mock.sol"; +import {Gatekeeper} from "../../src/Gatekeeper.sol"; +import {GhostBondingCalculator} from "../../src/StandardBondingCalculator.sol"; + +import {ITreasury} from "../../src/interfaces/ITreasury.sol"; +import {SafeERC20} from "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; contract StakingTest is Test { - address constant initializer = 0x0000000000000000000000000000000000000001; - address constant governor = 0x0000000000000000000000000000000000000003; - address constant guardian = 0x0000000000000000000000000000000000000004; - address constant policy = 0x0000000000000000000000000000000000000005; - address constant vault = 0x0000000000000000000000000000000000000006; - address constant alice = 0x0000000000000000000000000000000000000007; - address constant bob = 0x0000000000000000000000000000000000000008; + using SafeERC20 for Stinky; + + address constant INITIALIZER = 0x0000000000000000000000000000000000000001; + address constant GOVERNOR = 0x0000000000000000000000000000000000000003; + address constant GUARDIAN = 0x0000000000000000000000000000000000000004; + address constant POLICY = 0x0000000000000000000000000000000000000005; + address constant VAULT = 0x0000000000000000000000000000000000000006; + address constant ALICE = 0x0000000000000000000000000000000000000007; + address constant BOB = 0x0000000000000000000000000000000000000008; uint48 public constant EPOCH_LENGTH = 2200; uint48 public constant EPOCH_NUMBER = 1; @@ -38,20 +43,20 @@ contract StakingTest is Test { Gatekeeper gatekeeper; GhostBondingCalculator calculator; - uint256 public constant amount = 69; - uint256 public constant bigAmount = amount * 1e9; + uint256 public constant AMOUNT = 69; + uint256 public constant BIG_AMOUNT = AMOUNT * 1e9; event DistributorSet(address distributor); event WarmupSet(uint256 warmup); event Ghosted(bytes32 indexed receiver, uint256 indexed amount); function setUp() public { - vm.startPrank(initializer); + vm.startPrank(INITIALIZER); authority = new GhostAuthority( - governor, - guardian, - policy, - vault + GOVERNOR, + GUARDIAN, + POLICY, + VAULT ); ftso = new Fatso(address(authority), "Fatso", "FTSO"); stnk = new Stinky(INITIAL_INDEX, "Stinky", "STNK"); @@ -84,10 +89,10 @@ contract StakingTest is Test { assertEq(distribute, 0); } - function test_governorCouldSetDistributor(address maybeDistributor) public { + function test_GOVERNORCouldSetDistributor(address maybeDistributor) public { vm.assume(maybeDistributor != address(0)); assertEq(staking.distributor(), address(0)); - vm.prank(governor); + vm.prank(GOVERNOR); staking.setDistributor(maybeDistributor); assertEq(staking.distributor(), maybeDistributor); } @@ -96,21 +101,21 @@ contract StakingTest is Test { vm.assume(maybeDistributor != address(0)); vm.expectEmit(true, true, true, false, address(staking)); emit DistributorSet(maybeDistributor); - vm.prank(governor); + vm.prank(GOVERNOR); staking.setDistributor(maybeDistributor); } function test_arbitraryAddressCouldNotAddDistributor(address someone, address maybeDistributor) public { - vm.assume(maybeDistributor != address(0) && someone != governor); + vm.assume(maybeDistributor != address(0) && someone != GOVERNOR); vm.expectRevert(); vm.prank(someone); staking.setDistributor(maybeDistributor); } - function test_governorCouldSetWarmupPeriod(uint48 maybeWarmupPeriod) public { + function test_GOVERNORCouldSetWarmupPeriod(uint48 maybeWarmupPeriod) public { vm.assume(maybeWarmupPeriod > 0); assertEq(staking.warmupPeriod(), 0); - vm.prank(governor); + vm.prank(GOVERNOR); staking.setWarmupPeriod(maybeWarmupPeriod); assertEq(staking.warmupPeriod(), maybeWarmupPeriod); } @@ -118,233 +123,233 @@ contract StakingTest is Test { function test_emitsWarmupEvent(uint48 maybeWarmupPeriod) public { vm.expectEmit(true, true, true, false, address(staking)); emit WarmupSet(maybeWarmupPeriod); - vm.prank(governor); + vm.prank(GOVERNOR); staking.setWarmupPeriod(maybeWarmupPeriod); } function test_arbitraryAddressCouldNotSetWarmupPeriod(address someone, uint48 maybeWarmupPeriod) public { - vm.assume(maybeWarmupPeriod > 0 && someone != governor); + vm.assume(maybeWarmupPeriod > 0 && someone != GOVERNOR); vm.expectRevert(); vm.prank(someone); staking.setWarmupPeriod(maybeWarmupPeriod); } function test_stake_addAmountToTheWarmupWhenClaimIsFalse() public { - _mintAndApprove(alice, amount); + _mintAndApprove(ALICE, AMOUNT); - vm.prank(alice); - uint256 rebased = staking.stake(amount, alice, false, false); + vm.prank(ALICE); + uint256 rebased = staking.stake(AMOUNT, ALICE, false, false); - assertEq(ftso.balanceOf(alice), 0); + assertEq(ftso.balanceOf(ALICE), 0); assertEq(staking.sharesInWarmup(), stnk.sharesForBalance(rebased)); - (uint256 deposit, uint256 shares, uint48 expiry, bool lock) = staking.warmupInfo(alice); - assertEq(deposit, amount); - assertEq(shares, stnk.sharesForBalance(amount)); + (uint256 deposit, uint256 shares, uint48 expiry, bool lock) = staking.warmupInfo(ALICE); + assertEq(deposit, AMOUNT); + assertEq(shares, stnk.sharesForBalance(AMOUNT)); assertEq(expiry, 1); assertEq(lock, false); } function test_stake_exchangesFatsoToStinkyWhenClaimIsTrueAndRebasingIsTrue() public { - _mintAndApprove(alice, amount); + _mintAndApprove(ALICE, AMOUNT); - vm.prank(alice); - uint256 rebasedAmount = staking.stake(amount, alice, true, true); + vm.prank(ALICE); + uint256 rebasedAmount = staking.stake(AMOUNT, ALICE, true, true); - assertEq(ftso.balanceOf(alice), 0); - assertEq(stnk.balanceOf(alice), rebasedAmount); + assertEq(ftso.balanceOf(ALICE), 0); + assertEq(stnk.balanceOf(ALICE), rebasedAmount); } function test_stake_exchangesFatsoForNewlyMintedGhostWhenClaimIsTrueAndRebasingIsFalse() public { - _mintAndApprove(alice, amount); + _mintAndApprove(ALICE, AMOUNT); - vm.prank(alice); - uint256 rebasedAmount = staking.stake(amount, alice, false, true); + vm.prank(ALICE); + uint256 rebasedAmount = staking.stake(AMOUNT, ALICE, false, true); - assertEq(ftso.balanceOf(alice), 0); - assertEq(ghst.balanceOf(alice), rebasedAmount); + assertEq(ftso.balanceOf(ALICE), 0); + assertEq(ghst.balanceOf(ALICE), rebasedAmount); } function test_stake_addAmountToWarmupWhenClaimIsTrueAndWarmupGtZero() public { - _mintAndApprove(alice, amount); - vm.prank(governor); + _mintAndApprove(ALICE, AMOUNT); + vm.prank(GOVERNOR); staking.setWarmupPeriod(1); - vm.prank(alice); - uint256 rebased = staking.stake(amount, alice, false, true); + vm.prank(ALICE); + uint256 rebased = staking.stake(AMOUNT, ALICE, false, true); - assertEq(ftso.balanceOf(alice), 0); + assertEq(ftso.balanceOf(ALICE), 0); assertEq(staking.sharesInWarmup(), stnk.sharesForBalance(rebased)); - (uint256 deposit, uint256 shares, uint48 expiry, bool lock) = staking.warmupInfo(alice); - assertEq(deposit, amount); - assertEq(shares, stnk.sharesForBalance(amount)); + (uint256 deposit, uint256 shares, uint48 expiry, bool lock) = staking.warmupInfo(ALICE); + assertEq(deposit, AMOUNT); + assertEq(shares, stnk.sharesForBalance(AMOUNT)); assertEq(expiry, 2); assertEq(lock, false); } function test_stake_allowsSelfDepositWhenNotLocked() public { - _mintAndApprove(alice, amount); + _mintAndApprove(ALICE, AMOUNT); - vm.prank(alice); - staking.stake(amount, bob, false, false); + vm.prank(ALICE); + staking.stake(AMOUNT, BOB, false, false); - assertEq(ftso.balanceOf(alice), 0); + assertEq(ftso.balanceOf(ALICE), 0); } function test_stake_disablesExternalDepositsWhenLocked() public { - _mintAndApprove(alice, amount); - vm.prank(bob); + _mintAndApprove(ALICE, AMOUNT); + vm.prank(BOB); staking.toggleLock(); vm.expectRevert(); - vm.prank(alice); - staking.stake(amount, bob, false, false); + vm.prank(ALICE); + staking.stake(AMOUNT, BOB, false, false); - assertEq(ftso.balanceOf(alice), amount); + assertEq(ftso.balanceOf(ALICE), AMOUNT); } function test_claim_transferStinkyWhenRebasingIsTrue() public { - _prepareAndRoll(alice, amount, false, false); + _prepareAndRoll(ALICE, AMOUNT, false, false); - assertEq(stnk.balanceOf(alice), 0); - vm.prank(alice); - uint256 rebased = staking.claim(alice, true); - assertEq(stnk.balanceOf(alice), rebased); + assertEq(stnk.balanceOf(ALICE), 0); + vm.prank(ALICE); + uint256 rebased = staking.claim(ALICE, true); + assertEq(stnk.balanceOf(ALICE), rebased); assertEq(rebased > 0, true); } function test_claim_mintsGhostWhenRebasingIsFalse() public { - _prepareAndRoll(alice, amount, false, false); + _prepareAndRoll(ALICE, AMOUNT, false, false); - assertEq(ghst.balanceOf(alice), 0); - vm.prank(alice); - uint256 rebased = staking.claim(alice, false); - assertEq(ghst.balanceOf(alice), rebased); + assertEq(ghst.balanceOf(ALICE), 0); + vm.prank(ALICE); + uint256 rebased = staking.claim(ALICE, false); + assertEq(ghst.balanceOf(ALICE), rebased); assertEq(rebased > 0, true); } function test_claim_preventsExternalClaimsWhenLocked() public { - _prepareAndRoll(alice, amount, false, false); + _prepareAndRoll(ALICE, AMOUNT, false, false); - assertEq(ghst.balanceOf(alice), 0); - vm.prank(alice); + assertEq(ghst.balanceOf(ALICE), 0); + vm.prank(ALICE); staking.toggleLock(); vm.expectRevert(); - vm.prank(bob); - staking.claim(alice, false); - assertEq(ghst.balanceOf(alice), 0); + vm.prank(BOB); + staking.claim(ALICE, false); + assertEq(ghst.balanceOf(ALICE), 0); } function test_claim_allowExternalClaimsWhenNotLocked() public { - _prepareAndRoll(alice, amount, false, false); + _prepareAndRoll(ALICE, AMOUNT, false, false); - assertEq(ghst.balanceOf(alice), 0); - vm.prank(bob); - uint256 rebased = staking.claim(alice, false); - assertEq(ghst.balanceOf(alice), rebased); + assertEq(ghst.balanceOf(ALICE), 0); + vm.prank(BOB); + uint256 rebased = staking.claim(ALICE, false); + assertEq(ghst.balanceOf(ALICE), rebased); assertEq(rebased > 0, true); } function test_claim_doesNothingWhenThereIsNothingToClaim() public { - assertEq(ghst.balanceOf(alice), 0); - vm.prank(alice); - uint256 rebased = staking.claim(alice, false); - assertEq(ghst.balanceOf(alice), 0); + assertEq(ghst.balanceOf(ALICE), 0); + vm.prank(ALICE); + uint256 rebased = staking.claim(ALICE, false); + assertEq(ghst.balanceOf(ALICE), 0); assertEq(rebased, 0); } function test_claim_doesNothingWhenWarmupIsntOver() public { - _mintAndApprove(alice, amount); - vm.prank(governor); + _mintAndApprove(ALICE, AMOUNT); + vm.prank(GOVERNOR); staking.setWarmupPeriod(1337); - vm.prank(alice); - staking.stake(amount, alice, false, false); + vm.prank(ALICE); + staking.stake(AMOUNT, ALICE, false, false); - assertEq(stnk.balanceOf(alice), 0); - vm.prank(alice); - uint256 rebased = staking.claim(alice, true); - assertEq(stnk.balanceOf(alice), 0); + assertEq(stnk.balanceOf(ALICE), 0); + vm.prank(ALICE); + uint256 rebased = staking.claim(ALICE, true); + assertEq(stnk.balanceOf(ALICE), 0); assertEq(rebased, 0); } function test_forefeit_removesStakeFromWarmupAndReturnsFatso() public { - _prepareAndRoll(alice, amount, false, false); + _prepareAndRoll(ALICE, AMOUNT, false, false); - assertEq(ftso.balanceOf(alice), 0); - assertEq(staking.sharesInWarmup(), stnk.sharesForBalance(amount)); + assertEq(ftso.balanceOf(ALICE), 0); + assertEq(staking.sharesInWarmup(), stnk.sharesForBalance(AMOUNT)); - vm.prank(alice); + vm.prank(ALICE); uint256 deposit = staking.forfeit(); - assertEq(ftso.balanceOf(alice), deposit); + assertEq(ftso.balanceOf(ALICE), deposit); assertEq(staking.sharesInWarmup(), 0); - (uint256 depositInWarmup, uint256 shares, uint48 expiry,) = staking.warmupInfo(alice); + (uint256 depositInWarmup, uint256 shares, uint48 expiry,) = staking.warmupInfo(ALICE); assertEq(depositInWarmup, 0); assertEq(shares, 0); assertEq(expiry, 0); } function test_forefeit_transfersZeroIfThereIsNoBalanceInWarmup() public { - vm.prank(alice); + vm.prank(ALICE); uint256 deposit = staking.forfeit(); assertEq(deposit, 0); - assertEq(ftso.balanceOf(alice), 0); + assertEq(ftso.balanceOf(ALICE), 0); assertEq(staking.sharesInWarmup(), 0); } function test_unstake_canRedeemStinkyToFatso() public { - _prepareAndRoll(alice, amount, true, true); - uint256 aliceBalance = stnk.balanceOf(alice); - vm.startPrank(alice); + _prepareAndRoll(ALICE, AMOUNT, true, true); + uint256 aliceBalance = stnk.balanceOf(ALICE); + vm.startPrank(ALICE); stnk.approve(address(staking), aliceBalance); - staking.unstake(aliceBalance, alice, false, true); + staking.unstake(aliceBalance, ALICE, false, true); vm.stopPrank(); - assertEq(stnk.balanceOf(alice), 0); - assertEq(ftso.balanceOf(alice), amount); + assertEq(stnk.balanceOf(ALICE), 0); + assertEq(ftso.balanceOf(ALICE), AMOUNT); } function test_unstake_canRedeemGhostToFatso() public { - _prepareAndRoll(alice, amount, false, true); - uint256 aliceBalance = ghst.balanceOf(alice); - vm.startPrank(alice); + _prepareAndRoll(ALICE, AMOUNT, false, true); + uint256 aliceBalance = ghst.balanceOf(ALICE); + vm.startPrank(ALICE); ghst.approve(address(staking), aliceBalance); vm.roll(block.number + 69); - staking.unstake(aliceBalance, alice, false, false); + staking.unstake(aliceBalance, ALICE, false, false); vm.stopPrank(); - assertEq(ghst.balanceOf(alice), 0); - assertEq(ftso.balanceOf(alice), ghst.balanceFrom(aliceBalance)); + assertEq(ghst.balanceOf(ALICE), 0); + assertEq(ftso.balanceOf(ALICE), ghst.balanceFrom(aliceBalance)); } function test_wrap_convertsStinkyIntoGhost() public { - _prepareAndRoll(alice, amount, true, true); - uint256 aliceBalance = stnk.balanceOf(alice); - assertEq(ghst.balanceOf(alice), 0); + _prepareAndRoll(ALICE, AMOUNT, true, true); + uint256 aliceBalance = stnk.balanceOf(ALICE); + assertEq(ghst.balanceOf(ALICE), 0); - vm.startPrank(alice); + vm.startPrank(ALICE); stnk.approve(address(staking), aliceBalance); - uint256 newBalance = staking.wrap(alice, aliceBalance); + uint256 newBalance = staking.wrap(ALICE, aliceBalance); vm.stopPrank(); - assertEq(stnk.balanceOf(alice), 0); - assertEq(ghst.balanceOf(alice), newBalance); + assertEq(stnk.balanceOf(ALICE), 0); + assertEq(ghst.balanceOf(ALICE), newBalance); } function test_wrap_convertsGhostToStinky() public { - _prepareAndRoll(alice, amount, false, true); - uint256 aliceBalance = ghst.balanceOf(alice); - assertEq(stnk.balanceOf(alice), 0); + _prepareAndRoll(ALICE, AMOUNT, false, true); + uint256 aliceBalance = ghst.balanceOf(ALICE); + assertEq(stnk.balanceOf(ALICE), 0); vm.roll(block.number + 69); - vm.startPrank(alice); + vm.startPrank(ALICE); ghst.approve(address(staking), aliceBalance); - uint256 newBalance = staking.unwrap(alice, aliceBalance); + uint256 newBalance = staking.unwrap(ALICE, aliceBalance); vm.stopPrank(); - assertEq(ghst.balanceOf(alice), 0); - assertEq(stnk.balanceOf(alice), newBalance); + assertEq(ghst.balanceOf(ALICE), 0); + assertEq(stnk.balanceOf(ALICE), newBalance); } function test_rebase_doesNothingIfTheBlockIsBeforeTheEpochEndBlock() public { @@ -373,11 +378,11 @@ contract StakingTest is Test { assertEq(endBefore > block.timestamp, true); vm.prank(address(staking)); - stnk.transfer(alice, amount); - vm.prank(vault); - ftso.mint(address(staking), amount); + stnk.safeTransfer(ALICE, AMOUNT); + vm.prank(VAULT); + ftso.mint(address(staking), AMOUNT); - assertEq(stnk.balanceOf(alice), ftso.balanceOf(address(staking))); + assertEq(stnk.balanceOf(ALICE), ftso.balanceOf(address(staking))); vm.warp(endBefore); staking.rebase(); @@ -393,9 +398,9 @@ contract StakingTest is Test { assertEq(endBefore > block.timestamp, true); vm.prank(address(staking)); - stnk.transfer(alice, amount); - vm.prank(vault); - ftso.mint(address(staking), amount * 2); + stnk.safeTransfer(ALICE, AMOUNT); + vm.prank(VAULT); + ftso.mint(address(staking), AMOUNT * 2); vm.warp(endBefore); staking.rebase(); @@ -403,13 +408,13 @@ contract StakingTest is Test { (, uint48 numberAfter, uint48 endAfter, uint256 distributeAfter) = staking.epoch(); assertEq(endAfter, endBefore + length); assertEq(numberAfter, numberBefore + 1); - assertEq(distributeAfter, amount); + assertEq(distributeAfter, AMOUNT); } function test_rebase_callDistributorIfSet() public { (uint48 length, uint48 numberBefore, uint48 endBefore,) = staking.epoch(); assertEq(endBefore > block.timestamp, true); - uint256 extendedAmount = amount * 1e18; + uint256 extendedAmount = AMOUNT * 1e18; GhostDistributor distributor = new GhostDistributor( address(treasury), @@ -420,33 +425,33 @@ contract StakingTest is Test { ); ERC20Mock reserve = new ERC20Mock("Reserve Token", "RET"); - vm.startPrank(governor); + vm.startPrank(GOVERNOR); authority.pushVault(address(treasury)); staking.setDistributor(address(distributor)); treasury.enable(ITreasury.STATUS.REWARDMANAGER, address(distributor), address(0)); - treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, alice, address(0)); - treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, bob, address(0)); + treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, ALICE, address(0)); + treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, BOB, address(0)); treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator)); vm.stopPrank(); - vm.startPrank(bob); - reserve.mint(bob, extendedAmount); + vm.startPrank(BOB); + reserve.mint(BOB, extendedAmount); reserve.approve(address(treasury), extendedAmount); uint256 zeroProfit = treasury.tokenValue(address(reserve), extendedAmount); treasury.deposit(address(reserve), extendedAmount, zeroProfit); vm.stopPrank(); - vm.startPrank(alice); + vm.startPrank(ALICE); assertEq(ftso.balanceOf(address(staking)), 0); - reserve.mint(alice, extendedAmount); + reserve.mint(ALICE, extendedAmount); reserve.approve(address(treasury), extendedAmount); uint256 send = treasury.deposit(address(reserve), extendedAmount, 0); - assertEq(ftso.balanceOf(alice), send); + assertEq(ftso.balanceOf(ALICE), send); assertEq(reserve.balanceOf(address(treasury)), extendedAmount * 2); ftso.approve(address(staking), send); - staking.stake(send, alice, true, true); + staking.stake(send, ALICE, true, true); assertEq(ftso.balanceOf(address(staking)), send); - assertEq(stnk.balanceOf(alice), send); + assertEq(stnk.balanceOf(ALICE), send); vm.stopPrank(); assertEq(treasury.excessReserves(), send); @@ -465,7 +470,7 @@ contract StakingTest is Test { } function test_correctStakeAmountDuringRebase() public { - uint256 extendedAmount = amount * 1e18; + uint256 extendedAmount = AMOUNT * 1e18; uint256 bounty = 1; GhostDistributor distributor = new GhostDistributor( address(treasury), @@ -476,34 +481,34 @@ contract StakingTest is Test { ); ERC20Mock reserve = new ERC20Mock("Reserve Token", "RET"); - vm.startPrank(governor); + vm.startPrank(GOVERNOR); authority.pushVault(address(treasury)); staking.setDistributor(address(distributor)); distributor.setBounty(bounty); treasury.enable(ITreasury.STATUS.REWARDMANAGER, address(distributor), address(0)); - treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, alice, address(0)); + treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, ALICE, address(0)); treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator)); vm.stopPrank(); - vm.startPrank(alice); - reserve.mint(alice, extendedAmount); + vm.startPrank(ALICE); + reserve.mint(ALICE, extendedAmount); reserve.approve(address(treasury), type(uint256).max); - uint256 profit = treasury.tokenValue(address(reserve), extendedAmount) - amount; + uint256 profit = treasury.tokenValue(address(reserve), extendedAmount) - AMOUNT; treasury.deposit(address(reserve), extendedAmount, profit); vm.stopPrank(); (,, uint48 end,) = staking.epoch(); skip(end); - vm.startPrank(alice); + vm.startPrank(ALICE); ftso.approve(address(staking), type(uint256).max); - staking.stake(amount, alice, true, true); + staking.stake(AMOUNT, ALICE, true, true); vm.stopPrank(); - uint256 postBounty = amount + bounty; + uint256 postBounty = AMOUNT + bounty; - assertEq(stnk.balanceOf(alice), postBounty); + assertEq(stnk.balanceOf(ALICE), postBounty); assertEq(ftso.balanceOf(address(staking)), postBounty); skip(end + EPOCH_LENGTH); @@ -511,21 +516,21 @@ contract StakingTest is Test { (,,, uint256 distribute) = staking.epoch(); assertEq(distribute, postBounty); - assertEq(stnk.balanceOf(alice), postBounty); + assertEq(stnk.balanceOf(ALICE), postBounty); assertEq(ftso.balanceOf(address(staking)), 2 * postBounty + bounty); } function test_arbitraryAddressCouldNotAddGatekeeper(address someone, address maybeGatekeeper) public { - vm.assume(maybeGatekeeper != address(0) && someone != governor); + vm.assume(maybeGatekeeper != address(0) && someone != GOVERNOR); vm.expectRevert(); vm.prank(someone); staking.setDistributor(maybeGatekeeper); } - function test_governorCouldSetGatekeeper(address maybeGatekeeper) public { + function test_GOVERNORCouldSetGatekeeper(address maybeGatekeeper) public { vm.assume(maybeGatekeeper != address(0)); assertEq(staking.gatekeeper(), address(0)); - vm.prank(governor); + vm.prank(GOVERNOR); staking.setGatekeeperAddress(maybeGatekeeper); assertEq(staking.gatekeeper(), maybeGatekeeper); } @@ -533,80 +538,80 @@ contract StakingTest is Test { function test_couldNotGhostIfNoGatekeeper() public { assertEq(staking.ghostedSupply(), 0); vm.expectRevert(); - staking.ghost(bytes32(abi.encodePacked(alice)), amount); + staking.ghost(bytes32(abi.encodePacked(ALICE)), AMOUNT); assertEq(staking.ghostedSupply(), 0); } function test_couldNotMaterializeIfNoGatekeeper() public { assertEq(staking.ghostedSupply(), 0); vm.expectRevert(); - staking.materialize(alice, amount, 0, 0); // dummy rx and s + staking.materialize(ALICE, AMOUNT, 0, 0); // dummy rx and s assertEq(staking.ghostedSupply(), 0); } function test_couldNotGhostTokensIfNoGhst() public { assertEq(staking.gatekeeper(), address(0)); - vm.prank(governor); + vm.prank(GOVERNOR); staking.setGatekeeperAddress(address(gatekeeper)); assertEq(staking.gatekeeper(), address(gatekeeper)); assertEq(staking.ghostedSupply(), 0); vm.expectRevert(); - vm.prank(alice); - staking.ghost(bytes32(abi.encodePacked(alice)), amount); + vm.prank(ALICE); + staking.ghost(bytes32(abi.encodePacked(ALICE)), AMOUNT); assertEq(staking.ghostedSupply(), 0); } function test_correctlyGhostTokens() public { assertEq(staking.gatekeeper(), address(0)); - vm.prank(governor); + vm.prank(GOVERNOR); staking.setGatekeeperAddress(address(gatekeeper)); assertEq(staking.gatekeeper(), address(gatekeeper)); - _prepareAndRoll(alice, bigAmount, true, true); - uint256 aliceBalance = stnk.balanceOf(alice); + _prepareAndRoll(ALICE, BIG_AMOUNT, true, true); + uint256 aliceBalance = stnk.balanceOf(ALICE); - vm.startPrank(alice); + vm.startPrank(ALICE); stnk.approve(address(staking), aliceBalance); - uint256 ghstBalance = staking.wrap(alice, aliceBalance); + uint256 ghstBalance = staking.wrap(ALICE, aliceBalance); vm.stopPrank(); assertEq(staking.ghostedSupply(), 0); - assertEq(stnk.circulatingSupply(), bigAmount - 1); // precision fix + assertEq(stnk.circulatingSupply(), BIG_AMOUNT - 1); // precision fix assertEq(ghst.totalSupply(), ghstBalance); - vm.prank(alice); - staking.ghost(bytes32(abi.encodePacked(alice)), ghstBalance); + vm.prank(ALICE); + staking.ghost(bytes32(abi.encodePacked(ALICE)), ghstBalance); assertEq(staking.ghostedSupply(), ghstBalance); - assertEq(stnk.circulatingSupply(), bigAmount - 1); // precision fix + assertEq(stnk.circulatingSupply(), BIG_AMOUNT - 1); // precision fix assertEq(ghst.totalSupply(), 0); } function test_ghostTokensEmitsEvent() public { assertEq(staking.gatekeeper(), address(0)); - vm.prank(governor); + vm.prank(GOVERNOR); staking.setGatekeeperAddress(address(gatekeeper)); assertEq(staking.gatekeeper(), address(gatekeeper)); - _prepareAndRoll(alice, bigAmount, true, true); - uint256 aliceBalance = stnk.balanceOf(alice); + _prepareAndRoll(ALICE, BIG_AMOUNT, true, true); + uint256 aliceBalance = stnk.balanceOf(ALICE); - vm.startPrank(alice); + vm.startPrank(ALICE); stnk.approve(address(staking), aliceBalance); - uint256 ghstBalance = staking.wrap(alice, aliceBalance); + uint256 ghstBalance = staking.wrap(ALICE, aliceBalance); vm.stopPrank(); - bytes32 receiver = bytes32(abi.encodePacked(alice)); + bytes32 receiver = bytes32(abi.encodePacked(ALICE)); vm.expectEmit(true, true, true, false, address(gatekeeper)); emit Ghosted(receiver, ghstBalance); - vm.prank(alice); + vm.prank(ALICE); staking.ghost(receiver, ghstBalance); } function _mintAndApprove(address who, uint256 value) internal { - vm.prank(vault); + vm.prank(VAULT); ftso.mint(who, value); vm.prank(who); ftso.approve(address(staking), value); @@ -621,7 +626,7 @@ contract StakingTest is Test { vm.prank(who); uint256 rebased = staking.stake(value, who, rebase, claim); - (,, uint48 expiry,) = staking.warmupInfo(alice); + (,, uint48 expiry,) = staking.warmupInfo(ALICE); vm.roll(expiry); return rebased; } diff --git a/test/staking/StakingDistributor.t.sol b/test/staking/StakingDistributor.t.sol index 3d9ee9d..f9906a3 100644 --- a/test/staking/StakingDistributor.t.sol +++ b/test/staking/StakingDistributor.t.sol @@ -2,30 +2,32 @@ pragma solidity 0.8.20; import {Test} from "forge-std/Test.sol"; -import "../../src/FatsoERC20.sol"; -import "../../src/StinkyERC20.sol"; -import "../../src/GhstERC20.sol"; -import "../../src/GhostAuthority.sol"; -import "../../src/StakingDistributor.sol"; -import "../../src/Treasury.sol"; -import "../../src/Staking.sol"; -import "../../src/mocks/ERC20Mock.sol"; -import "../../src/StandardBondingCalculator.sol"; +import {Fatso} from "../../src/FatsoERC20.sol"; +import {Stinky} from "../../src/StinkyERC20.sol"; +import {Ghost} from "../../src/GhstERC20.sol"; +import {GhostAuthority} from "../../src/GhostAuthority.sol"; +import {GhostDistributor} from "../../src/StakingDistributor.sol"; +import {GhostTreasury} from "../../src/Treasury.sol"; +import {GhostStaking} from "../../src/Staking.sol"; +import {ERC20Mock} from "../../src/mocks/ERC20Mock.sol"; +import {GhostBondingCalculator} from "../../src/StandardBondingCalculator.sol"; + +import {ITreasury} from "../../src/interfaces/ITreasury.sol"; contract StakingDistributorTest is Test { - address public constant owner = 0x0000000000000000000000000000000000000001; - address public constant governor = 0x0000000000000000000000000000000000000002; - address public constant guardian = 0x0000000000000000000000000000000000000003; - address public constant other = 0x0000000000000000000000000000000000000004; - address public constant alice = 0x0000000000000000000000000000000000000005; - address public constant bob = 0x0000000000000000000000000000000000000006; + address public constant OWNER = 0x0000000000000000000000000000000000000001; + address public constant GOVERNOR = 0x0000000000000000000000000000000000000002; + address public constant GUARDIAN = 0x0000000000000000000000000000000000000003; + address public constant OTHER = 0x0000000000000000000000000000000000000004; + address public constant ALICE = 0x0000000000000000000000000000000000000005; + address public constant BOB = 0x0000000000000000000000000000000000000006; uint48 public constant EPOCH_LENGTH = 2200; uint48 public constant EPOCH_NUMBER = 1; uint48 public constant EPOCH_END_TIME = 1337; uint256 public constant INITIAL_INDEX = 10819917194513808e56; - uint256 public constant amount = 69 * 1e18; + uint256 public constant AMOUNT = 69 * 1e18; Fatso ftso; Stinky stnk; @@ -41,12 +43,12 @@ contract StakingDistributorTest is Test { uint256 public constant TEN_PERCENT = 1e5; function setUp() public { - vm.startPrank(owner); + vm.startPrank(OWNER); authority = new GhostAuthority( - governor, - guardian, - owner, - owner + GOVERNOR, + GUARDIAN, + OWNER, + OWNER ); reserve = new ERC20Mock("Reserve Token", "RET"); ftso = new Fatso(address(authority), "Fatso", "FTSO"); @@ -74,7 +76,7 @@ contract StakingDistributorTest is Test { ghst.initialize(address(staking)); vm.stopPrank(); - vm.startPrank(governor); + vm.startPrank(GOVERNOR); staking.setDistributor(address(distributor)); authority.pushVault(address(treasury)); vm.stopPrank(); @@ -83,7 +85,7 @@ contract StakingDistributorTest is Test { function test_distribute_onlyByStaking() public { _prepareTreasury(); vm.expectRevert(); - vm.prank(other); + vm.prank(OTHER); distributor.distribute(); vm.prank(address(staking)); @@ -91,11 +93,11 @@ contract StakingDistributorTest is Test { } function test_bounty_onlyByGovernor(address who) public { - vm.assume(who != governor); + vm.assume(who != GOVERNOR); _prepareTreasury(); assertEq(ftso.balanceOf(address(staking)), 0); - vm.prank(governor); + vm.prank(GOVERNOR); distributor.setBounty(1337); vm.prank(address(staking)); @@ -104,23 +106,23 @@ contract StakingDistributorTest is Test { } function test_nextRewardFor_zeroIfAddressIsEmpty() public view { - assertEq(ftso.balanceOf(bob), 0); - assertEq(distributor.nextRewardFor(bob), 0); + assertEq(ftso.balanceOf(BOB), 0); + assertEq(distributor.nextRewardFor(BOB), 0); } function test_nextRewardFor_nextRewardForAddress() public { _prepareTreasury(); - vm.startPrank(bob); - reserve.mint(bob, amount); - reserve.approve(address(treasury), amount); - uint256 send = treasury.deposit(address(reserve), amount, treasury.tokenValue(address(reserve), amount)); + vm.startPrank(BOB); + reserve.mint(BOB, AMOUNT); + reserve.approve(address(treasury), AMOUNT); + uint256 send = treasury.deposit(address(reserve), AMOUNT, treasury.tokenValue(address(reserve), AMOUNT)); vm.stopPrank(); - assertEq(ftso.balanceOf(bob), send); - assertEq(distributor.nextRewardFor(bob), send * TEN_PERCENT / 1e6); + assertEq(ftso.balanceOf(BOB), send); + assertEq(distributor.nextRewardFor(BOB), send * TEN_PERCENT / 1e6); } function test_setBounty_shouldRevertIfNotByGovernor(address who) public { - vm.assume(who != governor); + vm.assume(who != GOVERNOR); assertEq(distributor.bounty(), 0); vm.expectRevert(); vm.prank(who); @@ -128,16 +130,16 @@ contract StakingDistributorTest is Test { assertEq(distributor.bounty(), 0); } - function test_setBounty_governorShouldSet() public { + function test_setBounty_GOVERNORShouldSet() public { _prepareTreasury(); assertEq(distributor.bounty(), 0); - vm.prank(governor); + vm.prank(GOVERNOR); distributor.setBounty(1337); assertEq(distributor.bounty(), 1337); } function test_setPools_shouldRevertIfNotGovernor(address who) public { - vm.assume(who != governor); + vm.assume(who != GOVERNOR); address[] memory newPools = new address[](1); newPools[0] = who; vm.expectRevert(); @@ -145,19 +147,19 @@ contract StakingDistributorTest is Test { distributor.setPools(newPools); } - function test_setPools_governorShouldSet() public { + function test_setPools_GOVERNORShouldSet() public { address[] memory newPools = new address[](1); - newPools[0] = other; - vm.prank(governor); + newPools[0] = OTHER; + vm.prank(GOVERNOR); distributor.setPools(newPools); - assertEq(distributor.pools(0), other); + assertEq(distributor.pools(0), OTHER); } function test_removePools_shouldRevertIfNotGovernor(address who) public { - vm.assume(who != governor); + vm.assume(who != GOVERNOR); address[] memory newPools = new address[](1); - newPools[0] = other; - vm.prank(governor); + newPools[0] = OTHER; + vm.prank(GOVERNOR); distributor.setPools(newPools); vm.expectRevert(); @@ -165,43 +167,43 @@ contract StakingDistributorTest is Test { distributor.removePool(0); } - function test_removePools_governorShouldRemove() public { + function test_removePools_GOVERNORShouldRemove() public { address[] memory newPools = new address[](1); - newPools[0] = other; - vm.startPrank(governor); + newPools[0] = OTHER; + vm.startPrank(GOVERNOR); distributor.setPools(newPools); - assertEq(distributor.pools(0), other); + assertEq(distributor.pools(0), OTHER); distributor.removePool(0); vm.stopPrank(); } function test_addPool_shouldRevertIfNotGovernor(address who) public { - vm.assume(who != governor); + vm.assume(who != GOVERNOR); vm.expectRevert(); vm.prank(who); - distributor.addPool(other); + distributor.addPool(OTHER); } function test_addPool_shouldPushPoolWhenIndexTaken() public { - vm.prank(governor); - distributor.addPool(other); - assertEq(distributor.pools(0), other); + vm.prank(GOVERNOR); + distributor.addPool(OTHER); + assertEq(distributor.pools(0), OTHER); } function test_setAdjustment_shouldRevertIfNotGovernor(address who) public { - vm.assume(who != governor && who != guardian); + vm.assume(who != GOVERNOR && who != GUARDIAN); vm.expectRevert(); vm.prank(who); distributor.setAdjustment(69, 1337, true); } - function test_setAdjustment_governorShouldIncreaseAdjustment() public { - vm.prank(governor); + function test_setAdjustment_GOVERNORShouldIncreaseAdjustment() public { + vm.prank(GOVERNOR); distributor.setAdjustment(69, 1337, false); } function test_setAdjustment_shouldPopulateAdjustmentToRewardRateAfterRebase() public { - vm.prank(governor); + vm.prank(GOVERNOR); distributor.setAdjustment(69, TEN_PERCENT * 2, true); _prepareTreasury(); @@ -213,7 +215,7 @@ contract StakingDistributorTest is Test { } function test_setAdjustment_willNotAdjustIfRateIsZero() public { - vm.prank(governor); + vm.prank(GOVERNOR); distributor.setAdjustment(0, 1337, true); _prepareTreasury(); @@ -225,7 +227,7 @@ contract StakingDistributorTest is Test { } function test_setAdjustment_willStopIncreaseWhenTargetMet() public { - vm.prank(governor); + vm.prank(GOVERNOR); distributor.setAdjustment(69, 1337, true); _prepareTreasury(); @@ -237,7 +239,7 @@ contract StakingDistributorTest is Test { } function test_setAdjustment_willStopDecreaseWhenTargetMet() public { - vm.prank(governor); + vm.prank(GOVERNOR); distributor.setAdjustment(TEN_PERCENT, 1337, false); _prepareTreasury(); @@ -249,17 +251,17 @@ contract StakingDistributorTest is Test { } function _prepareTreasury() internal { - vm.startPrank(governor); + vm.startPrank(GOVERNOR); treasury.enable(ITreasury.STATUS.REWARDMANAGER, address(distributor), address(0)); - treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, alice, address(0)); - treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, bob, address(0)); + treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, ALICE, address(0)); + treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, BOB, address(0)); treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator)); vm.stopPrank(); - vm.startPrank(alice); - reserve.mint(alice, amount); - reserve.approve(address(treasury), amount); - treasury.deposit(address(reserve), amount, treasury.tokenValue(address(reserve), amount)); + vm.startPrank(ALICE); + reserve.mint(ALICE, AMOUNT); + reserve.approve(address(treasury), AMOUNT); + treasury.deposit(address(reserve), AMOUNT, treasury.tokenValue(address(reserve), AMOUNT)); vm.stopPrank(); } } diff --git a/test/tokens/Allowance.t.sol b/test/tokens/Allowance.t.sol index b64bd06..bc8bbab 100644 --- a/test/tokens/Allowance.t.sol +++ b/test/tokens/Allowance.t.sol @@ -1,9 +1,12 @@ pragma solidity 0.8.20; import {Test} from "forge-std/Test.sol"; -import "@openzeppelin-contracts/token/ERC20/ERC20.sol"; +import {ERC20} from "@openzeppelin-contracts/token/ERC20/ERC20.sol"; +import {SafeERC20} from "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; abstract contract ERC20AllowanceTest is Test { + using SafeERC20 for ERC20; + ERC20 tokenAllowance; uint256 amountAllowance; uint256 maxAmountAllowance; @@ -43,9 +46,9 @@ abstract contract ERC20AllowanceTest is Test { assertEq(tokenAllowance.balanceOf(aliceAllowance), amountAllowance); assertEq(tokenAllowance.balanceOf(bobAllowance), 0); assertEq(tokenAllowance.allowance(aliceAllowance, bobAllowance), amountAllowance); + vm.prank(bobAllowance); - bool success = tokenAllowance.transferFrom(aliceAllowance, bobAllowance, amountAllowance); - assertEq(success, true); + tokenAllowance.safeTransferFrom(aliceAllowance, bobAllowance, amountAllowance); assertEq(tokenAllowance.balanceOf(aliceAllowance), 0); assertEq(tokenAllowance.balanceOf(bobAllowance), amountAllowance); assertEq(tokenAllowance.allowance(aliceAllowance, bobAllowance), 0); @@ -58,9 +61,13 @@ abstract contract ERC20AllowanceTest is Test { assertEq(tokenAllowance.balanceOf(aliceAllowance), amountAllowance); assertEq(tokenAllowance.balanceOf(bobAllowance), 0); assertEq(tokenAllowance.allowance(aliceAllowance, bobAllowance), maxAmountAllowance); + vm.expectRevert(); vm.prank(bobAllowance); - tokenAllowance.transferFrom(aliceAllowance, bobAllowance, maxAmountAllowance); + assertEq(tokenAllowance.transferFrom(aliceAllowance, bobAllowance, maxAmountAllowance), false); + assertEq(tokenAllowance.balanceOf(aliceAllowance), amountAllowance); + assertEq(tokenAllowance.balanceOf(bobAllowance), 0); + assertEq(tokenAllowance.allowance(aliceAllowance, bobAllowance), maxAmountAllowance); } function test_allowance_couldNotTransferFromIfNotEnoughAllowance() public { @@ -70,9 +77,13 @@ abstract contract ERC20AllowanceTest is Test { assertEq(tokenAllowance.balanceOf(aliceAllowance), maxRealAmountAllowance); assertEq(tokenAllowance.balanceOf(bobAllowance), 0); assertEq(tokenAllowance.allowance(aliceAllowance, bobAllowance), amountAllowance); + vm.expectRevert(); vm.prank(bobAllowance); - tokenAllowance.transferFrom(aliceAllowance, bobAllowance, maxAmountAllowance); + assertEq(tokenAllowance.transferFrom(aliceAllowance, bobAllowance, maxAmountAllowance), false); + assertEq(tokenAllowance.balanceOf(aliceAllowance), maxRealAmountAllowance); + assertEq(tokenAllowance.balanceOf(bobAllowance), 0); + assertEq(tokenAllowance.allowance(aliceAllowance, bobAllowance), amountAllowance); } function _mintAllowanceTokens(address who, uint256 value) internal virtual; diff --git a/test/tokens/Ftso.t.sol b/test/tokens/Ftso.t.sol index b60eea1..b38ece5 100644 --- a/test/tokens/Ftso.t.sol +++ b/test/tokens/Ftso.t.sol @@ -2,99 +2,100 @@ pragma solidity 0.8.20; import {Test} from "forge-std/Test.sol"; -import "../../src/FatsoERC20.sol"; -import "../../src/GhostAuthority.sol"; +import {Fatso} from "../../src/FatsoERC20.sol"; +import {GhostAuthority} from "../../src/GhostAuthority.sol"; +import {GhostAccessControlled} from "../../src/types/GhostAccessControlled.sol"; -import "./Permit.t.sol"; -import "./Allowance.t.sol"; -import "./Transfer.t.sol"; +import {ERC20PermitTest} from "./Permit.t.sol"; +import {ERC20AllowanceTest} from "./Allowance.t.sol"; +import {ERC20TransferTest} from "./Transfer.t.sol"; contract FatsoTest is Test, ERC20PermitTest, ERC20AllowanceTest, ERC20TransferTest { GhostAuthority authority; Fatso token; - address constant deployer = 0x0000000000000000000000000000000000000001; - address constant vault = 0x0000000000000000000000000000000000000002; - address constant alice = 0x0000000000000000000000000000000000000003; - address constant bob = 0x0000000000000000000000000000000000000004; - uint256 constant amount = 69; - uint256 constant maxAmount = type(uint256).max; + address constant DEPLOYER = 0x0000000000000000000000000000000000000001; + address constant VAULT = 0x0000000000000000000000000000000000000002; + address constant ALICE = 0x0000000000000000000000000000000000000003; + address constant BOB = 0x0000000000000000000000000000000000000004; + uint256 constant AMOUNT = 69; + uint256 constant MAX_AMOUNT = type(uint256).max; - string constant name = "Fatso Test Name"; - string constant symbol = "FTSOTST"; + string constant NAME = "Fatso Test Name"; + string constant SYMBOL = "FTSOTST"; function setUp() public { authority = new GhostAuthority( - deployer, - deployer, - deployer, - vault + DEPLOYER, + DEPLOYER, + DEPLOYER, + VAULT ); - token = new Fatso(address(authority), name, symbol); - initializePermit(address(token), amount, maxAmount); - initializeAllowance(alice, bob, address(token), amount, maxAmount, amount); - initializeTransfer(alice, bob, address(token), amount, 0); + token = new Fatso(address(authority), NAME, SYMBOL); + initializePermit(address(token), AMOUNT, MAX_AMOUNT); + initializeAllowance(ALICE, BOB, address(token), AMOUNT, MAX_AMOUNT, AMOUNT); + initializeTransfer(ALICE, BOB, address(token), AMOUNT, MAX_AMOUNT); } function test_mint_couldHappenFromVault() public { uint256 totalSupply = token.totalSupply(); - vm.prank(vault); - token.mint(alice, amount); - assertEq(token.totalSupply(), totalSupply + amount); + vm.prank(VAULT); + token.mint(ALICE, AMOUNT); + assertEq(token.totalSupply(), totalSupply + AMOUNT); } function test_mint_couldNotMintFromArbitraryAccount(address who) public { - vm.assume(who != vault); + vm.assume(who != VAULT); vm.expectRevert(); vm.prank(who); - token.mint(alice, amount); + token.mint(ALICE, AMOUNT); } function test_correctlyConstructsAnERC20() public view { - assertEq(token.name(), name); - assertEq(token.symbol(), symbol); + assertEq(token.name(), NAME); + assertEq(token.symbol(), SYMBOL); assertEq(token.decimals(), 9); } function test_mint_couldBeDoneByVault() public { - assertEq(token.balanceOf(bob), 0); - vm.prank(vault); - token.mint(bob, 69); - assertEq(token.balanceOf(bob), 69); + assertEq(token.balanceOf(BOB), 0); + vm.prank(VAULT); + token.mint(BOB, AMOUNT); + assertEq(token.balanceOf(BOB), AMOUNT); } function test_mint_couldNotBeDoneByArbitraryAccount() public { vm.expectRevert(GhostAccessControlled.Unauthorized.selector); - vm.prank(deployer); - token.mint(bob, 69); - assertEq(token.balanceOf(bob), 0); + vm.prank(DEPLOYER); + token.mint(BOB, AMOUNT); + assertEq(token.balanceOf(BOB), 0); } function test_mint_totalSupplyIncreases() public { assertEq(token.totalSupply(), 0); - vm.prank(vault); - token.mint(bob, 69); - assertEq(token.totalSupply(), 69); + vm.prank(VAULT); + token.mint(BOB, AMOUNT); + assertEq(token.totalSupply(), AMOUNT); } function test_burn_totalSupplyReduces() public { - _mintTokens(bob, 69); - vm.prank(bob); - token.burn(69); + _mintTokens(BOB, AMOUNT); + vm.prank(BOB); + token.burn(AMOUNT); assertEq(token.totalSupply(), 0); } function test_burn_cannotExceedTotalSupply() public { - _mintTokens(bob, amount); + _mintTokens(BOB, AMOUNT); vm.expectRevert(); - vm.prank(bob); - token.burn(amount + 1); - assertEq(token.totalSupply(), amount); + vm.prank(BOB); + token.burn(AMOUNT + 1); + assertEq(token.totalSupply(), AMOUNT); } function _mintTokens(address who, uint256 value) internal { uint256 totalSupply = token.totalSupply(); - vm.prank(vault); + vm.prank(VAULT); token.mint(who, value); assertEq(token.totalSupply(), totalSupply + value); } @@ -110,4 +111,8 @@ contract FatsoTest is Test, ERC20PermitTest, ERC20AllowanceTest, ERC20TransferTe function _mintPermitTokens(address who, uint256 value) internal override { _mintTokens(who, value); } + + function _getCurrentTotalSupply() internal override view returns (uint256) { + return token.totalSupply(); + } } diff --git a/test/tokens/Ghst.t.sol b/test/tokens/Ghst.t.sol index 4a5642b..ff0d3d9 100644 --- a/test/tokens/Ghst.t.sol +++ b/test/tokens/Ghst.t.sol @@ -2,15 +2,15 @@ pragma solidity 0.8.20; import {Test} from "forge-std/Test.sol"; -import "../../src/GhstERC20.sol"; -import "../../src/StinkyERC20.sol"; -import "../../src/GhostAuthority.sol"; -import "../../src/Staking.sol"; +import {Ghost} from "../../src/GhstERC20.sol"; +import {Stinky} from "../../src/StinkyERC20.sol"; +import {GhostAuthority} from "../../src/GhostAuthority.sol"; +import {GhostStaking} from "../../src/Staking.sol"; -import "./Permit.t.sol"; -import "./Allowance.t.sol"; -import "./Transfer.t.sol"; -import "./Votes.t.sol"; +import {ERC20PermitTest} from "./Permit.t.sol"; +import {ERC20AllowanceTest} from "./Allowance.t.sol"; +import {ERC20TransferTest} from "./Transfer.t.sol"; +import {ERC20VotesTest} from "./Votes.t.sol"; contract GhostTest is Test, @@ -21,15 +21,15 @@ contract GhostTest is { uint256 constant public INITIAL_INDEX = 10819917194513808e56; - address constant initializer = 0x0000000000000000000000000000000000000001; - address constant alice = 0x0000000000000000000000000000000000000003; - address constant bob = 0x0000000000000000000000000000000000000004; - address constant treasury = 0x0000000000000000000000000000000000000005; - uint256 constant amount = 69; - uint256 constant maxAmount = type(uint256).max; + address constant INITIALIZER = 0x0000000000000000000000000000000000000001; + address constant ALICE = 0x0000000000000000000000000000000000000003; + address constant BOB = 0x0000000000000000000000000000000000000004; + address constant TREASURY = 0x0000000000000000000000000000000000000005; + uint256 constant AMOUNT = 69; + uint256 constant MAX_AMOUNT = type(uint256).max; - string constant name = "Ghost Test Name"; - string constant symbol = "GHSTTST"; + string constant NAME = "Ghost Test Name"; + string constant SYMBOL = "GHSTTST"; Stinky stnk; Ghost ghst; @@ -37,15 +37,15 @@ contract GhostTest is GhostStaking public staking; function setUp() public { - vm.startPrank(initializer); + vm.startPrank(INITIALIZER); authority = new GhostAuthority( - initializer, - initializer, - initializer, - initializer + INITIALIZER, + INITIALIZER, + INITIALIZER, + INITIALIZER ); stnk = new Stinky(INITIAL_INDEX, "Stinky", "STNK"); - ghst = new Ghost(address(stnk), name, symbol); + ghst = new Ghost(address(stnk), NAME, SYMBOL); staking = new GhostStaking( address(0), address(stnk), @@ -55,19 +55,19 @@ contract GhostTest is 1337, address(authority) ); - stnk.initialize(address(staking), treasury, address(ghst)); + stnk.initialize(address(staking), TREASURY, address(ghst)); ghst.initialize(address(staking)); vm.stopPrank(); - initializePermit(address(ghst), amount, maxAmount); - initializeAllowance(alice, bob, address(ghst), amount, maxAmount, amount); - initializeTransfer(alice, bob, address(ghst), amount, 0); - initializeVotes(alice, bob, address(ghst), amount); + initializePermit(address(ghst), AMOUNT, MAX_AMOUNT); + initializeAllowance(ALICE, BOB, address(ghst), AMOUNT, MAX_AMOUNT, AMOUNT); + initializeTransfer(ALICE, BOB, address(ghst), AMOUNT, MAX_AMOUNT); + initializeVotes(ALICE, BOB, address(ghst), AMOUNT); } function test_isConstructedCorrectly() public view { - assertEq(ghst.name(), name); - assertEq(ghst.symbol(), symbol); + assertEq(ghst.name(), NAME); + assertEq(ghst.symbol(), SYMBOL); assertEq(ghst.decimals(), 18); assertEq(ghst.staking(), address(staking)); assertEq(ghst.stnk(), address(stnk)); @@ -77,57 +77,57 @@ contract GhostTest is function test_mint_couldBeDoneByStaking() public { assertEq(ghst.totalSupply(), 0); vm.prank(address(staking)); - ghst.mint(alice, amount); - assertEq(ghst.totalSupply(), amount); - assertEq(ghst.balanceOf(alice), amount); + ghst.mint(ALICE, AMOUNT); + assertEq(ghst.totalSupply(), AMOUNT); + assertEq(ghst.balanceOf(ALICE), AMOUNT); } function test_mint_couldNotFromArbitraryAddress(address who) public { vm.assume(who != address(staking)); vm.expectRevert(); vm.prank(who); - ghst.mint(alice, amount); + ghst.mint(ALICE, AMOUNT); assertEq(ghst.totalSupply(), 0); assertEq(ghst.balanceOf(who), 0); } function test_burn_couldBeDoneByOwner() public { - _mintTokens(alice, amount); - assertEq(ghst.totalSupply(), amount); + _mintTokens(ALICE, AMOUNT); + assertEq(ghst.totalSupply(), AMOUNT); vm.prank(address(staking)); - ghst.burn(alice, amount); + ghst.burn(ALICE, AMOUNT); assertEq(ghst.totalSupply(), 0); - assertEq(ghst.balanceOf(alice), 0); + assertEq(ghst.balanceOf(ALICE), 0); } function test_burn_couldBeDoneByOwnerPartially(uint256 part) public { - vm.assume(part <= amount); - _mintTokens(alice, amount); - assertEq(ghst.totalSupply(), amount); + vm.assume(part <= AMOUNT); + _mintTokens(ALICE, AMOUNT); + assertEq(ghst.totalSupply(), AMOUNT); vm.prank(address(staking)); - ghst.burn(alice, part); - assertEq(ghst.totalSupply(), amount - part); - assertEq(ghst.balanceOf(alice), amount - part); + ghst.burn(ALICE, part); + assertEq(ghst.totalSupply(), AMOUNT - part); + assertEq(ghst.balanceOf(ALICE), AMOUNT - part); } function test_burn_couldNotBurnMoreThanBalance() public { - _mintTokens(alice, amount); - assertEq(ghst.totalSupply(), amount); + _mintTokens(ALICE, AMOUNT); + assertEq(ghst.totalSupply(), AMOUNT); vm.expectRevert(); - vm.prank(alice); - ghst.burn(alice, amount + 1); - assertEq(ghst.totalSupply(), amount); - assertEq(ghst.balanceOf(alice), amount); + vm.prank(ALICE); + ghst.burn(ALICE, AMOUNT + 1); + assertEq(ghst.totalSupply(), AMOUNT); + assertEq(ghst.balanceOf(ALICE), AMOUNT); } function test_burn_couldNotFromArbitraryAddress(address who) public { vm.assume(who != address(staking)); - _mintTokens(alice, amount); + _mintTokens(ALICE, AMOUNT); vm.expectRevert(); vm.prank(who); - ghst.burn(alice, amount); - assertEq(ghst.totalSupply(), amount); - assertEq(ghst.balanceOf(alice), amount); + ghst.burn(ALICE, AMOUNT); + assertEq(ghst.totalSupply(), AMOUNT); + assertEq(ghst.balanceOf(ALICE), AMOUNT); } function test_balanceToCalculatesCorrectly(uint256 balanceToAmount) public view { @@ -169,4 +169,8 @@ contract GhostTest is vm.prank(address(staking)); ghst.burn(who, value); } + + function _getCurrentTotalSupply() internal override view returns (uint256) { + return ghst.totalSupply(); + } } diff --git a/test/tokens/Permit.t.sol b/test/tokens/Permit.t.sol index dd6e20b..42a05a4 100644 --- a/test/tokens/Permit.t.sol +++ b/test/tokens/Permit.t.sol @@ -1,10 +1,14 @@ pragma solidity 0.8.20; import {Test} from "forge-std/Test.sol"; -import "../../src/mocks/SigUtils.sol"; -import "@openzeppelin-contracts/token/ERC20/extensions/ERC20Permit.sol"; +import {SigUtils} from "../../src/mocks/SigUtils.sol"; + +import {ERC20Permit} from "@openzeppelin-contracts/token/ERC20/extensions/ERC20Permit.sol"; +import {SafeERC20} from "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; abstract contract ERC20PermitTest is Test { + using SafeERC20 for ERC20Permit; + SigUtils sigUtils; ERC20Permit permitToken; @@ -13,8 +17,8 @@ abstract contract ERC20PermitTest is Test { uint256 permitAmount; uint256 maxPermitAmount; - uint256 constant ownerPrivateKey = 0xA11CE; - uint256 constant spenderPrivateKey = 0xB0B; + uint256 constant OWNER_PRIVATE_KEY = 0xA11CE; + uint256 constant SPENDER_PRIVATE_KEY = 0xB0B; function initializePermit( address token, @@ -26,8 +30,8 @@ abstract contract ERC20PermitTest is Test { permitToken = ERC20Permit(token); sigUtils = new SigUtils(permitToken.DOMAIN_SEPARATOR()); - owner = vm.addr(ownerPrivateKey); - spender = vm.addr(spenderPrivateKey); + owner = vm.addr(OWNER_PRIVATE_KEY); + spender = vm.addr(SPENDER_PRIVATE_KEY); } function test_permit_initialNonceIsZero() public view { @@ -47,7 +51,7 @@ abstract contract ERC20PermitTest is Test { bytes32 digest = sigUtils.getTypedDataHash(permit); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(OWNER_PRIVATE_KEY, digest); permitToken.permit( permit.owner, @@ -75,7 +79,7 @@ abstract contract ERC20PermitTest is Test { bytes32 digest = sigUtils.getTypedDataHash(permit); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(OWNER_PRIVATE_KEY, digest); vm.warp(1 days + 1 seconds); // fast forward one second past the deadline @@ -103,7 +107,7 @@ abstract contract ERC20PermitTest is Test { bytes32 digest = sigUtils.getTypedDataHash(permit); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(spenderPrivateKey, digest); // spender signs owner's approval + (uint8 v, bytes32 r, bytes32 s) = vm.sign(SPENDER_PRIVATE_KEY, digest); // spender signs owner's approval vm.expectRevert(); permitToken.permit( @@ -129,7 +133,7 @@ abstract contract ERC20PermitTest is Test { bytes32 digest = sigUtils.getTypedDataHash(permit); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(OWNER_PRIVATE_KEY, digest); vm.expectRevert(); permitToken.permit( @@ -155,7 +159,7 @@ abstract contract ERC20PermitTest is Test { bytes32 digest = sigUtils.getTypedDataHash(permit); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(OWNER_PRIVATE_KEY, digest); permitToken.permit( permit.owner, @@ -191,7 +195,7 @@ abstract contract ERC20PermitTest is Test { bytes32 digest = sigUtils.getTypedDataHash(permit); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(OWNER_PRIVATE_KEY, digest); permitToken.permit( permit.owner, @@ -204,7 +208,7 @@ abstract contract ERC20PermitTest is Test { ); vm.prank(spender); - permitToken.transferFrom(owner, spender, permitAmount); + permitToken.safeTransferFrom(owner, spender, permitAmount); assertEq(permitToken.balanceOf(owner), 0); assertEq(permitToken.balanceOf(spender), permitAmount); @@ -223,7 +227,7 @@ abstract contract ERC20PermitTest is Test { bytes32 digest = sigUtils.getTypedDataHash(permit); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(OWNER_PRIVATE_KEY, digest); permitToken.permit( permit.owner, @@ -236,11 +240,10 @@ abstract contract ERC20PermitTest is Test { ); vm.prank(spender); - permitToken.transferFrom(owner, spender, permitAmount); + permitToken.safeTransferFrom(owner, spender, permitAmount); assertEq(permitToken.balanceOf(owner), 0); assertEq(permitToken.balanceOf(spender), permitAmount); - assertEq(permitToken.allowance(owner, spender), maxPermitAmount); } function test_permit_invalidAllowance() public { @@ -255,7 +258,7 @@ abstract contract ERC20PermitTest is Test { bytes32 digest = sigUtils.getTypedDataHash(permit); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(OWNER_PRIVATE_KEY, digest); permitToken.permit( permit.owner, @@ -269,22 +272,25 @@ abstract contract ERC20PermitTest is Test { vm.expectRevert(); vm.prank(spender); - permitToken.transferFrom(owner, spender, permitAmount); + assertEq(permitToken.transferFrom(owner, spender, permitAmount), false); + assertEq(permitToken.balanceOf(owner), permitAmount); + assertEq(permitToken.balanceOf(spender), 0); } - function test_permit_ivnalidBalance() public { - _mintPermitTokens(owner, permitAmount); + function test_permit_invalidBalance() public { + uint256 smallAmount = 2; + _mintPermitTokens(owner, smallAmount); SigUtils.Permit memory permit = SigUtils.Permit({ owner: owner, spender: spender, - value: 2, + value: permitAmount, nonce: 0, deadline: 1 days }); bytes32 digest = sigUtils.getTypedDataHash(permit); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(OWNER_PRIVATE_KEY, digest); permitToken.permit( permit.owner, @@ -298,7 +304,9 @@ abstract contract ERC20PermitTest is Test { vm.expectRevert(); vm.prank(spender); - permitToken.transferFrom(owner, spender, permitAmount); + assertEq(permitToken.transferFrom(owner, spender, permitAmount), false); + assertEq(permitToken.balanceOf(owner), smallAmount); + assertEq(permitToken.balanceOf(spender), 0); } function _mintPermitTokens(address who, uint256 permitAmount) internal virtual; diff --git a/test/tokens/Reserve.t.sol b/test/tokens/Reserve.t.sol index d451985..4274643 100644 --- a/test/tokens/Reserve.t.sol +++ b/test/tokens/Reserve.t.sol @@ -1,20 +1,18 @@ pragma solidity 0.8.20; import {Test} from "forge-std/Test.sol"; -import "../../src/mocks/Reserve.sol"; - -import "@openzeppelin-contracts/token/ERC20/IERC20.sol"; +import {Reserve} from "../../src/mocks/Reserve.sol"; contract ReserveTest is Test { - address constant initializer = 0x0000000000000000000000000000000000000001; - address constant faucetAddress = 0x0000000000000000000000000000000000000002; - address constant aliceAddress = 0x0000000000000000000000000000000000000003; - address constant bobAddress = 0x0000000000000000000000000000000000000004; - uint256 constant conversionRate = 69 * 10e5; - uint256 constant sendAmount = 1e16; + address constant INITIALIZER = 0x0000000000000000000000000000000000000001; + address constant FAUCET_ADDRESS = 0x0000000000000000000000000000000000000002; + address constant ALICE_ADDRESS = 0x0000000000000000000000000000000000000003; + address constant BOB_ADDRESS = 0x0000000000000000000000000000000000000004; + uint256 constant CONVERSION_RATE = 69 * 10e5; + uint256 constant SEND_AMOUNT = 1e16; - string constant name = "Test DAI"; - string constant symbol = "tDAI"; + string constant NAME = "Test DAI"; + string constant SYMBOL = "tDAI"; Reserve reserve; @@ -22,68 +20,68 @@ contract ReserveTest is Test { event LogStakingContractUpdated(address stakingContract); function setUp() public { - vm.prank(initializer); + vm.prank(INITIALIZER); reserve = new Reserve( "Test DAI", "tDAI", - conversionRate + CONVERSION_RATE ); } function test_isConstructedCorrectly() public view { - assertEq(reserve.name(), name); - assertEq(reserve.symbol(), symbol); + assertEq(reserve.name(), NAME); + assertEq(reserve.symbol(), SYMBOL); assertEq(reserve.decimals(), 18); assertEq(reserve.totalSupply(), 0); assertEq(reserve.donationRate(), 0); - assertEq(reserve.conversionRate(), conversionRate); + assertEq(reserve.conversionRate(), CONVERSION_RATE); } function test_mint_couldBeDoneWithValue() public { - assertEq(reserve.balanceOf(aliceAddress), 0); - deal(aliceAddress, sendAmount); + assertEq(reserve.balanceOf(ALICE_ADDRESS), 0); + deal(ALICE_ADDRESS, SEND_AMOUNT); - vm.prank(aliceAddress); - reserve.mint{ value: sendAmount }(aliceAddress); + vm.prank(ALICE_ADDRESS); + reserve.mint{ value: SEND_AMOUNT }(ALICE_ADDRESS); - assertEq(reserve.balanceOf(aliceAddress), sendAmount * conversionRate); + assertEq(reserve.balanceOf(ALICE_ADDRESS), SEND_AMOUNT * CONVERSION_RATE); } function test_mint_couldNotBeDoneWithoutEmptyValue() public { - assertEq(reserve.balanceOf(aliceAddress), 0); - vm.prank(aliceAddress); - reserve.mint(aliceAddress); - assertEq(reserve.balanceOf(aliceAddress), 0); + assertEq(reserve.balanceOf(ALICE_ADDRESS), 0); + vm.prank(ALICE_ADDRESS); + reserve.mint(ALICE_ADDRESS); + assertEq(reserve.balanceOf(ALICE_ADDRESS), 0); } function test_mint_couldNotMintIfNotEnoughValue() public { - assertEq(reserve.balanceOf(aliceAddress), 0); + assertEq(reserve.balanceOf(ALICE_ADDRESS), 0); bool didRevert = false; - vm.prank(aliceAddress); - try reserve.mint{ value: type(uint256).max }(aliceAddress) { + vm.prank(ALICE_ADDRESS); + try reserve.mint{ value: type(uint256).max }(ALICE_ADDRESS) { } catch { didRevert = true; } assertEq(didRevert, true); - assertEq(reserve.balanceOf(aliceAddress), 0); + assertEq(reserve.balanceOf(ALICE_ADDRESS), 0); } function test_mint_superMintCouldBeDoneFromDeployer() public { - assertEq(reserve.balanceOf(initializer), 0); - vm.prank(initializer); - reserve.superMint(initializer, 420 * 1e18); - assertEq(reserve.balanceOf(initializer), 420 * 1e18); + assertEq(reserve.balanceOf(INITIALIZER), 0); + vm.prank(INITIALIZER); + reserve.superMint(INITIALIZER, 420 * 1e18); + assertEq(reserve.balanceOf(INITIALIZER), 420 * 1e18); } function test_mint_superMintCouldNotBeDoneFromArbitraryAddress() public { - assertEq(reserve.balanceOf(aliceAddress), 0); + assertEq(reserve.balanceOf(ALICE_ADDRESS), 0); vm.expectRevert(); - vm.prank(aliceAddress); - reserve.superMint(aliceAddress, 420 * 1e18); - assertEq(reserve.balanceOf(aliceAddress), 0); + vm.prank(ALICE_ADDRESS); + reserve.superMint(ALICE_ADDRESS, 420 * 1e18); + assertEq(reserve.balanceOf(ALICE_ADDRESS), 0); } function test_mint_donationNotTakenIfRateNotSet() public { @@ -91,11 +89,11 @@ contract ReserveTest is Test { assertEq(reserve.donationRate(), 0); assertEq(reserve.accumulatedDonation(), 0); - deal(aliceAddress, sendAmount); - vm.prank(aliceAddress); - reserve.mint{ value: sendAmount }(aliceAddress); + deal(ALICE_ADDRESS, SEND_AMOUNT); + vm.prank(ALICE_ADDRESS); + reserve.mint{ value: SEND_AMOUNT }(ALICE_ADDRESS); - assertEq(reserve.totalSupply(), sendAmount * conversionRate); + assertEq(reserve.totalSupply(), SEND_AMOUNT * CONVERSION_RATE); assertEq(reserve.donationRate(), 0); assertEq(reserve.accumulatedDonation(), 0); } @@ -105,195 +103,195 @@ contract ReserveTest is Test { assertEq(reserve.donationRate(), 0); assertEq(reserve.accumulatedDonation(), 0); - vm.prank(initializer); + vm.prank(INITIALIZER); reserve.changeDonationRate(1e4); // 10% - deal(aliceAddress, sendAmount); - vm.prank(aliceAddress); - reserve.mint{ value: sendAmount }(aliceAddress); + deal(ALICE_ADDRESS, SEND_AMOUNT); + vm.prank(ALICE_ADDRESS); + reserve.mint{ value: SEND_AMOUNT }(ALICE_ADDRESS); - assertEq(reserve.totalSupply(), sendAmount * conversionRate); + assertEq(reserve.totalSupply(), SEND_AMOUNT * CONVERSION_RATE); assertEq(reserve.donationRate(), 1e4); - assertEq(reserve.accumulatedDonation(), sendAmount * 1e4 / 1e5); + assertEq(reserve.accumulatedDonation(), SEND_AMOUNT * 1e4 / 1e5); } function test_rate_couldBeChangedByDeployer() public { - assertEq(reserve.conversionRate(), conversionRate); - vm.prank(initializer); + assertEq(reserve.conversionRate(), CONVERSION_RATE); + vm.prank(INITIALIZER); reserve.changeRate(1337); assertEq(reserve.conversionRate(), 1337); } function test_rate_couldNotBeChangedByArbitraryAddress() public { - assertEq(reserve.conversionRate(), conversionRate); + assertEq(reserve.conversionRate(), CONVERSION_RATE); vm.expectRevert(); - vm.prank(aliceAddress); + vm.prank(ALICE_ADDRESS); reserve.changeRate(1337); - assertEq(reserve.conversionRate(), conversionRate); + assertEq(reserve.conversionRate(), CONVERSION_RATE); } function test_withdraw_couldBeDoneByDeployer() public { assertEq(address(reserve).balance, 0); - vm.prank(initializer); + vm.prank(INITIALIZER); reserve.changeDonationRate(1e5); - deal(aliceAddress, sendAmount); - vm.prank(aliceAddress); - reserve.mint{ value: sendAmount }(aliceAddress); + deal(ALICE_ADDRESS, SEND_AMOUNT); + vm.prank(ALICE_ADDRESS); + reserve.mint{ value: SEND_AMOUNT }(ALICE_ADDRESS); - assertEq(address(reserve).balance, sendAmount); + assertEq(address(reserve).balance, SEND_AMOUNT); - vm.prank(initializer); - reserve.withdraw(payable(faucetAddress)); + vm.prank(INITIALIZER); + reserve.withdraw(payable(FAUCET_ADDRESS)); assertEq(address(reserve).balance, 0); - assertEq(faucetAddress.balance, sendAmount); + assertEq(FAUCET_ADDRESS.balance, SEND_AMOUNT); } function test_withdraw_onlyAccumulatedDonationsCouldBeWithdrawn() public { assertEq(address(reserve).balance, 0); - vm.prank(initializer); + vm.prank(INITIALIZER); reserve.changeDonationRate(5 * 1e4); // 50% - deal(aliceAddress, sendAmount); - vm.prank(aliceAddress); - reserve.mint{ value: sendAmount }(aliceAddress); + deal(ALICE_ADDRESS, SEND_AMOUNT); + vm.prank(ALICE_ADDRESS); + reserve.mint{ value: SEND_AMOUNT }(ALICE_ADDRESS); - assertEq(address(reserve).balance, sendAmount); + assertEq(address(reserve).balance, SEND_AMOUNT); - vm.prank(initializer); - reserve.withdraw(payable(faucetAddress)); - assertEq(address(reserve).balance, sendAmount / 2); - assertEq(faucetAddress.balance, sendAmount / 2); + vm.prank(INITIALIZER); + reserve.withdraw(payable(FAUCET_ADDRESS)); + assertEq(address(reserve).balance, SEND_AMOUNT / 2); + assertEq(FAUCET_ADDRESS.balance, SEND_AMOUNT / 2); - vm.prank(initializer); - reserve.withdraw(payable(faucetAddress)); - assertEq(address(reserve).balance, sendAmount / 2); - assertEq(faucetAddress.balance, sendAmount / 2); + vm.prank(INITIALIZER); + reserve.withdraw(payable(FAUCET_ADDRESS)); + assertEq(address(reserve).balance, SEND_AMOUNT / 2); + assertEq(FAUCET_ADDRESS.balance, SEND_AMOUNT / 2); } function test_withdraw_couldNotBeDoneByArbitraryAddress() public { assertEq(address(reserve).balance, 0); - deal(aliceAddress, sendAmount); - vm.prank(aliceAddress); - reserve.mint{ value: sendAmount }(aliceAddress); + deal(ALICE_ADDRESS, SEND_AMOUNT); + vm.prank(ALICE_ADDRESS); + reserve.mint{ value: SEND_AMOUNT }(ALICE_ADDRESS); - assertEq(address(reserve).balance, sendAmount); + assertEq(address(reserve).balance, SEND_AMOUNT); vm.expectRevert(); - vm.prank(aliceAddress); - reserve.withdraw(payable(aliceAddress)); + vm.prank(ALICE_ADDRESS); + reserve.withdraw(payable(ALICE_ADDRESS)); - assertEq(address(reserve).balance, sendAmount); - assertEq(aliceAddress.balance, 0); + assertEq(address(reserve).balance, SEND_AMOUNT); + assertEq(ALICE_ADDRESS.balance, 0); } function test_burn_shouldReturnFullAmountIfRateNotSet() public { - deal(aliceAddress, sendAmount); - vm.prank(aliceAddress); - reserve.mint{ value: sendAmount }(aliceAddress); + deal(ALICE_ADDRESS, SEND_AMOUNT); + vm.prank(ALICE_ADDRESS); + reserve.mint{ value: SEND_AMOUNT }(ALICE_ADDRESS); - uint256 balance = reserve.balanceOf(aliceAddress); - assertEq(reserve.totalSupply(), sendAmount * conversionRate); + uint256 balance = reserve.balanceOf(ALICE_ADDRESS); + assertEq(reserve.totalSupply(), SEND_AMOUNT * CONVERSION_RATE); assertEq(reserve.totalSupply(), balance); assertEq(reserve.accumulatedDonation(), 0); - assertEq(aliceAddress.balance, 0); + assertEq(ALICE_ADDRESS.balance, 0); - vm.prank(aliceAddress); + vm.prank(ALICE_ADDRESS); reserve.burn(balance); assertEq(reserve.totalSupply(), 0); - assertEq(reserve.balanceOf(aliceAddress), 0); + assertEq(reserve.balanceOf(ALICE_ADDRESS), 0); assertEq(reserve.accumulatedDonation(), 0); - assertEq(aliceAddress.balance, sendAmount); + assertEq(ALICE_ADDRESS.balance, SEND_AMOUNT); } function test_burn_shouldTakeDonationInAccordanceToRate() public { - vm.prank(initializer); + vm.prank(INITIALIZER); reserve.changeDonationRate(5 * 1e4); // 50% - deal(aliceAddress, sendAmount); - vm.prank(aliceAddress); - reserve.mint{ value: sendAmount }(aliceAddress); + deal(ALICE_ADDRESS, SEND_AMOUNT); + vm.prank(ALICE_ADDRESS); + reserve.mint{ value: SEND_AMOUNT }(ALICE_ADDRESS); - uint256 balance = reserve.balanceOf(aliceAddress); - assertEq(reserve.totalSupply(), sendAmount * conversionRate); + uint256 balance = reserve.balanceOf(ALICE_ADDRESS); + assertEq(reserve.totalSupply(), SEND_AMOUNT * CONVERSION_RATE); assertEq(reserve.totalSupply(), balance); - assertEq(reserve.accumulatedDonation(), sendAmount / 2); - assertEq(aliceAddress.balance, 0); + assertEq(reserve.accumulatedDonation(), SEND_AMOUNT / 2); + assertEq(ALICE_ADDRESS.balance, 0); - vm.prank(aliceAddress); + vm.prank(ALICE_ADDRESS); reserve.burn(balance); assertEq(reserve.totalSupply(), 0); - assertEq(reserve.balanceOf(aliceAddress), 0); - assertEq(reserve.accumulatedDonation(), sendAmount / 2); - assertEq(aliceAddress.balance, sendAmount / 2); + assertEq(reserve.balanceOf(ALICE_ADDRESS), 0); + assertEq(reserve.accumulatedDonation(), SEND_AMOUNT / 2); + assertEq(ALICE_ADDRESS.balance, SEND_AMOUNT / 2); } function test_burn_multipleUsersAccumulateInTotal() public { - vm.prank(initializer); + vm.prank(INITIALIZER); reserve.changeDonationRate(5 * 1e4); // 50% - deal(aliceAddress, sendAmount); - vm.prank(aliceAddress); - reserve.mint{ value: sendAmount }(aliceAddress); + deal(ALICE_ADDRESS, SEND_AMOUNT); + vm.prank(ALICE_ADDRESS); + reserve.mint{ value: SEND_AMOUNT }(ALICE_ADDRESS); - vm.prank(initializer); - reserve.changeRate(conversionRate * 9); + vm.prank(INITIALIZER); + reserve.changeRate(CONVERSION_RATE * 9); - deal(bobAddress, sendAmount); - vm.prank(bobAddress); - reserve.mint{ value: sendAmount }(bobAddress); + deal(BOB_ADDRESS, SEND_AMOUNT); + vm.prank(BOB_ADDRESS); + reserve.mint{ value: SEND_AMOUNT }(BOB_ADDRESS); - assertEq(aliceAddress.balance, 0); - assertEq(bobAddress.balance, 0); - uint256 aliceBalance = reserve.balanceOf(aliceAddress); - uint256 bobBalance = reserve.balanceOf(bobAddress); + assertEq(ALICE_ADDRESS.balance, 0); + assertEq(BOB_ADDRESS.balance, 0); + uint256 aliceBalance = reserve.balanceOf(ALICE_ADDRESS); + uint256 bobBalance = reserve.balanceOf(BOB_ADDRESS); uint256 bobEstimation = reserve.estimateAmount(bobBalance); uint256 aliceEstimation = reserve.estimateAmount(aliceBalance); - vm.prank(bobAddress); + vm.prank(BOB_ADDRESS); reserve.burn(bobBalance); - vm.prank(aliceAddress); + vm.prank(ALICE_ADDRESS); reserve.burn(aliceBalance); - assertEq(bobAddress.balance, sendAmount * 9 / 10); - assertEq(bobAddress.balance, bobEstimation); - assertEq(aliceAddress.balance, sendAmount / 10); - assertEq(aliceAddress.balance, aliceEstimation); + assertEq(BOB_ADDRESS.balance, SEND_AMOUNT * 9 / 10); + assertEq(BOB_ADDRESS.balance, bobEstimation); + assertEq(ALICE_ADDRESS.balance, SEND_AMOUNT / 10); + assertEq(ALICE_ADDRESS.balance, aliceEstimation); assertEq(reserve.totalSupply(), 0); - assertEq(reserve.accumulatedDonation(), sendAmount); - assertEq(address(reserve).balance, sendAmount); + assertEq(reserve.accumulatedDonation(), SEND_AMOUNT); + assertEq(address(reserve).balance, SEND_AMOUNT); } function test_reserveFallback() public { assertEq(address(reserve).balance, 0); - assertEq(reserve.balanceOf(aliceAddress), 0); + assertEq(reserve.balanceOf(ALICE_ADDRESS), 0); - vm.prank(aliceAddress); + vm.prank(ALICE_ADDRESS); (bool success, ) = address(reserve).call(abi.encodeWithSignature("nonExistentFunction()")); require(success, "Fallback call failed"); assertEq(address(reserve).balance, 0); - assertEq(reserve.balanceOf(aliceAddress), 0); + assertEq(reserve.balanceOf(ALICE_ADDRESS), 0); } function test_reserveReceive() public { assertEq(address(reserve).balance, 0); - assertEq(reserve.balanceOf(aliceAddress), 0); + assertEq(reserve.balanceOf(ALICE_ADDRESS), 0); - deal(aliceAddress, sendAmount); - vm.prank(aliceAddress); - (bool success, ) = address(reserve).call{value: sendAmount}(""); + deal(ALICE_ADDRESS, SEND_AMOUNT); + vm.prank(ALICE_ADDRESS); + (bool success, ) = address(reserve).call{value: SEND_AMOUNT}(""); require(success, "Transfer of native failed"); - uint256 estimatedReceiveAmount = sendAmount * reserve.conversionRate(); - assertEq(address(reserve).balance, sendAmount); - assertEq(reserve.balanceOf(aliceAddress), estimatedReceiveAmount); + uint256 estimatedReceiveAmount = SEND_AMOUNT * reserve.conversionRate(); + assertEq(address(reserve).balance, SEND_AMOUNT); + assertEq(reserve.balanceOf(ALICE_ADDRESS), estimatedReceiveAmount); } } diff --git a/test/tokens/Stnk.t.sol b/test/tokens/Stnk.t.sol index 08a0e8c..04abbfe 100644 --- a/test/tokens/Stnk.t.sol +++ b/test/tokens/Stnk.t.sol @@ -1,21 +1,22 @@ pragma solidity 0.8.20; import {Test} from "forge-std/Test.sol"; -import {console} from "forge-std/console.sol"; -import "../../src/FatsoERC20.sol"; -import "../../src/StinkyERC20.sol"; -import "../../src/GhstERC20.sol"; -import "../../src/GhostAuthority.sol"; -import "../../src/Staking.sol"; +import {Fatso} from "../../src/FatsoERC20.sol"; +import {Stinky} from "../../src/StinkyERC20.sol"; +import {Ghost} from "../../src/GhstERC20.sol"; +import {GhostAuthority} from "../../src/GhostAuthority.sol"; +import {GhostStaking} from "../../src/Staking.sol"; -import "./Permit.t.sol"; -import "./Allowance.t.sol"; -import "./Transfer.t.sol"; +import {ERC20PermitTest} from "./Permit.t.sol"; +import {ERC20AllowanceTest} from "./Allowance.t.sol"; +import {ERC20TransferTest} from "./Transfer.t.sol"; -import "@openzeppelin-contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; contract StinkyTest is Test, ERC20PermitTest, ERC20AllowanceTest, ERC20TransferTest { + using SafeERC20 for Stinky; + uint256 private constant INITIAL_SHARES_SUPPLY = 5 * 10**15; // 15 or 16 uint256 private constant TOTAL_SHARES = type(uint256).max - (type(uint256).max % INITIAL_SHARES_SUPPLY); @@ -28,29 +29,28 @@ contract StinkyTest is Test, ERC20PermitTest, ERC20AllowanceTest, ERC20TransferT GhostAuthority public authority; GhostStaking public staking; - address constant initializer = 0x0000000000000000000000000000000000000001; - address constant alice = 0x0000000000000000000000000000000000000003; - address constant bob = 0x0000000000000000000000000000000000000004; - address constant treasury = 0x0000000000000000000000000000000000000005; - uint256 constant amount = 69; - uint256 constant maxAmount = type(uint256).max; + address constant INITIALIZER = 0x0000000000000000000000000000000000000001; + address constant ALICE = 0x0000000000000000000000000000000000000003; + address constant BOB = 0x0000000000000000000000000000000000000004; + address constant TREASURY = 0x0000000000000000000000000000000000000005; + uint256 constant AMOUNT = 69; - string constant name = "Stinky Test Name"; - string constant symbol = "STNKTST"; + string constant NAME = "Stinky Test Name"; + string constant SYMBOL = "STNKTST"; event Transfer(address indexed from, address indexed to, uint256 value); event LogStakingContractUpdated(address stakingContract); function setUp() public { - vm.startPrank(initializer); + vm.startPrank(INITIALIZER); authority = new GhostAuthority( - initializer, - initializer, - initializer, - initializer + INITIALIZER, + INITIALIZER, + INITIALIZER, + INITIALIZER ); ftso = new Fatso(address(authority), "Fatso", "FTSO"); - stnk = new Stinky(INITIAL_INDEX, name, symbol); + stnk = new Stinky(INITIAL_INDEX, NAME, SYMBOL); ghst = new Ghost(address(stnk), "Ghost", "GHST"); staking = new GhostStaking( address(ftso), @@ -64,41 +64,41 @@ contract StinkyTest is Test, ERC20PermitTest, ERC20AllowanceTest, ERC20TransferT ghst.initialize(address(staking)); vm.stopPrank(); - initializePermit(address(stnk), amount, maxAmount); - initializeAllowance(alice, bob, address(stnk), amount, maxAmount, TOTAL_INITIAL_SUPPLY); - initializeTransfer(alice, bob, address(stnk), amount, TOTAL_INITIAL_SUPPLY); + initializePermit(address(stnk), AMOUNT, TOTAL_INITIAL_SUPPLY); + initializeAllowance(ALICE, BOB, address(stnk), AMOUNT, TOTAL_INITIAL_SUPPLY, TOTAL_INITIAL_SUPPLY); + initializeTransfer(ALICE, BOB, address(stnk), AMOUNT, TOTAL_INITIAL_SUPPLY); } function test_isConstructedCorrectly() public view { - assertEq(stnk.name(), name); - assertEq(stnk.symbol(), symbol); + assertEq(stnk.name(), NAME); + assertEq(stnk.symbol(), SYMBOL); assertEq(stnk.decimals(), 9); assertEq(stnk.totalSupply(), TOTAL_INITIAL_SUPPLY); assertEq(stnk.index(), INITIAL_INDEX / (TOTAL_SHARES / INITIAL_SHARES_SUPPLY)); } function test_initialization_couldBeDoneByInitializer() public { - vm.prank(initializer); - stnk.initialize(address(staking), treasury, address(ghst)); + vm.prank(INITIALIZER); + stnk.initialize(address(staking), TREASURY, address(ghst)); assertEq(stnk.staking(), address(staking)); - assertEq(stnk.treasury(), treasury); + assertEq(stnk.treasury(), TREASURY); assertEq(stnk.ghst(), address(ghst)); } function test_initialization_couldNotBeDoneByArbitraryAddress(address who) public { - vm.assume(who != initializer); + vm.assume(who != INITIALIZER); vm.expectRevert(); vm.prank(who); stnk.initialize(who, who, who); } function test_initialization_couldBeDoneOnlyOnce() public { - vm.prank(initializer); - stnk.initialize(address(staking), treasury, address(ghst)); + vm.prank(INITIALIZER); + stnk.initialize(address(staking), TREASURY, address(ghst)); vm.expectRevert(); - vm.prank(initializer); - stnk.initialize(initializer, initializer, initializer); + vm.prank(INITIALIZER); + stnk.initialize(INITIALIZER, INITIALIZER, INITIALIZER); } function test_initialization_correctTotalSharesOfStaking() public { @@ -119,56 +119,56 @@ contract StinkyTest is Test, ERC20PermitTest, ERC20AllowanceTest, ERC20TransferT } function test_circulatingSupplyIsCorrecBasedOnTotalSupply() public { - _mintTokens(alice, amount); - assertEq(stnk.circulatingSupply(), amount); - assertEq(stnk.balanceOf(address(staking)), TOTAL_INITIAL_SUPPLY - amount); + _mintTokens(ALICE, AMOUNT); + assertEq(stnk.circulatingSupply(), AMOUNT); + assertEq(stnk.balanceOf(address(staking)), TOTAL_INITIAL_SUPPLY - AMOUNT); } function test_circulatingSupplyIsCorrecBasedOnStakingBalance() public { - _mintTokens(alice, amount); - assertEq(stnk.circulatingSupply(), amount); - vm.prank(alice); - stnk.transfer(address(staking), amount); + _mintTokens(ALICE, AMOUNT); + assertEq(stnk.circulatingSupply(), AMOUNT); + vm.prank(ALICE); + stnk.safeTransfer(address(staking), AMOUNT); assertEq(stnk.circulatingSupply(), 0); assertEq(stnk.balanceOf(address(staking)), TOTAL_INITIAL_SUPPLY); } function test_circulatingSupplyIsCorrectBasedOnSupplyInWarmup() public { - vm.startPrank(initializer); - stnk.initialize(address(staking), treasury, address(ghst)); + vm.startPrank(INITIALIZER); + stnk.initialize(address(staking), TREASURY, address(ghst)); staking.setWarmupPeriod(1337); - ftso.mint(alice, amount); + ftso.mint(ALICE, AMOUNT); vm.stopPrank(); assertEq(stnk.circulatingSupply(), 0); - assertEq(ftso.totalSupply(), amount); + assertEq(ftso.totalSupply(), AMOUNT); assertEq(stnk.totalSupply(), TOTAL_INITIAL_SUPPLY); assertEq(stnk.balanceOf(address(staking)), TOTAL_INITIAL_SUPPLY); - vm.startPrank(alice); - ftso.approve(address(staking), amount); - staking.stake(amount, alice, true, true); + vm.startPrank(ALICE); + ftso.approve(address(staking), AMOUNT); + staking.stake(AMOUNT, ALICE, true, true); vm.stopPrank(); - assertEq(stnk.circulatingSupply(), amount); - assertEq(ftso.totalSupply(), amount); + assertEq(stnk.circulatingSupply(), AMOUNT); + assertEq(ftso.totalSupply(), AMOUNT); assertEq(stnk.totalSupply(), TOTAL_INITIAL_SUPPLY); assertEq(stnk.balanceOf(address(staking)), TOTAL_INITIAL_SUPPLY); } function test_circulatingSupplyIsCorrectBasedOnGhostSupply() public { - vm.startPrank(initializer); - stnk.initialize(address(staking), treasury, address(ghst)); - ftso.mint(alice, amount); + vm.startPrank(INITIALIZER); + stnk.initialize(address(staking), TREASURY, address(ghst)); + ftso.mint(ALICE, AMOUNT); vm.stopPrank(); - vm.startPrank(alice); - ftso.approve(address(staking), amount); - staking.stake(amount, alice, false, true); + vm.startPrank(ALICE); + ftso.approve(address(staking), AMOUNT); + staking.stake(AMOUNT, ALICE, false, true); vm.stopPrank(); - uint256 balanceTo = amount * 1e18 / ghst.index(); - assertEq(ghst.balanceOf(alice), balanceTo); + uint256 balanceTo = AMOUNT * 1e18 / ghst.index(); + assertEq(ghst.balanceOf(ALICE), balanceTo); uint256 balanceFrom = ghst.totalSupply() * ghst.index() / 1e18; assertEq(stnk.circulatingSupply(), balanceFrom); } @@ -196,75 +196,78 @@ contract StinkyTest is Test, ERC20PermitTest, ERC20AllowanceTest, ERC20TransferT assertEq(stnk.sharesForBalance(amountToTest), amountToTest * sharesPerUnit); } - function test_balanceForSharesCorrect(uint256 amountToTest) public view { + function test_balance_forSharesCorrect(uint256 amountToTest) public view { vm.assume(amountToTest < type(uint128).max); uint256 sharesPerUnit = stnk.sharesForBalance(1); assertEq(stnk.balanceForShares(amountToTest), amountToTest / sharesPerUnit); } - function test_debt_CouldBeChangedByTreasury() public { - _mintTokens(alice, amount); - assertEq(stnk.debtBalances(alice), 0); - vm.prank(treasury); - stnk.changeDebt(amount, alice, true); - assertEq(stnk.debtBalances(alice), amount); - vm.prank(treasury); - stnk.changeDebt(amount, alice, false); - assertEq(stnk.debtBalances(alice), 0); + function test_debt_couldBeChangedByTreasury() public { + _mintTokens(ALICE, AMOUNT); + assertEq(stnk.debtBalances(ALICE), 0); + vm.prank(TREASURY); + stnk.changeDebt(AMOUNT, ALICE, true); + assertEq(stnk.debtBalances(ALICE), AMOUNT); + vm.prank(TREASURY); + stnk.changeDebt(AMOUNT, ALICE, false); + assertEq(stnk.debtBalances(ALICE), 0); } - function test_debt_CouldNotBeChangeByArbitraryAddress(address someone) public { - vm.assume(someone != treasury); - _mintTokens(alice, amount); - assertEq(stnk.debtBalances(alice), 0); + function test_debt_couldNotBeChangeByArbitraryAddress(address someone) public { + vm.assume(someone != TREASURY); + _mintTokens(ALICE, AMOUNT); + assertEq(stnk.debtBalances(ALICE), 0); vm.expectRevert(); vm.prank(someone); - stnk.changeDebt(amount, alice, true); + stnk.changeDebt(AMOUNT, ALICE, true); } - function test_bala_nceCouldNotDropBelowDebt() public { - _mintTokens(alice, amount * 3); - vm.prank(treasury); - stnk.changeDebt(amount, alice, true); - assertEq(stnk.balanceOf(bob), 0); - vm.prank(alice); - stnk.transfer(bob, amount); - assertEq(stnk.balanceOf(bob), amount); + function test_balance_couldNotDropBelowDebt() public { + _mintTokens(ALICE, AMOUNT * 3); + vm.prank(TREASURY); + stnk.changeDebt(AMOUNT, ALICE, true); + assertEq(stnk.balanceOf(BOB), 0); + + vm.prank(ALICE); + stnk.safeTransfer(BOB, AMOUNT); + assertEq(stnk.balanceOf(BOB), AMOUNT); + vm.expectRevert(); - vm.prank(alice); - stnk.transfer(bob, amount * 2); - assertEq(stnk.balanceOf(bob), amount); + vm.prank(ALICE); + assertEq(stnk.transfer(BOB, AMOUNT * 2), false); + assertEq(stnk.balanceOf(BOB), AMOUNT); + assertEq(stnk.balanceOf(ALICE), AMOUNT * 2); } function test_rebase_couldNotBeDoneFromArbitraryAddress(address someone) public { vm.assume(someone != address(staking)); vm.expectRevert(); vm.prank(someone); - stnk.rebase(amount, 1337); + stnk.rebase(AMOUNT, 1337); } function test_rebase_nothingChangesIfDeltaIsZero() public { uint256 epoch = 1337; uint256 prevSupply = stnk.totalSupply(); uint256 prevIndex = stnk.index(); - _mintTokens(alice, amount); - assertEq(stnk.balanceOf(alice), amount); + _mintTokens(ALICE, AMOUNT); + assertEq(stnk.balanceOf(ALICE), AMOUNT); vm.prank(address(staking)); stnk.rebase(0, epoch); assertEq(stnk.totalSupply(), prevSupply); assertEq(stnk.index(), prevIndex); - assertEq(stnk.balanceOf(alice), amount); + assertEq(stnk.balanceOf(ALICE), AMOUNT); } function test_rebase_changesIfProfitAndCirculatingSupply() public { uint256 epoch = 1337; - _mintTokens(alice, amount); - assertEq(stnk.balanceOf(alice), amount); + _mintTokens(ALICE, AMOUNT); + assertEq(stnk.balanceOf(ALICE), AMOUNT); vm.prank(address(staking)); - stnk.rebase(amount, epoch); - assertEq(stnk.balanceOf(alice), amount * 2); + stnk.rebase(AMOUNT, epoch); + assertEq(stnk.balanceOf(ALICE), AMOUNT * 2); assertEq(stnk.totalSupply(), TOTAL_INITIAL_SUPPLY * 2); } @@ -273,9 +276,9 @@ contract StinkyTest is Test, ERC20PermitTest, ERC20AllowanceTest, ERC20TransferT _initialize(); assertEq(stnk.balanceOf(address(staking)), TOTAL_INITIAL_SUPPLY); vm.prank(address(staking)); - stnk.rebase(amount, epoch); - assertEq(stnk.balanceOf(address(staking)), TOTAL_INITIAL_SUPPLY + amount); - assertEq(stnk.totalSupply(), TOTAL_INITIAL_SUPPLY + amount); + stnk.rebase(AMOUNT, epoch); + assertEq(stnk.balanceOf(address(staking)), TOTAL_INITIAL_SUPPLY + AMOUNT); + assertEq(stnk.totalSupply(), TOTAL_INITIAL_SUPPLY + AMOUNT); } function test_rebase_couldNotExceedMaxSupply() public { @@ -289,10 +292,10 @@ contract StinkyTest is Test, ERC20PermitTest, ERC20AllowanceTest, ERC20TransferT } function _initialize() internal { - vm.prank(initializer); - stnk.initialize(address(staking), treasury, address(ghst)); + vm.prank(INITIALIZER); + stnk.initialize(address(staking), TREASURY, address(ghst)); assertEq(stnk.staking(), address(staking)); - assertEq(stnk.treasury(), treasury); + assertEq(stnk.treasury(), TREASURY); assertEq(stnk.ghst(), address(ghst)); } @@ -300,7 +303,7 @@ contract StinkyTest is Test, ERC20PermitTest, ERC20AllowanceTest, ERC20TransferT _initialize(); uint256 totalSupply = stnk.totalSupply(); vm.prank(address(staking)); - stnk.transfer(who, value); + stnk.safeTransfer(who, value); assertEq(stnk.totalSupply(), totalSupply); } @@ -315,4 +318,8 @@ contract StinkyTest is Test, ERC20PermitTest, ERC20AllowanceTest, ERC20TransferT function _mintPermitTokens(address who, uint256 value) internal override { _mintTokens(who, value); } + + function _getCurrentTotalSupply() internal override pure returns (uint256) { + return TOTAL_INITIAL_SUPPLY; + } } diff --git a/test/tokens/Transfer.t.sol b/test/tokens/Transfer.t.sol index ebf9ecd..a1f5d6a 100644 --- a/test/tokens/Transfer.t.sol +++ b/test/tokens/Transfer.t.sol @@ -1,9 +1,12 @@ pragma solidity 0.8.20; import {Test} from "forge-std/Test.sol"; -import "@openzeppelin-contracts/token/ERC20/ERC20.sol"; +import {ERC20} from "@openzeppelin-contracts/token/ERC20/ERC20.sol"; +import {SafeERC20} from "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; abstract contract ERC20TransferTest is Test { + using SafeERC20 for ERC20; + ERC20 tokenTransfer; uint256 amountTransfer; uint256 totalSupplyTransfer; @@ -30,8 +33,7 @@ abstract contract ERC20TransferTest is Test { assertEq(tokenTransfer.balanceOf(aliceTransfer), amountTransfer); assertEq(tokenTransfer.balanceOf(bobTransfer), 0); vm.prank(aliceTransfer); - bool success = tokenTransfer.transfer(bobTransfer, amountTransfer); - assertEq(success, true); + tokenTransfer.safeTransfer(bobTransfer, amountTransfer); assertEq(tokenTransfer.balanceOf(bobTransfer), amountTransfer); assertEq(tokenTransfer.balanceOf(aliceTransfer), 0); } @@ -43,8 +45,7 @@ abstract contract ERC20TransferTest is Test { assertEq(tokenTransfer.balanceOf(aliceTransfer), fuzzingTransferAmount); assertEq(tokenTransfer.balanceOf(bobTransfer), 0); vm.prank(aliceTransfer); - bool success = tokenTransfer.transfer(bobTransfer, fuzzingTransferAmount); - assertEq(success, true); + tokenTransfer.safeTransfer(bobTransfer, fuzzingTransferAmount); assertEq(tokenTransfer.balanceOf(bobTransfer), fuzzingTransferAmount); assertEq(tokenTransfer.balanceOf(aliceTransfer), 0); } @@ -53,25 +54,20 @@ abstract contract ERC20TransferTest is Test { _mintTransferTokens(aliceTransfer, amountTransfer); vm.expectRevert(); vm.prank(aliceTransfer); - tokenTransfer.transfer(bobTransfer, type(uint256).max); + assertEq(tokenTransfer.transfer(bobTransfer, amountTransfer * 2), false); + assertEq(tokenTransfer.balanceOf(aliceTransfer), amountTransfer); + assertEq(tokenTransfer.balanceOf(bobTransfer), 0); } function test_transfer_doesNotChangeTotalSupply() public { - assertEq(tokenTransfer.totalSupply(), totalSupplyTransfer); _mintTransferTokens(aliceTransfer, amountTransfer); - if (totalSupplyTransfer == 0) { - assertEq(tokenTransfer.totalSupply(), amountTransfer); - vm.prank(aliceTransfer); - tokenTransfer.transfer(bobTransfer, amountTransfer); - assertEq(tokenTransfer.totalSupply(), amountTransfer); - } else { - assertEq(tokenTransfer.totalSupply(), totalSupplyTransfer); - vm.prank(aliceTransfer); - tokenTransfer.transfer(bobTransfer, amountTransfer); - assertEq(tokenTransfer.totalSupply(), totalSupplyTransfer); - } - + assertEq(tokenTransfer.totalSupply(), _getCurrentTotalSupply()); + vm.prank(aliceTransfer); + tokenTransfer.safeTransfer(bobTransfer, amountTransfer); + assertEq(tokenTransfer.totalSupply(), _getCurrentTotalSupply()); } function _mintTransferTokens(address who, uint256 value) internal virtual; + + function _getCurrentTotalSupply() internal virtual returns (uint256); } diff --git a/test/tokens/Votes.t.sol b/test/tokens/Votes.t.sol index 6080bcc..259e735 100644 --- a/test/tokens/Votes.t.sol +++ b/test/tokens/Votes.t.sol @@ -1,18 +1,21 @@ pragma solidity 0.8.20; import {Test} from "forge-std/Test.sol"; -import "@openzeppelin-contracts/token/ERC20/extensions/ERC20Votes.sol"; -import "@openzeppelin-contracts/utils/structs/Checkpoints.sol"; +import {ERC20Votes} from "@openzeppelin-contracts/token/ERC20/extensions/ERC20Votes.sol"; +import {Checkpoints} from "@openzeppelin-contracts/utils/structs/Checkpoints.sol"; +import {SafeERC20} from "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; abstract contract ERC20VotesTest is Test { + using SafeERC20 for ERC20Votes; + ERC20Votes tokenVotes; uint256 amountVotes; address public aliceVotes; address public bobVotes; - address constant public charlieVotes = 0x0000000000000000000000000000000000000069; - address constant public eveVotes = 0x0000000000000000000000000000000000001337; + address constant public CHARLIE_VOTES = 0x0000000000000000000000000000000000000069; + address constant public EVE_VOTES = 0x0000000000000000000000000000000000001337; event DelegateChanged( address indexed delegator, @@ -72,15 +75,15 @@ abstract contract ERC20VotesTest is Test { vm.expectRevert(); vm.prank(aliceVotes); - tokenVotes.delegate(charlieVotes); + tokenVotes.delegate(CHARLIE_VOTES); assertEq(tokenVotes.delegates(aliceVotes), aliceVotes); assertEq(tokenVotes.delegates(bobVotes), bobVotes); - assertEq(tokenVotes.delegates(charlieVotes), charlieVotes); + assertEq(tokenVotes.delegates(CHARLIE_VOTES), CHARLIE_VOTES); assertEq(tokenVotes.getVotes(aliceVotes), amountVotes); assertEq(tokenVotes.getVotes(bobVotes), 0); - assertEq(tokenVotes.getVotes(charlieVotes), 0); + assertEq(tokenVotes.getVotes(CHARLIE_VOTES), 0); // 1 Checkpoint generated assertEq(tokenVotes.numCheckpoints(aliceVotes), 1); @@ -145,39 +148,39 @@ abstract contract ERC20VotesTest is Test { emit DelegateVotesChanged(address(this), 100, 100 - 1); vm.prank(address(this)); - tokenVotes.transfer(bobVotes, 1); + tokenVotes.safeTransfer(bobVotes, 1); assertEq(tokenVotes.getVotes(address(this)), 100 - 1); // case 2: 'to' has a delegatee - _mintVotesTokens(charlieVotes, 100); + _mintVotesTokens(CHARLIE_VOTES, 100); vm.expectRevert(); - vm.prank(charlieVotes); - tokenVotes.delegate(eveVotes); + vm.prank(CHARLIE_VOTES); + tokenVotes.delegate(EVE_VOTES); vm.roll(3); vm.expectEmit(true, false, false, true, address(tokenVotes)); - emit DelegateVotesChanged(charlieVotes, 100, 100 - 1); + emit DelegateVotesChanged(CHARLIE_VOTES, 100, 100 - 1); vm.expectEmit(true, false, false, true, address(tokenVotes)); - emit DelegateVotesChanged(eveVotes, 0, 1); + emit DelegateVotesChanged(EVE_VOTES, 0, 1); - vm.prank(charlieVotes); - tokenVotes.transfer(eveVotes, 1); - assertEq(tokenVotes.getVotes(charlieVotes), 100 - 1); - assertEq(tokenVotes.getVotes(eveVotes), 1); + vm.prank(CHARLIE_VOTES); + tokenVotes.safeTransfer(EVE_VOTES, 1); + assertEq(tokenVotes.getVotes(CHARLIE_VOTES), 100 - 1); + assertEq(tokenVotes.getVotes(EVE_VOTES), 1); // test for {transferFrom} // case 3: 'to' has no delegatee vm.roll(4); assertEq(tokenVotes.delegates(aliceVotes), aliceVotes); assertEq(tokenVotes.delegates(bobVotes), bobVotes); - assertEq(tokenVotes.delegates(charlieVotes), charlieVotes); - assertEq(tokenVotes.delegates(eveVotes), eveVotes); + assertEq(tokenVotes.delegates(CHARLIE_VOTES), CHARLIE_VOTES); + assertEq(tokenVotes.delegates(EVE_VOTES), EVE_VOTES); tokenVotes.approve(aliceVotes, 100); assertEq(tokenVotes.delegates(aliceVotes), aliceVotes); assertEq(tokenVotes.delegates(bobVotes), bobVotes); - assertEq(tokenVotes.delegates(charlieVotes), charlieVotes); - assertEq(tokenVotes.delegates(eveVotes), eveVotes); + assertEq(tokenVotes.delegates(CHARLIE_VOTES), CHARLIE_VOTES); + assertEq(tokenVotes.delegates(EVE_VOTES), EVE_VOTES); vm.startPrank(aliceVotes); vm.expectEmit(true, false, false, true, address(tokenVotes)); @@ -185,21 +188,21 @@ abstract contract ERC20VotesTest is Test { vm.expectEmit(true, false, false, true, address(tokenVotes)); emit DelegateVotesChanged(bobVotes, 1, 2); - tokenVotes.transferFrom(address(this), bobVotes, 1); + tokenVotes.safeTransferFrom(address(this), bobVotes, 1); // case 4: 'to' has a delegatee vm.roll(5); assertEq(tokenVotes.delegates(aliceVotes), aliceVotes); assertEq(tokenVotes.delegates(bobVotes), bobVotes); - assertEq(tokenVotes.delegates(charlieVotes), charlieVotes); - assertEq(tokenVotes.delegates(eveVotes), eveVotes); + assertEq(tokenVotes.delegates(CHARLIE_VOTES), CHARLIE_VOTES); + assertEq(tokenVotes.delegates(EVE_VOTES), EVE_VOTES); vm.expectEmit(true, false, false, true, address(tokenVotes)); emit DelegateVotesChanged(address(this), 98, 98 - 1); vm.expectEmit(true, false, false, true, address(tokenVotes)); - emit DelegateVotesChanged(charlieVotes, 99, 99 + 1); + emit DelegateVotesChanged(CHARLIE_VOTES, 99, 99 + 1); - tokenVotes.transferFrom(address(this), charlieVotes, 1); + tokenVotes.safeTransferFrom(address(this), CHARLIE_VOTES, 1); } function test_votes_getPastVotesAndGetPastTotalSupply() external { diff --git a/test/treasury/Treasury.t.sol b/test/treasury/Treasury.t.sol index ff8abb3..ff6e912 100644 --- a/test/treasury/Treasury.t.sol +++ b/test/treasury/Treasury.t.sol @@ -1,23 +1,23 @@ pragma solidity 0.8.20; import {Test} from "forge-std/Test.sol"; -import {StdChains} from "forge-std/StdChains.sol"; -import "../../src/FatsoERC20.sol"; -import "../../src/GhostAuthority.sol"; -import "../../src/Treasury.sol"; -import "../../src/StandardBondingCalculator.sol"; -import "../../src/mocks/ERC20Mock.sol"; +import {Fatso} from "../../src/FatsoERC20.sol"; +import {GhostAuthority} from "../../src/GhostAuthority.sol"; +import {GhostTreasury} from "../../src/Treasury.sol"; +import {GhostBondingCalculator} from "../../src/StandardBondingCalculator.sol"; +import {ERC20Mock} from "../../src/mocks/ERC20Mock.sol"; + +import {ITreasury} from "../../src/interfaces/ITreasury.sol"; +import {IUniswapV2Pair} from "@uniswap-v2-core/interfaces/IUniswapV2Pair.sol"; contract GhostTreasuryTest is Test { - address public constant owner = 0x0000000000000000000000000000000000000001; - address public constant governor = 0x0000000000000000000000000000000000000002; - address public constant guardian = 0x0000000000000000000000000000000000000003; - address public constant other = 0x0000000000000000000000000000000000000004; - address public constant alice = 0x0000000000000000000000000000000000000005; - address public constant bob = 0x0000000000000000000000000000000000000006; + address public constant OWNER = 0x0000000000000000000000000000000000000001; + address public constant GOVERNOR = 0x0000000000000000000000000000000000000002; + address public constant GUARDIAN = 0x0000000000000000000000000000000000000003; + address public constant ALICE = 0x0000000000000000000000000000000000000004; - uint256 public constant amount = 69 * 1e18; + uint256 public constant AMOUNT = 69 * 1e18; Fatso ftso; ERC20Mock reserve; @@ -27,12 +27,12 @@ contract GhostTreasuryTest is Test { GhostBondingCalculator calculator; function setUp() public { - vm.startPrank(owner); + vm.startPrank(OWNER); authority = new GhostAuthority( - governor, - guardian, - owner, - owner + GOVERNOR, + GUARDIAN, + OWNER, + OWNER ); reserve = new ERC20Mock("Reserve Token", "RET"); liquidity = new ERC20Mock("Liquidity Token", "LDT"); @@ -41,11 +41,11 @@ contract GhostTreasuryTest is Test { calculator = new GhostBondingCalculator(address(ftso), 1, 1); vm.stopPrank(); - vm.prank(governor); + vm.prank(GOVERNOR); authority.pushVault(address(treasury)); - vm.startPrank(alice); - reserve.mint(alice, amount); + vm.startPrank(ALICE); + reserve.mint(ALICE, AMOUNT); reserve.approve(address(treasury), type(uint256).max); ftso.approve(address(treasury), type(uint256).max); vm.stopPrank(); @@ -53,109 +53,109 @@ contract GhostTreasuryTest is Test { function test_deposit_onlyIfApprovedTokenAndApprovedAddress() public { vm.expectRevert(); - vm.prank(alice); - treasury.deposit(address(reserve), amount, 0); + vm.prank(ALICE); + treasury.deposit(address(reserve), AMOUNT, 0); - vm.prank(governor); - treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, alice, address(0)); + vm.prank(GOVERNOR); + treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, ALICE, address(0)); vm.expectRevert(); - vm.prank(alice); - treasury.deposit(address(reserve), amount, 0); + vm.prank(ALICE); + treasury.deposit(address(reserve), AMOUNT, 0); - vm.prank(governor); + vm.prank(GOVERNOR); treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator)); - vm.prank(alice); - uint256 send = treasury.deposit(address(reserve), amount, 0); + vm.prank(ALICE); + uint256 send = treasury.deposit(address(reserve), AMOUNT, 0); - assertEq(ftso.balanceOf(alice), send); - assertEq(reserve.balanceOf(address(treasury)), amount); + assertEq(ftso.balanceOf(ALICE), send); + assertEq(reserve.balanceOf(address(treasury)), AMOUNT); } function test_withdraw_onlyIfApprovedTokenAndApprovedAddress() public { - vm.startPrank(governor); - treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, alice, address(0)); + vm.startPrank(GOVERNOR); + treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, ALICE, address(0)); treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator)); vm.stopPrank(); - vm.prank(alice); - treasury.deposit(address(reserve), amount, 0); + vm.prank(ALICE); + treasury.deposit(address(reserve), AMOUNT, 0); vm.expectRevert(); - vm.prank(alice); - treasury.withdraw(address(reserve), amount); + vm.prank(ALICE); + treasury.withdraw(address(reserve), AMOUNT); - vm.prank(governor); - treasury.enable(ITreasury.STATUS.RESERVESPENDER, alice, address(0)); + vm.prank(GOVERNOR); + treasury.enable(ITreasury.STATUS.RESERVESPENDER, ALICE, address(0)); - vm.prank(alice); - treasury.withdraw(address(reserve), amount); + vm.prank(ALICE); + treasury.withdraw(address(reserve), AMOUNT); - assertEq(ftso.balanceOf(alice), 0); + assertEq(ftso.balanceOf(ALICE), 0); assertEq(reserve.balanceOf(address(treasury)), 0); } function test_manage_onlyIfApprovedTokenAndApprovedAddress() public { - vm.startPrank(governor); - treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, alice, address(0)); + vm.startPrank(GOVERNOR); + treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, ALICE, address(0)); treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator)); vm.stopPrank(); - uint256 tokenValue = treasury.tokenValue(address(reserve), amount); - vm.prank(alice); - uint256 send = treasury.deposit(address(reserve), amount, tokenValue); + uint256 tokenValue = treasury.tokenValue(address(reserve), AMOUNT); + vm.prank(ALICE); + uint256 send = treasury.deposit(address(reserve), AMOUNT, tokenValue); vm.expectRevert(); - vm.prank(alice); - treasury.manage(address(reserve), amount); + vm.prank(ALICE); + treasury.manage(address(reserve), AMOUNT); - vm.prank(governor); - treasury.enable(ITreasury.STATUS.RESERVEMANAGER, alice, address(0)); + vm.prank(GOVERNOR); + treasury.enable(ITreasury.STATUS.RESERVEMANAGER, ALICE, address(0)); - vm.prank(alice); - treasury.manage(address(reserve), amount); + vm.prank(ALICE); + treasury.manage(address(reserve), AMOUNT); - assertEq(ftso.balanceOf(alice), send); - assertEq(reserve.balanceOf(alice), amount); + assertEq(ftso.balanceOf(ALICE), send); + assertEq(reserve.balanceOf(ALICE), AMOUNT); assertEq(reserve.balanceOf(address(treasury)), 0); } function test_mint_onlyIfApprovedTokenAndApprovedAddress() public { - vm.startPrank(governor); - treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, alice, address(0)); + vm.startPrank(GOVERNOR); + treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, ALICE, address(0)); treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator)); vm.stopPrank(); - uint256 tokenValue = treasury.tokenValue(address(reserve), amount); - vm.prank(alice); - uint256 send = treasury.deposit(address(reserve), amount, tokenValue); + uint256 tokenValue = treasury.tokenValue(address(reserve), AMOUNT); + vm.prank(ALICE); + uint256 send = treasury.deposit(address(reserve), AMOUNT, tokenValue); vm.expectRevert(); - vm.prank(alice); - treasury.mint(alice, 69); + vm.prank(ALICE); + treasury.mint(ALICE, 69); - vm.prank(governor); - treasury.enable(ITreasury.STATUS.REWARDMANAGER, alice, address(0)); + vm.prank(GOVERNOR); + treasury.enable(ITreasury.STATUS.REWARDMANAGER, ALICE, address(0)); - vm.prank(alice); - treasury.mint(alice, 69); + vm.prank(ALICE); + treasury.mint(ALICE, 69); - assertEq(ftso.balanceOf(alice), send + 69); - assertEq(reserve.balanceOf(address(treasury)), amount); + assertEq(ftso.balanceOf(ALICE), send + 69); + assertEq(reserve.balanceOf(address(treasury)), AMOUNT); } function test_auditTreasuryReserves() public { - vm.startPrank(governor); - treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, alice, address(0)); + vm.startPrank(GOVERNOR); + treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, ALICE, address(0)); treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator)); vm.stopPrank(); - uint256 tokenValue = treasury.tokenValue(address(reserve), amount); - vm.prank(alice); - treasury.deposit(address(reserve), amount, tokenValue); + uint256 tokenValue = treasury.tokenValue(address(reserve), AMOUNT); + vm.prank(ALICE); + treasury.deposit(address(reserve), AMOUNT, tokenValue); - vm.prank(governor); + vm.prank(GOVERNOR); treasury.auditReserves(); assertEq(treasury.permissions(ITreasury.STATUS.RESERVETOKEN, address(reserve)), true); @@ -166,7 +166,7 @@ contract GhostTreasuryTest is Test { } function test_randomAddressCouldNotEnableStatusAndCalculator(address who) public { - vm.assume(who != governor); + vm.assume(who != GOVERNOR); vm.expectRevert(); vm.prank(who); @@ -182,7 +182,7 @@ contract GhostTreasuryTest is Test { } function test_enableStatusAndCalculator() public { - vm.startPrank(governor); + vm.startPrank(GOVERNOR); treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator)); treasury.enable(ITreasury.STATUS.LIQUIDITYTOKEN, address(liquidity), address(calculator)); treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, msg.sender, address(0)); @@ -200,9 +200,9 @@ contract GhostTreasuryTest is Test { } function test_randomAddressCouldNotDisableStatusByAddress(address who) public { - vm.assume(who != governor && who != guardian); + vm.assume(who != GOVERNOR && who != GUARDIAN); - vm.startPrank(governor); + vm.startPrank(GOVERNOR); treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator)); treasury.enable(ITreasury.STATUS.LIQUIDITYTOKEN, address(liquidity), address(calculator)); treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, msg.sender, address(0)); @@ -222,13 +222,13 @@ contract GhostTreasuryTest is Test { } function test_disableStatusByAddress() public { - vm.startPrank(governor); + vm.startPrank(GOVERNOR); treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator)); treasury.enable(ITreasury.STATUS.LIQUIDITYTOKEN, address(liquidity), address(calculator)); treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, msg.sender, address(0)); vm.stopPrank(); - vm.startPrank(governor); + vm.startPrank(GOVERNOR); treasury.disable(ITreasury.STATUS.RESERVETOKEN, address(reserve)); treasury.disable(ITreasury.STATUS.LIQUIDITYTOKEN, address(liquidity)); treasury.disable(ITreasury.STATUS.RESERVEDEPOSITOR, msg.sender); @@ -242,7 +242,7 @@ contract GhostTreasuryTest is Test { function test_mainnet_disableReserveAndLiquidity() public { address realDexPair = 0xB20bd5D04BE54f870D5C0d3cA85d82b34B836405; - vm.startPrank(governor); + vm.startPrank(GOVERNOR); treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator)); treasury.enable(ITreasury.STATUS.LIQUIDITYTOKEN, realDexPair, address(calculator)); vm.stopPrank(); @@ -258,7 +258,7 @@ contract GhostTreasuryTest is Test { assertEq(liquidityValue + reserveEps >= reserves, true); assertEq(liquidityValue - reserveEps <= reserves, true); - vm.startPrank(governor); + vm.startPrank(GOVERNOR); treasury.disable(ITreasury.STATUS.RESERVETOKEN, address(reserve)); treasury.disable(ITreasury.STATUS.LIQUIDITYTOKEN, realDexPair); vm.stopPrank(); @@ -270,7 +270,7 @@ contract GhostTreasuryTest is Test { function test_mainnet_tokenValueIsCorret() public { address realDexPair = 0xB20bd5D04BE54f870D5C0d3cA85d82b34B836405; - vm.startPrank(governor); + vm.startPrank(GOVERNOR); treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator)); treasury.enable(ITreasury.STATUS.LIQUIDITYTOKEN, realDexPair, address(calculator)); vm.stopPrank(); @@ -288,7 +288,7 @@ contract GhostTreasuryTest is Test { } function test_randomAddressCouldNotTriggerTimelock(address who) public { - vm.assume(who != governor); + vm.assume(who != GOVERNOR); vm.expectRevert(); vm.prank(who); treasury.toggleTimelock(); @@ -298,26 +298,26 @@ contract GhostTreasuryTest is Test { assertEq(treasury.timelockEnabled(), false); assertEq(treasury.onChainGovernanceTimelock(), 0); - vm.prank(governor); + vm.prank(GOVERNOR); treasury.toggleTimelock(); uint256 queuedTime = block.number + 69 * 7; assertEq(treasury.timelockEnabled(), false); assertEq(treasury.onChainGovernanceTimelock(), queuedTime); vm.roll(queuedTime + 1); - vm.prank(governor); + vm.prank(GOVERNOR); treasury.toggleTimelock(); assertEq(treasury.timelockEnabled(), true); assertEq(treasury.onChainGovernanceTimelock(), 0); - vm.prank(governor); + vm.prank(GOVERNOR); treasury.toggleTimelock(); queuedTime = block.number + 69 * 7; assertEq(treasury.timelockEnabled(), true); assertEq(treasury.onChainGovernanceTimelock(), queuedTime); vm.roll(queuedTime + 1); - vm.prank(governor); + vm.prank(GOVERNOR); treasury.toggleTimelock(); assertEq(treasury.timelockEnabled(), false); assertEq(treasury.onChainGovernanceTimelock(), 0); diff --git a/test/treasury/TreasuryCoefficienBigger.sol b/test/treasury/TreasuryCoefficienBigger.sol index 2707667..efe7053 100644 --- a/test/treasury/TreasuryCoefficienBigger.sol +++ b/test/treasury/TreasuryCoefficienBigger.sol @@ -1,23 +1,27 @@ pragma solidity 0.8.20; import {Test} from "forge-std/Test.sol"; -import {StdChains} from "forge-std/StdChains.sol"; -import "../../src/FatsoERC20.sol"; -import "../../src/GhostAuthority.sol"; -import "../../src/Treasury.sol"; -import "../../src/StandardBondingCalculator.sol"; -import "../../src/mocks/ERC20Mock.sol"; +import {Fatso} from "../../src/FatsoERC20.sol"; +import {GhostAuthority} from "../../src/GhostAuthority.sol"; +import {GhostTreasury} from "../../src/Treasury.sol"; +import {GhostBondingCalculator} from "../../src/StandardBondingCalculator.sol"; +import {ERC20Mock} from "../../src/mocks/ERC20Mock.sol"; + +import {ITreasury} from "../../src/interfaces/ITreasury.sol"; +import {IERC20} from "@openzeppelin-contracts/token/ERC20/IERC20.sol"; +import {IERC20Metadata} from "@openzeppelin-contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {SafeERC20} from "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; contract GhostTreasuryCoefficienBiggerTest is Test { - address public constant owner = 0x0000000000000000000000000000000000000001; - address public constant governor = 0x0000000000000000000000000000000000000002; - address public constant guardian = 0x0000000000000000000000000000000000000003; - address public constant other = 0x0000000000000000000000000000000000000004; - address public constant alice = 0x0000000000000000000000000000000000000005; - address public constant bob = 0x0000000000000000000000000000000000000006; + using SafeERC20 for IERC20; - uint256 public constant amount = 69 * 1e18; + address public constant OWNER = 0x0000000000000000000000000000000000000001; + address public constant GOVERNOR = 0x0000000000000000000000000000000000000002; + address public constant GUARDIAN = 0x0000000000000000000000000000000000000003; + address public constant ALICE = 0x0000000000000000000000000000000000000004; + + uint256 public constant AMOUNT = 69 * 1e18; Fatso ftso; ERC20Mock reserve; @@ -27,12 +31,12 @@ contract GhostTreasuryCoefficienBiggerTest is Test { GhostBondingCalculator calculator; function setUp() public { - vm.startPrank(owner); + vm.startPrank(OWNER); authority = new GhostAuthority( - governor, - guardian, - owner, - owner + GOVERNOR, + GUARDIAN, + OWNER, + OWNER ); reserve = new ERC20Mock("Reserve Token", "RET"); liquidity = new ERC20Mock("Liquidity Token", "LDT"); @@ -41,31 +45,31 @@ contract GhostTreasuryCoefficienBiggerTest is Test { calculator = new GhostBondingCalculator(address(ftso), 20, 1); vm.stopPrank(); - vm.prank(governor); + vm.prank(GOVERNOR); authority.pushVault(address(treasury)); - vm.startPrank(alice); - reserve.mint(alice, amount); + vm.startPrank(ALICE); + reserve.mint(ALICE, AMOUNT); reserve.approve(address(treasury), type(uint256).max); ftso.approve(address(treasury), type(uint256).max); vm.stopPrank(); } function test_auditTreasuryReservesWithCoefficient() public { - vm.startPrank(governor); - treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, alice, address(0)); + vm.startPrank(GOVERNOR); + treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, ALICE, address(0)); treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator)); vm.stopPrank(); assertEq(treasury.totalReserves(), 0); - uint256 tokenValue = treasury.tokenValue(address(reserve), amount); - vm.prank(alice); - IERC20(reserve).transfer(address(treasury), amount); + uint256 tokenValue = treasury.tokenValue(address(reserve), AMOUNT); + vm.prank(ALICE); + IERC20(reserve).safeTransfer(address(treasury), AMOUNT); assertEq(treasury.totalReserves(), 0); - vm.prank(governor); + vm.prank(GOVERNOR); treasury.auditReserves(); assertEq(treasury.totalReserves(), tokenValue); @@ -81,8 +85,8 @@ contract GhostTreasuryCoefficienBiggerTest is Test { } function test_originalCoefficientCorrect() public { - vm.startPrank(governor); - treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, alice, address(0)); + vm.startPrank(GOVERNOR); + treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, ALICE, address(0)); treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator)); vm.stopPrank(); diff --git a/test/treasury/TreasuryCoefficientLesser.sol b/test/treasury/TreasuryCoefficientLesser.sol index 7be1f5e..29f12b5 100644 --- a/test/treasury/TreasuryCoefficientLesser.sol +++ b/test/treasury/TreasuryCoefficientLesser.sol @@ -1,23 +1,27 @@ pragma solidity 0.8.20; import {Test} from "forge-std/Test.sol"; -import {StdChains} from "forge-std/StdChains.sol"; -import "../../src/FatsoERC20.sol"; -import "../../src/GhostAuthority.sol"; -import "../../src/Treasury.sol"; -import "../../src/StandardBondingCalculator.sol"; -import "../../src/mocks/ERC20Mock.sol"; +import {Fatso} from "../../src/FatsoERC20.sol"; +import {GhostAuthority} from "../../src/GhostAuthority.sol"; +import {GhostTreasury} from "../../src/Treasury.sol"; +import {GhostBondingCalculator} from "../../src/StandardBondingCalculator.sol"; +import {ERC20Mock} from "../../src/mocks/ERC20Mock.sol"; + +import {ITreasury} from "../../src/interfaces/ITreasury.sol"; +import {IERC20} from "@openzeppelin-contracts/token/ERC20/IERC20.sol"; +import {IERC20Metadata} from "@openzeppelin-contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {SafeERC20} from "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; contract GhostTreasuryCoefficientLesserTest is Test { - address public constant owner = 0x0000000000000000000000000000000000000001; - address public constant governor = 0x0000000000000000000000000000000000000002; - address public constant guardian = 0x0000000000000000000000000000000000000003; - address public constant other = 0x0000000000000000000000000000000000000004; - address public constant alice = 0x0000000000000000000000000000000000000005; - address public constant bob = 0x0000000000000000000000000000000000000006; + using SafeERC20 for IERC20; - uint256 public constant amount = 69 * 1e18; + address public constant OWNER = 0x0000000000000000000000000000000000000001; + address public constant GOVERNOR = 0x0000000000000000000000000000000000000002; + address public constant GUARDIAN = 0x0000000000000000000000000000000000000003; + address public constant ALICE = 0x0000000000000000000000000000000000000004; + + uint256 public constant AMOUNT = 69 * 1e18; Fatso ftso; ERC20Mock reserve; @@ -27,12 +31,12 @@ contract GhostTreasuryCoefficientLesserTest is Test { GhostBondingCalculator calculator; function setUp() public { - vm.startPrank(owner); + vm.startPrank(OWNER); authority = new GhostAuthority( - governor, - guardian, - owner, - owner + GOVERNOR, + GUARDIAN, + OWNER, + OWNER ); reserve = new ERC20Mock("Reserve Token", "RET"); liquidity = new ERC20Mock("Liquidity Token", "LDT"); @@ -41,11 +45,11 @@ contract GhostTreasuryCoefficientLesserTest is Test { calculator = new GhostBondingCalculator(address(ftso), 1, 20); vm.stopPrank(); - vm.prank(governor); + vm.prank(GOVERNOR); authority.pushVault(address(treasury)); - vm.startPrank(alice); - reserve.mint(alice, amount); + vm.startPrank(ALICE); + reserve.mint(ALICE, AMOUNT); reserve.approve(address(treasury), type(uint256).max); ftso.approve(address(treasury), type(uint256).max); vm.stopPrank(); @@ -53,45 +57,45 @@ contract GhostTreasuryCoefficientLesserTest is Test { function test_deposit_onlyIfApprovedTokenAndApprovedAddress() public { vm.expectRevert(); - vm.prank(alice); - treasury.deposit(address(reserve), amount, 0); + vm.prank(ALICE); + treasury.deposit(address(reserve), AMOUNT, 0); - vm.prank(governor); - treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, alice, address(0)); + vm.prank(GOVERNOR); + treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, ALICE, address(0)); vm.expectRevert(); - vm.prank(alice); - treasury.deposit(address(reserve), amount, 0); + vm.prank(ALICE); + treasury.deposit(address(reserve), AMOUNT, 0); - vm.prank(governor); + vm.prank(GOVERNOR); treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator)); - vm.prank(alice); - uint256 send = treasury.deposit(address(reserve), amount, 0); + vm.prank(ALICE); + uint256 send = treasury.deposit(address(reserve), AMOUNT, 0); - assertEq(ftso.balanceOf(alice), send); - assertEq(reserve.balanceOf(address(treasury)), amount); + assertEq(ftso.balanceOf(ALICE), send); + assertEq(reserve.balanceOf(address(treasury)), AMOUNT); - vm.startPrank(governor); - treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, alice, address(0)); + vm.startPrank(GOVERNOR); + treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, ALICE, address(0)); treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator)); vm.stopPrank(); } function test_auditTreasuryReservesWithCoefficient() public { - vm.startPrank(governor); - treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, alice, address(0)); + vm.startPrank(GOVERNOR); + treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, ALICE, address(0)); treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator)); vm.stopPrank(); assertEq(treasury.totalReserves(), 0); - uint256 tokenValue = treasury.tokenValue(address(reserve), amount); - vm.prank(alice); - IERC20(reserve).transfer(address(treasury), amount); + uint256 tokenValue = treasury.tokenValue(address(reserve), AMOUNT); + vm.prank(ALICE); + IERC20(reserve).safeTransfer(address(treasury), AMOUNT); assertEq(treasury.totalReserves(), 0); - vm.prank(governor); + vm.prank(GOVERNOR); treasury.auditReserves(); assertEq(treasury.totalReserves(), tokenValue); @@ -107,8 +111,8 @@ contract GhostTreasuryCoefficientLesserTest is Test { } function test_originalCoefficientCorrect() public { - vm.startPrank(governor); - treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, alice, address(0)); + vm.startPrank(GOVERNOR); + treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, ALICE, address(0)); treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator)); vm.stopPrank(); diff --git a/test/treasury/TreasuryRedemption.t.sol b/test/treasury/TreasuryRedemption.t.sol index 442d3f2..42f2238 100644 --- a/test/treasury/TreasuryRedemption.t.sol +++ b/test/treasury/TreasuryRedemption.t.sol @@ -1,78 +1,83 @@ pragma solidity 0.8.20; import {Test} from "forge-std/Test.sol"; -import {StdChains} from "forge-std/StdChains.sol"; -import "../../src/GhostAuthority.sol"; -import "../../src/Treasury.sol"; -import "../../src/StandardBondingCalculator.sol"; +import {GhostAuthority} from "../../src/GhostAuthority.sol"; +import {GhostTreasury} from "../../src/Treasury.sol"; +import {GhostBondingCalculator} from "../../src/StandardBondingCalculator.sol"; -import "@uniswap-v2-periphery-1.1.0-beta.0/interfaces/IWETH.sol"; +import {ITreasury} from "../../src/interfaces/ITreasury.sol"; +import {IERC20} from "@openzeppelin-contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; + +import {IWETH} from "@uniswap-v2-periphery-1.1.0-beta.0/interfaces/IWETH.sol"; contract GhostTreasuryRedemptionTest is Test { - address public constant owner = 0x0000000000000000000000000000000000000001; - address public constant governor = 0x0000000000000000000000000000000000000002; - address public constant guardian = 0x0000000000000000000000000000000000000003; + using SafeERC20 for IERC20; - uint256 public constant amount = 69 * 1e18; - address public constant dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F; - address public constant pair = 0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11; - address public constant router = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D; - address public constant weth = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; + address public constant OWNER = 0x0000000000000000000000000000000000000001; + address public constant GOVERNOR = 0x0000000000000000000000000000000000000002; + address public constant GUARDIAN = 0x0000000000000000000000000000000000000003; + + uint256 public constant AMOUNT = 69 * 1e18; + address public constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F; + address public constant PAIR = 0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11; + address public constant ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D; + address public constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; GhostTreasury treasury; GhostAuthority authority; GhostBondingCalculator calculator; function setUp() public { - vm.startPrank(owner); + vm.startPrank(OWNER); authority = new GhostAuthority( - governor, - guardian, - owner, - owner + GOVERNOR, + GUARDIAN, + OWNER, + OWNER ); - treasury = new GhostTreasury(dai, 69, address(authority)); - calculator = new GhostBondingCalculator(dai, 4000, 1); + treasury = new GhostTreasury(DAI, 69, address(authority)); + calculator = new GhostBondingCalculator(DAI, 4000, 1); vm.stopPrank(); - vm.startPrank(governor); - treasury.enable(ITreasury.STATUS.RESERVETOKEN, weth, address(calculator)); - treasury.enable(ITreasury.STATUS.LIQUIDITYTOKEN, pair, address(calculator)); + vm.startPrank(GOVERNOR); + treasury.enable(ITreasury.STATUS.RESERVETOKEN, WETH, address(calculator)); + treasury.enable(ITreasury.STATUS.LIQUIDITYTOKEN, PAIR, address(calculator)); vm.stopPrank(); } function test_mainnet_redemptionWorksCorrectly() public { - vm.deal(owner, amount); - vm.startPrank(owner); - IWETH(weth).deposit{value: amount}(); - IERC20(weth).transfer(address(treasury), amount); - assertEq(IERC20(weth).balanceOf(address(treasury)), amount); + vm.deal(OWNER, AMOUNT); + vm.startPrank(OWNER); + IWETH(WETH).deposit{value: AMOUNT}(); + IERC20(WETH).safeTransfer(address(treasury), AMOUNT); + assertEq(IERC20(WETH).balanceOf(address(treasury)), AMOUNT); vm.stopPrank(); assertEq(treasury.totalReserves(), 0); - vm.prank(governor); + vm.prank(GOVERNOR); treasury.auditReserves(); uint256 prevTotalReserves = treasury.totalReserves(); assertEq(prevTotalReserves > 0, true); - assertEq(IERC20(pair).balanceOf(address(treasury)), 0); - assertEq(IERC20(pair).balanceOf(address(treasury)), 0); + assertEq(IERC20(PAIR).balanceOf(address(treasury)), 0); + assertEq(IERC20(PAIR).balanceOf(address(treasury)), 0); - vm.prank(governor); - treasury.redeemReserve(router, amount); + vm.prank(GOVERNOR); + treasury.redeemReserve(ROUTER, AMOUNT); - assertEq(IERC20(dai).balanceOf(address(treasury)), 0); - assertEq(IERC20(weth).balanceOf(address(treasury)), 0); - assertEq(IERC20(pair).balanceOf(address(treasury)) > 0, true); + assertEq(IERC20(DAI).balanceOf(address(treasury)), 0); + assertEq(IERC20(WETH).balanceOf(address(treasury)), 0); + assertEq(IERC20(PAIR).balanceOf(address(treasury)) > 0, true); - uint256 liquidity = IERC20(pair).balanceOf(address(treasury)); - vm.prank(governor); - treasury.forfeitReserves(router, liquidity, false); + uint256 liquidity = IERC20(PAIR).balanceOf(address(treasury)); + vm.prank(GOVERNOR); + treasury.forfeitReserves(ROUTER, liquidity, false); - assertEq(IERC20(dai).balanceOf(address(treasury)) > 0, true); - assertEq(IERC20(weth).balanceOf(address(treasury)) > 0, true); - assertEq(IERC20(pair).balanceOf(address(treasury)), 0); + assertEq(IERC20(DAI).balanceOf(address(treasury)) > 0, true); + assertEq(IERC20(WETH).balanceOf(address(treasury)) > 0, true); + assertEq(IERC20(PAIR).balanceOf(address(treasury)), 0); } }