From 2d09249daaef77fbcd4cfb9af06cbf31575c5b18 Mon Sep 17 00:00:00 2001 From: Mitch Oz Date: Tue, 9 Jan 2024 14:25:55 -0600 Subject: [PATCH 01/31] make modifications for transferAllocation function --- contracts/ModifiedTokenDistro.sol | 461 ++++++++++++++++++++++ contracts/interfaces/IDistro.sol | 2 +- contracts/interfaces/IDistroModified.sol | 102 +++++ contracts/tokens/GIV.sol | 2 +- contracts/tokens/UniswapV3RewardToken.sol | 8 +- test/ModifyTokenDistro.t.sol | 311 +++++++++++++++ 6 files changed, 880 insertions(+), 6 deletions(-) create mode 100644 contracts/ModifiedTokenDistro.sol create mode 100644 contracts/interfaces/IDistroModified.sol create mode 100644 test/ModifyTokenDistro.t.sol diff --git a/contracts/ModifiedTokenDistro.sol b/contracts/ModifiedTokenDistro.sol new file mode 100644 index 0000000..66a7272 --- /dev/null +++ b/contracts/ModifiedTokenDistro.sol @@ -0,0 +1,461 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.6; + +import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import "@openzeppelin/contracts/utils/math/SafeMath.sol"; +import "./interfaces/IDistroModified.sol"; + +/** + * Contract responsible for managing the release of tokens over time. + * The distributor is in charge of releasing the corresponding amounts to its recipients. + * This distributor is expected to be another smart contract, such as a merkledrop or the liquidity mining smart contract + */ +contract TokenDistro is + Initializable, + IDistro, + AccessControlEnumerableUpgradeable +{ + using SafeMath for uint256; + using SafeERC20Upgradeable for IERC20Upgradeable; + + // bytes32 public constant DISTRIBUTOR_ROLE = keccak256("DISTRIBUTOR_ROLE"); + bytes32 public constant DISTRIBUTOR_ROLE = + 0xfbd454f36a7e1a388bd6fc3ab10d434aa4578f811acbbcf33afb1c697486313c; + + // Structure to of the accounting for each account + struct accountStatus { + uint256 allocatedTokens; + uint256 claimed; + } + + mapping(address => accountStatus) public balances; // Mapping with all accounts that have received an allocation + + uint256 public override totalTokens; // total tokens to be distribute + uint256 public startTime; // Instant of time in which distribution begins + uint256 public cliffTime; // Instant of time in which tokens will begin to be released + uint256 public duration; + uint256 public initialAmount; // Initial amount that will be available from startTime + uint256 public lockedAmount; // Amount that will be released over time from cliffTime + + IERC20Upgradeable public token; // Token to be distribute + bool public cancelable; // Variable that allows the ADMIN_ROLE to cancel an allocation + + /** + * @dev Emitted when the DISTRIBUTOR allocate an amount of givBack to a recipient + */ + event GivBackPaid(address distributor); + + /** + * @dev Emitted when the DISTRIBUTOR allocate an amount of praise rewards to a recipient + */ + event PraiseRewardPaid(address distributor); + + /** + * @dev Emitted when the duration is changed + */ + event DurationChanged(uint256 newDuration); + + modifier onlyDistributor() { + require( + hasRole(DISTRIBUTOR_ROLE, msg.sender), + "TokenDistro::onlyDistributor: ONLY_DISTRIBUTOR_ROLE" + ); + + require( + balances[msg.sender].claimed == 0, + "TokenDistro::onlyDistributor: DISTRIBUTOR_CANNOT_CLAIM" + ); + _; + } + + /** + * @dev Initially the deployer of the contract will be able to assign the tokens to one or several addresses, + * these addresses (EOA or Smart Contracts) are responsible to allocate tokens to specific addresses which can + * later claim them + * @param _totalTokens Total amount of tokens to distribute + * @param _startTime Unix time that the distribution begins + * @param _cliffPeriod Number of seconds to delay the claiming period for the tokens not initially released + * @param _duration Time it will take for all tokens to be distributed + * @param _initialPercentage Percentage of tokens initially released (2 decimals, 1/10000) + * @param _token Address of the token to distribute + * @param _cancelable In case the owner wants to have the power to cancel an assignment + */ + function initialize( + uint256 _totalTokens, + uint256 _startTime, + uint256 _cliffPeriod, + uint256 _duration, + uint256 _initialPercentage, + IERC20Upgradeable _token, + bool _cancelable + ) public initializer { + require( + _duration >= _cliffPeriod, + "TokenDistro::constructor: DURATION_LESS_THAN_CLIFF" + ); + require( + _initialPercentage <= 10000, + "TokenDistro::constructor: INITIALPERCENTAGE_GREATER_THAN_100" + ); + __AccessControlEnumerable_init(); + _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); + + uint256 _initialAmount = (_totalTokens * _initialPercentage) / 10000; + + token = _token; + duration = _duration; + startTime = _startTime; + totalTokens = _totalTokens; + initialAmount = _initialAmount; + cliffTime = _startTime + _cliffPeriod; + lockedAmount = _totalTokens - _initialAmount; + balances[address(this)].allocatedTokens = _totalTokens; + cancelable = _cancelable; + } + + /** + * Function that allows the DEFAULT_ADMIN_ROLE to assign set a new startTime if it hasn't started yet + * @param newStartTime new startTime + * + * Emits a {StartTimeChanged} event. + * + */ + function setStartTime(uint256 newStartTime) external override { + require( + hasRole(DEFAULT_ADMIN_ROLE, msg.sender), + "TokenDistro::setStartTime: ONLY_ADMIN_ROLE" + ); + require( + startTime > getTimestamp() && newStartTime > getTimestamp(), + "TokenDistro::setStartTime: IF_HAS_NOT_STARTED_YET" + ); + + uint256 _cliffPeriod = cliffTime - startTime; + startTime = newStartTime; + cliffTime = newStartTime + _cliffPeriod; + + emit StartTimeChanged(startTime, cliffTime); + } + + /** + * Function that allows the DEFAULT_ADMIN_ROLE to assign tokens to an address who later can distribute them. + * @dev It is required that the DISTRIBUTOR_ROLE is already held by the address to which an amount will be assigned + * @param distributor the address, generally a smart contract, that will determine who gets how many tokens + * @param amount Total amount of tokens to assign to that address for distributing + * + * Emits a {Assign} event. + * + */ + function assign(address distributor, uint256 amount) external override { + require( + hasRole(DEFAULT_ADMIN_ROLE, msg.sender), + "TokenDistro::assign: ONLY_ADMIN_ROLE" + ); + require( + hasRole(DISTRIBUTOR_ROLE, distributor), + "TokenDistro::assign: ONLY_TO_DISTRIBUTOR_ROLE" + ); + + balances[address(this)].allocatedTokens = + balances[address(this)].allocatedTokens - + amount; + balances[distributor].allocatedTokens = + balances[distributor].allocatedTokens + + amount; + + emit Assign(msg.sender, distributor, amount); + } + + /** + * Function to claim tokens for a specific address. It uses the current timestamp + * + * Emits a {claim} event. + * + */ + function claimTo(address account) external { + // This check is not necessary as it does not break anything, just changes the claimed value + // for this contract + //require(address(this) != account, "TokenDistro::claimTo: CANNOT_CLAIM_FOR_CONTRACT_ITSELF"); + _claim(account); + } + + /** + * Function to claim tokens for a specific address. It uses the current timestamp + * + * Emits a {claim} event. + * + */ + function claim() external override { + _claim(msg.sender); + } + + /** + * Function that allows to the distributor address to allocate some amount of tokens to a specific recipient + * @param recipient of token allocation + * @param amount allocated amount + * @param claim whether claim after allocate + * + * Emits a {Allocate} event. + * + */ + function _allocate( + address recipient, + uint256 amount, + bool claim + ) internal { + require( + !hasRole(DISTRIBUTOR_ROLE, recipient), + "TokenDistro::allocate: DISTRIBUTOR_NOT_VALID_RECIPIENT" + ); + + balances[msg.sender].allocatedTokens = + balances[msg.sender].allocatedTokens - + amount; + + balances[recipient].allocatedTokens = + balances[recipient].allocatedTokens + + amount; + + if (claim && claimableNow(recipient) > 0) { + _claim(recipient); + } + + emit Allocate(msg.sender, recipient, amount); + } + + function allocate( + address recipient, + uint256 amount, + bool claim + ) external override onlyDistributor { + _allocate(recipient, amount, claim); + } + + /** + * Function that allows to the distributor address to allocate some amounts of tokens to specific recipients + * @dev Needs to be initialized: Nobody has the DEFAULT_ADMIN_ROLE and all available tokens have been assigned + * @param recipients of token allocation + * @param amounts allocated amount + * + * Unlike allocate method it doesn't claim recipients available balance + */ + function _allocateMany( + address[] memory recipients, + uint256[] memory amounts + ) internal onlyDistributor { + require( + recipients.length == amounts.length, + "TokenDistro::allocateMany: INPUT_LENGTH_NOT_MATCH" + ); + + for (uint256 i = 0; i < recipients.length; i++) { + _allocate(recipients[i], amounts[i], false); + } + } + + function allocateMany(address[] memory recipients, uint256[] memory amounts) + external + override + { + _allocateMany(recipients, amounts); + } + + function sendGIVbacks(address[] memory recipients, uint256[] memory amounts) + external + override + { + _allocateMany(recipients, amounts); + emit GivBackPaid(msg.sender); + } + + function sendPraiseRewards( + address[] memory recipients, + uint256[] memory amounts + ) external { + _allocateMany(recipients, amounts); + emit PraiseRewardPaid(msg.sender); + } + + /** + * Function that allows a recipient to change its address + * @dev The change can only be made to an address that has not previously received an allocation & + * the distributor cannot change its address + * + * Emits a {ChangeAddress} event. + * + */ + function changeAddress(address newAddress) external override { + // require( + // balances[newAddress].allocatedTokens == 0 && + // balances[newAddress].claimed == 0, + // "TokenDistro::changeAddress: ADDRESS_ALREADY_IN_USE" + // ); + + require( + !hasRole(DISTRIBUTOR_ROLE, msg.sender) && + !hasRole(DISTRIBUTOR_ROLE, newAddress), + "TokenDistro::changeAddress: DISTRIBUTOR_ROLE_NOT_A_VALID_ADDRESS" + ); + // balance adds instead of overwrites + balances[newAddress].allocatedTokens += balances[msg.sender] + .allocatedTokens; + balances[msg.sender].allocatedTokens = 0; + + balances[newAddress].claimed += balances[msg.sender].claimed; + balances[msg.sender].claimed = 0; + + emit ChangeAddress(msg.sender, newAddress); + } + + /** + * Function to get the current timestamp from the block + */ + function getTimestamp() public view virtual override returns (uint256) { + return block.timestamp; + } + + /** + * Function to get the total claimable tokens at some moment + * @param timestamp Unix time to check the number of tokens claimable + * @return Number of tokens claimable at that timestamp + */ + function globallyClaimableAt(uint256 timestamp) + public + view + override + returns (uint256) + { + if (timestamp < startTime) return 0; + if (timestamp < cliffTime) return initialAmount; + if (timestamp > startTime + duration) return totalTokens; + + uint256 deltaTime = timestamp - startTime; + return initialAmount + (deltaTime * lockedAmount) / duration; + } + + /** + * Function to get the unlocked tokes at some moment for a specific address + * @param recipient account to query + * @param timestamp Instant of time in which the calculation is made + */ + function claimableAt(address recipient, uint256 timestamp) + public + view + override + returns (uint256) + { + require( + !hasRole(DISTRIBUTOR_ROLE, recipient), + "TokenDistro::claimableAt: DISTRIBUTOR_ROLE_CANNOT_CLAIM" + ); + require( + timestamp >= getTimestamp(), + "TokenDistro::claimableAt: NOT_VALID_PAST_TIMESTAMP" + ); + uint256 unlockedAmount = (globallyClaimableAt(timestamp) * + balances[recipient].allocatedTokens) / totalTokens; + + return unlockedAmount - balances[recipient].claimed; + } + + /** + * Function to get the unlocked tokens for a specific address. It uses the current timestamp + * @param recipient account to query + */ + function claimableNow(address recipient) + public + view + override + returns (uint256) + { + return claimableAt(recipient, getTimestamp()); + } + + /** + * Function that allows the DEFAULT_ADMIN_ROLE to change a recipient in case it wants to cancel an allocation + * @dev The change can only be made when cancelable is true and to an address that has not previously received + * an allocation and the distributor cannot change its address + * + * Emits a {ChangeAddress} event. + * + */ + function transferAllocation(address prevRecipient, address newRecipient) + external + override + { + require(balances[prevRecipient].allocatedTokens > 0, "TokenDistro::transferAllocation: NO_ALLOCATION_TO_TRANSFER"); + require( + hasRole(DEFAULT_ADMIN_ROLE, msg.sender), + "TokenDistro::transferAllocation: ONLY_ADMIN_ROLE" + ); + + // require( + // balances[newRecipient].allocatedTokens == 0 && + // balances[newRecipient].claimed == 0, + // "TokenDistro::cancelAllocation: ADDRESS_ALREADY_IN_USE" + // ); + + require( + !hasRole(DISTRIBUTOR_ROLE, prevRecipient) && + !hasRole(DISTRIBUTOR_ROLE, newRecipient), + "TokenDistro::transferAllocation: DISTRIBUTOR_ROLE_NOT_A_VALID_ADDRESS" + ); + // balance adds instead of overwrites + balances[newRecipient].allocatedTokens = balances[prevRecipient] + .allocatedTokens.add(balances[newRecipient].allocatedTokens); + balances[prevRecipient].allocatedTokens = 0; + + balances[newRecipient].claimed = balances[prevRecipient].claimed.add( + balances[newRecipient].claimed); + + balances[prevRecipient].claimed = 0; + + emit ChangeAddress(prevRecipient, newRecipient); + } + + /** + * Function to claim tokens for a specific address. It uses the current timestamp + * + * Emits a {claim} event. + * + */ + function _claim(address recipient) private { + uint256 remainingToClaim = claimableNow(recipient); + + require( + remainingToClaim > 0, + "TokenDistro::claim: NOT_ENOUGH_TOKENS_TO_CLAIM" + ); + + balances[recipient].claimed = + balances[recipient].claimed + + remainingToClaim; + + token.safeTransfer(recipient, remainingToClaim); + + emit Claim(recipient, remainingToClaim); + } + + /** + * Function to change the duration + */ + function setDuration(uint256 newDuration) public { + require( + hasRole(DEFAULT_ADMIN_ROLE, msg.sender), + "TokenDistro::setDuration: ONLY_ADMIN_ROLE" + ); + + require( + startTime > getTimestamp(), + "TokenDistro::setDuration: IF_HAS_NOT_STARTED_YET" + ); + + duration = newDuration; + + emit DurationChanged(newDuration); + } + +} diff --git a/contracts/interfaces/IDistro.sol b/contracts/interfaces/IDistro.sol index 165416f..975ef7b 100644 --- a/contracts/interfaces/IDistro.sol +++ b/contracts/interfaces/IDistro.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity =0.8.10; +pragma solidity ^0.8.10; interface IDistro { /** diff --git a/contracts/interfaces/IDistroModified.sol b/contracts/interfaces/IDistroModified.sol new file mode 100644 index 0000000..1709e57 --- /dev/null +++ b/contracts/interfaces/IDistroModified.sol @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity ^0.8.10; + +interface IDistro { + /** + * @dev Emitted when someone makes a claim of tokens + */ + event Claim(address indexed grantee, uint256 amount); + /** + * @dev Emitted when the DISTRIBUTOR allocate an amount to a grantee + */ + event Allocate(address indexed distributor, address indexed grantee, uint256 amount); + /** + * @dev Emitted when the DEFAULT_ADMIN assign an amount to a DISTRIBUTOR + */ + event Assign(address indexed admin, address indexed distributor, uint256 amount); + /** + * @dev Emitted when someone change their reception address + */ + event ChangeAddress(address indexed oldAddress, address indexed newAddress); + + /** + * @dev Emitted when a new startTime is set + */ + event StartTimeChanged(uint256 newStartTime, uint256 newCliffTime); + + /** + * @dev Returns the total amount of tokens will be streamed + */ + function totalTokens() external view returns (uint256); + + /** + * Function that allows the DEFAULT_ADMIN_ROLE to assign set a new startTime if it hasn't started yet + * @param newStartTime new startTime + * + * Emits a {StartTimeChanged} event. + * + */ + function setStartTime(uint256 newStartTime) external; + + /** + * Function that allows the DEFAULT_ADMIN_ROLE to assign tokens to an address who later can distribute them. + * @dev It is required that the DISTRIBUTOR_ROLE is already held by the address to which an amount will be assigned + * @param distributor the address, generally a smart contract, that will determine who gets how many tokens + * @param amount Total amount of tokens to assign to that address for distributing + */ + function assign(address distributor, uint256 amount) external; + + /** + * Function to claim tokens for a specific address. It uses the current timestamp + */ + function claim() external; + + /** + * Function that allows to the distributor address to allocate some amount of tokens to a specific recipient + * @dev Needs to be initialized: Nobody has the DEFAULT_ADMIN_ROLE and all available tokens have been assigned + * @param recipient of token allocation + * @param amount allocated amount + * @param claim whether claim after allocate + */ + function allocate(address recipient, uint256 amount, bool claim) external; + + /** + * Function that allows to the distributor address to allocate some amounts of tokens to specific recipients + * @dev Needs to be initialized: Nobody has the DEFAULT_ADMIN_ROLE and all available tokens have been assigned + * @param recipients of token allocation + * @param amounts allocated amount + */ + function allocateMany(address[] memory recipients, uint256[] memory amounts) external; + + function sendGIVbacks(address[] memory recipients, uint256[] memory amounts) external; + + /** + * Function that allows a recipient to change its address + * @dev The change can only be made to an address that has not previously received an allocation & + * the distributor cannot change its address + */ + function changeAddress(address newAddress) external; + + /** + * Function to get the current timestamp from the block + */ + function getTimestamp() external view returns (uint256); + + /** + * Function to get the total unlocked tokes at some moment + */ + function globallyClaimableAt(uint256 timestamp) external view returns (uint256); + + /** + * Function to get the unlocked tokes at some moment for a specific address + */ + function claimableAt(address recipient, uint256 timestamp) external view returns (uint256); + + /** + * Function to get the unlocked tokens for a specific address. It uses the current timestamp + */ + function claimableNow(address recipient) external view returns (uint256); + + function transferAllocation(address prevRecipient, address newRecipient) external; +} diff --git a/contracts/tokens/GIV.sol b/contracts/tokens/GIV.sol index c431498..dd27180 100644 --- a/contracts/tokens/GIV.sol +++ b/contracts/tokens/GIV.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.6; -import "openzeppelin-contracts-v4/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; // Lightweight token modelled after UNI-LP: // https://github.com/Uniswap/uniswap-v2-core/blob/v1.0.1/contracts/UniswapV2ERC20.sol diff --git a/contracts/tokens/UniswapV3RewardToken.sol b/contracts/tokens/UniswapV3RewardToken.sol index e076be0..3523a94 100644 --- a/contracts/tokens/UniswapV3RewardToken.sol +++ b/contracts/tokens/UniswapV3RewardToken.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.6; +pragma solidity ^0.8.6; -import "openzeppelin-contracts-v4/token/ERC20/IERC20.sol"; -import "openzeppelin-contracts-upgradable-v4/access/OwnableUpgradeable.sol"; -import "../Interfaces/IDistro.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import "../interfaces/IDistro.sol"; contract UniswapV3RewardToken is IERC20, OwnableUpgradeable { uint256 public initialBalance; diff --git a/test/ModifyTokenDistro.t.sol b/test/ModifyTokenDistro.t.sol new file mode 100644 index 0000000..007cf17 --- /dev/null +++ b/test/ModifyTokenDistro.t.sol @@ -0,0 +1,311 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.6; + +import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import "@openzeppelin/contracts/utils/math/SafeMath.sol"; +import '@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol'; +import '@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol'; +import 'forge-std/Test.sol'; +import 'forge-std/console.sol'; +import '../contracts/ModifiedTokenDistro.sol'; + +contract TestModifyDistro is Test { + using SafeERC20Upgradeable for IERC20Upgradeable; + using SafeMath for uint256; + ProxyAdmin proxyAdmin; + IERC20Upgradeable givToken; + address givethMultisig; + address distributor; + address firstRecipient; + address secondRecipient; + address thirdRecipient; + + // deploy the token distro + TransparentUpgradeableProxy tokenDistroProxy; + IDistro tokenDistroInterface; + TokenDistro tokenDistro; + TokenDistro tokenDistroImplementation; + uint256 assignedAmount = 10000000000000000000000000; + uint256 forkBlock = 22501098; + + constructor() { + uint256 forkId = vm.createFork('https://rpc.ankr.com/gnosis', forkBlock); //https://xdai-archive.blockscout.com/ + vm.selectFork(forkId); + proxyAdmin = ProxyAdmin(address(0x076C250700D210e6cf8A27D1EB1Fd754FB487986)); + tokenDistro = TokenDistro(address(0xc0dbDcA66a0636236fAbe1B3C16B1bD4C84bB1E1)); + tokenDistroProxy = TransparentUpgradeableProxy(payable(address(0xc0dbDcA66a0636236fAbe1B3C16B1bD4C84bB1E1))); + givethMultisig = 0x4D9339dd97db55e3B9bCBE65dE39fF9c04d1C2cd; + givToken = IERC20Upgradeable(address(0x4f4F9b8D5B4d0Dc10506e5551B0513B61fD59e75)); + distributor = address(5); + firstRecipient = address(6); + secondRecipient = address(7); + thirdRecipient = address(8); + } + + function setUp() public { + vm.startPrank(givethMultisig); + tokenDistroImplementation = new TokenDistro(); + // proxyAdmin.upgradeAndCall(tokenDistroProxy, address(tokenDistroImplementation), abi.encodeWithSelector(TokenDistro(tokenDistroImplementation).initialize.selector, 2000000000000000000000000000, 1640361600, 1640361600, 157680000, givToken, true)); + proxyAdmin.upgrade(tokenDistroProxy, address(tokenDistroImplementation)); + tokenDistro.grantRole(keccak256("DISTRIBUTOR_ROLE"), distributor); + tokenDistro.assign(distributor, assignedAmount); + vm.stopPrank(); + + vm.label(address(tokenDistro), 'tokenDistroContract'); + vm.label(address(tokenDistroImplementation), 'tokenDistroImplementation'); + vm.label(address(tokenDistroProxy), 'tokenDistroProxy'); + vm.label(address(givToken), 'givToken'); + vm.label(address(givethMultisig), 'givethMultisig'); + vm.label(address(distributor), 'distributor'); + vm.label(address(firstRecipient), 'firstRecipient'); + vm.label(address(secondRecipient), 'secondRecipient'); + vm.label(address(thirdRecipient), 'thirdRecipient'); + + } + function testTransferAllocation(uint256 amount1, uint256 amount2, uint256 amount3) public { + // bound the amounts to be between 1 and 1/3 of the assigned amount so it cannot go over the assigned amount + amount1 = bound(amount1, 1, assignedAmount.div(3)); + amount2 = bound(amount2, 1, assignedAmount.div(3)); + amount3 = bound(amount3, 1, assignedAmount.div(3)); + // setup the distribution arrays for allocation + address[] memory recipients = new address[](3); + recipients[0] = firstRecipient; + recipients[1] = secondRecipient; + recipients[2] = thirdRecipient; + + uint256[] memory amounts = new uint256[](3); + amounts[0] = amount1; + amounts[1] = amount2; + amounts[2] = amount3; + + // give some starting allocations to the recipients + vm.prank(distributor); + tokenDistro.allocateMany(recipients, amounts); + + // save balance values + (uint256 firstRecipientAllocatedTokens,) = tokenDistro.balances(firstRecipient); + (uint256 secondRecipientAllocatedTokens,) = tokenDistro.balances(secondRecipient); + // make first transfer from first recipient to second recipient + vm.prank(givethMultisig); + tokenDistro.transferAllocation(firstRecipient, secondRecipient); + + // save balance values after first transfer + (uint256 secondRecipientAllocatedTokensAfterTransfer,) = tokenDistro.balances(secondRecipient); + (uint256 firstRecipientAllocatedTokensAfterTransfer,) = tokenDistro.balances(firstRecipient); + // log some stuff + console.log('secondRecipientAllocatedTokensAfterTransfer: ', secondRecipientAllocatedTokensAfterTransfer); + console.log('secondRecipientAllocatedTokens: ', secondRecipientAllocatedTokens); + console.log('firstRecipientAllocatedTokensAfterTransfer: ', firstRecipientAllocatedTokensAfterTransfer); + console.log('firstRecipientAllocatedTokens: ', firstRecipientAllocatedTokens); + // assertions + assertEq(secondRecipientAllocatedTokensAfterTransfer, (firstRecipientAllocatedTokens.add(secondRecipientAllocatedTokens))); + assertEq(firstRecipientAllocatedTokensAfterTransfer,0); + + // do second transfer from second recip to third recip + vm.prank(givethMultisig); + tokenDistro.transferAllocation(secondRecipient, thirdRecipient); + + // save balance values after second transfer + (uint256 thirdRecipientAllocatedTokensAfterTransfer,) = tokenDistro.balances(thirdRecipient); + (uint256 secondRecipientAllocatedTokensAfterSecondTransfer,) = tokenDistro.balances(secondRecipient); + // expected amount should be the sum of all three amounts + uint256 expectedAmount = amount1.add(amount2.add(amount3)); + // log some stuff + console.log('thirdRecipientAllocatedTokensAfterTransfer: ', thirdRecipientAllocatedTokensAfterTransfer); + console.log('expectedAmount: ', expectedAmount); + // assertions + assertEq(thirdRecipientAllocatedTokensAfterTransfer,expectedAmount); + assertEq(secondRecipientAllocatedTokensAfterSecondTransfer,0); + + } + + function testTransferAllocationWithClaim(uint256 amount1, uint256 amount2) public { + amount1 = bound(amount1, 10, assignedAmount.div(2)); + amount2 = bound(amount2, 10, assignedAmount.div(2)); + + address[] memory recipients = new address[](2); + recipients[0] = firstRecipient; + recipients[1] = secondRecipient; + + uint256[] memory amounts = new uint256[](2); + amounts[0] = amount1; + amounts[1] = amount2; + + vm.prank(distributor); + tokenDistro.allocateMany(recipients, amounts); + + // skip ahead some time and then claim tokens + skip(14 days); + console.log('claimable for first recipient',tokenDistro.claimableNow(firstRecipient)); + console.log('claimable for second recipient', tokenDistro.claimableNow(secondRecipient)); + + vm.prank(firstRecipient); + tokenDistro.claim(); + vm.prank(secondRecipient); + tokenDistro.claim(); + + // save balance values + (, uint256 secondRecipientClaimedTokens) = tokenDistro.balances(secondRecipient); + (, uint256 firstRecipientClaimedTokens) = tokenDistro.balances(firstRecipient); + // transfer allocation to second recipient + vm.prank(givethMultisig); + tokenDistro.transferAllocation(firstRecipient, secondRecipient); + // check values of second recipient after transfer + (uint256 secondAllocatedAfterTransfer, uint256 secondClaimedAfterTransfer) = tokenDistro.balances(secondRecipient); + (uint256 firstAllocatedAfterTransfer, uint256 firstClaimedAfterTransfer) = tokenDistro.balances(firstRecipient); + // assertions + assertEq(secondAllocatedAfterTransfer, (amount1.add(amount2))); + assertEq(secondClaimedAfterTransfer, (secondRecipientClaimedTokens.add(firstRecipientClaimedTokens))); + assertEq(firstAllocatedAfterTransfer, 0); + assertEq(firstClaimedAfterTransfer, 0); + + } + + function testChangeAddress(uint256 amount1, uint256 amount2, uint256 amount3) public { + // bound the amounts to be between 1 and 1/3 of the assigned amount so it cannot go over the assigned amount + amount1 = bound(amount1, 1, assignedAmount.div(3)); + amount2 = bound(amount2, 1, assignedAmount.div(3)); + amount3 = bound(amount3, 1, assignedAmount.div(3)); + // setup the distribution arrays for allocation + address[] memory recipients = new address[](3); + recipients[0] = firstRecipient; + recipients[1] = secondRecipient; + recipients[2] = thirdRecipient; + + uint256[] memory amounts = new uint256[](3); + amounts[0] = amount1; + amounts[1] = amount2; + amounts[2] = amount3; + + // give some starting allocations to the recipients + vm.prank(distributor); + tokenDistro.allocateMany(recipients, amounts); + + // save balance values + (uint256 firstRecipientAllocatedTokens,) = tokenDistro.balances(firstRecipient); + (uint256 secondRecipientAllocatedTokens,) = tokenDistro.balances(secondRecipient); + // make first transfer from first recipient to second recipient + vm.prank(firstRecipient); + tokenDistro.changeAddress(secondRecipient); + + // save balance values after first transfer + (uint256 secondRecipientAllocatedTokensAfterTransfer,) = tokenDistro.balances(secondRecipient); + (uint256 firstRecipientAllocatedTokensAfterTransfer,) = tokenDistro.balances(firstRecipient); + // log some stuff + console.log('secondRecipientAllocatedTokensAfterTransfer: ', secondRecipientAllocatedTokensAfterTransfer); + console.log('secondRecipientAllocatedTokens: ', secondRecipientAllocatedTokens); + console.log('firstRecipientAllocatedTokensAfterTransfer: ', firstRecipientAllocatedTokensAfterTransfer); + console.log('firstRecipientAllocatedTokens: ', firstRecipientAllocatedTokens); + // assertions + assertEq(secondRecipientAllocatedTokensAfterTransfer, (firstRecipientAllocatedTokens.add(secondRecipientAllocatedTokens))); + assertEq(firstRecipientAllocatedTokensAfterTransfer,0); + + // do second transfer from second recip to third recip + vm.prank(secondRecipient); + tokenDistro.changeAddress(thirdRecipient); + + // save balance values after second transfer + (uint256 thirdRecipientAllocatedTokensAfterTransfer,) = tokenDistro.balances(thirdRecipient); + (uint256 secondRecipientAllocatedTokensAfterSecondTransfer,) = tokenDistro.balances(secondRecipient); + // expected amount should be the sum of all three amounts + uint256 expectedAmount = amount1.add(amount2.add(amount3)); + // log some stuff + console.log('thirdRecipientAllocatedTokensAfterTransfer: ', thirdRecipientAllocatedTokensAfterTransfer); + console.log('expectedAmount: ', expectedAmount); + // assertions + assertEq(thirdRecipientAllocatedTokensAfterTransfer,expectedAmount); + assertEq(secondRecipientAllocatedTokensAfterSecondTransfer,0); + + } + + function testChangeAddressWithClaim(uint256 amount1, uint256 amount2) public { + /// @aminlatifi for some reason this does not want to work with the min bound as 1 - throws no tokens to claim error + amount1 = bound(amount1, 10, assignedAmount.div(2)); + amount2 = bound(amount2, 10, assignedAmount.div(2)); + + address[] memory recipients = new address[](2); + recipients[0] = firstRecipient; + recipients[1] = secondRecipient; + + uint256[] memory amounts = new uint256[](2); + amounts[0] = amount1; + amounts[1] = amount2; + + vm.prank(distributor); + tokenDistro.allocateMany(recipients, amounts); + + // skip ahead some time and then claim tokens + skip(14 days); + console.log('claimable for first recipient',tokenDistro.claimableNow(firstRecipient)); + console.log('claimable for second recipient', tokenDistro.claimableNow(secondRecipient)); + + vm.prank(firstRecipient); + tokenDistro.claim(); + vm.prank(secondRecipient); + tokenDistro.claim(); + + // save balance values + (, uint256 secondRecipientClaimedTokens) = tokenDistro.balances(secondRecipient); + (, uint256 firstRecipientClaimedTokens) = tokenDistro.balances(firstRecipient); + // transfer allocation to second recipient + vm.prank(firstRecipient); + tokenDistro.changeAddress(secondRecipient); + // check values of second recipient after transfer + (uint256 secondAllocatedAfterTransfer, uint256 secondClaimedAfterTransfer) = tokenDistro.balances(secondRecipient); + (uint256 firstAllocatedAfterTransfer, uint256 firstClaimedAfterTransfer) = tokenDistro.balances(firstRecipient); + // assertions + assertEq(secondAllocatedAfterTransfer, (amount1.add(amount2))); + assertEq(secondClaimedAfterTransfer, (secondRecipientClaimedTokens.add(firstRecipientClaimedTokens))); + assertEq(firstAllocatedAfterTransfer, 0); + assertEq(firstClaimedAfterTransfer, 0); + + } + + + // function testCancelAllocation() public { + // uint256 amount = 100000000000; + // vm.prank(distributor); + // tokenDistro.allocate(firstRecipient, amount, false); + // (uint256 allocatedTokens,uint256 claimedTokens) = tokenDistro.balances(firstRecipient); + // assertEq(allocatedTokens, amount); + // assertEq(claimedTokens, 0); + // vm.prank(givethMultisig); + // tokenDistro.cancelAllocation(firstRecipient); + // (uint256 allocatedTokensAfterCancel, uint256 claimedTokensAfterCancel) = tokenDistro.balances(firstRecipient); + // assertEq(allocatedTokensAfterCancel, 0); + // assertEq(claimedTokensAfterCancel, 0); + // } + + // function testCancelAllocationWithClaim() public { + // uint256 amount = 100000000000; + // vm.prank(distributor); + // tokenDistro.allocate(firstRecipient, amount, true); + + // skip(14 days); + // vm.prank(firstRecipient); + // tokenDistro.claim(); + // (,uint256 claimedTokensAfterClaim) = tokenDistro.balances(firstRecipient); + // vm.prank(givethMultisig); + // tokenDistro.cancelAllocation(firstRecipient); + // (uint256 allocatedTokensAfterCancel, uint256 claimedTokensAfterCancel) = tokenDistro.balances(firstRecipient); + // assertEq(allocatedTokensAfterCancel, claimedTokensAfterClaim); + // assertEq(claimedTokensAfterCancel, claimedTokensAfterClaim); + // } + + // function testCancelAllocationRevert() public { + // testCancelAllocationWithClaim(); + + // skip(14 days); + + // console.log('claimable for first recipient',tokenDistro.claimableNow(firstRecipient)); + // // vm.expectRevert("TokenDistro::claim: NOT_ENOUGH_TOKENS_TO_CLAIM"); + + // // vm.prank(firstRecipient); + // // tokenDistro.claim(); + + // } + +} \ No newline at end of file From 059ce20b5566d03d0ed77f6b5f8dafd239b8c436 Mon Sep 17 00:00:00 2001 From: Mitch Oz Date: Tue, 9 Jan 2024 14:30:23 -0600 Subject: [PATCH 02/31] forge fmt --- contracts/ModifiedTokenDistro.sol | 200 ++------ contracts/tokens/BridgeToken.sol | 255 ++-------- contracts/tokens/GIV.sol | 139 ++---- contracts/tokens/MinimeToken.sol | 290 +++--------- contracts/tokens/TokenERC677.sol | 251 ++-------- contracts/tokens/UniswapV3RewardToken.sol | 54 +-- script/deployRelayer.s.sol | 8 +- script/deployRelayerOptimism.s.sol | 10 +- script/deployTokenDistro.s.sol | 17 +- test/GIVpowerTest.sol | 4 +- test/ModifyTokenDistro.t.sol | 547 +++++++++++----------- test/UnipoolTests/UnipoolGIVpowerTest.sol | 12 +- 12 files changed, 559 insertions(+), 1228 deletions(-) diff --git a/contracts/ModifiedTokenDistro.sol b/contracts/ModifiedTokenDistro.sol index 66a7272..da1e7cb 100644 --- a/contracts/ModifiedTokenDistro.sol +++ b/contracts/ModifiedTokenDistro.sol @@ -1,29 +1,24 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.6; -import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; -import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; -import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol"; -import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; -import "@openzeppelin/contracts/utils/math/SafeMath.sol"; -import "./interfaces/IDistroModified.sol"; +import '@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol'; +import '@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol'; +import '@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol'; +import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; +import '@openzeppelin/contracts/utils/math/SafeMath.sol'; +import './interfaces/IDistroModified.sol'; /** * Contract responsible for managing the release of tokens over time. * The distributor is in charge of releasing the corresponding amounts to its recipients. * This distributor is expected to be another smart contract, such as a merkledrop or the liquidity mining smart contract */ -contract TokenDistro is - Initializable, - IDistro, - AccessControlEnumerableUpgradeable -{ +contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeable { using SafeMath for uint256; using SafeERC20Upgradeable for IERC20Upgradeable; // bytes32 public constant DISTRIBUTOR_ROLE = keccak256("DISTRIBUTOR_ROLE"); - bytes32 public constant DISTRIBUTOR_ROLE = - 0xfbd454f36a7e1a388bd6fc3ab10d434aa4578f811acbbcf33afb1c697486313c; + bytes32 public constant DISTRIBUTOR_ROLE = 0xfbd454f36a7e1a388bd6fc3ab10d434aa4578f811acbbcf33afb1c697486313c; // Structure to of the accounting for each account struct accountStatus { @@ -59,15 +54,9 @@ contract TokenDistro is event DurationChanged(uint256 newDuration); modifier onlyDistributor() { - require( - hasRole(DISTRIBUTOR_ROLE, msg.sender), - "TokenDistro::onlyDistributor: ONLY_DISTRIBUTOR_ROLE" - ); + require(hasRole(DISTRIBUTOR_ROLE, msg.sender), 'TokenDistro::onlyDistributor: ONLY_DISTRIBUTOR_ROLE'); - require( - balances[msg.sender].claimed == 0, - "TokenDistro::onlyDistributor: DISTRIBUTOR_CANNOT_CLAIM" - ); + require(balances[msg.sender].claimed == 0, 'TokenDistro::onlyDistributor: DISTRIBUTOR_CANNOT_CLAIM'); _; } @@ -92,14 +81,8 @@ contract TokenDistro is IERC20Upgradeable _token, bool _cancelable ) public initializer { - require( - _duration >= _cliffPeriod, - "TokenDistro::constructor: DURATION_LESS_THAN_CLIFF" - ); - require( - _initialPercentage <= 10000, - "TokenDistro::constructor: INITIALPERCENTAGE_GREATER_THAN_100" - ); + require(_duration >= _cliffPeriod, 'TokenDistro::constructor: DURATION_LESS_THAN_CLIFF'); + require(_initialPercentage <= 10000, 'TokenDistro::constructor: INITIALPERCENTAGE_GREATER_THAN_100'); __AccessControlEnumerable_init(); _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); @@ -124,13 +107,10 @@ contract TokenDistro is * */ function setStartTime(uint256 newStartTime) external override { - require( - hasRole(DEFAULT_ADMIN_ROLE, msg.sender), - "TokenDistro::setStartTime: ONLY_ADMIN_ROLE" - ); + require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), 'TokenDistro::setStartTime: ONLY_ADMIN_ROLE'); require( startTime > getTimestamp() && newStartTime > getTimestamp(), - "TokenDistro::setStartTime: IF_HAS_NOT_STARTED_YET" + 'TokenDistro::setStartTime: IF_HAS_NOT_STARTED_YET' ); uint256 _cliffPeriod = cliffTime - startTime; @@ -150,21 +130,11 @@ contract TokenDistro is * */ function assign(address distributor, uint256 amount) external override { - require( - hasRole(DEFAULT_ADMIN_ROLE, msg.sender), - "TokenDistro::assign: ONLY_ADMIN_ROLE" - ); - require( - hasRole(DISTRIBUTOR_ROLE, distributor), - "TokenDistro::assign: ONLY_TO_DISTRIBUTOR_ROLE" - ); + require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), 'TokenDistro::assign: ONLY_ADMIN_ROLE'); + require(hasRole(DISTRIBUTOR_ROLE, distributor), 'TokenDistro::assign: ONLY_TO_DISTRIBUTOR_ROLE'); - balances[address(this)].allocatedTokens = - balances[address(this)].allocatedTokens - - amount; - balances[distributor].allocatedTokens = - balances[distributor].allocatedTokens + - amount; + balances[address(this)].allocatedTokens = balances[address(this)].allocatedTokens - amount; + balances[distributor].allocatedTokens = balances[distributor].allocatedTokens + amount; emit Assign(msg.sender, distributor, amount); } @@ -201,23 +171,12 @@ contract TokenDistro is * Emits a {Allocate} event. * */ - function _allocate( - address recipient, - uint256 amount, - bool claim - ) internal { - require( - !hasRole(DISTRIBUTOR_ROLE, recipient), - "TokenDistro::allocate: DISTRIBUTOR_NOT_VALID_RECIPIENT" - ); + function _allocate(address recipient, uint256 amount, bool claim) internal { + require(!hasRole(DISTRIBUTOR_ROLE, recipient), 'TokenDistro::allocate: DISTRIBUTOR_NOT_VALID_RECIPIENT'); - balances[msg.sender].allocatedTokens = - balances[msg.sender].allocatedTokens - - amount; + balances[msg.sender].allocatedTokens = balances[msg.sender].allocatedTokens - amount; - balances[recipient].allocatedTokens = - balances[recipient].allocatedTokens + - amount; + balances[recipient].allocatedTokens = balances[recipient].allocatedTokens + amount; if (claim && claimableNow(recipient) > 0) { _claim(recipient); @@ -226,11 +185,7 @@ contract TokenDistro is emit Allocate(msg.sender, recipient, amount); } - function allocate( - address recipient, - uint256 amount, - bool claim - ) external override onlyDistributor { + function allocate(address recipient, uint256 amount, bool claim) external override onlyDistributor { _allocate(recipient, amount, claim); } @@ -242,39 +197,24 @@ contract TokenDistro is * * Unlike allocate method it doesn't claim recipients available balance */ - function _allocateMany( - address[] memory recipients, - uint256[] memory amounts - ) internal onlyDistributor { - require( - recipients.length == amounts.length, - "TokenDistro::allocateMany: INPUT_LENGTH_NOT_MATCH" - ); + function _allocateMany(address[] memory recipients, uint256[] memory amounts) internal onlyDistributor { + require(recipients.length == amounts.length, 'TokenDistro::allocateMany: INPUT_LENGTH_NOT_MATCH'); for (uint256 i = 0; i < recipients.length; i++) { _allocate(recipients[i], amounts[i], false); } } - function allocateMany(address[] memory recipients, uint256[] memory amounts) - external - override - { + function allocateMany(address[] memory recipients, uint256[] memory amounts) external override { _allocateMany(recipients, amounts); } - function sendGIVbacks(address[] memory recipients, uint256[] memory amounts) - external - override - { + function sendGIVbacks(address[] memory recipients, uint256[] memory amounts) external override { _allocateMany(recipients, amounts); emit GivBackPaid(msg.sender); } - function sendPraiseRewards( - address[] memory recipients, - uint256[] memory amounts - ) external { + function sendPraiseRewards(address[] memory recipients, uint256[] memory amounts) external { _allocateMany(recipients, amounts); emit PraiseRewardPaid(msg.sender); } @@ -295,13 +235,11 @@ contract TokenDistro is // ); require( - !hasRole(DISTRIBUTOR_ROLE, msg.sender) && - !hasRole(DISTRIBUTOR_ROLE, newAddress), - "TokenDistro::changeAddress: DISTRIBUTOR_ROLE_NOT_A_VALID_ADDRESS" + !hasRole(DISTRIBUTOR_ROLE, msg.sender) && !hasRole(DISTRIBUTOR_ROLE, newAddress), + 'TokenDistro::changeAddress: DISTRIBUTOR_ROLE_NOT_A_VALID_ADDRESS' ); // balance adds instead of overwrites - balances[newAddress].allocatedTokens += balances[msg.sender] - .allocatedTokens; + balances[newAddress].allocatedTokens += balances[msg.sender].allocatedTokens; balances[msg.sender].allocatedTokens = 0; balances[newAddress].claimed += balances[msg.sender].claimed; @@ -322,12 +260,7 @@ contract TokenDistro is * @param timestamp Unix time to check the number of tokens claimable * @return Number of tokens claimable at that timestamp */ - function globallyClaimableAt(uint256 timestamp) - public - view - override - returns (uint256) - { + function globallyClaimableAt(uint256 timestamp) public view override returns (uint256) { if (timestamp < startTime) return 0; if (timestamp < cliffTime) return initialAmount; if (timestamp > startTime + duration) return totalTokens; @@ -341,22 +274,10 @@ contract TokenDistro is * @param recipient account to query * @param timestamp Instant of time in which the calculation is made */ - function claimableAt(address recipient, uint256 timestamp) - public - view - override - returns (uint256) - { - require( - !hasRole(DISTRIBUTOR_ROLE, recipient), - "TokenDistro::claimableAt: DISTRIBUTOR_ROLE_CANNOT_CLAIM" - ); - require( - timestamp >= getTimestamp(), - "TokenDistro::claimableAt: NOT_VALID_PAST_TIMESTAMP" - ); - uint256 unlockedAmount = (globallyClaimableAt(timestamp) * - balances[recipient].allocatedTokens) / totalTokens; + function claimableAt(address recipient, uint256 timestamp) public view override returns (uint256) { + require(!hasRole(DISTRIBUTOR_ROLE, recipient), 'TokenDistro::claimableAt: DISTRIBUTOR_ROLE_CANNOT_CLAIM'); + require(timestamp >= getTimestamp(), 'TokenDistro::claimableAt: NOT_VALID_PAST_TIMESTAMP'); + uint256 unlockedAmount = (globallyClaimableAt(timestamp) * balances[recipient].allocatedTokens) / totalTokens; return unlockedAmount - balances[recipient].claimed; } @@ -365,12 +286,7 @@ contract TokenDistro is * Function to get the unlocked tokens for a specific address. It uses the current timestamp * @param recipient account to query */ - function claimableNow(address recipient) - public - view - override - returns (uint256) - { + function claimableNow(address recipient) public view override returns (uint256) { return claimableAt(recipient, getTimestamp()); } @@ -382,15 +298,11 @@ contract TokenDistro is * Emits a {ChangeAddress} event. * */ - function transferAllocation(address prevRecipient, address newRecipient) - external - override - { - require(balances[prevRecipient].allocatedTokens > 0, "TokenDistro::transferAllocation: NO_ALLOCATION_TO_TRANSFER"); + function transferAllocation(address prevRecipient, address newRecipient) external override { require( - hasRole(DEFAULT_ADMIN_ROLE, msg.sender), - "TokenDistro::transferAllocation: ONLY_ADMIN_ROLE" + balances[prevRecipient].allocatedTokens > 0, 'TokenDistro::transferAllocation: NO_ALLOCATION_TO_TRANSFER' ); + require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), 'TokenDistro::transferAllocation: ONLY_ADMIN_ROLE'); // require( // balances[newRecipient].allocatedTokens == 0 && @@ -399,17 +311,15 @@ contract TokenDistro is // ); require( - !hasRole(DISTRIBUTOR_ROLE, prevRecipient) && - !hasRole(DISTRIBUTOR_ROLE, newRecipient), - "TokenDistro::transferAllocation: DISTRIBUTOR_ROLE_NOT_A_VALID_ADDRESS" + !hasRole(DISTRIBUTOR_ROLE, prevRecipient) && !hasRole(DISTRIBUTOR_ROLE, newRecipient), + 'TokenDistro::transferAllocation: DISTRIBUTOR_ROLE_NOT_A_VALID_ADDRESS' ); // balance adds instead of overwrites - balances[newRecipient].allocatedTokens = balances[prevRecipient] - .allocatedTokens.add(balances[newRecipient].allocatedTokens); + balances[newRecipient].allocatedTokens = + balances[prevRecipient].allocatedTokens.add(balances[newRecipient].allocatedTokens); balances[prevRecipient].allocatedTokens = 0; - balances[newRecipient].claimed = balances[prevRecipient].claimed.add( - balances[newRecipient].claimed); + balances[newRecipient].claimed = balances[prevRecipient].claimed.add(balances[newRecipient].claimed); balances[prevRecipient].claimed = 0; @@ -425,14 +335,9 @@ contract TokenDistro is function _claim(address recipient) private { uint256 remainingToClaim = claimableNow(recipient); - require( - remainingToClaim > 0, - "TokenDistro::claim: NOT_ENOUGH_TOKENS_TO_CLAIM" - ); + require(remainingToClaim > 0, 'TokenDistro::claim: NOT_ENOUGH_TOKENS_TO_CLAIM'); - balances[recipient].claimed = - balances[recipient].claimed + - remainingToClaim; + balances[recipient].claimed = balances[recipient].claimed + remainingToClaim; token.safeTransfer(recipient, remainingToClaim); @@ -443,19 +348,12 @@ contract TokenDistro is * Function to change the duration */ function setDuration(uint256 newDuration) public { - require( - hasRole(DEFAULT_ADMIN_ROLE, msg.sender), - "TokenDistro::setDuration: ONLY_ADMIN_ROLE" - ); + require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), 'TokenDistro::setDuration: ONLY_ADMIN_ROLE'); - require( - startTime > getTimestamp(), - "TokenDistro::setDuration: IF_HAS_NOT_STARTED_YET" - ); + require(startTime > getTimestamp(), 'TokenDistro::setDuration: IF_HAS_NOT_STARTED_YET'); duration = newDuration; emit DurationChanged(newDuration); } - } diff --git a/contracts/tokens/BridgeToken.sol b/contracts/tokens/BridgeToken.sol index d3d715d..fba0286 100644 --- a/contracts/tokens/BridgeToken.sol +++ b/contracts/tokens/BridgeToken.sol @@ -157,24 +157,13 @@ pragma solidity ^0.4.24; * @dev see https://github.com/ethereum/EIPs/issues/20 */ contract ERC20 is ERC20Basic { - function allowance(address _owner, address _spender) - public - view - returns (uint256); + function allowance(address _owner, address _spender) public view returns (uint256); - function transferFrom( - address _from, - address _to, - uint256 _value - ) public returns (bool); + function transferFrom(address _from, address _to, uint256 _value) public returns (bool); function approve(address _spender, uint256 _value) public returns (bool); - event Approval( - address indexed owner, - address indexed spender, - uint256 value - ); + event Approval(address indexed owner, address indexed spender, uint256 value); } // File: openzeppelin-solidity/contracts/token/ERC20/StandardToken.sol @@ -197,11 +186,7 @@ contract StandardToken is ERC20, BasicToken { * @param _to address The address which you want to transfer to * @param _value uint256 the amount of tokens to be transferred */ - function transferFrom( - address _from, - address _to, - uint256 _value - ) public returns (bool) { + function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { require(_value <= balances[_from]); require(_value <= allowed[_from][msg.sender]); require(_to != address(0)); @@ -234,11 +219,7 @@ contract StandardToken is ERC20, BasicToken { * @param _spender address The address which will spend the funds. * @return A uint256 specifying the amount of tokens still available for the spender. */ - function allowance(address _owner, address _spender) - public - view - returns (uint256) - { + function allowance(address _owner, address _spender) public view returns (uint256) { return allowed[_owner][_spender]; } @@ -251,13 +232,8 @@ contract StandardToken is ERC20, BasicToken { * @param _spender The address which will spend the funds. * @param _addedValue The amount of tokens to increase the allowance by. */ - function increaseApproval(address _spender, uint256 _addedValue) - public - returns (bool) - { - allowed[msg.sender][_spender] = ( - allowed[msg.sender][_spender].add(_addedValue) - ); + function increaseApproval(address _spender, uint256 _addedValue) public returns (bool) { + allowed[msg.sender][_spender] = (allowed[msg.sender][_spender].add(_addedValue)); emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); return true; } @@ -271,10 +247,7 @@ contract StandardToken is ERC20, BasicToken { * @param _spender The address which will spend the funds. * @param _subtractedValue The amount of tokens to decrease the allowance by. */ - function decreaseApproval(address _spender, uint256 _subtractedValue) - public - returns (bool) - { + function decreaseApproval(address _spender, uint256 _subtractedValue) public returns (bool) { uint256 oldValue = allowed[msg.sender][_spender]; if (_subtractedValue >= oldValue) { allowed[msg.sender][_spender] = 0; @@ -299,10 +272,7 @@ contract Ownable { address public owner; event OwnershipRenounced(address indexed previousOwner); - event OwnershipTransferred( - address indexed previousOwner, - address indexed newOwner - ); + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender @@ -381,12 +351,7 @@ contract MintableToken is StandardToken, Ownable { * @param _amount The amount of tokens to mint. * @return A boolean that indicates if the operation was successful. */ - function mint(address _to, uint256 _amount) - public - hasMintPermission - canMint - returns (bool) - { + function mint(address _to, uint256 _amount) public hasMintPermission canMint returns (bool) { totalSupply_ = totalSupply_.add(_amount); balances[_to] = balances[_to].add(_amount); emit Mint(_to, _amount); @@ -420,11 +385,7 @@ contract DetailedERC20 is ERC20 { string public symbol; uint8 public decimals; - constructor( - string _name, - string _symbol, - uint8 _decimals - ) public { + constructor(string _name, string _symbol, uint8 _decimals) public { name = _name; symbol = _symbol; decimals = _decimals; @@ -467,26 +428,13 @@ library AddressUtils { pragma solidity 0.4.24; contract ERC677 is ERC20 { - event Transfer( - address indexed from, - address indexed to, - uint256 value, - bytes data - ); - - function transferAndCall( - address, - uint256, - bytes - ) external returns (bool); - - function increaseAllowance(address spender, uint256 addedValue) - public - returns (bool); + event Transfer(address indexed from, address indexed to, uint256 value, bytes data); - function decreaseAllowance(address spender, uint256 subtractedValue) - public - returns (bool); + function transferAndCall(address, uint256, bytes) external returns (bool); + + function increaseAllowance(address spender, uint256 addedValue) public returns (bool); + + function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool); } // File: contracts/interfaces/IBurnableMintableERC677Token.sol @@ -564,31 +512,17 @@ contract Claimable { safeTransfer(_token, _to, balance); } - function safeTransfer( - address _token, - address _to, - uint256 _value - ) internal { + function safeTransfer(address _token, address _to, uint256 _value) internal { bytes memory returnData; bool returnDataResult; bytes memory callData = abi.encodeWithSelector(TRANSFER, _to, _value); assembly { - let result := call( - gas, - _token, - 0x0, - add(callData, 0x20), - mload(callData), - 0, - 32 - ) + let result := call(gas, _token, 0x0, add(callData, 0x20), mload(callData), 0, 32) returnData := mload(0) returnDataResult := mload(0) switch result - case 0 { - revert(0, 0) - } + case 0 { revert(0, 0) } } // Return data is optional @@ -606,24 +540,14 @@ pragma solidity 0.4.24; * @title ERC677BridgeToken * @dev The basic implementation of a bridgeable ERC677-compatible token */ -contract ERC677BridgeToken is - IBurnableMintableERC677Token, - DetailedERC20, - BurnableToken, - MintableToken, - Claimable -{ +contract ERC677BridgeToken is IBurnableMintableERC677Token, DetailedERC20, BurnableToken, MintableToken, Claimable { bytes4 internal constant ON_TOKEN_TRANSFER = 0xa4c0ed36; // onTokenTransfer(address,uint256,bytes) address internal bridgeContractAddr; event ContractFallbackCallFailed(address from, address to, uint256 value); - constructor( - string _name, - string _symbol, - uint8 _decimals - ) public DetailedERC20(_name, _symbol, _decimals) { + constructor(string _name, string _symbol, uint8 _decimals) public DetailedERC20(_name, _symbol, _decimals) { // solhint-disable-previous-line no-empty-blocks } @@ -642,11 +566,7 @@ contract ERC677BridgeToken is _; } - function transferAndCall( - address _to, - uint256 _value, - bytes _data - ) external validRecipient(_to) returns (bool) { + function transferAndCall(address _to, uint256 _value, bytes _data) external validRecipient(_to) returns (bool) { require(superTransfer(_to, _value)); emit Transfer(msg.sender, _to, _value, _data); @@ -656,22 +576,11 @@ contract ERC677BridgeToken is return true; } - function getTokenInterfacesVersion() - external - pure - returns ( - uint64 major, - uint64 minor, - uint64 patch - ) - { + function getTokenInterfacesVersion() external pure returns (uint64 major, uint64 minor, uint64 patch) { return (2, 2, 0); } - function superTransfer(address _to, uint256 _value) - internal - returns (bool) - { + function superTransfer(address _to, uint256 _value) internal returns (bool) { return super.transfer(_to, _value); } @@ -681,25 +590,14 @@ contract ERC677BridgeToken is return true; } - function transferFrom( - address _from, - address _to, - uint256 _value - ) public returns (bool) { + function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { require(super.transferFrom(_from, _to, _value)); callAfterTransfer(_from, _to, _value); return true; } - function callAfterTransfer( - address _from, - address _to, - uint256 _value - ) internal { - if ( - AddressUtils.isContract(_to) && - !contractFallback(_from, _to, _value, new bytes(0)) - ) { + function callAfterTransfer(address _from, address _to, uint256 _value) internal { + if (AddressUtils.isContract(_to) && !contractFallback(_from, _to, _value, new bytes(0))) { require(!isBridge(_to)); emit ContractFallbackCallFailed(_from, _to, _value); } @@ -716,16 +614,8 @@ contract ERC677BridgeToken is * @param _value amount of tokens that was sent * @param _data set of extra bytes that can be passed to the recipient */ - function contractFallback( - address _from, - address _to, - uint256 _value, - bytes _data - ) private returns (bool) { - return - _to.call( - abi.encodeWithSelector(ON_TOKEN_TRANSFER, _from, _value, _data) - ); + function contractFallback(address _from, address _to, uint256 _value, bytes _data) private returns (bool) { + return _to.call(abi.encodeWithSelector(ON_TOKEN_TRANSFER, _from, _value, _data)); } function finishMinting() public returns (bool) { @@ -736,25 +626,15 @@ contract ERC677BridgeToken is revert(); } - function claimTokens(address _token, address _to) - public - onlyOwner - validAddress(_to) - { + function claimTokens(address _token, address _to) public onlyOwner validAddress(_to) { claimValues(_token, _to); } - function increaseAllowance(address spender, uint256 addedValue) - public - returns (bool) - { + function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { return super.increaseApproval(spender, addedValue); } - function decreaseAllowance(address spender, uint256 subtractedValue) - public - returns (bool) - { + function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { return super.decreaseApproval(spender, subtractedValue); } } @@ -764,29 +644,24 @@ contract ERC677BridgeToken is pragma solidity 0.4.24; contract PermittableToken is ERC677BridgeToken { - string public constant version = "1"; + string public constant version = '1'; // EIP712 niceties bytes32 public DOMAIN_SEPARATOR; // bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address holder,address spender,uint256 nonce,uint256 expiry,bool allowed)"); - bytes32 public constant PERMIT_TYPEHASH = - 0xea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb; + bytes32 public constant PERMIT_TYPEHASH = 0xea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb; mapping(address => uint256) public nonces; mapping(address => mapping(address => uint256)) public expirations; - constructor( - string memory _name, - string memory _symbol, - uint8 _decimals, - uint256 _chainId - ) public ERC677BridgeToken(_name, _symbol, _decimals) { + constructor(string memory _name, string memory _symbol, uint8 _decimals, uint256 _chainId) + public + ERC677BridgeToken(_name, _symbol, _decimals) + { require(_chainId != 0); DOMAIN_SEPARATOR = keccak256( abi.encode( - keccak256( - "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" - ), + keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'), keccak256(bytes(_name)), keccak256(bytes(version)), _chainId, @@ -803,11 +678,7 @@ contract PermittableToken is ERC677BridgeToken { /// @param _recipient The address of the recipient. /// @param _amount The value to transfer. /// @return Success status. - function transferFrom( - address _sender, - address _recipient, - uint256 _amount - ) public returns (bool) { + function transferFrom(address _sender, address _recipient, uint256 _amount) public returns (bool) { require(_sender != address(0)); require(_recipient != address(0)); @@ -822,18 +693,11 @@ contract PermittableToken is ERC677BridgeToken { // If allowance is limited, adjust it. // In this case `transferFrom` works like the generic allowed[_sender][msg.sender] = allowedAmount.sub(_amount); - emit Approval( - _sender, - msg.sender, - allowed[_sender][msg.sender] - ); + emit Approval(_sender, msg.sender, allowed[_sender][msg.sender]); } else { // If allowance is unlimited by `permit`, `approve`, or `increaseAllowance` // function, don't adjust it. But the expiration date must be empty or in the future - require( - expirations[_sender][msg.sender] == 0 || - expirations[_sender][msg.sender] >= _now() - ); + require(expirations[_sender][msg.sender] == 0 || expirations[_sender][msg.sender] >= _now()); } } else { // If `_sender` is `msg.sender`, @@ -863,11 +727,7 @@ contract PermittableToken is ERC677BridgeToken { /// @param _from The address of the sender. /// @param _to The address of the recipient. /// @param _amount The value to transfer. - function move( - address _from, - address _to, - uint256 _amount - ) public { + function move(address _from, address _to, uint256 _amount) public { transferFrom(_from, _to, _amount); } @@ -899,23 +759,14 @@ contract PermittableToken is ERC677BridgeToken { bytes32 digest = keccak256( abi.encodePacked( - "\x19\x01", + '\x19\x01', DOMAIN_SEPARATOR, - keccak256( - abi.encode( - PERMIT_TYPEHASH, - _holder, - _spender, - _nonce, - _expiry, - _allowed - ) - ) + keccak256(abi.encode(PERMIT_TYPEHASH, _holder, _spender, _nonce, _expiry, _allowed)) ) ); - require(_holder == ecrecover(digest, _v, _r, _s), "Sigature Error"); - require(_nonce == nonces[_holder]++, "Nonce Error"); + require(_holder == ecrecover(digest, _v, _r, _s), 'Sigature Error'); + require(_nonce == nonces[_holder]++, 'Nonce Error'); uint256 amount = _allowed ? uint256(-1) : 0; @@ -930,15 +781,7 @@ contract PermittableToken is ERC677BridgeToken { } /// @dev Version of the token contract. - function getTokenInterfacesVersion() - external - pure - returns ( - uint64 major, - uint64 minor, - uint64 patch - ) - { + function getTokenInterfacesVersion() external pure returns (uint64 major, uint64 minor, uint64 patch) { return (2, 3, 0); } } diff --git a/contracts/tokens/GIV.sol b/contracts/tokens/GIV.sol index dd27180..f9c485c 100644 --- a/contracts/tokens/GIV.sol +++ b/contracts/tokens/GIV.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.6; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; // Lightweight token modelled after UNI-LP: // https://github.com/Uniswap/uniswap-v2-core/blob/v1.0.1/contracts/UniswapV2ERC20.sol @@ -18,27 +18,23 @@ contract GIV is IERC20 { // bytes32 public constant PERMIT_TYPEHASH = // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); - bytes32 public constant PERMIT_TYPEHASH = - 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; + bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; // bytes32 public constant TRANSFER_WITH_AUTHORIZATION_TYPEHASH = // keccak256("TransferWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)"); bytes32 public constant TRANSFER_WITH_AUTHORIZATION_TYPEHASH = 0x7c7c6cdb67a18743f49ec6fa9b35f50d52ed05cbed4cc592e13b44501c1a2267; // bytes32 public constant EIP712DOMAIN_HASH = // keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)") - bytes32 public constant EIP712DOMAIN_HASH = - 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; + bytes32 public constant EIP712DOMAIN_HASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; // bytes32 public constant NAME_HASH = // keccak256("Giveth") - bytes32 public constant NAME_HASH = - 0x33ef7d8509d7fc60c9fbe6cfb57a52ac1d91ca62f595d3b55c7cbdbb6372f902; + bytes32 public constant NAME_HASH = 0x33ef7d8509d7fc60c9fbe6cfb57a52ac1d91ca62f595d3b55c7cbdbb6372f902; // bytes32 public constant VERSION_HASH = // keccak256("1") - bytes32 public constant VERSION_HASH = - 0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6; + bytes32 public constant VERSION_HASH = 0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6; - string public constant name = "Giveth"; - string public constant symbol = "GIV"; + string public constant name = 'Giveth'; + string public constant symbol = 'GIV'; uint8 public constant decimals = 18; address public minter; @@ -54,7 +50,7 @@ contract GIV is IERC20 { event ChangeMinter(address indexed minter); modifier onlyMinter() { - require(msg.sender == minter, "GIV:NOT_MINTER"); + require(msg.sender == minter, 'GIV:NOT_MINTER'); _; } @@ -62,22 +58,11 @@ contract GIV is IERC20 { _changeMinter(initialMinter); } - function _validateSignedData( - address signer, - bytes32 encodeData, - uint8 v, - bytes32 r, - bytes32 s - ) internal view { - bytes32 digest = keccak256( - abi.encodePacked("\x19\x01", getDomainSeparator(), encodeData) - ); + function _validateSignedData(address signer, bytes32 encodeData, uint8 v, bytes32 r, bytes32 s) internal view { + bytes32 digest = keccak256(abi.encodePacked('\x19\x01', getDomainSeparator(), encodeData)); address recoveredAddress = ecrecover(digest, v, r, s); // Explicitly disallow authorizations for address(0) as ecrecover returns address(0) on malformed messages - require( - recoveredAddress != address(0) && recoveredAddress == signer, - "GIV:INVALID_SIGNATURE" - ); + require(recoveredAddress != address(0) && recoveredAddress == signer, 'GIV:INVALID_SIGNATURE'); } function _changeMinter(address newMinter) internal { @@ -98,24 +83,13 @@ contract GIV is IERC20 { emit Transfer(from, address(0), value); } - function _approve( - address owner, - address spender, - uint256 value - ) private { + function _approve(address owner, address spender, uint256 value) private { allowance[owner][spender] = value; emit Approval(owner, spender, value); } - function _transfer( - address from, - address to, - uint256 value - ) private { - require( - to != address(this) && to != address(0), - "GIV:NOT_VALID_TRANSFER" - ); + function _transfer(address from, address to, uint256 value) private { + require(to != address(this) && to != address(0), 'GIV:NOT_VALID_TRANSFER'); // Balance is implicitly checked with SafeMath's underflow protection balanceOf[from] = balanceOf[from] - value; balanceOf[to] = balanceOf[to] + value; @@ -129,23 +103,10 @@ contract GIV is IERC20 { } function getDomainSeparator() public view returns (bytes32) { - return - keccak256( - abi.encode( - EIP712DOMAIN_HASH, - NAME_HASH, - VERSION_HASH, - getChainId(), - address(this) - ) - ); - } - - function mint(address to, uint256 value) - external - onlyMinter - returns (bool) - { + return keccak256(abi.encode(EIP712DOMAIN_HASH, NAME_HASH, VERSION_HASH, getChainId(), address(this))); + } + + function mint(address to, uint256 value) external onlyMinter returns (bool) { _mint(to, value); return true; } @@ -159,29 +120,17 @@ contract GIV is IERC20 { return true; } - function approve(address spender, uint256 value) - external - override - returns (bool) - { + function approve(address spender, uint256 value) external override returns (bool) { _approve(msg.sender, spender, value); return true; } - function transfer(address to, uint256 value) - external - override - returns (bool) - { + function transfer(address to, uint256 value) external override returns (bool) { _transfer(msg.sender, to, value); return true; } - function transferFrom( - address from, - address to, - uint256 value - ) external override returns (bool) { + function transferFrom(address from, address to, uint256 value) external override returns (bool) { uint256 fromAllowance = allowance[from][msg.sender]; if (fromAllowance != type(uint256).max) { // Allowance is implicitly checked with solidity underflow protection @@ -191,26 +140,11 @@ contract GIV is IERC20 { return true; } - function permit( - address owner, - address spender, - uint256 value, - uint256 deadline, - uint8 v, - bytes32 r, - bytes32 s - ) external { - require(deadline >= block.timestamp, "GIV:AUTH_EXPIRED"); - bytes32 encodeData = keccak256( - abi.encode( - PERMIT_TYPEHASH, - owner, - spender, - value, - nonces[owner]++, - deadline - ) - ); + function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) + external + { + require(deadline >= block.timestamp, 'GIV:AUTH_EXPIRED'); + bytes32 encodeData = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline)); _validateSignedData(owner, encodeData, v, r, s); _approve(owner, spender, value); } @@ -226,21 +160,12 @@ contract GIV is IERC20 { bytes32 r, bytes32 s ) external { - require(block.timestamp > validAfter, "GIV:AUTH_NOT_YET_VALID"); - require(block.timestamp < validBefore, "GIV:AUTH_EXPIRED"); - require(!authorizationState[from][nonce], "GIV:AUTH_ALREADY_USED"); - - bytes32 encodeData = keccak256( - abi.encode( - TRANSFER_WITH_AUTHORIZATION_TYPEHASH, - from, - to, - value, - validAfter, - validBefore, - nonce - ) - ); + require(block.timestamp > validAfter, 'GIV:AUTH_NOT_YET_VALID'); + require(block.timestamp < validBefore, 'GIV:AUTH_EXPIRED'); + require(!authorizationState[from][nonce], 'GIV:AUTH_ALREADY_USED'); + + bytes32 encodeData = + keccak256(abi.encode(TRANSFER_WITH_AUTHORIZATION_TYPEHASH, from, to, value, validAfter, validBefore, nonce)); _validateSignedData(from, encodeData, v, r, s); authorizationState[from][nonce] = true; diff --git a/contracts/tokens/MinimeToken.sol b/contracts/tokens/MinimeToken.sol index 12aa107..1e0b9c4 100644 --- a/contracts/tokens/MinimeToken.sol +++ b/contracts/tokens/MinimeToken.sol @@ -1,5 +1,5 @@ /** - *Submitted for verification at Etherscan.io on 2021-06-07 + * Submitted for verification at Etherscan.io on 2021-06-07 */ // File: contracts/ITokenController.sol @@ -20,11 +20,7 @@ interface ITokenController { /// @param _to The destination of the transfer /// @param _amount The amount of the transfer /// @return False if the controller does not authorize the transfer - function onTransfer( - address _from, - address _to, - uint256 _amount - ) external returns (bool); + function onTransfer(address _from, address _to, uint256 _amount) external returns (bool); /// @notice Notifies the controller about an approval allowing the /// controller to react if desired @@ -32,11 +28,7 @@ interface ITokenController { /// @param _spender The spender in the `approve()` call /// @param _amount The amount in the `approve()` call /// @return False if the controller does not authorize the approval - function onApprove( - address _owner, - address _spender, - uint256 _amount - ) external returns (bool); + function onApprove(address _owner, address _spender, uint256 _amount) external returns (bool); } // File: contracts/MiniMeToken.sol @@ -87,12 +79,7 @@ contract Controlled { } contract ApproveAndCallFallBack { - function receiveApproval( - address from, - uint256 _amount, - address _token, - bytes _data - ) public; + function receiveApproval(address from, uint256 _amount, address _token, bytes _data) public; } /// @dev The actual token contract, the default controller is the msg.sender @@ -102,7 +89,7 @@ contract MiniMeToken is Controlled { string public name; //The Token's name: e.g. DigixDAO Tokens uint8 public decimals; //Number of decimals of the smallest unit string public symbol; //An identifier: e.g. REP - string public version = "MMT_0.1"; //An arbitrary versioning scheme + string public version = 'MMT_0.1'; //An arbitrary versioning scheme bytes32 public nameHash; //Name Hash to generate the domain separator @@ -116,20 +103,17 @@ contract MiniMeToken is Controlled { uint256 public constant CHAINID = 0x04; // bytes32 public view PERMIT_TYPEHASH = // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); - bytes32 public constant PERMIT_TYPEHASH = - 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; + bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; // bytes32 public view TRANSFER_WITH_AUTHORIZATION_TYPEHASH = // keccak256("TransferWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)"); bytes32 public constant TRANSFER_WITH_AUTHORIZATION_TYPEHASH = 0x7c7c6cdb67a18743f49ec6fa9b35f50d52ed05cbed4cc592e13b44501c1a2267; // bytes32 public view EIP712DOMAIN_HASH = // keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)") - bytes32 public constant EIP712DOMAIN_HASH = - 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; + bytes32 public constant EIP712DOMAIN_HASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; // bytes32 public view VERSION_HASH = // keccak256("1") - bytes32 public constant VERSION_HASH = - 0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6; + bytes32 public constant VERSION_HASH = 0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6; /// @dev `Checkpoint` is the structure that attaches a block number to a /// given value, the block number attached is the one that last changed the @@ -214,10 +198,7 @@ contract MiniMeToken is Controlled { /// @param _to The address of the recipient /// @param _amount The amount of tokens to be transferred /// @return Whether the transfer was successful or not - function transfer(address _to, uint256 _amount) - public - returns (bool success) - { + function transfer(address _to, uint256 _amount) public returns (bool success) { require(transfersEnabled); return doTransfer(msg.sender, _to, _amount); } @@ -228,11 +209,7 @@ contract MiniMeToken is Controlled { /// @param _to The address of the recipient /// @param _amount The amount of tokens to be transferred /// @return True if the transfer was successful - function transferFrom( - address _from, - address _to, - uint256 _amount - ) public returns (bool success) { + function transferFrom(address _from, address _to, uint256 _amount) public returns (bool success) { // The controller of this contract can move tokens around at will, // this is important to recognize! Confirm that you trust the // controller of this contract, which in most situations should be @@ -253,11 +230,7 @@ contract MiniMeToken is Controlled { /// @param _to The address of the recipient /// @param _amount The amount of tokens to be transferred /// @return True if the transfer was successful - function doTransfer( - address _from, - address _to, - uint256 _amount - ) internal returns (bool) { + function doTransfer(address _from, address _to, uint256 _amount) internal returns (bool) { if (_amount == 0) { return true; } @@ -273,10 +246,7 @@ contract MiniMeToken is Controlled { // Alerts the token controller of the transfer if (isContract(controller)) { // Adding the ` == true` makes the linter shut up so... - require( - ITokenController(controller).onTransfer(_from, _to, _amount) == - true - ); + require(ITokenController(controller).onTransfer(_from, _to, _amount) == true); } // First update the balance array with the new value for the address // sending the tokens @@ -293,11 +263,7 @@ contract MiniMeToken is Controlled { /// @param _owner The address that's balance is being requested /// @return The balance of `_owner` at the current block - function balanceOf(address _owner) - public - constant - returns (uint256 balance) - { + function balanceOf(address _owner) public view returns (uint256 balance) { return balanceOfAt(_owner, block.number); } @@ -306,10 +272,7 @@ contract MiniMeToken is Controlled { /// @param _spender The address of the account able to transfer the tokens /// @param _amount The amount of tokens to be approved for transfer /// @return True if the approval was successful - function approve(address _spender, uint256 _amount) - public - returns (bool success) - { + function approve(address _spender, uint256 _amount) public returns (bool success) { _approve(msg.sender, _spender, _amount); return true; } @@ -321,11 +284,7 @@ contract MiniMeToken is Controlled { /// @param _spender The address of the account able to transfer the tokens /// @param _amount The amount of tokens to be approved for transfer /// @return True if the approval was successful - function _approve( - address _owner, - address _spender, - uint256 _amount - ) private { + function _approve(address _owner, address _spender, uint256 _amount) private { require(transfersEnabled); // To change the approve amount you first have to reduce the addresses` @@ -337,13 +296,7 @@ contract MiniMeToken is Controlled { // Alerts the token controller of the approve function call if (isContract(controller)) { // Adding the ` == true` makes the linter shut up so... - require( - ITokenController(controller).onApprove( - _owner, - _spender, - _amount - ) == true - ); + require(ITokenController(controller).onApprove(_owner, _spender, _amount) == true); } allowed[_owner][_spender] = _amount; Approval(_owner, _spender, _amount); @@ -354,11 +307,7 @@ contract MiniMeToken is Controlled { /// @param _spender The address of the account able to transfer the tokens /// @return Amount of remaining tokens of _owner that _spender is allowed /// to spend - function allowance(address _owner, address _spender) - public - constant - returns (uint256 remaining) - { + function allowance(address _owner, address _spender) public view returns (uint256 remaining) { return allowed[_owner][_spender]; } @@ -369,11 +318,10 @@ contract MiniMeToken is Controlled { /// @param _spender The address of the contract able to transfer the tokens /// @param _amount The amount of tokens to be approved for transfer /// @return True if the function call was successful - function approveAndCall( - ApproveAndCallFallBack _spender, - uint256 _amount, - bytes _extraData - ) public returns (bool success) { + function approveAndCall(ApproveAndCallFallBack _spender, uint256 _amount, bytes _extraData) + public + returns (bool success) + { require(approve(_spender, _amount)); _spender.receiveApproval(msg.sender, _amount, this, _extraData); @@ -383,7 +331,7 @@ contract MiniMeToken is Controlled { /// @dev This function makes it easy to get the total number of tokens /// @return The total number of tokens - function totalSupply() public constant returns (uint256) { + function totalSupply() public view returns (uint256) { return totalSupplyAt(block.number); } @@ -399,51 +347,26 @@ contract MiniMeToken is Controlled { bytes32 _r, bytes32 _s ) public { - require(_deadline >= block.timestamp, "permit: AUTH_EXPIRED"); + require(_deadline >= block.timestamp, 'permit: AUTH_EXPIRED'); - bytes32 encodeData = keccak256( - abi.encode( - PERMIT_TYPEHASH, - _owner, - _spender, - _value, - nonces[_owner]++, - _deadline - ) - ); + bytes32 encodeData = + keccak256(abi.encode(PERMIT_TYPEHASH, _owner, _spender, _value, nonces[_owner]++, _deadline)); _validateSignedData(_owner, encodeData, _v, _r, _s); _approve(_owner, _spender, _value); } - function getDomainSeparator() public constant returns (bytes32) { - return - keccak256( - abi.encode( - EIP712DOMAIN_HASH, - nameHash, - VERSION_HASH, - CHAINID, - address(this) - ) - ); + function getDomainSeparator() public view returns (bytes32) { + return keccak256(abi.encode(EIP712DOMAIN_HASH, nameHash, VERSION_HASH, CHAINID, address(this))); } - function _validateSignedData( - address _signer, - bytes32 _encodeData, - uint8 _v, - bytes32 _r, - bytes32 _s - ) internal constant { - bytes32 digest = keccak256( - abi.encodePacked("\x19\x01", getDomainSeparator(), _encodeData) - ); + function _validateSignedData(address _signer, bytes32 _encodeData, uint8 _v, bytes32 _r, bytes32 _s) + internal + view + { + bytes32 digest = keccak256(abi.encodePacked('\x19\x01', getDomainSeparator(), _encodeData)); address recoveredAddress = ecrecover(digest, _v, _r, _s); // Explicitly disallow authorizations for address(0) as ecrecover returns address(0) on malformed messages - require( - recoveredAddress != 0 && recoveredAddress == _signer, - "_validateSignedData: INVALID_SIGNATURE" - ); + require(recoveredAddress != 0 && recoveredAddress == _signer, '_validateSignedData: INVALID_SIGNATURE'); } function transferWithAuthorization( @@ -457,29 +380,12 @@ contract MiniMeToken is Controlled { bytes32 _r, bytes32 _s ) external { - require( - block.timestamp > _validAfter, - "transferWithAuthorization: AUTH_NOT_YET_VALID" - ); - require( - block.timestamp < _validBefore, - "transferWithAuthorization: AUTH_EXPIRED" - ); - require( - !authorizationState[_from][_nonce], - "transferWithAuthorization: AUTH_ALREADY_USED" - ); + require(block.timestamp > _validAfter, 'transferWithAuthorization: AUTH_NOT_YET_VALID'); + require(block.timestamp < _validBefore, 'transferWithAuthorization: AUTH_EXPIRED'); + require(!authorizationState[_from][_nonce], 'transferWithAuthorization: AUTH_ALREADY_USED'); bytes32 encodeData = keccak256( - abi.encode( - TRANSFER_WITH_AUTHORIZATION_TYPEHASH, - _from, - _to, - _value, - _validAfter, - _validBefore, - _nonce - ) + abi.encode(TRANSFER_WITH_AUTHORIZATION_TYPEHASH, _from, _to, _value, _validAfter, _validBefore, _nonce) ); _validateSignedData(_from, encodeData, _v, _r, _s); @@ -497,26 +403,15 @@ contract MiniMeToken is Controlled { /// @param _owner The address from which the balance will be retrieved /// @param _blockNumber The block number when the balance is queried /// @return The balance at `_blockNumber` - function balanceOfAt(address _owner, uint256 _blockNumber) - public - constant - returns (uint256) - { + function balanceOfAt(address _owner, uint256 _blockNumber) public view returns (uint256) { // These next few lines are used when the balance of the token is // requested before a check point was ever created for this token, it // requires that the `parentToken.balanceOfAt` be queried at the // genesis block for that token as this contains initial balance of // this token - if ( - (balances[_owner].length == 0) || - (balances[_owner][0].fromBlock > _blockNumber) - ) { + if ((balances[_owner].length == 0) || (balances[_owner][0].fromBlock > _blockNumber)) { if (address(parentToken) != 0) { - return - parentToken.balanceOfAt( - _owner, - min(_blockNumber, parentSnapShotBlock) - ); + return parentToken.balanceOfAt(_owner, min(_blockNumber, parentSnapShotBlock)); } else { // Has no parent return 0; @@ -531,25 +426,15 @@ contract MiniMeToken is Controlled { /// @notice Total amount of tokens at a specific `_blockNumber`. /// @param _blockNumber The block number when the totalSupply is queried /// @return The total amount of tokens at `_blockNumber` - function totalSupplyAt(uint256 _blockNumber) - public - constant - returns (uint256) - { + function totalSupplyAt(uint256 _blockNumber) public view returns (uint256) { // These next few lines are used when the totalSupply of the token is // requested before a check point was ever created for this token, it // requires that the `parentToken.totalSupplyAt` be queried at the // genesis block for this token as that contains totalSupply of this // token at this block number. - if ( - (totalSupplyHistory.length == 0) || - (totalSupplyHistory[0].fromBlock > _blockNumber) - ) { + if ((totalSupplyHistory.length == 0) || (totalSupplyHistory[0].fromBlock > _blockNumber)) { if (address(parentToken) != 0) { - return - parentToken.totalSupplyAt( - min(_blockNumber, parentSnapShotBlock) - ); + return parentToken.totalSupplyAt(min(_blockNumber, parentSnapShotBlock)); } else { return 0; } @@ -581,17 +466,10 @@ contract MiniMeToken is Controlled { uint256 _snapshotBlock, bool _transfersEnabled ) public returns (MiniMeToken) { - uint256 snapshot = _snapshotBlock == 0 - ? block.number - 1 - : _snapshotBlock; + uint256 snapshot = _snapshotBlock == 0 ? block.number - 1 : _snapshotBlock; MiniMeToken cloneToken = tokenFactory.createCloneToken( - this, - snapshot, - _cloneTokenName, - _cloneDecimalUnits, - _cloneTokenSymbol, - _transfersEnabled + this, snapshot, _cloneTokenName, _cloneDecimalUnits, _cloneTokenSymbol, _transfersEnabled ); cloneToken.changeController(msg.sender); @@ -609,11 +487,7 @@ contract MiniMeToken is Controlled { /// @param _owner The address that will be assigned the new tokens /// @param _amount The quantity of tokens generated /// @return True if the tokens are generated correctly - function generateTokens(address _owner, uint256 _amount) - public - onlyController - returns (bool) - { + function generateTokens(address _owner, uint256 _amount) public onlyController returns (bool) { uint256 curTotalSupply = totalSupply(); require(curTotalSupply + _amount >= curTotalSupply); // Check for overflow uint256 previousBalanceTo = balanceOf(_owner); @@ -628,11 +502,7 @@ contract MiniMeToken is Controlled { /// @param _owner The address that will lose the tokens /// @param _amount The quantity of tokens to burn /// @return True if the tokens are burned correctly - function destroyTokens(address _owner, uint256 _amount) - public - onlyController - returns (bool) - { + function destroyTokens(address _owner, uint256 _amount) public onlyController returns (bool) { uint256 curTotalSupply = totalSupply(); require(curTotalSupply >= _amount); uint256 previousBalanceFrom = balanceOf(_owner); @@ -661,16 +531,13 @@ contract MiniMeToken is Controlled { /// @param checkpoints The history of values being queried /// @param _block The block number to retrieve the value at /// @return The number of tokens being queried - function getValueAt(Checkpoint[] storage checkpoints, uint256 _block) - internal - constant - returns (uint256) - { + function getValueAt(Checkpoint[] storage checkpoints, uint256 _block) internal view returns (uint256) { if (checkpoints.length == 0) return 0; // Shortcut for the actual value - if (_block >= checkpoints[checkpoints.length - 1].fromBlock) + if (_block >= checkpoints[checkpoints.length - 1].fromBlock) { return checkpoints[checkpoints.length - 1].value; + } if (_block < checkpoints[0].fromBlock) return 0; // Binary search of the value in the array @@ -691,24 +558,15 @@ contract MiniMeToken is Controlled { /// `totalSupplyHistory` /// @param checkpoints The history of data being updated /// @param _value The new number of tokens - function updateValueAtNow(Checkpoint[] storage checkpoints, uint256 _value) - internal - { + function updateValueAtNow(Checkpoint[] storage checkpoints, uint256 _value) internal { require(_value <= uint128(-1)); - if ( - (checkpoints.length == 0) || - (checkpoints[checkpoints.length - 1].fromBlock < block.number) - ) { - Checkpoint storage newCheckPoint = checkpoints[ - checkpoints.length++ - ]; + if ((checkpoints.length == 0) || (checkpoints[checkpoints.length - 1].fromBlock < block.number)) { + Checkpoint storage newCheckPoint = checkpoints[checkpoints.length++]; newCheckPoint.fromBlock = uint128(block.number); newCheckPoint.value = uint128(_value); } else { - Checkpoint storage oldCheckPoint = checkpoints[ - checkpoints.length - 1 - ]; + Checkpoint storage oldCheckPoint = checkpoints[checkpoints.length - 1]; oldCheckPoint.value = uint128(_value); } } @@ -716,7 +574,7 @@ contract MiniMeToken is Controlled { /// @dev Internal function to determine if an address is a contract /// @param _addr The address being queried /// @return True if `_addr` is a contract - function isContract(address _addr) internal constant returns (bool) { + function isContract(address _addr) internal view returns (bool) { uint256 size; if (_addr == 0) return false; @@ -738,11 +596,7 @@ contract MiniMeToken is Controlled { function() external payable { require(isContract(controller)); // Adding the ` == true` makes the linter shut up so... - require( - ITokenController(controller).proxyPayment.value(msg.value)( - msg.sender - ) == true - ); + require(ITokenController(controller).proxyPayment.value(msg.value)(msg.sender) == true); } ////////// @@ -768,18 +622,10 @@ contract MiniMeToken is Controlled { //////////////// // Events //////////////// - event ClaimedTokens( - address indexed _token, - address indexed _controller, - uint256 _amount - ); + event ClaimedTokens(address indexed _token, address indexed _controller, uint256 _amount); event Transfer(address indexed _from, address indexed _to, uint256 _amount); event NewCloneToken(address indexed _cloneToken, uint256 _snapshotBlock); - event Approval( - address indexed _owner, - address indexed _spender, - uint256 _amount - ); + event Approval(address indexed _owner, address indexed _spender, uint256 _amount); event AuthorizationUsed(address indexed authorizer, bytes32 indexed nonce); } @@ -791,11 +637,7 @@ contract MiniMeToken is Controlled { /// In solidity this is the way to create a contract from a contract of the /// same class contract MiniMeTokenFactory { - event NewFactoryCloneToken( - address indexed _cloneToken, - address indexed _parentToken, - uint256 _snapshotBlock - ); + event NewFactoryCloneToken(address indexed _cloneToken, address indexed _parentToken, uint256 _snapshotBlock); /// @notice Update the DApp by creating a new token with new functionalities /// the msg.sender becomes the controller of this clone token @@ -816,21 +658,11 @@ contract MiniMeTokenFactory { bool _transfersEnabled ) public returns (MiniMeToken) { MiniMeToken newToken = new MiniMeToken( - this, - _parentToken, - _snapshotBlock, - _tokenName, - _decimalUnits, - _tokenSymbol, - _transfersEnabled + this, _parentToken, _snapshotBlock, _tokenName, _decimalUnits, _tokenSymbol, _transfersEnabled ); newToken.changeController(msg.sender); - NewFactoryCloneToken( - address(newToken), - address(_parentToken), - _snapshotBlock - ); + NewFactoryCloneToken(address(newToken), address(_parentToken), _snapshotBlock); return newToken; } } diff --git a/contracts/tokens/TokenERC677.sol b/contracts/tokens/TokenERC677.sol index 277f88d..30db119 100644 --- a/contracts/tokens/TokenERC677.sol +++ b/contracts/tokens/TokenERC677.sol @@ -157,24 +157,13 @@ pragma solidity ^0.4.24; * @dev see https://github.com/ethereum/EIPs/issues/20 */ contract ERC20 is ERC20Basic { - function allowance(address _owner, address _spender) - public - view - returns (uint256); + function allowance(address _owner, address _spender) public view returns (uint256); - function transferFrom( - address _from, - address _to, - uint256 _value - ) public returns (bool); + function transferFrom(address _from, address _to, uint256 _value) public returns (bool); function approve(address _spender, uint256 _value) public returns (bool); - event Approval( - address indexed owner, - address indexed spender, - uint256 value - ); + event Approval(address indexed owner, address indexed spender, uint256 value); } // File: openzeppelin-solidity/contracts/token/ERC20/StandardToken.sol @@ -197,11 +186,7 @@ contract StandardToken is ERC20, BasicToken { * @param _to address The address which you want to transfer to * @param _value uint256 the amount of tokens to be transferred */ - function transferFrom( - address _from, - address _to, - uint256 _value - ) public returns (bool) { + function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { require(_value <= balances[_from]); require(_value <= allowed[_from][msg.sender]); require(_to != address(0)); @@ -234,11 +219,7 @@ contract StandardToken is ERC20, BasicToken { * @param _spender address The address which will spend the funds. * @return A uint256 specifying the amount of tokens still available for the spender. */ - function allowance(address _owner, address _spender) - public - view - returns (uint256) - { + function allowance(address _owner, address _spender) public view returns (uint256) { return allowed[_owner][_spender]; } @@ -251,13 +232,8 @@ contract StandardToken is ERC20, BasicToken { * @param _spender The address which will spend the funds. * @param _addedValue The amount of tokens to increase the allowance by. */ - function increaseApproval(address _spender, uint256 _addedValue) - public - returns (bool) - { - allowed[msg.sender][_spender] = ( - allowed[msg.sender][_spender].add(_addedValue) - ); + function increaseApproval(address _spender, uint256 _addedValue) public returns (bool) { + allowed[msg.sender][_spender] = (allowed[msg.sender][_spender].add(_addedValue)); emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); return true; } @@ -271,10 +247,7 @@ contract StandardToken is ERC20, BasicToken { * @param _spender The address which will spend the funds. * @param _subtractedValue The amount of tokens to decrease the allowance by. */ - function decreaseApproval(address _spender, uint256 _subtractedValue) - public - returns (bool) - { + function decreaseApproval(address _spender, uint256 _subtractedValue) public returns (bool) { uint256 oldValue = allowed[msg.sender][_spender]; if (_subtractedValue >= oldValue) { allowed[msg.sender][_spender] = 0; @@ -299,10 +272,7 @@ contract Ownable { address public owner; event OwnershipRenounced(address indexed previousOwner); - event OwnershipTransferred( - address indexed previousOwner, - address indexed newOwner - ); + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender @@ -381,12 +351,7 @@ contract MintableToken is StandardToken, Ownable { * @param _amount The amount of tokens to mint. * @return A boolean that indicates if the operation was successful. */ - function mint(address _to, uint256 _amount) - public - hasMintPermission - canMint - returns (bool) - { + function mint(address _to, uint256 _amount) public hasMintPermission canMint returns (bool) { totalSupply_ = totalSupply_.add(_amount); balances[_to] = balances[_to].add(_amount); emit Mint(_to, _amount); @@ -420,11 +385,7 @@ contract DetailedERC20 is ERC20 { string public symbol; uint8 public decimals; - constructor( - string _name, - string _symbol, - uint8 _decimals - ) public { + constructor(string _name, string _symbol, uint8 _decimals) public { name = _name; symbol = _symbol; decimals = _decimals; @@ -467,26 +428,13 @@ library AddressUtils { pragma solidity 0.4.24; contract ERC677 is ERC20 { - event Transfer( - address indexed from, - address indexed to, - uint256 value, - bytes data - ); - - function transferAndCall( - address, - uint256, - bytes - ) external returns (bool); - - function increaseAllowance(address spender, uint256 addedValue) - public - returns (bool); + event Transfer(address indexed from, address indexed to, uint256 value, bytes data); - function decreaseAllowance(address spender, uint256 subtractedValue) - public - returns (bool); + function transferAndCall(address, uint256, bytes) external returns (bool); + + function increaseAllowance(address spender, uint256 addedValue) public returns (bool); + + function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool); } // File: contracts/interfaces/IBurnableMintableERC677Token.sol @@ -564,31 +512,17 @@ contract Claimable { safeTransfer(_token, _to, balance); } - function safeTransfer( - address _token, - address _to, - uint256 _value - ) internal { + function safeTransfer(address _token, address _to, uint256 _value) internal { bytes memory returnData; bool returnDataResult; bytes memory callData = abi.encodeWithSelector(TRANSFER, _to, _value); assembly { - let result := call( - gas, - _token, - 0x0, - add(callData, 0x20), - mload(callData), - 0, - 32 - ) + let result := call(gas, _token, 0x0, add(callData, 0x20), mload(callData), 0, 32) returnData := mload(0) returnDataResult := mload(0) switch result - case 0 { - revert(0, 0) - } + case 0 { revert(0, 0) } } // Return data is optional @@ -606,24 +540,14 @@ pragma solidity 0.4.24; * @title ERC677BridgeToken * @dev The basic implementation of a bridgeable ERC677-compatible token */ -contract ERC677BridgeToken is - IBurnableMintableERC677Token, - DetailedERC20, - BurnableToken, - MintableToken, - Claimable -{ +contract ERC677BridgeToken is IBurnableMintableERC677Token, DetailedERC20, BurnableToken, MintableToken, Claimable { bytes4 internal constant ON_TOKEN_TRANSFER = 0xa4c0ed36; // onTokenTransfer(address,uint256,bytes) address internal bridgeContractAddr; event ContractFallbackCallFailed(address from, address to, uint256 value); - constructor( - string _name, - string _symbol, - uint8 _decimals - ) public DetailedERC20(_name, _symbol, _decimals) { + constructor(string _name, string _symbol, uint8 _decimals) public DetailedERC20(_name, _symbol, _decimals) { // solhint-disable-previous-line no-empty-blocks } @@ -642,11 +566,7 @@ contract ERC677BridgeToken is _; } - function transferAndCall( - address _to, - uint256 _value, - bytes _data - ) external validRecipient(_to) returns (bool) { + function transferAndCall(address _to, uint256 _value, bytes _data) external validRecipient(_to) returns (bool) { require(superTransfer(_to, _value)); emit Transfer(msg.sender, _to, _value, _data); @@ -656,22 +576,11 @@ contract ERC677BridgeToken is return true; } - function getTokenInterfacesVersion() - external - pure - returns ( - uint64 major, - uint64 minor, - uint64 patch - ) - { + function getTokenInterfacesVersion() external pure returns (uint64 major, uint64 minor, uint64 patch) { return (2, 2, 0); } - function superTransfer(address _to, uint256 _value) - internal - returns (bool) - { + function superTransfer(address _to, uint256 _value) internal returns (bool) { return super.transfer(_to, _value); } @@ -681,25 +590,14 @@ contract ERC677BridgeToken is return true; } - function transferFrom( - address _from, - address _to, - uint256 _value - ) public returns (bool) { + function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { require(super.transferFrom(_from, _to, _value)); callAfterTransfer(_from, _to, _value); return true; } - function callAfterTransfer( - address _from, - address _to, - uint256 _value - ) internal { - if ( - AddressUtils.isContract(_to) && - !contractFallback(_from, _to, _value, new bytes(0)) - ) { + function callAfterTransfer(address _from, address _to, uint256 _value) internal { + if (AddressUtils.isContract(_to) && !contractFallback(_from, _to, _value, new bytes(0))) { require(!isBridge(_to)); emit ContractFallbackCallFailed(_from, _to, _value); } @@ -716,16 +614,8 @@ contract ERC677BridgeToken is * @param _value amount of tokens that was sent * @param _data set of extra bytes that can be passed to the recipient */ - function contractFallback( - address _from, - address _to, - uint256 _value, - bytes _data - ) private returns (bool) { - return - _to.call( - abi.encodeWithSelector(ON_TOKEN_TRANSFER, _from, _value, _data) - ); + function contractFallback(address _from, address _to, uint256 _value, bytes _data) private returns (bool) { + return _to.call(abi.encodeWithSelector(ON_TOKEN_TRANSFER, _from, _value, _data)); } function finishMinting() public returns (bool) { @@ -736,25 +626,15 @@ contract ERC677BridgeToken is revert(); } - function claimTokens(address _token, address _to) - public - onlyOwner - validAddress(_to) - { + function claimTokens(address _token, address _to) public onlyOwner validAddress(_to) { claimValues(_token, _to); } - function increaseAllowance(address spender, uint256 addedValue) - public - returns (bool) - { + function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { return super.increaseApproval(spender, addedValue); } - function decreaseAllowance(address spender, uint256 subtractedValue) - public - returns (bool) - { + function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { return super.decreaseApproval(spender, subtractedValue); } } @@ -764,29 +644,24 @@ contract ERC677BridgeToken is pragma solidity 0.4.24; contract PermittableToken is ERC677BridgeToken { - string public constant version = "1"; + string public constant version = '1'; // EIP712 niceties bytes32 public DOMAIN_SEPARATOR; // bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address holder,address spender,uint256 nonce,uint256 expiry,bool allowed)"); - bytes32 public constant PERMIT_TYPEHASH = - 0xea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb; + bytes32 public constant PERMIT_TYPEHASH = 0xea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb; mapping(address => uint256) public nonces; mapping(address => mapping(address => uint256)) public expirations; - constructor( - string memory _name, - string memory _symbol, - uint8 _decimals, - uint256 _chainId - ) public ERC677BridgeToken(_name, _symbol, _decimals) { + constructor(string memory _name, string memory _symbol, uint8 _decimals, uint256 _chainId) + public + ERC677BridgeToken(_name, _symbol, _decimals) + { require(_chainId != 0); DOMAIN_SEPARATOR = keccak256( abi.encode( - keccak256( - "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" - ), + keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'), keccak256(bytes(_name)), keccak256(bytes(version)), _chainId, @@ -803,11 +678,7 @@ contract PermittableToken is ERC677BridgeToken { /// @param _recipient The address of the recipient. /// @param _amount The value to transfer. /// @return Success status. - function transferFrom( - address _sender, - address _recipient, - uint256 _amount - ) public returns (bool) { + function transferFrom(address _sender, address _recipient, uint256 _amount) public returns (bool) { require(_sender != address(0)); require(_recipient != address(0)); @@ -822,18 +693,11 @@ contract PermittableToken is ERC677BridgeToken { // If allowance is limited, adjust it. // In this case `transferFrom` works like the generic allowed[_sender][msg.sender] = allowedAmount.sub(_amount); - emit Approval( - _sender, - msg.sender, - allowed[_sender][msg.sender] - ); + emit Approval(_sender, msg.sender, allowed[_sender][msg.sender]); } else { // If allowance is unlimited by `permit`, `approve`, or `increaseAllowance` // function, don't adjust it. But the expiration date must be empty or in the future - require( - expirations[_sender][msg.sender] == 0 || - expirations[_sender][msg.sender] >= _now() - ); + require(expirations[_sender][msg.sender] == 0 || expirations[_sender][msg.sender] >= _now()); } } else { // If `_sender` is `msg.sender`, @@ -863,11 +727,7 @@ contract PermittableToken is ERC677BridgeToken { /// @param _from The address of the sender. /// @param _to The address of the recipient. /// @param _amount The value to transfer. - function move( - address _from, - address _to, - uint256 _amount - ) public { + function move(address _from, address _to, uint256 _amount) public { transferFrom(_from, _to, _amount); } @@ -899,18 +759,9 @@ contract PermittableToken is ERC677BridgeToken { bytes32 digest = keccak256( abi.encodePacked( - "\x19\x01", + '\x19\x01', DOMAIN_SEPARATOR, - keccak256( - abi.encode( - PERMIT_TYPEHASH, - _holder, - _spender, - _nonce, - _expiry, - _allowed - ) - ) + keccak256(abi.encode(PERMIT_TYPEHASH, _holder, _spender, _nonce, _expiry, _allowed)) ) ); @@ -930,15 +781,7 @@ contract PermittableToken is ERC677BridgeToken { } /// @dev Version of the token contract. - function getTokenInterfacesVersion() - external - pure - returns ( - uint64 major, - uint64 minor, - uint64 patch - ) - { + function getTokenInterfacesVersion() external pure returns (uint64 major, uint64 minor, uint64 patch) { return (2, 3, 0); } } diff --git a/contracts/tokens/UniswapV3RewardToken.sol b/contracts/tokens/UniswapV3RewardToken.sol index 3523a94..deb47b8 100644 --- a/contracts/tokens/UniswapV3RewardToken.sol +++ b/contracts/tokens/UniswapV3RewardToken.sol @@ -2,15 +2,15 @@ pragma solidity ^0.8.6; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; -import "../interfaces/IDistro.sol"; +import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol'; +import '../interfaces/IDistro.sol'; contract UniswapV3RewardToken is IERC20, OwnableUpgradeable { uint256 public initialBalance; - string public constant name = "Giveth Uniswap V3 Reward Token"; - string public constant symbol = "GUR"; + string public constant name = 'Giveth Uniswap V3 Reward Token'; + string public constant symbol = 'GUR'; uint8 public constant decimals = 18; IDistro public tokenDistro; @@ -35,10 +35,7 @@ contract UniswapV3RewardToken is IERC20, OwnableUpgradeable { /// @param account The account that enabled the contract event Enabled(address account); - function initialize(IDistro _tokenDistribution, address _uniswapV3Staker) - public - initializer - { + function initialize(IDistro _tokenDistribution, address _uniswapV3Staker) public initializer { __Ownable_init(); tokenDistro = _tokenDistribution; uniswapV3Staker = _uniswapV3Staker; @@ -53,15 +50,8 @@ contract UniswapV3RewardToken is IERC20, OwnableUpgradeable { return true; } - function transfer(address to, uint256 value) - external - override - returns (bool) - { - require( - msg.sender == uniswapV3Staker, - "GivethUniswapV3Reward:transfer:ONLY_STAKER" - ); + function transfer(address to, uint256 value) external override returns (bool) { + require(msg.sender == uniswapV3Staker, 'GivethUniswapV3Reward:transfer:ONLY_STAKER'); totalSupply = totalSupply - value; if (!disabled) { @@ -74,27 +64,14 @@ contract UniswapV3RewardToken is IERC20, OwnableUpgradeable { return true; } - function transferFrom( - address from, - address to, - uint256 value - ) external override returns (bool) { - require( - from == owner(), - "GivethUniswapV3Reward:transferFrom:ONLY_OWNER_CAN_ADD_INCENTIVES" - ); + function transferFrom(address from, address to, uint256 value) external override returns (bool) { + require(from == owner(), 'GivethUniswapV3Reward:transferFrom:ONLY_OWNER_CAN_ADD_INCENTIVES'); // Only uniswapV3Staker can do the transferFrom - require( - msg.sender == uniswapV3Staker, - "GivethUniswapV3Reward:transferFrom:ONLY_STAKER" - ); + require(msg.sender == uniswapV3Staker, 'GivethUniswapV3Reward:transferFrom:ONLY_STAKER'); // Only to uniswapV3Staker is allowed - require( - to == uniswapV3Staker, - "GivethUniswapV3Reward:transferFrom:ONLY_TO_STAKER" - ); + require(to == uniswapV3Staker, 'GivethUniswapV3Reward:transferFrom:ONLY_TO_STAKER'); totalSupply = totalSupply + value; @@ -102,12 +79,7 @@ contract UniswapV3RewardToken is IERC20, OwnableUpgradeable { return true; } - function allowance(address, address spender) - external - view - override - returns (uint256) - { + function allowance(address, address spender) external view override returns (uint256) { if (spender == uniswapV3Staker) return type(uint256).max; return 0; } diff --git a/script/deployRelayer.s.sol b/script/deployRelayer.s.sol index acb05f5..275690e 100644 --- a/script/deployRelayer.s.sol +++ b/script/deployRelayer.s.sol @@ -29,9 +29,11 @@ contract deployRelayer is Script { givbacksRelayerProxyAdmin = new ProxyAdmin(); // new implementation implementation = new GIVbacksRelayer(); - givbacksRelayerProxy = - new TransparentUpgradeableProxy(payable(address(implementation)), address(givbacksRelayerProxyAdmin), - abi.encodeWithSelector(GIVbacksRelayer(givbacksRelayer).initialize.selector, tokenDistro, deployer, batcher)); + givbacksRelayerProxy = new TransparentUpgradeableProxy( + payable(address(implementation)), + address(givbacksRelayerProxyAdmin), + abi.encodeWithSelector(GIVbacksRelayer(givbacksRelayer).initialize.selector, tokenDistro, deployer, batcher) + ); givbacksRelayer = GIVbacksRelayer(address(givbacksRelayerProxy)); console.log('proxy admin', address(givbacksRelayerProxyAdmin)); diff --git a/script/deployRelayerOptimism.s.sol b/script/deployRelayerOptimism.s.sol index f8353e3..4ba11f2 100644 --- a/script/deployRelayerOptimism.s.sol +++ b/script/deployRelayerOptimism.s.sol @@ -33,9 +33,13 @@ contract deployRelayer is Script { givbacksRelayerProxyAdmin = new ProxyAdmin(); // new implementation implementation = new GIVbacksRelayer(); - givbacksRelayerProxy = - new TransparentUpgradeableProxy(payable(address(implementation)), address(givbacksRelayerProxyAdmin), - abi.encodeWithSelector(GIVbacksRelayer(givbacksRelayer).initialize.selector, tokenDistro, deployer, batcherAgent)); + givbacksRelayerProxy = new TransparentUpgradeableProxy( + payable(address(implementation)), + address(givbacksRelayerProxyAdmin), + abi.encodeWithSelector( + GIVbacksRelayer(givbacksRelayer).initialize.selector, tokenDistro, deployer, batcherAgent + ) + ); givbacksRelayer = GIVbacksRelayer(address(givbacksRelayerProxy)); tokenDistro.grantRole(keccak256('DISTRIBUTOR_ROLE'), address(givbacksRelayer)); tokenDistro.assign(address(givbacksRelayer), 2500000 ether); diff --git a/script/deployTokenDistro.s.sol b/script/deployTokenDistro.s.sol index 121408f..842f99c 100644 --- a/script/deployTokenDistro.s.sol +++ b/script/deployTokenDistro.s.sol @@ -35,9 +35,20 @@ contract deployTokenDistro is Script { tokenDistroProxyAdmin = new ProxyAdmin(); // new implementation implementation = new TokenDistro(); - tokenDistroProxy = - new TransparentUpgradeableProxy(payable(address(implementation)), address(tokenDistroProxyAdmin), - abi.encodeWithSelector(TokenDistro(tokenDistro).initialize.selector, totalTokens, startTime, cliffPeriod, duration, initialPercentage, givToken, cancelable)); + tokenDistroProxy = new TransparentUpgradeableProxy( + payable(address(implementation)), + address(tokenDistroProxyAdmin), + abi.encodeWithSelector( + TokenDistro(tokenDistro).initialize.selector, + totalTokens, + startTime, + cliffPeriod, + duration, + initialPercentage, + givToken, + cancelable + ) + ); tokenDistro = TokenDistro(address(tokenDistroProxy)); console.log('proxy admin', address(tokenDistroProxyAdmin)); diff --git a/test/GIVpowerTest.sol b/test/GIVpowerTest.sol index a2464d1..b193a05 100644 --- a/test/GIVpowerTest.sol +++ b/test/GIVpowerTest.sol @@ -95,9 +95,7 @@ contract GIVpowerTest is Test { function getImplementationStorageData(address[] memory _users) public view returns (StorageData memory) { uint256[] memory usersBalances = new uint256[](_users.length); - uint256[] memory usersRewardsPerTokenPaid = new uint256[]( - _users.length - ); + uint256[] memory usersRewardsPerTokenPaid = new uint256[](_users.length); uint256[] memory usersRewards = new uint256[](_users.length); for (uint256 i = 0; i < _users.length; i++) { diff --git a/test/ModifyTokenDistro.t.sol b/test/ModifyTokenDistro.t.sol index 007cf17..335ed0c 100644 --- a/test/ModifyTokenDistro.t.sol +++ b/test/ModifyTokenDistro.t.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.6; -import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; -import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; -import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol"; -import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; -import "@openzeppelin/contracts/utils/math/SafeMath.sol"; +import '@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol'; +import '@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol'; +import '@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol'; +import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; +import '@openzeppelin/contracts/utils/math/SafeMath.sol'; import '@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol'; import '@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol'; import 'forge-std/Test.sol'; @@ -15,6 +15,7 @@ import '../contracts/ModifiedTokenDistro.sol'; contract TestModifyDistro is Test { using SafeERC20Upgradeable for IERC20Upgradeable; using SafeMath for uint256; + ProxyAdmin proxyAdmin; IERC20Upgradeable givToken; address givethMultisig; @@ -31,7 +32,7 @@ contract TestModifyDistro is Test { uint256 assignedAmount = 10000000000000000000000000; uint256 forkBlock = 22501098; - constructor() { + constructor() { uint256 forkId = vm.createFork('https://rpc.ankr.com/gnosis', forkBlock); //https://xdai-archive.blockscout.com/ vm.selectFork(forkId); proxyAdmin = ProxyAdmin(address(0x076C250700D210e6cf8A27D1EB1Fd754FB487986)); @@ -43,269 +44,271 @@ contract TestModifyDistro is Test { firstRecipient = address(6); secondRecipient = address(7); thirdRecipient = address(8); - } - - function setUp() public { - vm.startPrank(givethMultisig); - tokenDistroImplementation = new TokenDistro(); - // proxyAdmin.upgradeAndCall(tokenDistroProxy, address(tokenDistroImplementation), abi.encodeWithSelector(TokenDistro(tokenDistroImplementation).initialize.selector, 2000000000000000000000000000, 1640361600, 1640361600, 157680000, givToken, true)); - proxyAdmin.upgrade(tokenDistroProxy, address(tokenDistroImplementation)); - tokenDistro.grantRole(keccak256("DISTRIBUTOR_ROLE"), distributor); - tokenDistro.assign(distributor, assignedAmount); - vm.stopPrank(); - - vm.label(address(tokenDistro), 'tokenDistroContract'); - vm.label(address(tokenDistroImplementation), 'tokenDistroImplementation'); - vm.label(address(tokenDistroProxy), 'tokenDistroProxy'); - vm.label(address(givToken), 'givToken'); - vm.label(address(givethMultisig), 'givethMultisig'); - vm.label(address(distributor), 'distributor'); - vm.label(address(firstRecipient), 'firstRecipient'); - vm.label(address(secondRecipient), 'secondRecipient'); - vm.label(address(thirdRecipient), 'thirdRecipient'); - - } - function testTransferAllocation(uint256 amount1, uint256 amount2, uint256 amount3) public { - // bound the amounts to be between 1 and 1/3 of the assigned amount so it cannot go over the assigned amount - amount1 = bound(amount1, 1, assignedAmount.div(3)); - amount2 = bound(amount2, 1, assignedAmount.div(3)); - amount3 = bound(amount3, 1, assignedAmount.div(3)); - // setup the distribution arrays for allocation - address[] memory recipients = new address[](3); - recipients[0] = firstRecipient; - recipients[1] = secondRecipient; - recipients[2] = thirdRecipient; - - uint256[] memory amounts = new uint256[](3); - amounts[0] = amount1; - amounts[1] = amount2; - amounts[2] = amount3; - - // give some starting allocations to the recipients - vm.prank(distributor); - tokenDistro.allocateMany(recipients, amounts); - - // save balance values - (uint256 firstRecipientAllocatedTokens,) = tokenDistro.balances(firstRecipient); - (uint256 secondRecipientAllocatedTokens,) = tokenDistro.balances(secondRecipient); - // make first transfer from first recipient to second recipient - vm.prank(givethMultisig); - tokenDistro.transferAllocation(firstRecipient, secondRecipient); - - // save balance values after first transfer - (uint256 secondRecipientAllocatedTokensAfterTransfer,) = tokenDistro.balances(secondRecipient); - (uint256 firstRecipientAllocatedTokensAfterTransfer,) = tokenDistro.balances(firstRecipient); - // log some stuff - console.log('secondRecipientAllocatedTokensAfterTransfer: ', secondRecipientAllocatedTokensAfterTransfer); - console.log('secondRecipientAllocatedTokens: ', secondRecipientAllocatedTokens); - console.log('firstRecipientAllocatedTokensAfterTransfer: ', firstRecipientAllocatedTokensAfterTransfer); - console.log('firstRecipientAllocatedTokens: ', firstRecipientAllocatedTokens); - // assertions - assertEq(secondRecipientAllocatedTokensAfterTransfer, (firstRecipientAllocatedTokens.add(secondRecipientAllocatedTokens))); - assertEq(firstRecipientAllocatedTokensAfterTransfer,0); - - // do second transfer from second recip to third recip - vm.prank(givethMultisig); - tokenDistro.transferAllocation(secondRecipient, thirdRecipient); - - // save balance values after second transfer - (uint256 thirdRecipientAllocatedTokensAfterTransfer,) = tokenDistro.balances(thirdRecipient); - (uint256 secondRecipientAllocatedTokensAfterSecondTransfer,) = tokenDistro.balances(secondRecipient); - // expected amount should be the sum of all three amounts - uint256 expectedAmount = amount1.add(amount2.add(amount3)); - // log some stuff - console.log('thirdRecipientAllocatedTokensAfterTransfer: ', thirdRecipientAllocatedTokensAfterTransfer); - console.log('expectedAmount: ', expectedAmount); - // assertions - assertEq(thirdRecipientAllocatedTokensAfterTransfer,expectedAmount); - assertEq(secondRecipientAllocatedTokensAfterSecondTransfer,0); - - } - - function testTransferAllocationWithClaim(uint256 amount1, uint256 amount2) public { - amount1 = bound(amount1, 10, assignedAmount.div(2)); - amount2 = bound(amount2, 10, assignedAmount.div(2)); - - address[] memory recipients = new address[](2); - recipients[0] = firstRecipient; - recipients[1] = secondRecipient; - - uint256[] memory amounts = new uint256[](2); - amounts[0] = amount1; - amounts[1] = amount2; - - vm.prank(distributor); - tokenDistro.allocateMany(recipients, amounts); - - // skip ahead some time and then claim tokens - skip(14 days); - console.log('claimable for first recipient',tokenDistro.claimableNow(firstRecipient)); - console.log('claimable for second recipient', tokenDistro.claimableNow(secondRecipient)); - - vm.prank(firstRecipient); - tokenDistro.claim(); - vm.prank(secondRecipient); - tokenDistro.claim(); - - // save balance values - (, uint256 secondRecipientClaimedTokens) = tokenDistro.balances(secondRecipient); - (, uint256 firstRecipientClaimedTokens) = tokenDistro.balances(firstRecipient); - // transfer allocation to second recipient - vm.prank(givethMultisig); - tokenDistro.transferAllocation(firstRecipient, secondRecipient); - // check values of second recipient after transfer - (uint256 secondAllocatedAfterTransfer, uint256 secondClaimedAfterTransfer) = tokenDistro.balances(secondRecipient); - (uint256 firstAllocatedAfterTransfer, uint256 firstClaimedAfterTransfer) = tokenDistro.balances(firstRecipient); - // assertions - assertEq(secondAllocatedAfterTransfer, (amount1.add(amount2))); - assertEq(secondClaimedAfterTransfer, (secondRecipientClaimedTokens.add(firstRecipientClaimedTokens))); - assertEq(firstAllocatedAfterTransfer, 0); - assertEq(firstClaimedAfterTransfer, 0); - - } - - function testChangeAddress(uint256 amount1, uint256 amount2, uint256 amount3) public { - // bound the amounts to be between 1 and 1/3 of the assigned amount so it cannot go over the assigned amount - amount1 = bound(amount1, 1, assignedAmount.div(3)); - amount2 = bound(amount2, 1, assignedAmount.div(3)); - amount3 = bound(amount3, 1, assignedAmount.div(3)); - // setup the distribution arrays for allocation - address[] memory recipients = new address[](3); - recipients[0] = firstRecipient; - recipients[1] = secondRecipient; - recipients[2] = thirdRecipient; - - uint256[] memory amounts = new uint256[](3); - amounts[0] = amount1; - amounts[1] = amount2; - amounts[2] = amount3; - - // give some starting allocations to the recipients - vm.prank(distributor); - tokenDistro.allocateMany(recipients, amounts); - - // save balance values - (uint256 firstRecipientAllocatedTokens,) = tokenDistro.balances(firstRecipient); - (uint256 secondRecipientAllocatedTokens,) = tokenDistro.balances(secondRecipient); - // make first transfer from first recipient to second recipient - vm.prank(firstRecipient); - tokenDistro.changeAddress(secondRecipient); - - // save balance values after first transfer - (uint256 secondRecipientAllocatedTokensAfterTransfer,) = tokenDistro.balances(secondRecipient); - (uint256 firstRecipientAllocatedTokensAfterTransfer,) = tokenDistro.balances(firstRecipient); - // log some stuff - console.log('secondRecipientAllocatedTokensAfterTransfer: ', secondRecipientAllocatedTokensAfterTransfer); - console.log('secondRecipientAllocatedTokens: ', secondRecipientAllocatedTokens); - console.log('firstRecipientAllocatedTokensAfterTransfer: ', firstRecipientAllocatedTokensAfterTransfer); - console.log('firstRecipientAllocatedTokens: ', firstRecipientAllocatedTokens); - // assertions - assertEq(secondRecipientAllocatedTokensAfterTransfer, (firstRecipientAllocatedTokens.add(secondRecipientAllocatedTokens))); - assertEq(firstRecipientAllocatedTokensAfterTransfer,0); - - // do second transfer from second recip to third recip - vm.prank(secondRecipient); - tokenDistro.changeAddress(thirdRecipient); - - // save balance values after second transfer - (uint256 thirdRecipientAllocatedTokensAfterTransfer,) = tokenDistro.balances(thirdRecipient); - (uint256 secondRecipientAllocatedTokensAfterSecondTransfer,) = tokenDistro.balances(secondRecipient); - // expected amount should be the sum of all three amounts - uint256 expectedAmount = amount1.add(amount2.add(amount3)); - // log some stuff - console.log('thirdRecipientAllocatedTokensAfterTransfer: ', thirdRecipientAllocatedTokensAfterTransfer); - console.log('expectedAmount: ', expectedAmount); - // assertions - assertEq(thirdRecipientAllocatedTokensAfterTransfer,expectedAmount); - assertEq(secondRecipientAllocatedTokensAfterSecondTransfer,0); - - } - - function testChangeAddressWithClaim(uint256 amount1, uint256 amount2) public { - /// @aminlatifi for some reason this does not want to work with the min bound as 1 - throws no tokens to claim error - amount1 = bound(amount1, 10, assignedAmount.div(2)); - amount2 = bound(amount2, 10, assignedAmount.div(2)); - - address[] memory recipients = new address[](2); - recipients[0] = firstRecipient; - recipients[1] = secondRecipient; - - uint256[] memory amounts = new uint256[](2); - amounts[0] = amount1; - amounts[1] = amount2; - - vm.prank(distributor); - tokenDistro.allocateMany(recipients, amounts); - - // skip ahead some time and then claim tokens - skip(14 days); - console.log('claimable for first recipient',tokenDistro.claimableNow(firstRecipient)); - console.log('claimable for second recipient', tokenDistro.claimableNow(secondRecipient)); - - vm.prank(firstRecipient); - tokenDistro.claim(); - vm.prank(secondRecipient); - tokenDistro.claim(); - - // save balance values - (, uint256 secondRecipientClaimedTokens) = tokenDistro.balances(secondRecipient); - (, uint256 firstRecipientClaimedTokens) = tokenDistro.balances(firstRecipient); - // transfer allocation to second recipient - vm.prank(firstRecipient); - tokenDistro.changeAddress(secondRecipient); - // check values of second recipient after transfer - (uint256 secondAllocatedAfterTransfer, uint256 secondClaimedAfterTransfer) = tokenDistro.balances(secondRecipient); - (uint256 firstAllocatedAfterTransfer, uint256 firstClaimedAfterTransfer) = tokenDistro.balances(firstRecipient); - // assertions - assertEq(secondAllocatedAfterTransfer, (amount1.add(amount2))); - assertEq(secondClaimedAfterTransfer, (secondRecipientClaimedTokens.add(firstRecipientClaimedTokens))); - assertEq(firstAllocatedAfterTransfer, 0); - assertEq(firstClaimedAfterTransfer, 0); - - } - - - // function testCancelAllocation() public { - // uint256 amount = 100000000000; - // vm.prank(distributor); - // tokenDistro.allocate(firstRecipient, amount, false); - // (uint256 allocatedTokens,uint256 claimedTokens) = tokenDistro.balances(firstRecipient); - // assertEq(allocatedTokens, amount); - // assertEq(claimedTokens, 0); - // vm.prank(givethMultisig); - // tokenDistro.cancelAllocation(firstRecipient); - // (uint256 allocatedTokensAfterCancel, uint256 claimedTokensAfterCancel) = tokenDistro.balances(firstRecipient); - // assertEq(allocatedTokensAfterCancel, 0); - // assertEq(claimedTokensAfterCancel, 0); - // } - - // function testCancelAllocationWithClaim() public { - // uint256 amount = 100000000000; - // vm.prank(distributor); - // tokenDistro.allocate(firstRecipient, amount, true); - - // skip(14 days); - // vm.prank(firstRecipient); - // tokenDistro.claim(); - // (,uint256 claimedTokensAfterClaim) = tokenDistro.balances(firstRecipient); - // vm.prank(givethMultisig); - // tokenDistro.cancelAllocation(firstRecipient); - // (uint256 allocatedTokensAfterCancel, uint256 claimedTokensAfterCancel) = tokenDistro.balances(firstRecipient); - // assertEq(allocatedTokensAfterCancel, claimedTokensAfterClaim); - // assertEq(claimedTokensAfterCancel, claimedTokensAfterClaim); - // } - - // function testCancelAllocationRevert() public { - // testCancelAllocationWithClaim(); - - // skip(14 days); - - // console.log('claimable for first recipient',tokenDistro.claimableNow(firstRecipient)); - // // vm.expectRevert("TokenDistro::claim: NOT_ENOUGH_TOKENS_TO_CLAIM"); - - // // vm.prank(firstRecipient); - // // tokenDistro.claim(); - - // } - -} \ No newline at end of file + } + + function setUp() public { + vm.startPrank(givethMultisig); + tokenDistroImplementation = new TokenDistro(); + // proxyAdmin.upgradeAndCall(tokenDistroProxy, address(tokenDistroImplementation), abi.encodeWithSelector(TokenDistro(tokenDistroImplementation).initialize.selector, 2000000000000000000000000000, 1640361600, 1640361600, 157680000, givToken, true)); + proxyAdmin.upgrade(tokenDistroProxy, address(tokenDistroImplementation)); + tokenDistro.grantRole(keccak256('DISTRIBUTOR_ROLE'), distributor); + tokenDistro.assign(distributor, assignedAmount); + vm.stopPrank(); + + vm.label(address(tokenDistro), 'tokenDistroContract'); + vm.label(address(tokenDistroImplementation), 'tokenDistroImplementation'); + vm.label(address(tokenDistroProxy), 'tokenDistroProxy'); + vm.label(address(givToken), 'givToken'); + vm.label(address(givethMultisig), 'givethMultisig'); + vm.label(address(distributor), 'distributor'); + vm.label(address(firstRecipient), 'firstRecipient'); + vm.label(address(secondRecipient), 'secondRecipient'); + vm.label(address(thirdRecipient), 'thirdRecipient'); + } + + function testTransferAllocation(uint256 amount1, uint256 amount2, uint256 amount3) public { + // bound the amounts to be between 1 and 1/3 of the assigned amount so it cannot go over the assigned amount + amount1 = bound(amount1, 1, assignedAmount.div(3)); + amount2 = bound(amount2, 1, assignedAmount.div(3)); + amount3 = bound(amount3, 1, assignedAmount.div(3)); + // setup the distribution arrays for allocation + address[] memory recipients = new address[](3); + recipients[0] = firstRecipient; + recipients[1] = secondRecipient; + recipients[2] = thirdRecipient; + + uint256[] memory amounts = new uint256[](3); + amounts[0] = amount1; + amounts[1] = amount2; + amounts[2] = amount3; + + // give some starting allocations to the recipients + vm.prank(distributor); + tokenDistro.allocateMany(recipients, amounts); + + // save balance values + (uint256 firstRecipientAllocatedTokens,) = tokenDistro.balances(firstRecipient); + (uint256 secondRecipientAllocatedTokens,) = tokenDistro.balances(secondRecipient); + // make first transfer from first recipient to second recipient + vm.prank(givethMultisig); + tokenDistro.transferAllocation(firstRecipient, secondRecipient); + + // save balance values after first transfer + (uint256 secondRecipientAllocatedTokensAfterTransfer,) = tokenDistro.balances(secondRecipient); + (uint256 firstRecipientAllocatedTokensAfterTransfer,) = tokenDistro.balances(firstRecipient); + // log some stuff + console.log('secondRecipientAllocatedTokensAfterTransfer: ', secondRecipientAllocatedTokensAfterTransfer); + console.log('secondRecipientAllocatedTokens: ', secondRecipientAllocatedTokens); + console.log('firstRecipientAllocatedTokensAfterTransfer: ', firstRecipientAllocatedTokensAfterTransfer); + console.log('firstRecipientAllocatedTokens: ', firstRecipientAllocatedTokens); + // assertions + assertEq( + secondRecipientAllocatedTokensAfterTransfer, + (firstRecipientAllocatedTokens.add(secondRecipientAllocatedTokens)) + ); + assertEq(firstRecipientAllocatedTokensAfterTransfer, 0); + + // do second transfer from second recip to third recip + vm.prank(givethMultisig); + tokenDistro.transferAllocation(secondRecipient, thirdRecipient); + + // save balance values after second transfer + (uint256 thirdRecipientAllocatedTokensAfterTransfer,) = tokenDistro.balances(thirdRecipient); + (uint256 secondRecipientAllocatedTokensAfterSecondTransfer,) = tokenDistro.balances(secondRecipient); + // expected amount should be the sum of all three amounts + uint256 expectedAmount = amount1.add(amount2.add(amount3)); + // log some stuff + console.log('thirdRecipientAllocatedTokensAfterTransfer: ', thirdRecipientAllocatedTokensAfterTransfer); + console.log('expectedAmount: ', expectedAmount); + // assertions + assertEq(thirdRecipientAllocatedTokensAfterTransfer, expectedAmount); + assertEq(secondRecipientAllocatedTokensAfterSecondTransfer, 0); + } + + function testTransferAllocationWithClaim(uint256 amount1, uint256 amount2) public { + amount1 = bound(amount1, 10, assignedAmount.div(2)); + amount2 = bound(amount2, 10, assignedAmount.div(2)); + + address[] memory recipients = new address[](2); + recipients[0] = firstRecipient; + recipients[1] = secondRecipient; + + uint256[] memory amounts = new uint256[](2); + amounts[0] = amount1; + amounts[1] = amount2; + + vm.prank(distributor); + tokenDistro.allocateMany(recipients, amounts); + + // skip ahead some time and then claim tokens + skip(14 days); + console.log('claimable for first recipient', tokenDistro.claimableNow(firstRecipient)); + console.log('claimable for second recipient', tokenDistro.claimableNow(secondRecipient)); + + vm.prank(firstRecipient); + tokenDistro.claim(); + vm.prank(secondRecipient); + tokenDistro.claim(); + + // save balance values + (, uint256 secondRecipientClaimedTokens) = tokenDistro.balances(secondRecipient); + (, uint256 firstRecipientClaimedTokens) = tokenDistro.balances(firstRecipient); + // transfer allocation to second recipient + vm.prank(givethMultisig); + tokenDistro.transferAllocation(firstRecipient, secondRecipient); + // check values of second recipient after transfer + (uint256 secondAllocatedAfterTransfer, uint256 secondClaimedAfterTransfer) = + tokenDistro.balances(secondRecipient); + (uint256 firstAllocatedAfterTransfer, uint256 firstClaimedAfterTransfer) = tokenDistro.balances(firstRecipient); + // assertions + assertEq(secondAllocatedAfterTransfer, (amount1.add(amount2))); + assertEq(secondClaimedAfterTransfer, (secondRecipientClaimedTokens.add(firstRecipientClaimedTokens))); + assertEq(firstAllocatedAfterTransfer, 0); + assertEq(firstClaimedAfterTransfer, 0); + } + + function testChangeAddress(uint256 amount1, uint256 amount2, uint256 amount3) public { + // bound the amounts to be between 1 and 1/3 of the assigned amount so it cannot go over the assigned amount + amount1 = bound(amount1, 1, assignedAmount.div(3)); + amount2 = bound(amount2, 1, assignedAmount.div(3)); + amount3 = bound(amount3, 1, assignedAmount.div(3)); + // setup the distribution arrays for allocation + address[] memory recipients = new address[](3); + recipients[0] = firstRecipient; + recipients[1] = secondRecipient; + recipients[2] = thirdRecipient; + + uint256[] memory amounts = new uint256[](3); + amounts[0] = amount1; + amounts[1] = amount2; + amounts[2] = amount3; + + // give some starting allocations to the recipients + vm.prank(distributor); + tokenDistro.allocateMany(recipients, amounts); + + // save balance values + (uint256 firstRecipientAllocatedTokens,) = tokenDistro.balances(firstRecipient); + (uint256 secondRecipientAllocatedTokens,) = tokenDistro.balances(secondRecipient); + // make first transfer from first recipient to second recipient + vm.prank(firstRecipient); + tokenDistro.changeAddress(secondRecipient); + + // save balance values after first transfer + (uint256 secondRecipientAllocatedTokensAfterTransfer,) = tokenDistro.balances(secondRecipient); + (uint256 firstRecipientAllocatedTokensAfterTransfer,) = tokenDistro.balances(firstRecipient); + // log some stuff + console.log('secondRecipientAllocatedTokensAfterTransfer: ', secondRecipientAllocatedTokensAfterTransfer); + console.log('secondRecipientAllocatedTokens: ', secondRecipientAllocatedTokens); + console.log('firstRecipientAllocatedTokensAfterTransfer: ', firstRecipientAllocatedTokensAfterTransfer); + console.log('firstRecipientAllocatedTokens: ', firstRecipientAllocatedTokens); + // assertions + assertEq( + secondRecipientAllocatedTokensAfterTransfer, + (firstRecipientAllocatedTokens.add(secondRecipientAllocatedTokens)) + ); + assertEq(firstRecipientAllocatedTokensAfterTransfer, 0); + + // do second transfer from second recip to third recip + vm.prank(secondRecipient); + tokenDistro.changeAddress(thirdRecipient); + + // save balance values after second transfer + (uint256 thirdRecipientAllocatedTokensAfterTransfer,) = tokenDistro.balances(thirdRecipient); + (uint256 secondRecipientAllocatedTokensAfterSecondTransfer,) = tokenDistro.balances(secondRecipient); + // expected amount should be the sum of all three amounts + uint256 expectedAmount = amount1.add(amount2.add(amount3)); + // log some stuff + console.log('thirdRecipientAllocatedTokensAfterTransfer: ', thirdRecipientAllocatedTokensAfterTransfer); + console.log('expectedAmount: ', expectedAmount); + // assertions + assertEq(thirdRecipientAllocatedTokensAfterTransfer, expectedAmount); + assertEq(secondRecipientAllocatedTokensAfterSecondTransfer, 0); + } + + function testChangeAddressWithClaim(uint256 amount1, uint256 amount2) public { + /// @aminlatifi for some reason this does not want to work with the min bound as 1 - throws no tokens to claim error + amount1 = bound(amount1, 10, assignedAmount.div(2)); + amount2 = bound(amount2, 10, assignedAmount.div(2)); + + address[] memory recipients = new address[](2); + recipients[0] = firstRecipient; + recipients[1] = secondRecipient; + + uint256[] memory amounts = new uint256[](2); + amounts[0] = amount1; + amounts[1] = amount2; + + vm.prank(distributor); + tokenDistro.allocateMany(recipients, amounts); + + // skip ahead some time and then claim tokens + skip(14 days); + console.log('claimable for first recipient', tokenDistro.claimableNow(firstRecipient)); + console.log('claimable for second recipient', tokenDistro.claimableNow(secondRecipient)); + + vm.prank(firstRecipient); + tokenDistro.claim(); + vm.prank(secondRecipient); + tokenDistro.claim(); + + // save balance values + (, uint256 secondRecipientClaimedTokens) = tokenDistro.balances(secondRecipient); + (, uint256 firstRecipientClaimedTokens) = tokenDistro.balances(firstRecipient); + // transfer allocation to second recipient + vm.prank(firstRecipient); + tokenDistro.changeAddress(secondRecipient); + // check values of second recipient after transfer + (uint256 secondAllocatedAfterTransfer, uint256 secondClaimedAfterTransfer) = + tokenDistro.balances(secondRecipient); + (uint256 firstAllocatedAfterTransfer, uint256 firstClaimedAfterTransfer) = tokenDistro.balances(firstRecipient); + // assertions + assertEq(secondAllocatedAfterTransfer, (amount1.add(amount2))); + assertEq(secondClaimedAfterTransfer, (secondRecipientClaimedTokens.add(firstRecipientClaimedTokens))); + assertEq(firstAllocatedAfterTransfer, 0); + assertEq(firstClaimedAfterTransfer, 0); + } + + // function testCancelAllocation() public { + // uint256 amount = 100000000000; + // vm.prank(distributor); + // tokenDistro.allocate(firstRecipient, amount, false); + // (uint256 allocatedTokens,uint256 claimedTokens) = tokenDistro.balances(firstRecipient); + // assertEq(allocatedTokens, amount); + // assertEq(claimedTokens, 0); + // vm.prank(givethMultisig); + // tokenDistro.cancelAllocation(firstRecipient); + // (uint256 allocatedTokensAfterCancel, uint256 claimedTokensAfterCancel) = tokenDistro.balances(firstRecipient); + // assertEq(allocatedTokensAfterCancel, 0); + // assertEq(claimedTokensAfterCancel, 0); + // } + + // function testCancelAllocationWithClaim() public { + // uint256 amount = 100000000000; + // vm.prank(distributor); + // tokenDistro.allocate(firstRecipient, amount, true); + + // skip(14 days); + // vm.prank(firstRecipient); + // tokenDistro.claim(); + // (,uint256 claimedTokensAfterClaim) = tokenDistro.balances(firstRecipient); + // vm.prank(givethMultisig); + // tokenDistro.cancelAllocation(firstRecipient); + // (uint256 allocatedTokensAfterCancel, uint256 claimedTokensAfterCancel) = tokenDistro.balances(firstRecipient); + // assertEq(allocatedTokensAfterCancel, claimedTokensAfterClaim); + // assertEq(claimedTokensAfterCancel, claimedTokensAfterClaim); + // } + + // function testCancelAllocationRevert() public { + // testCancelAllocationWithClaim(); + + // skip(14 days); + + // console.log('claimable for first recipient',tokenDistro.claimableNow(firstRecipient)); + // // vm.expectRevert("TokenDistro::claim: NOT_ENOUGH_TOKENS_TO_CLAIM"); + + // // vm.prank(firstRecipient); + // // tokenDistro.claim(); + + // } +} diff --git a/test/UnipoolTests/UnipoolGIVpowerTest.sol b/test/UnipoolTests/UnipoolGIVpowerTest.sol index 38d61dc..7981353 100644 --- a/test/UnipoolTests/UnipoolGIVpowerTest.sol +++ b/test/UnipoolTests/UnipoolGIVpowerTest.sol @@ -75,9 +75,11 @@ contract UnipoolGIVpowerTest is Test { givethMultisig = unipoolGIVpowerProxyAdmin.owner(); // new implementation implementation = new UnipoolGIVpower(); - unipoolGIVpowerProxy = - new TransparentUpgradeableProxy(payable(address(implementation)), address(unipoolGIVpowerProxyAdmin), - abi.encodeWithSelector(UnipoolGIVpower(givPower).initialize.selector, iDistro, givToken, 14 days)); + unipoolGIVpowerProxy = new TransparentUpgradeableProxy( + payable(address(implementation)), + address(unipoolGIVpowerProxyAdmin), + abi.encodeWithSelector(UnipoolGIVpower(givPower).initialize.selector, iDistro, givToken, 14 days) + ); givPower = UnipoolGIVpower(address(unipoolGIVpowerProxy)); // mint @@ -97,9 +99,7 @@ contract UnipoolGIVpowerTest is Test { function getImplementationStorageData(address[] memory _users) public view returns (StorageData memory) { uint256[] memory usersBalances = new uint256[](_users.length); - uint256[] memory usersRewardsPerTokenPaid = new uint256[]( - _users.length - ); + uint256[] memory usersRewardsPerTokenPaid = new uint256[](_users.length); uint256[] memory usersRewards = new uint256[](_users.length); for (uint256 i = 0; i < _users.length; i++) { From afa189a9825b1440b4fceb3e00999c8603782f46 Mon Sep 17 00:00:00 2001 From: Mitch Oz Date: Wed, 31 Jan 2024 16:49:41 -0600 Subject: [PATCH 03/31] fix typo in import --- contracts/tokens/UniswapV3RewardToken.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/tokens/UniswapV3RewardToken.sol b/contracts/tokens/UniswapV3RewardToken.sol index 2fb672f..d31e32b 100644 --- a/contracts/tokens/UniswapV3RewardToken.sol +++ b/contracts/tokens/UniswapV3RewardToken.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.10; import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol'; -import '../Interfaces/IDistro.sol'; +import '../interfaces/IDistro.sol'; contract UniswapV3RewardToken is IERC20, OwnableUpgradeable { uint256 public initialBalance; From e15fece0069e2992c6e529dab38f1c16372f1521 Mon Sep 17 00:00:00 2001 From: Mitch Oz Date: Fri, 9 Feb 2024 11:21:56 -0600 Subject: [PATCH 04/31] add internal transferAllocation function, remove safemath --- contracts/ModifiedTokenDistro.sol | 70 +++++++++++-------------------- test/ModifyTokenDistro.t.sol | 12 +++--- 2 files changed, 31 insertions(+), 51 deletions(-) diff --git a/contracts/ModifiedTokenDistro.sol b/contracts/ModifiedTokenDistro.sol index da1e7cb..cb60305 100644 --- a/contracts/ModifiedTokenDistro.sol +++ b/contracts/ModifiedTokenDistro.sol @@ -5,7 +5,6 @@ import '@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeab import '@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol'; import '@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol'; import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import '@openzeppelin/contracts/utils/math/SafeMath.sol'; import './interfaces/IDistroModified.sol'; /** @@ -13,8 +12,7 @@ import './interfaces/IDistroModified.sol'; * The distributor is in charge of releasing the corresponding amounts to its recipients. * This distributor is expected to be another smart contract, such as a merkledrop or the liquidity mining smart contract */ -contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeable { - using SafeMath for uint256; +contract TokenDistroV2 is Initializable, IDistro, AccessControlEnumerableUpgradeable { using SafeERC20Upgradeable for IERC20Upgradeable; // bytes32 public constant DISTRIBUTOR_ROLE = keccak256("DISTRIBUTOR_ROLE"); @@ -228,24 +226,7 @@ contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeab * */ function changeAddress(address newAddress) external override { - // require( - // balances[newAddress].allocatedTokens == 0 && - // balances[newAddress].claimed == 0, - // "TokenDistro::changeAddress: ADDRESS_ALREADY_IN_USE" - // ); - - require( - !hasRole(DISTRIBUTOR_ROLE, msg.sender) && !hasRole(DISTRIBUTOR_ROLE, newAddress), - 'TokenDistro::changeAddress: DISTRIBUTOR_ROLE_NOT_A_VALID_ADDRESS' - ); - // balance adds instead of overwrites - balances[newAddress].allocatedTokens += balances[msg.sender].allocatedTokens; - balances[msg.sender].allocatedTokens = 0; - - balances[newAddress].claimed += balances[msg.sender].claimed; - balances[msg.sender].claimed = 0; - - emit ChangeAddress(msg.sender, newAddress); + _transferAllocation(msg.sender, newAddress); } /** @@ -299,31 +280,10 @@ contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeab * */ function transferAllocation(address prevRecipient, address newRecipient) external override { - require( - balances[prevRecipient].allocatedTokens > 0, 'TokenDistro::transferAllocation: NO_ALLOCATION_TO_TRANSFER' - ); - require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), 'TokenDistro::transferAllocation: ONLY_ADMIN_ROLE'); - - // require( - // balances[newRecipient].allocatedTokens == 0 && - // balances[newRecipient].claimed == 0, - // "TokenDistro::cancelAllocation: ADDRESS_ALREADY_IN_USE" - // ); + require(cancelable, 'TokenDistro::transferAllocation: NOT_CANCELABLE'); - require( - !hasRole(DISTRIBUTOR_ROLE, prevRecipient) && !hasRole(DISTRIBUTOR_ROLE, newRecipient), - 'TokenDistro::transferAllocation: DISTRIBUTOR_ROLE_NOT_A_VALID_ADDRESS' - ); - // balance adds instead of overwrites - balances[newRecipient].allocatedTokens = - balances[prevRecipient].allocatedTokens.add(balances[newRecipient].allocatedTokens); - balances[prevRecipient].allocatedTokens = 0; - - balances[newRecipient].claimed = balances[prevRecipient].claimed.add(balances[newRecipient].claimed); - - balances[prevRecipient].claimed = 0; - - emit ChangeAddress(prevRecipient, newRecipient); + require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), 'TokenDistro::transferAllocation: ONLY_ADMIN_ROLE'); + _transferAllocation(prevRecipient, newRecipient); } /** @@ -356,4 +316,24 @@ contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeab emit DurationChanged(newDuration); } + + function _transferAllocation(address prevRecipient, address newRecipient) internal { + require( + balances[prevRecipient].allocatedTokens > 0, 'TokenDistro::transferAllocation: NO_ALLOCATION_TO_TRANSFER' + ); + require( + !hasRole(DISTRIBUTOR_ROLE, prevRecipient) && !hasRole(DISTRIBUTOR_ROLE, newRecipient), + 'TokenDistro::transferAllocation: DISTRIBUTOR_ROLE_NOT_A_VALID_ADDRESS' + ); + // balance adds instead of overwrites + balances[newRecipient].allocatedTokens = + balances[prevRecipient].allocatedTokens + balances[newRecipient].allocatedTokens; + balances[prevRecipient].allocatedTokens = 0; + + balances[newRecipient].claimed = balances[prevRecipient].claimed + balances[newRecipient].claimed; + + balances[prevRecipient].claimed = 0; + + emit ChangeAddress(prevRecipient, newRecipient); + } } diff --git a/test/ModifyTokenDistro.t.sol b/test/ModifyTokenDistro.t.sol index 335ed0c..3418f1a 100644 --- a/test/ModifyTokenDistro.t.sol +++ b/test/ModifyTokenDistro.t.sol @@ -27,8 +27,8 @@ contract TestModifyDistro is Test { // deploy the token distro TransparentUpgradeableProxy tokenDistroProxy; IDistro tokenDistroInterface; - TokenDistro tokenDistro; - TokenDistro tokenDistroImplementation; + TokenDistroV2 tokenDistro; + TokenDistroV2 tokenDistroImplementation; uint256 assignedAmount = 10000000000000000000000000; uint256 forkBlock = 22501098; @@ -36,7 +36,7 @@ contract TestModifyDistro is Test { uint256 forkId = vm.createFork('https://rpc.ankr.com/gnosis', forkBlock); //https://xdai-archive.blockscout.com/ vm.selectFork(forkId); proxyAdmin = ProxyAdmin(address(0x076C250700D210e6cf8A27D1EB1Fd754FB487986)); - tokenDistro = TokenDistro(address(0xc0dbDcA66a0636236fAbe1B3C16B1bD4C84bB1E1)); + tokenDistro = TokenDistroV2(address(0xc0dbDcA66a0636236fAbe1B3C16B1bD4C84bB1E1)); tokenDistroProxy = TransparentUpgradeableProxy(payable(address(0xc0dbDcA66a0636236fAbe1B3C16B1bD4C84bB1E1))); givethMultisig = 0x4D9339dd97db55e3B9bCBE65dE39fF9c04d1C2cd; givToken = IERC20Upgradeable(address(0x4f4F9b8D5B4d0Dc10506e5551B0513B61fD59e75)); @@ -48,8 +48,8 @@ contract TestModifyDistro is Test { function setUp() public { vm.startPrank(givethMultisig); - tokenDistroImplementation = new TokenDistro(); - // proxyAdmin.upgradeAndCall(tokenDistroProxy, address(tokenDistroImplementation), abi.encodeWithSelector(TokenDistro(tokenDistroImplementation).initialize.selector, 2000000000000000000000000000, 1640361600, 1640361600, 157680000, givToken, true)); + tokenDistroImplementation = new TokenDistroV2(); + // proxyAdmin.upgradeAndCall(tokenDistroProxy, address(tokenDistroImplementation), abi.encodeWithSelector(TokenDistroV2(tokenDistroImplementation).initialize.selector, 2000000000000000000000000000, 1640361600, 1640361600, 157680000, givToken, true)); proxyAdmin.upgrade(tokenDistroProxy, address(tokenDistroImplementation)); tokenDistro.grantRole(keccak256('DISTRIBUTOR_ROLE'), distributor); tokenDistro.assign(distributor, assignedAmount); @@ -305,7 +305,7 @@ contract TestModifyDistro is Test { // skip(14 days); // console.log('claimable for first recipient',tokenDistro.claimableNow(firstRecipient)); - // // vm.expectRevert("TokenDistro::claim: NOT_ENOUGH_TOKENS_TO_CLAIM"); + // // vm.expectRevert("TokenDistroV2::claim: NOT_ENOUGH_TOKENS_TO_CLAIM"); // // vm.prank(firstRecipient); // // tokenDistro.claim(); From b7f27a8cf10f138e26d83a3fd8e532878c75bf1e Mon Sep 17 00:00:00 2001 From: Mitch Oz Date: Thu, 15 Feb 2024 11:13:41 -0600 Subject: [PATCH 05/31] add more checks from review --- contracts/ModifiedTokenDistro.sol | 18 ++++++++----- test/ModifyTokenDistro.t.sol | 45 +------------------------------ 2 files changed, 13 insertions(+), 50 deletions(-) diff --git a/contracts/ModifiedTokenDistro.sol b/contracts/ModifiedTokenDistro.sol index cb60305..8367abc 100644 --- a/contracts/ModifiedTokenDistro.sol +++ b/contracts/ModifiedTokenDistro.sol @@ -130,6 +130,7 @@ contract TokenDistroV2 is Initializable, IDistro, AccessControlEnumerableUpgrade function assign(address distributor, uint256 amount) external override { require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), 'TokenDistro::assign: ONLY_ADMIN_ROLE'); require(hasRole(DISTRIBUTOR_ROLE, distributor), 'TokenDistro::assign: ONLY_TO_DISTRIBUTOR_ROLE'); + require(balances[address(this)].allocatedTokens > amount, 'TokenDistro::assign: NOT_ENOUGH_TOKENS'); balances[address(this)].allocatedTokens = balances[address(this)].allocatedTokens - amount; balances[distributor].allocatedTokens = balances[distributor].allocatedTokens + amount; @@ -171,7 +172,7 @@ contract TokenDistroV2 is Initializable, IDistro, AccessControlEnumerableUpgrade */ function _allocate(address recipient, uint256 amount, bool claim) internal { require(!hasRole(DISTRIBUTOR_ROLE, recipient), 'TokenDistro::allocate: DISTRIBUTOR_NOT_VALID_RECIPIENT'); - + require(balances[msg.sender].allocatedTokens > amount, 'TokenDistro::allocate NOT_ENOUGH_TOKENS'); balances[msg.sender].allocatedTokens = balances[msg.sender].allocatedTokens - amount; balances[recipient].allocatedTokens = balances[recipient].allocatedTokens + amount; @@ -196,9 +197,10 @@ contract TokenDistroV2 is Initializable, IDistro, AccessControlEnumerableUpgrade * Unlike allocate method it doesn't claim recipients available balance */ function _allocateMany(address[] memory recipients, uint256[] memory amounts) internal onlyDistributor { - require(recipients.length == amounts.length, 'TokenDistro::allocateMany: INPUT_LENGTH_NOT_MATCH'); + uint256 length = recipients.length; + require(length == amounts.length, 'TokenDistro::allocateMany: INPUT_LENGTH_NOT_MATCH'); - for (uint256 i = 0; i < recipients.length; i++) { + for (uint256 i = 0; i < length; i++) { _allocate(recipients[i], amounts[i], false); } } @@ -242,6 +244,7 @@ contract TokenDistroV2 is Initializable, IDistro, AccessControlEnumerableUpgrade * @return Number of tokens claimable at that timestamp */ function globallyClaimableAt(uint256 timestamp) public view override returns (uint256) { + require(duration > 0, 'TokenDistro::globallyClaimableAt: DURATION_ZERO'); if (timestamp < startTime) return 0; if (timestamp < cliffTime) return initialAmount; if (timestamp > startTime + duration) return totalTokens; @@ -258,9 +261,10 @@ contract TokenDistroV2 is Initializable, IDistro, AccessControlEnumerableUpgrade function claimableAt(address recipient, uint256 timestamp) public view override returns (uint256) { require(!hasRole(DISTRIBUTOR_ROLE, recipient), 'TokenDistro::claimableAt: DISTRIBUTOR_ROLE_CANNOT_CLAIM'); require(timestamp >= getTimestamp(), 'TokenDistro::claimableAt: NOT_VALID_PAST_TIMESTAMP'); + require(totalTokens > 0, 'TokenDistro::claimableAt: TOTAL_TOKENS_ZERO'); uint256 unlockedAmount = (globallyClaimableAt(timestamp) * balances[recipient].allocatedTokens) / totalTokens; - - return unlockedAmount - balances[recipient].claimed; + if (unlockedAmount > balances[recipient].claimed) return unlockedAmount - balances[recipient].claimed; + return 0; } /** @@ -319,7 +323,9 @@ contract TokenDistroV2 is Initializable, IDistro, AccessControlEnumerableUpgrade function _transferAllocation(address prevRecipient, address newRecipient) internal { require( - balances[prevRecipient].allocatedTokens > 0, 'TokenDistro::transferAllocation: NO_ALLOCATION_TO_TRANSFER' + balances[prevRecipient].allocatedTokens > 0 + && balances[prevRecipient].allocatedTokens != balances[prevRecipient].claimed, + 'TokenDistro::transferAllocation: NO_ALLOCATION_TO_TRANSFER' ); require( !hasRole(DISTRIBUTOR_ROLE, prevRecipient) && !hasRole(DISTRIBUTOR_ROLE, newRecipient), diff --git a/test/ModifyTokenDistro.t.sol b/test/ModifyTokenDistro.t.sol index 3418f1a..d830df9 100644 --- a/test/ModifyTokenDistro.t.sol +++ b/test/ModifyTokenDistro.t.sol @@ -228,7 +228,7 @@ contract TestModifyDistro is Test { function testChangeAddressWithClaim(uint256 amount1, uint256 amount2) public { /// @aminlatifi for some reason this does not want to work with the min bound as 1 - throws no tokens to claim error - amount1 = bound(amount1, 10, assignedAmount.div(2)); + amount1 = bound(amount1, 10, (assignedAmount-1).div(2)); amount2 = bound(amount2, 10, assignedAmount.div(2)); address[] memory recipients = new address[](2); @@ -268,47 +268,4 @@ contract TestModifyDistro is Test { assertEq(firstAllocatedAfterTransfer, 0); assertEq(firstClaimedAfterTransfer, 0); } - - // function testCancelAllocation() public { - // uint256 amount = 100000000000; - // vm.prank(distributor); - // tokenDistro.allocate(firstRecipient, amount, false); - // (uint256 allocatedTokens,uint256 claimedTokens) = tokenDistro.balances(firstRecipient); - // assertEq(allocatedTokens, amount); - // assertEq(claimedTokens, 0); - // vm.prank(givethMultisig); - // tokenDistro.cancelAllocation(firstRecipient); - // (uint256 allocatedTokensAfterCancel, uint256 claimedTokensAfterCancel) = tokenDistro.balances(firstRecipient); - // assertEq(allocatedTokensAfterCancel, 0); - // assertEq(claimedTokensAfterCancel, 0); - // } - - // function testCancelAllocationWithClaim() public { - // uint256 amount = 100000000000; - // vm.prank(distributor); - // tokenDistro.allocate(firstRecipient, amount, true); - - // skip(14 days); - // vm.prank(firstRecipient); - // tokenDistro.claim(); - // (,uint256 claimedTokensAfterClaim) = tokenDistro.balances(firstRecipient); - // vm.prank(givethMultisig); - // tokenDistro.cancelAllocation(firstRecipient); - // (uint256 allocatedTokensAfterCancel, uint256 claimedTokensAfterCancel) = tokenDistro.balances(firstRecipient); - // assertEq(allocatedTokensAfterCancel, claimedTokensAfterClaim); - // assertEq(claimedTokensAfterCancel, claimedTokensAfterClaim); - // } - - // function testCancelAllocationRevert() public { - // testCancelAllocationWithClaim(); - - // skip(14 days); - - // console.log('claimable for first recipient',tokenDistro.claimableNow(firstRecipient)); - // // vm.expectRevert("TokenDistroV2::claim: NOT_ENOUGH_TOKENS_TO_CLAIM"); - - // // vm.prank(firstRecipient); - // // tokenDistro.claim(); - - // } } From 4162390048a8b0af97112036fcca6a2ea4cb982f Mon Sep 17 00:00:00 2001 From: Mitch Oz Date: Thu, 15 Feb 2024 11:15:50 -0600 Subject: [PATCH 06/31] forge fmt --- test/ModifyTokenDistro.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ModifyTokenDistro.t.sol b/test/ModifyTokenDistro.t.sol index d830df9..94ca069 100644 --- a/test/ModifyTokenDistro.t.sol +++ b/test/ModifyTokenDistro.t.sol @@ -228,7 +228,7 @@ contract TestModifyDistro is Test { function testChangeAddressWithClaim(uint256 amount1, uint256 amount2) public { /// @aminlatifi for some reason this does not want to work with the min bound as 1 - throws no tokens to claim error - amount1 = bound(amount1, 10, (assignedAmount-1).div(2)); + amount1 = bound(amount1, 10, (assignedAmount - 1).div(2)); amount2 = bound(amount2, 10, assignedAmount.div(2)); address[] memory recipients = new address[](2); From 321d2c684af9785c50a1de7ed30cedbda71a662a Mon Sep 17 00:00:00 2001 From: Mitch Oz Date: Fri, 16 Feb 2024 09:10:44 -0600 Subject: [PATCH 07/31] add comment to tranferAllocation --- contracts/ModifiedTokenDistro.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/ModifiedTokenDistro.sol b/contracts/ModifiedTokenDistro.sol index 8367abc..4ce0444 100644 --- a/contracts/ModifiedTokenDistro.sol +++ b/contracts/ModifiedTokenDistro.sol @@ -282,6 +282,7 @@ contract TokenDistroV2 is Initializable, IDistro, AccessControlEnumerableUpgrade * * Emits a {ChangeAddress} event. * + * Formerly called cancelAllocation, this is an admin only function and should only be called manually */ function transferAllocation(address prevRecipient, address newRecipient) external override { require(cancelable, 'TokenDistro::transferAllocation: NOT_CANCELABLE'); From a98fd5a17bdb969b979c2c4e02241c6fd199bab8 Mon Sep 17 00:00:00 2001 From: Mitch Oz Date: Fri, 16 Feb 2024 09:29:21 -0600 Subject: [PATCH 08/31] test fix --- test/ModifyTokenDistro.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ModifyTokenDistro.t.sol b/test/ModifyTokenDistro.t.sol index 94ca069..f492cb7 100644 --- a/test/ModifyTokenDistro.t.sol +++ b/test/ModifyTokenDistro.t.sol @@ -126,7 +126,7 @@ contract TestModifyDistro is Test { } function testTransferAllocationWithClaim(uint256 amount1, uint256 amount2) public { - amount1 = bound(amount1, 10, assignedAmount.div(2)); + amount1 = bound(amount1, 10, (assignedAmount - 1).div(2)); amount2 = bound(amount2, 10, assignedAmount.div(2)); address[] memory recipients = new address[](2); From 9ce32b6bca44cd30c5937c9fa94d86ec4719ed70 Mon Sep 17 00:00:00 2001 From: Mitch Oz Date: Fri, 16 Feb 2024 11:12:11 -0600 Subject: [PATCH 09/31] explcitly set node-version --- .github/workflows/slither.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/slither.yml b/.github/workflows/slither.yml index 7a8dab9..b00705b 100644 --- a/.github/workflows/slither.yml +++ b/.github/workflows/slither.yml @@ -13,6 +13,9 @@ jobs: name: Slither check runs-on: ubuntu-latest steps: + - uses: actions/setup-node@v4 + with: node-version: '18' + - uses: actions/checkout@v3 with: submodules: recursive @@ -34,6 +37,7 @@ jobs: with: sarif: results.sarif target: 'contracts/' + node-version: '18' - name: Upload SARIF file uses: github/codeql-action/upload-sarif@v2 From 61908deb89bdd78a834f082ea0f93ad35a20692c Mon Sep 17 00:00:00 2001 From: Mitch Oz Date: Fri, 16 Feb 2024 11:14:41 -0600 Subject: [PATCH 10/31] syntax --- .github/workflows/slither.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/slither.yml b/.github/workflows/slither.yml index b00705b..2b64f74 100644 --- a/.github/workflows/slither.yml +++ b/.github/workflows/slither.yml @@ -14,7 +14,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/setup-node@v4 - with: node-version: '18' + with: + node-version: '18' - uses: actions/checkout@v3 with: From 51d419523a2efb5a09570313d30978288be461f4 Mon Sep 17 00:00:00 2001 From: Mitch Oz Date: Fri, 16 Feb 2024 11:34:48 -0600 Subject: [PATCH 11/31] specify node 20 --- .github/workflows/slither.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/slither.yml b/.github/workflows/slither.yml index 2b64f74..ba6aeec 100644 --- a/.github/workflows/slither.yml +++ b/.github/workflows/slither.yml @@ -15,7 +15,7 @@ jobs: steps: - uses: actions/setup-node@v4 with: - node-version: '18' + node-version: '20' - uses: actions/checkout@v3 with: @@ -24,7 +24,7 @@ jobs: - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 with: - version: nightly + version: 2.0.0 - name: Install deps run: | @@ -38,9 +38,9 @@ jobs: with: sarif: results.sarif target: 'contracts/' - node-version: '18' + node-version: '20' - name: Upload SARIF file - uses: github/codeql-action/upload-sarif@v2 + uses: github/codeql-action/upload-sarif@v3 with: sarif_file: ${{ steps.slither.outputs.sarif }} From 3e4dafc3d7208fb660e57e1e7bd2c0d00d543bdb Mon Sep 17 00:00:00 2001 From: Mitch <67759413+divine-comedian@users.noreply.github.com> Date: Fri, 16 Feb 2024 11:40:13 -0600 Subject: [PATCH 12/31] Update slither.yml --- .github/workflows/slither.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/slither.yml b/.github/workflows/slither.yml index ba6aeec..5483e1a 100644 --- a/.github/workflows/slither.yml +++ b/.github/workflows/slither.yml @@ -24,7 +24,7 @@ jobs: - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 with: - version: 2.0.0 + version: 0.2.0 - name: Install deps run: | From 8b0058aaecd219f9aaf66f66ff63bde5f70656c8 Mon Sep 17 00:00:00 2001 From: Mitch <67759413+divine-comedian@users.noreply.github.com> Date: Fri, 16 Feb 2024 11:48:33 -0600 Subject: [PATCH 13/31] Update slither.yml --- .github/workflows/slither.yml | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/.github/workflows/slither.yml b/.github/workflows/slither.yml index 5483e1a..afdb75f 100644 --- a/.github/workflows/slither.yml +++ b/.github/workflows/slither.yml @@ -13,32 +13,19 @@ jobs: name: Slither check runs-on: ubuntu-latest steps: - - uses: actions/setup-node@v4 - with: - node-version: '20' - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive - - name: Install Foundry - uses: foundry-rs/foundry-toolchain@v1 - with: - version: 0.2.0 - - - name: Install deps - run: | - forge --version - forge install - - name: Run Slither - uses: crytic/slither-action@main + uses: crytic/slither-action@v0.3.1 id: slither - continue-on-error: true with: sarif: results.sarif target: 'contracts/' node-version: '20' + fail-on: none - name: Upload SARIF file uses: github/codeql-action/upload-sarif@v3 From 7933fdc28c619036f8d75a8e8343c175f5a55df7 Mon Sep 17 00:00:00 2001 From: Mitch <67759413+divine-comedian@users.noreply.github.com> Date: Fri, 16 Feb 2024 11:57:22 -0600 Subject: [PATCH 14/31] Update slither.yml --- .github/workflows/slither.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/slither.yml b/.github/workflows/slither.yml index afdb75f..4d81f8a 100644 --- a/.github/workflows/slither.yml +++ b/.github/workflows/slither.yml @@ -17,7 +17,7 @@ jobs: - uses: actions/checkout@v4 with: submodules: recursive - + - run: pwd - name: Run Slither uses: crytic/slither-action@v0.3.1 id: slither From abcd65974a9f130a1bdfd1598b9c8c5c8fa43b5d Mon Sep 17 00:00:00 2001 From: Mitch <67759413+divine-comedian@users.noreply.github.com> Date: Fri, 16 Feb 2024 12:01:12 -0600 Subject: [PATCH 15/31] Update slither.yml --- .github/workflows/slither.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/slither.yml b/.github/workflows/slither.yml index 4d81f8a..a906ebd 100644 --- a/.github/workflows/slither.yml +++ b/.github/workflows/slither.yml @@ -17,7 +17,8 @@ jobs: - uses: actions/checkout@v4 with: submodules: recursive - - run: pwd + - run: ls --all + - run: ls ../ --all - name: Run Slither uses: crytic/slither-action@v0.3.1 id: slither From 1c30d0032a1bd9864c93db764f7ed16b9e2d3dec Mon Sep 17 00:00:00 2001 From: Mitch <67759413+divine-comedian@users.noreply.github.com> Date: Fri, 16 Feb 2024 12:08:20 -0600 Subject: [PATCH 16/31] Update slither.yml --- .github/workflows/slither.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/slither.yml b/.github/workflows/slither.yml index a906ebd..73692c0 100644 --- a/.github/workflows/slither.yml +++ b/.github/workflows/slither.yml @@ -17,15 +17,13 @@ jobs: - uses: actions/checkout@v4 with: submodules: recursive - - run: ls --all - - run: ls ../ --all + - name: Run Slither - uses: crytic/slither-action@v0.3.1 + uses: crytic/slither-action@v0.3.0 id: slither with: sarif: results.sarif target: 'contracts/' - node-version: '20' fail-on: none - name: Upload SARIF file From 4ada5ab6b3ce60aefb294e506874157ab3924d9e Mon Sep 17 00:00:00 2001 From: Mitch Oz Date: Mon, 19 Feb 2024 13:08:09 -0600 Subject: [PATCH 17/31] add sendPraise to interface, forge fmt, remove some checks --- contracts/ModifiedTokenDistro.sol | 7 ++----- contracts/TokenDistro.sol | 7 +++++++ contracts/interfaces/IDistroModified.sol | 2 ++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/contracts/ModifiedTokenDistro.sol b/contracts/ModifiedTokenDistro.sol index 4ce0444..0bbef6c 100644 --- a/contracts/ModifiedTokenDistro.sol +++ b/contracts/ModifiedTokenDistro.sol @@ -12,7 +12,7 @@ import './interfaces/IDistroModified.sol'; * The distributor is in charge of releasing the corresponding amounts to its recipients. * This distributor is expected to be another smart contract, such as a merkledrop or the liquidity mining smart contract */ -contract TokenDistroV2 is Initializable, IDistro, AccessControlEnumerableUpgradeable { +contract TokenDistroV1 is Initializable, IDistro, AccessControlEnumerableUpgradeable { using SafeERC20Upgradeable for IERC20Upgradeable; // bytes32 public constant DISTRIBUTOR_ROLE = keccak256("DISTRIBUTOR_ROLE"); @@ -261,7 +261,6 @@ contract TokenDistroV2 is Initializable, IDistro, AccessControlEnumerableUpgrade function claimableAt(address recipient, uint256 timestamp) public view override returns (uint256) { require(!hasRole(DISTRIBUTOR_ROLE, recipient), 'TokenDistro::claimableAt: DISTRIBUTOR_ROLE_CANNOT_CLAIM'); require(timestamp >= getTimestamp(), 'TokenDistro::claimableAt: NOT_VALID_PAST_TIMESTAMP'); - require(totalTokens > 0, 'TokenDistro::claimableAt: TOTAL_TOKENS_ZERO'); uint256 unlockedAmount = (globallyClaimableAt(timestamp) * balances[recipient].allocatedTokens) / totalTokens; if (unlockedAmount > balances[recipient].claimed) return unlockedAmount - balances[recipient].claimed; return 0; @@ -324,9 +323,7 @@ contract TokenDistroV2 is Initializable, IDistro, AccessControlEnumerableUpgrade function _transferAllocation(address prevRecipient, address newRecipient) internal { require( - balances[prevRecipient].allocatedTokens > 0 - && balances[prevRecipient].allocatedTokens != balances[prevRecipient].claimed, - 'TokenDistro::transferAllocation: NO_ALLOCATION_TO_TRANSFER' + balances[prevRecipient].allocatedTokens > 0, 'TokenDistro::transferAllocation: NO_ALLOCATION_TO_TRANSFER' ); require( !hasRole(DISTRIBUTOR_ROLE, prevRecipient) && !hasRole(DISTRIBUTOR_ROLE, newRecipient), diff --git a/contracts/TokenDistro.sol b/contracts/TokenDistro.sol index 226ac91..3a081a5 100644 --- a/contracts/TokenDistro.sol +++ b/contracts/TokenDistro.sol @@ -339,4 +339,11 @@ contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeab emit DurationChanged(newDuration); } + + event PraiseRewardPaid(address distributor); + + function sendPraiseRewards(address[] memory recipients, uint256[] memory amounts) external { + _allocateMany(recipients, amounts); + emit PraiseRewardPaid(msg.sender); + } } diff --git a/contracts/interfaces/IDistroModified.sol b/contracts/interfaces/IDistroModified.sol index 1709e57..bcac027 100644 --- a/contracts/interfaces/IDistroModified.sol +++ b/contracts/interfaces/IDistroModified.sol @@ -99,4 +99,6 @@ interface IDistro { function claimableNow(address recipient) external view returns (uint256); function transferAllocation(address prevRecipient, address newRecipient) external; + + function sendPraiseRewards(address[] memory recipients, uint256[] memory amounts) external; } From ef0e40c0ffa1667d5b1aa3cef43e88b530073d40 Mon Sep 17 00:00:00 2001 From: Mitch Oz Date: Mon, 19 Feb 2024 13:15:53 -0600 Subject: [PATCH 18/31] add sendPraise to interface, forge fmt, remove some checks --- contracts/ModifiedTokenDistro.sol | 7 ++----- contracts/interfaces/IDistroModified.sol | 2 ++ test/ModifyTokenDistro.t.sol | 9 ++++----- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/contracts/ModifiedTokenDistro.sol b/contracts/ModifiedTokenDistro.sol index 4ce0444..0bbef6c 100644 --- a/contracts/ModifiedTokenDistro.sol +++ b/contracts/ModifiedTokenDistro.sol @@ -12,7 +12,7 @@ import './interfaces/IDistroModified.sol'; * The distributor is in charge of releasing the corresponding amounts to its recipients. * This distributor is expected to be another smart contract, such as a merkledrop or the liquidity mining smart contract */ -contract TokenDistroV2 is Initializable, IDistro, AccessControlEnumerableUpgradeable { +contract TokenDistroV1 is Initializable, IDistro, AccessControlEnumerableUpgradeable { using SafeERC20Upgradeable for IERC20Upgradeable; // bytes32 public constant DISTRIBUTOR_ROLE = keccak256("DISTRIBUTOR_ROLE"); @@ -261,7 +261,6 @@ contract TokenDistroV2 is Initializable, IDistro, AccessControlEnumerableUpgrade function claimableAt(address recipient, uint256 timestamp) public view override returns (uint256) { require(!hasRole(DISTRIBUTOR_ROLE, recipient), 'TokenDistro::claimableAt: DISTRIBUTOR_ROLE_CANNOT_CLAIM'); require(timestamp >= getTimestamp(), 'TokenDistro::claimableAt: NOT_VALID_PAST_TIMESTAMP'); - require(totalTokens > 0, 'TokenDistro::claimableAt: TOTAL_TOKENS_ZERO'); uint256 unlockedAmount = (globallyClaimableAt(timestamp) * balances[recipient].allocatedTokens) / totalTokens; if (unlockedAmount > balances[recipient].claimed) return unlockedAmount - balances[recipient].claimed; return 0; @@ -324,9 +323,7 @@ contract TokenDistroV2 is Initializable, IDistro, AccessControlEnumerableUpgrade function _transferAllocation(address prevRecipient, address newRecipient) internal { require( - balances[prevRecipient].allocatedTokens > 0 - && balances[prevRecipient].allocatedTokens != balances[prevRecipient].claimed, - 'TokenDistro::transferAllocation: NO_ALLOCATION_TO_TRANSFER' + balances[prevRecipient].allocatedTokens > 0, 'TokenDistro::transferAllocation: NO_ALLOCATION_TO_TRANSFER' ); require( !hasRole(DISTRIBUTOR_ROLE, prevRecipient) && !hasRole(DISTRIBUTOR_ROLE, newRecipient), diff --git a/contracts/interfaces/IDistroModified.sol b/contracts/interfaces/IDistroModified.sol index 1709e57..bcac027 100644 --- a/contracts/interfaces/IDistroModified.sol +++ b/contracts/interfaces/IDistroModified.sol @@ -99,4 +99,6 @@ interface IDistro { function claimableNow(address recipient) external view returns (uint256); function transferAllocation(address prevRecipient, address newRecipient) external; + + function sendPraiseRewards(address[] memory recipients, uint256[] memory amounts) external; } diff --git a/test/ModifyTokenDistro.t.sol b/test/ModifyTokenDistro.t.sol index f492cb7..e6e5531 100644 --- a/test/ModifyTokenDistro.t.sol +++ b/test/ModifyTokenDistro.t.sol @@ -27,8 +27,8 @@ contract TestModifyDistro is Test { // deploy the token distro TransparentUpgradeableProxy tokenDistroProxy; IDistro tokenDistroInterface; - TokenDistroV2 tokenDistro; - TokenDistroV2 tokenDistroImplementation; + TokenDistroV1 tokenDistro; + TokenDistroV1 tokenDistroImplementation; uint256 assignedAmount = 10000000000000000000000000; uint256 forkBlock = 22501098; @@ -36,7 +36,7 @@ contract TestModifyDistro is Test { uint256 forkId = vm.createFork('https://rpc.ankr.com/gnosis', forkBlock); //https://xdai-archive.blockscout.com/ vm.selectFork(forkId); proxyAdmin = ProxyAdmin(address(0x076C250700D210e6cf8A27D1EB1Fd754FB487986)); - tokenDistro = TokenDistroV2(address(0xc0dbDcA66a0636236fAbe1B3C16B1bD4C84bB1E1)); + tokenDistro = TokenDistroV1(address(0xc0dbDcA66a0636236fAbe1B3C16B1bD4C84bB1E1)); tokenDistroProxy = TransparentUpgradeableProxy(payable(address(0xc0dbDcA66a0636236fAbe1B3C16B1bD4C84bB1E1))); givethMultisig = 0x4D9339dd97db55e3B9bCBE65dE39fF9c04d1C2cd; givToken = IERC20Upgradeable(address(0x4f4F9b8D5B4d0Dc10506e5551B0513B61fD59e75)); @@ -48,8 +48,7 @@ contract TestModifyDistro is Test { function setUp() public { vm.startPrank(givethMultisig); - tokenDistroImplementation = new TokenDistroV2(); - // proxyAdmin.upgradeAndCall(tokenDistroProxy, address(tokenDistroImplementation), abi.encodeWithSelector(TokenDistroV2(tokenDistroImplementation).initialize.selector, 2000000000000000000000000000, 1640361600, 1640361600, 157680000, givToken, true)); + tokenDistroImplementation = new TokenDistroV1(); proxyAdmin.upgrade(tokenDistroProxy, address(tokenDistroImplementation)); tokenDistro.grantRole(keccak256('DISTRIBUTOR_ROLE'), distributor); tokenDistro.assign(distributor, assignedAmount); From 5c99dd7745954ac9cfd47a4f4b2e5d82172e47fd Mon Sep 17 00:00:00 2001 From: Mitch Oz Date: Mon, 19 Feb 2024 13:25:43 -0600 Subject: [PATCH 19/31] revert tokendistro changes --- contracts/TokenDistro.sol | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/contracts/TokenDistro.sol b/contracts/TokenDistro.sol index 3a081a5..47f0f1b 100644 --- a/contracts/TokenDistro.sol +++ b/contracts/TokenDistro.sol @@ -339,11 +339,4 @@ contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeab emit DurationChanged(newDuration); } - - event PraiseRewardPaid(address distributor); - - function sendPraiseRewards(address[] memory recipients, uint256[] memory amounts) external { - _allocateMany(recipients, amounts); - emit PraiseRewardPaid(msg.sender); - } -} +} \ No newline at end of file From 5e9c632bc162c1a6ed53a7894423b69042aea705 Mon Sep 17 00:00:00 2001 From: Mitch Oz Date: Mon, 19 Feb 2024 16:48:44 -0600 Subject: [PATCH 20/31] remove checks from Griff's feedback --- contracts/ModifiedTokenDistro.sol | 7 ++----- contracts/TokenDistro.sol | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/contracts/ModifiedTokenDistro.sol b/contracts/ModifiedTokenDistro.sol index 0bbef6c..790cc0d 100644 --- a/contracts/ModifiedTokenDistro.sol +++ b/contracts/ModifiedTokenDistro.sol @@ -130,7 +130,6 @@ contract TokenDistroV1 is Initializable, IDistro, AccessControlEnumerableUpgrade function assign(address distributor, uint256 amount) external override { require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), 'TokenDistro::assign: ONLY_ADMIN_ROLE'); require(hasRole(DISTRIBUTOR_ROLE, distributor), 'TokenDistro::assign: ONLY_TO_DISTRIBUTOR_ROLE'); - require(balances[address(this)].allocatedTokens > amount, 'TokenDistro::assign: NOT_ENOUGH_TOKENS'); balances[address(this)].allocatedTokens = balances[address(this)].allocatedTokens - amount; balances[distributor].allocatedTokens = balances[distributor].allocatedTokens + amount; @@ -172,7 +171,6 @@ contract TokenDistroV1 is Initializable, IDistro, AccessControlEnumerableUpgrade */ function _allocate(address recipient, uint256 amount, bool claim) internal { require(!hasRole(DISTRIBUTOR_ROLE, recipient), 'TokenDistro::allocate: DISTRIBUTOR_NOT_VALID_RECIPIENT'); - require(balances[msg.sender].allocatedTokens > amount, 'TokenDistro::allocate NOT_ENOUGH_TOKENS'); balances[msg.sender].allocatedTokens = balances[msg.sender].allocatedTokens - amount; balances[recipient].allocatedTokens = balances[recipient].allocatedTokens + amount; @@ -244,7 +242,6 @@ contract TokenDistroV1 is Initializable, IDistro, AccessControlEnumerableUpgrade * @return Number of tokens claimable at that timestamp */ function globallyClaimableAt(uint256 timestamp) public view override returns (uint256) { - require(duration > 0, 'TokenDistro::globallyClaimableAt: DURATION_ZERO'); if (timestamp < startTime) return 0; if (timestamp < cliffTime) return initialAmount; if (timestamp > startTime + duration) return totalTokens; @@ -262,8 +259,8 @@ contract TokenDistroV1 is Initializable, IDistro, AccessControlEnumerableUpgrade require(!hasRole(DISTRIBUTOR_ROLE, recipient), 'TokenDistro::claimableAt: DISTRIBUTOR_ROLE_CANNOT_CLAIM'); require(timestamp >= getTimestamp(), 'TokenDistro::claimableAt: NOT_VALID_PAST_TIMESTAMP'); uint256 unlockedAmount = (globallyClaimableAt(timestamp) * balances[recipient].allocatedTokens) / totalTokens; - if (unlockedAmount > balances[recipient].claimed) return unlockedAmount - balances[recipient].claimed; - return 0; + + return unlockedAmount - balances[recipient].claimed; } /** diff --git a/contracts/TokenDistro.sol b/contracts/TokenDistro.sol index 47f0f1b..226ac91 100644 --- a/contracts/TokenDistro.sol +++ b/contracts/TokenDistro.sol @@ -339,4 +339,4 @@ contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeab emit DurationChanged(newDuration); } -} \ No newline at end of file +} From 9b41730543203df4fea889b3618506371f708a9d Mon Sep 17 00:00:00 2001 From: Mitch Oz Date: Tue, 20 Feb 2024 08:02:30 -0600 Subject: [PATCH 21/31] add latest version of token distro --- contracts/TokenDistro.sol | 215 +++++++++++++++++++++++++++++--------- 1 file changed, 165 insertions(+), 50 deletions(-) diff --git a/contracts/TokenDistro.sol b/contracts/TokenDistro.sol index 226ac91..513a6aa 100644 --- a/contracts/TokenDistro.sol +++ b/contracts/TokenDistro.sol @@ -1,22 +1,27 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.6; +pragma solidity =0.8.6; -import '@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol'; -import '@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol'; -import '@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol'; -import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import './interfaces/IDistro.sol'; +import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import "./interfaces/IDistro.sol"; /** * Contract responsible for managing the release of tokens over time. * The distributor is in charge of releasing the corresponding amounts to its recipients. * This distributor is expected to be another smart contract, such as a merkledrop or the liquidity mining smart contract */ -contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeable { +contract TokenDistro is + Initializable, + IDistro, + AccessControlEnumerableUpgradeable +{ using SafeERC20Upgradeable for IERC20Upgradeable; // bytes32 public constant DISTRIBUTOR_ROLE = keccak256("DISTRIBUTOR_ROLE"); - bytes32 public constant DISTRIBUTOR_ROLE = 0xfbd454f36a7e1a388bd6fc3ab10d434aa4578f811acbbcf33afb1c697486313c; + bytes32 public constant DISTRIBUTOR_ROLE = + 0xfbd454f36a7e1a388bd6fc3ab10d434aa4578f811acbbcf33afb1c697486313c; // Structure to of the accounting for each account struct accountStatus { @@ -41,15 +46,26 @@ contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeab */ event GivBackPaid(address distributor); + /** + * @dev Emitted when the DISTRIBUTOR allocate an amount of praise rewards to a recipient + */ + event PraiseRewardPaid(address distributor); + /** * @dev Emitted when the duration is changed */ event DurationChanged(uint256 newDuration); modifier onlyDistributor() { - require(hasRole(DISTRIBUTOR_ROLE, msg.sender), 'TokenDistro::onlyDistributor: ONLY_DISTRIBUTOR_ROLE'); + require( + hasRole(DISTRIBUTOR_ROLE, msg.sender), + "TokenDistro::onlyDistributor: ONLY_DISTRIBUTOR_ROLE" + ); - require(balances[msg.sender].claimed == 0, 'TokenDistro::onlyDistributor: DISTRIBUTOR_CANNOT_CLAIM'); + require( + balances[msg.sender].claimed == 0, + "TokenDistro::onlyDistributor: DISTRIBUTOR_CANNOT_CLAIM" + ); _; } @@ -74,8 +90,14 @@ contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeab IERC20Upgradeable _token, bool _cancelable ) public initializer { - require(_duration >= _cliffPeriod, 'TokenDistro::constructor: DURATION_LESS_THAN_CLIFF'); - require(_initialPercentage <= 10000, 'TokenDistro::constructor: INITIALPERCENTAGE_GREATER_THAN_100'); + require( + _duration >= _cliffPeriod, + "TokenDistro::constructor: DURATION_LESS_THAN_CLIFF" + ); + require( + _initialPercentage <= 10000, + "TokenDistro::constructor: INITIALPERCENTAGE_GREATER_THAN_100" + ); __AccessControlEnumerable_init(); _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); @@ -100,10 +122,13 @@ contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeab * */ function setStartTime(uint256 newStartTime) external override { - require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), 'TokenDistro::setStartTime: ONLY_ADMIN_ROLE'); + require( + hasRole(DEFAULT_ADMIN_ROLE, msg.sender), + "TokenDistro::setStartTime: ONLY_ADMIN_ROLE" + ); require( startTime > getTimestamp() && newStartTime > getTimestamp(), - 'TokenDistro::setStartTime: IF_HAS_NOT_STARTED_YET' + "TokenDistro::setStartTime: IF_HAS_NOT_STARTED_YET" ); uint256 _cliffPeriod = cliffTime - startTime; @@ -123,11 +148,21 @@ contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeab * */ function assign(address distributor, uint256 amount) external override { - require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), 'TokenDistro::assign: ONLY_ADMIN_ROLE'); - require(hasRole(DISTRIBUTOR_ROLE, distributor), 'TokenDistro::assign: ONLY_TO_DISTRIBUTOR_ROLE'); + require( + hasRole(DEFAULT_ADMIN_ROLE, msg.sender), + "TokenDistro::assign: ONLY_ADMIN_ROLE" + ); + require( + hasRole(DISTRIBUTOR_ROLE, distributor), + "TokenDistro::assign: ONLY_TO_DISTRIBUTOR_ROLE" + ); - balances[address(this)].allocatedTokens = balances[address(this)].allocatedTokens - amount; - balances[distributor].allocatedTokens = balances[distributor].allocatedTokens + amount; + balances[address(this)].allocatedTokens = + balances[address(this)].allocatedTokens - + amount; + balances[distributor].allocatedTokens = + balances[distributor].allocatedTokens + + amount; emit Assign(msg.sender, distributor, amount); } @@ -164,12 +199,23 @@ contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeab * Emits a {Allocate} event. * */ - function _allocate(address recipient, uint256 amount, bool claim) internal { - require(!hasRole(DISTRIBUTOR_ROLE, recipient), 'TokenDistro::allocate: DISTRIBUTOR_NOT_VALID_RECIPIENT'); + function _allocate( + address recipient, + uint256 amount, + bool claim + ) internal { + require( + !hasRole(DISTRIBUTOR_ROLE, recipient), + "TokenDistro::allocate: DISTRIBUTOR_NOT_VALID_RECIPIENT" + ); - balances[msg.sender].allocatedTokens = balances[msg.sender].allocatedTokens - amount; + balances[msg.sender].allocatedTokens = + balances[msg.sender].allocatedTokens - + amount; - balances[recipient].allocatedTokens = balances[recipient].allocatedTokens + amount; + balances[recipient].allocatedTokens = + balances[recipient].allocatedTokens + + amount; if (claim && claimableNow(recipient) > 0) { _claim(recipient); @@ -178,7 +224,11 @@ contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeab emit Allocate(msg.sender, recipient, amount); } - function allocate(address recipient, uint256 amount, bool claim) external override onlyDistributor { + function allocate( + address recipient, + uint256 amount, + bool claim + ) external override onlyDistributor { _allocate(recipient, amount, claim); } @@ -190,23 +240,43 @@ contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeab * * Unlike allocate method it doesn't claim recipients available balance */ - function _allocateMany(address[] memory recipients, uint256[] memory amounts) internal onlyDistributor { - require(recipients.length == amounts.length, 'TokenDistro::allocateMany: INPUT_LENGTH_NOT_MATCH'); + function _allocateMany( + address[] memory recipients, + uint256[] memory amounts + ) internal onlyDistributor { + require( + recipients.length == amounts.length, + "TokenDistro::allocateMany: INPUT_LENGTH_NOT_MATCH" + ); for (uint256 i = 0; i < recipients.length; i++) { _allocate(recipients[i], amounts[i], false); } } - function allocateMany(address[] memory recipients, uint256[] memory amounts) external override { + function allocateMany(address[] memory recipients, uint256[] memory amounts) + external + override + { _allocateMany(recipients, amounts); } - function sendGIVbacks(address[] memory recipients, uint256[] memory amounts) external override { + function sendGIVbacks(address[] memory recipients, uint256[] memory amounts) + external + override + { _allocateMany(recipients, amounts); emit GivBackPaid(msg.sender); } + function sendPraiseRewards( + address[] memory recipients, + uint256[] memory amounts + ) external override { + _allocateMany(recipients, amounts); + emit PraiseRewardPaid(msg.sender); + } + /** * Function that allows a recipient to change its address * @dev The change can only be made to an address that has not previously received an allocation & @@ -217,16 +287,19 @@ contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeab */ function changeAddress(address newAddress) external override { require( - balances[newAddress].allocatedTokens == 0 && balances[newAddress].claimed == 0, - 'TokenDistro::changeAddress: ADDRESS_ALREADY_IN_USE' + balances[newAddress].allocatedTokens == 0 && + balances[newAddress].claimed == 0, + "TokenDistro::changeAddress: ADDRESS_ALREADY_IN_USE" ); require( - !hasRole(DISTRIBUTOR_ROLE, msg.sender) && !hasRole(DISTRIBUTOR_ROLE, newAddress), - 'TokenDistro::changeAddress: DISTRIBUTOR_ROLE_NOT_A_VALID_ADDRESS' + !hasRole(DISTRIBUTOR_ROLE, msg.sender) && + !hasRole(DISTRIBUTOR_ROLE, newAddress), + "TokenDistro::changeAddress: DISTRIBUTOR_ROLE_NOT_A_VALID_ADDRESS" ); - balances[newAddress].allocatedTokens = balances[msg.sender].allocatedTokens; + balances[newAddress].allocatedTokens = balances[msg.sender] + .allocatedTokens; balances[msg.sender].allocatedTokens = 0; balances[newAddress].claimed = balances[msg.sender].claimed; @@ -247,7 +320,12 @@ contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeab * @param timestamp Unix time to check the number of tokens claimable * @return Number of tokens claimable at that timestamp */ - function globallyClaimableAt(uint256 timestamp) public view override returns (uint256) { + function globallyClaimableAt(uint256 timestamp) + public + view + override + returns (uint256) + { if (timestamp < startTime) return 0; if (timestamp < cliffTime) return initialAmount; if (timestamp > startTime + duration) return totalTokens; @@ -261,10 +339,22 @@ contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeab * @param recipient account to query * @param timestamp Instant of time in which the calculation is made */ - function claimableAt(address recipient, uint256 timestamp) public view override returns (uint256) { - require(!hasRole(DISTRIBUTOR_ROLE, recipient), 'TokenDistro::claimableAt: DISTRIBUTOR_ROLE_CANNOT_CLAIM'); - require(timestamp >= getTimestamp(), 'TokenDistro::claimableAt: NOT_VALID_PAST_TIMESTAMP'); - uint256 unlockedAmount = (globallyClaimableAt(timestamp) * balances[recipient].allocatedTokens) / totalTokens; + function claimableAt(address recipient, uint256 timestamp) + public + view + override + returns (uint256) + { + require( + !hasRole(DISTRIBUTOR_ROLE, recipient), + "TokenDistro::claimableAt: DISTRIBUTOR_ROLE_CANNOT_CLAIM" + ); + require( + timestamp >= getTimestamp(), + "TokenDistro::claimableAt: NOT_VALID_PAST_TIMESTAMP" + ); + uint256 unlockedAmount = (globallyClaimableAt(timestamp) * + balances[recipient].allocatedTokens) / totalTokens; return unlockedAmount - balances[recipient].claimed; } @@ -273,7 +363,12 @@ contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeab * Function to get the unlocked tokens for a specific address. It uses the current timestamp * @param recipient account to query */ - function claimableNow(address recipient) public view override returns (uint256) { + function claimableNow(address recipient) + public + view + override + returns (uint256) + { return claimableAt(recipient, getTimestamp()); } @@ -285,22 +380,31 @@ contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeab * Emits a {ChangeAddress} event. * */ - function cancelAllocation(address prevRecipient, address newRecipient) external override { - require(cancelable, 'TokenDistro::cancelAllocation: NOT_CANCELABLE'); + function cancelAllocation(address prevRecipient, address newRecipient) + external + override + { + require(cancelable, "TokenDistro::cancelAllocation: NOT_CANCELABLE"); - require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), 'TokenDistro::cancelAllocation: ONLY_ADMIN_ROLE'); + require( + hasRole(DEFAULT_ADMIN_ROLE, msg.sender), + "TokenDistro::cancelAllocation: ONLY_ADMIN_ROLE" + ); require( - balances[newRecipient].allocatedTokens == 0 && balances[newRecipient].claimed == 0, - 'TokenDistro::cancelAllocation: ADDRESS_ALREADY_IN_USE' + balances[newRecipient].allocatedTokens == 0 && + balances[newRecipient].claimed == 0, + "TokenDistro::cancelAllocation: ADDRESS_ALREADY_IN_USE" ); require( - !hasRole(DISTRIBUTOR_ROLE, prevRecipient) && !hasRole(DISTRIBUTOR_ROLE, newRecipient), - 'TokenDistro::cancelAllocation: DISTRIBUTOR_ROLE_NOT_A_VALID_ADDRESS' + !hasRole(DISTRIBUTOR_ROLE, prevRecipient) && + !hasRole(DISTRIBUTOR_ROLE, newRecipient), + "TokenDistro::cancelAllocation: DISTRIBUTOR_ROLE_NOT_A_VALID_ADDRESS" ); - balances[newRecipient].allocatedTokens = balances[prevRecipient].allocatedTokens; + balances[newRecipient].allocatedTokens = balances[prevRecipient] + .allocatedTokens; balances[prevRecipient].allocatedTokens = 0; balances[newRecipient].claimed = balances[prevRecipient].claimed; @@ -318,9 +422,14 @@ contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeab function _claim(address recipient) private { uint256 remainingToClaim = claimableNow(recipient); - require(remainingToClaim > 0, 'TokenDistro::claim: NOT_ENOUGH_TOKENS_TO_CLAIM'); + require( + remainingToClaim > 0, + "TokenDistro::claim: NOT_ENOUGH_TOKENS_TO_CLAIM" + ); - balances[recipient].claimed = balances[recipient].claimed + remainingToClaim; + balances[recipient].claimed = + balances[recipient].claimed + + remainingToClaim; token.safeTransfer(recipient, remainingToClaim); @@ -331,9 +440,15 @@ contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeab * Function to change the duration */ function setDuration(uint256 newDuration) public { - require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), 'TokenDistro::setDuration: ONLY_ADMIN_ROLE'); + require( + hasRole(DEFAULT_ADMIN_ROLE, msg.sender), + "TokenDistro::setDuration: ONLY_ADMIN_ROLE" + ); - require(startTime > getTimestamp(), 'TokenDistro::setDuration: IF_HAS_NOT_STARTED_YET'); + require( + startTime > getTimestamp(), + "TokenDistro::setDuration: IF_HAS_NOT_STARTED_YET" + ); duration = newDuration; From 021dc012824bd23050483e43f036cf469dafd5e7 Mon Sep 17 00:00:00 2001 From: Mitch Oz Date: Tue, 20 Feb 2024 08:07:45 -0600 Subject: [PATCH 22/31] forge fmt, missing override on praise --- contracts/ModifiedTokenDistro.sol | 2 +- contracts/TokenDistro.sol | 205 ++++++++---------------------- 2 files changed, 51 insertions(+), 156 deletions(-) diff --git a/contracts/ModifiedTokenDistro.sol b/contracts/ModifiedTokenDistro.sol index 790cc0d..0566ec9 100644 --- a/contracts/ModifiedTokenDistro.sol +++ b/contracts/ModifiedTokenDistro.sol @@ -212,7 +212,7 @@ contract TokenDistroV1 is Initializable, IDistro, AccessControlEnumerableUpgrade emit GivBackPaid(msg.sender); } - function sendPraiseRewards(address[] memory recipients, uint256[] memory amounts) external { + function sendPraiseRewards(address[] memory recipients, uint256[] memory amounts) external override { _allocateMany(recipients, amounts); emit PraiseRewardPaid(msg.sender); } diff --git a/contracts/TokenDistro.sol b/contracts/TokenDistro.sol index 513a6aa..62d5ad2 100644 --- a/contracts/TokenDistro.sol +++ b/contracts/TokenDistro.sol @@ -1,27 +1,22 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity =0.8.6; -import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; -import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; -import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol"; -import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; -import "./interfaces/IDistro.sol"; +import '@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol'; +import '@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol'; +import '@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol'; +import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; +import './interfaces/IDistro.sol'; /** * Contract responsible for managing the release of tokens over time. * The distributor is in charge of releasing the corresponding amounts to its recipients. * This distributor is expected to be another smart contract, such as a merkledrop or the liquidity mining smart contract */ -contract TokenDistro is - Initializable, - IDistro, - AccessControlEnumerableUpgradeable -{ +contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeable { using SafeERC20Upgradeable for IERC20Upgradeable; // bytes32 public constant DISTRIBUTOR_ROLE = keccak256("DISTRIBUTOR_ROLE"); - bytes32 public constant DISTRIBUTOR_ROLE = - 0xfbd454f36a7e1a388bd6fc3ab10d434aa4578f811acbbcf33afb1c697486313c; + bytes32 public constant DISTRIBUTOR_ROLE = 0xfbd454f36a7e1a388bd6fc3ab10d434aa4578f811acbbcf33afb1c697486313c; // Structure to of the accounting for each account struct accountStatus { @@ -57,15 +52,9 @@ contract TokenDistro is event DurationChanged(uint256 newDuration); modifier onlyDistributor() { - require( - hasRole(DISTRIBUTOR_ROLE, msg.sender), - "TokenDistro::onlyDistributor: ONLY_DISTRIBUTOR_ROLE" - ); + require(hasRole(DISTRIBUTOR_ROLE, msg.sender), 'TokenDistro::onlyDistributor: ONLY_DISTRIBUTOR_ROLE'); - require( - balances[msg.sender].claimed == 0, - "TokenDistro::onlyDistributor: DISTRIBUTOR_CANNOT_CLAIM" - ); + require(balances[msg.sender].claimed == 0, 'TokenDistro::onlyDistributor: DISTRIBUTOR_CANNOT_CLAIM'); _; } @@ -90,14 +79,8 @@ contract TokenDistro is IERC20Upgradeable _token, bool _cancelable ) public initializer { - require( - _duration >= _cliffPeriod, - "TokenDistro::constructor: DURATION_LESS_THAN_CLIFF" - ); - require( - _initialPercentage <= 10000, - "TokenDistro::constructor: INITIALPERCENTAGE_GREATER_THAN_100" - ); + require(_duration >= _cliffPeriod, 'TokenDistro::constructor: DURATION_LESS_THAN_CLIFF'); + require(_initialPercentage <= 10000, 'TokenDistro::constructor: INITIALPERCENTAGE_GREATER_THAN_100'); __AccessControlEnumerable_init(); _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); @@ -122,13 +105,10 @@ contract TokenDistro is * */ function setStartTime(uint256 newStartTime) external override { - require( - hasRole(DEFAULT_ADMIN_ROLE, msg.sender), - "TokenDistro::setStartTime: ONLY_ADMIN_ROLE" - ); + require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), 'TokenDistro::setStartTime: ONLY_ADMIN_ROLE'); require( startTime > getTimestamp() && newStartTime > getTimestamp(), - "TokenDistro::setStartTime: IF_HAS_NOT_STARTED_YET" + 'TokenDistro::setStartTime: IF_HAS_NOT_STARTED_YET' ); uint256 _cliffPeriod = cliffTime - startTime; @@ -148,21 +128,11 @@ contract TokenDistro is * */ function assign(address distributor, uint256 amount) external override { - require( - hasRole(DEFAULT_ADMIN_ROLE, msg.sender), - "TokenDistro::assign: ONLY_ADMIN_ROLE" - ); - require( - hasRole(DISTRIBUTOR_ROLE, distributor), - "TokenDistro::assign: ONLY_TO_DISTRIBUTOR_ROLE" - ); + require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), 'TokenDistro::assign: ONLY_ADMIN_ROLE'); + require(hasRole(DISTRIBUTOR_ROLE, distributor), 'TokenDistro::assign: ONLY_TO_DISTRIBUTOR_ROLE'); - balances[address(this)].allocatedTokens = - balances[address(this)].allocatedTokens - - amount; - balances[distributor].allocatedTokens = - balances[distributor].allocatedTokens + - amount; + balances[address(this)].allocatedTokens = balances[address(this)].allocatedTokens - amount; + balances[distributor].allocatedTokens = balances[distributor].allocatedTokens + amount; emit Assign(msg.sender, distributor, amount); } @@ -199,23 +169,12 @@ contract TokenDistro is * Emits a {Allocate} event. * */ - function _allocate( - address recipient, - uint256 amount, - bool claim - ) internal { - require( - !hasRole(DISTRIBUTOR_ROLE, recipient), - "TokenDistro::allocate: DISTRIBUTOR_NOT_VALID_RECIPIENT" - ); + function _allocate(address recipient, uint256 amount, bool claim) internal { + require(!hasRole(DISTRIBUTOR_ROLE, recipient), 'TokenDistro::allocate: DISTRIBUTOR_NOT_VALID_RECIPIENT'); - balances[msg.sender].allocatedTokens = - balances[msg.sender].allocatedTokens - - amount; + balances[msg.sender].allocatedTokens = balances[msg.sender].allocatedTokens - amount; - balances[recipient].allocatedTokens = - balances[recipient].allocatedTokens + - amount; + balances[recipient].allocatedTokens = balances[recipient].allocatedTokens + amount; if (claim && claimableNow(recipient) > 0) { _claim(recipient); @@ -224,11 +183,7 @@ contract TokenDistro is emit Allocate(msg.sender, recipient, amount); } - function allocate( - address recipient, - uint256 amount, - bool claim - ) external override onlyDistributor { + function allocate(address recipient, uint256 amount, bool claim) external override onlyDistributor { _allocate(recipient, amount, claim); } @@ -240,39 +195,24 @@ contract TokenDistro is * * Unlike allocate method it doesn't claim recipients available balance */ - function _allocateMany( - address[] memory recipients, - uint256[] memory amounts - ) internal onlyDistributor { - require( - recipients.length == amounts.length, - "TokenDistro::allocateMany: INPUT_LENGTH_NOT_MATCH" - ); + function _allocateMany(address[] memory recipients, uint256[] memory amounts) internal onlyDistributor { + require(recipients.length == amounts.length, 'TokenDistro::allocateMany: INPUT_LENGTH_NOT_MATCH'); for (uint256 i = 0; i < recipients.length; i++) { _allocate(recipients[i], amounts[i], false); } } - function allocateMany(address[] memory recipients, uint256[] memory amounts) - external - override - { + function allocateMany(address[] memory recipients, uint256[] memory amounts) external override { _allocateMany(recipients, amounts); } - function sendGIVbacks(address[] memory recipients, uint256[] memory amounts) - external - override - { + function sendGIVbacks(address[] memory recipients, uint256[] memory amounts) external override { _allocateMany(recipients, amounts); emit GivBackPaid(msg.sender); } - function sendPraiseRewards( - address[] memory recipients, - uint256[] memory amounts - ) external override { + function sendPraiseRewards(address[] memory recipients, uint256[] memory amounts) external override { _allocateMany(recipients, amounts); emit PraiseRewardPaid(msg.sender); } @@ -287,19 +227,16 @@ contract TokenDistro is */ function changeAddress(address newAddress) external override { require( - balances[newAddress].allocatedTokens == 0 && - balances[newAddress].claimed == 0, - "TokenDistro::changeAddress: ADDRESS_ALREADY_IN_USE" + balances[newAddress].allocatedTokens == 0 && balances[newAddress].claimed == 0, + 'TokenDistro::changeAddress: ADDRESS_ALREADY_IN_USE' ); require( - !hasRole(DISTRIBUTOR_ROLE, msg.sender) && - !hasRole(DISTRIBUTOR_ROLE, newAddress), - "TokenDistro::changeAddress: DISTRIBUTOR_ROLE_NOT_A_VALID_ADDRESS" + !hasRole(DISTRIBUTOR_ROLE, msg.sender) && !hasRole(DISTRIBUTOR_ROLE, newAddress), + 'TokenDistro::changeAddress: DISTRIBUTOR_ROLE_NOT_A_VALID_ADDRESS' ); - balances[newAddress].allocatedTokens = balances[msg.sender] - .allocatedTokens; + balances[newAddress].allocatedTokens = balances[msg.sender].allocatedTokens; balances[msg.sender].allocatedTokens = 0; balances[newAddress].claimed = balances[msg.sender].claimed; @@ -320,12 +257,7 @@ contract TokenDistro is * @param timestamp Unix time to check the number of tokens claimable * @return Number of tokens claimable at that timestamp */ - function globallyClaimableAt(uint256 timestamp) - public - view - override - returns (uint256) - { + function globallyClaimableAt(uint256 timestamp) public view override returns (uint256) { if (timestamp < startTime) return 0; if (timestamp < cliffTime) return initialAmount; if (timestamp > startTime + duration) return totalTokens; @@ -339,22 +271,10 @@ contract TokenDistro is * @param recipient account to query * @param timestamp Instant of time in which the calculation is made */ - function claimableAt(address recipient, uint256 timestamp) - public - view - override - returns (uint256) - { - require( - !hasRole(DISTRIBUTOR_ROLE, recipient), - "TokenDistro::claimableAt: DISTRIBUTOR_ROLE_CANNOT_CLAIM" - ); - require( - timestamp >= getTimestamp(), - "TokenDistro::claimableAt: NOT_VALID_PAST_TIMESTAMP" - ); - uint256 unlockedAmount = (globallyClaimableAt(timestamp) * - balances[recipient].allocatedTokens) / totalTokens; + function claimableAt(address recipient, uint256 timestamp) public view override returns (uint256) { + require(!hasRole(DISTRIBUTOR_ROLE, recipient), 'TokenDistro::claimableAt: DISTRIBUTOR_ROLE_CANNOT_CLAIM'); + require(timestamp >= getTimestamp(), 'TokenDistro::claimableAt: NOT_VALID_PAST_TIMESTAMP'); + uint256 unlockedAmount = (globallyClaimableAt(timestamp) * balances[recipient].allocatedTokens) / totalTokens; return unlockedAmount - balances[recipient].claimed; } @@ -363,12 +283,7 @@ contract TokenDistro is * Function to get the unlocked tokens for a specific address. It uses the current timestamp * @param recipient account to query */ - function claimableNow(address recipient) - public - view - override - returns (uint256) - { + function claimableNow(address recipient) public view override returns (uint256) { return claimableAt(recipient, getTimestamp()); } @@ -380,31 +295,22 @@ contract TokenDistro is * Emits a {ChangeAddress} event. * */ - function cancelAllocation(address prevRecipient, address newRecipient) - external - override - { - require(cancelable, "TokenDistro::cancelAllocation: NOT_CANCELABLE"); + function cancelAllocation(address prevRecipient, address newRecipient) external override { + require(cancelable, 'TokenDistro::cancelAllocation: NOT_CANCELABLE'); - require( - hasRole(DEFAULT_ADMIN_ROLE, msg.sender), - "TokenDistro::cancelAllocation: ONLY_ADMIN_ROLE" - ); + require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), 'TokenDistro::cancelAllocation: ONLY_ADMIN_ROLE'); require( - balances[newRecipient].allocatedTokens == 0 && - balances[newRecipient].claimed == 0, - "TokenDistro::cancelAllocation: ADDRESS_ALREADY_IN_USE" + balances[newRecipient].allocatedTokens == 0 && balances[newRecipient].claimed == 0, + 'TokenDistro::cancelAllocation: ADDRESS_ALREADY_IN_USE' ); require( - !hasRole(DISTRIBUTOR_ROLE, prevRecipient) && - !hasRole(DISTRIBUTOR_ROLE, newRecipient), - "TokenDistro::cancelAllocation: DISTRIBUTOR_ROLE_NOT_A_VALID_ADDRESS" + !hasRole(DISTRIBUTOR_ROLE, prevRecipient) && !hasRole(DISTRIBUTOR_ROLE, newRecipient), + 'TokenDistro::cancelAllocation: DISTRIBUTOR_ROLE_NOT_A_VALID_ADDRESS' ); - balances[newRecipient].allocatedTokens = balances[prevRecipient] - .allocatedTokens; + balances[newRecipient].allocatedTokens = balances[prevRecipient].allocatedTokens; balances[prevRecipient].allocatedTokens = 0; balances[newRecipient].claimed = balances[prevRecipient].claimed; @@ -422,14 +328,9 @@ contract TokenDistro is function _claim(address recipient) private { uint256 remainingToClaim = claimableNow(recipient); - require( - remainingToClaim > 0, - "TokenDistro::claim: NOT_ENOUGH_TOKENS_TO_CLAIM" - ); + require(remainingToClaim > 0, 'TokenDistro::claim: NOT_ENOUGH_TOKENS_TO_CLAIM'); - balances[recipient].claimed = - balances[recipient].claimed + - remainingToClaim; + balances[recipient].claimed = balances[recipient].claimed + remainingToClaim; token.safeTransfer(recipient, remainingToClaim); @@ -440,15 +341,9 @@ contract TokenDistro is * Function to change the duration */ function setDuration(uint256 newDuration) public { - require( - hasRole(DEFAULT_ADMIN_ROLE, msg.sender), - "TokenDistro::setDuration: ONLY_ADMIN_ROLE" - ); + require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), 'TokenDistro::setDuration: ONLY_ADMIN_ROLE'); - require( - startTime > getTimestamp(), - "TokenDistro::setDuration: IF_HAS_NOT_STARTED_YET" - ); + require(startTime > getTimestamp(), 'TokenDistro::setDuration: IF_HAS_NOT_STARTED_YET'); duration = newDuration; From 1fcb74cf912b8f23e83dab8f066629065e26cea8 Mon Sep 17 00:00:00 2001 From: Amin Latifi Date: Sun, 3 Mar 2024 15:00:07 +0330 Subject: [PATCH 23/31] Moved changes to the same TokenDistro contract Reverted the name to the same TokenDistro --- contracts/ModifiedTokenDistro.sol | 340 ------------------ contracts/TokenDistro.sol | 71 ++-- contracts/interfaces/IDistro.sol | 4 +- contracts/interfaces/IDistroModified.sol | 104 ------ script/deployRelayerOptimism.s.sol | 2 +- ...l => TokenDistro.TransferAllocation.t.sol} | 12 +- 6 files changed, 39 insertions(+), 494 deletions(-) delete mode 100644 contracts/ModifiedTokenDistro.sol delete mode 100644 contracts/interfaces/IDistroModified.sol rename test/{ModifyTokenDistro.t.sol => TokenDistro.TransferAllocation.t.sol} (97%) diff --git a/contracts/ModifiedTokenDistro.sol b/contracts/ModifiedTokenDistro.sol deleted file mode 100644 index 0566ec9..0000000 --- a/contracts/ModifiedTokenDistro.sol +++ /dev/null @@ -1,340 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.6; - -import '@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol'; -import '@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol'; -import '@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol'; -import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import './interfaces/IDistroModified.sol'; - -/** - * Contract responsible for managing the release of tokens over time. - * The distributor is in charge of releasing the corresponding amounts to its recipients. - * This distributor is expected to be another smart contract, such as a merkledrop or the liquidity mining smart contract - */ -contract TokenDistroV1 is Initializable, IDistro, AccessControlEnumerableUpgradeable { - using SafeERC20Upgradeable for IERC20Upgradeable; - - // bytes32 public constant DISTRIBUTOR_ROLE = keccak256("DISTRIBUTOR_ROLE"); - bytes32 public constant DISTRIBUTOR_ROLE = 0xfbd454f36a7e1a388bd6fc3ab10d434aa4578f811acbbcf33afb1c697486313c; - - // Structure to of the accounting for each account - struct accountStatus { - uint256 allocatedTokens; - uint256 claimed; - } - - mapping(address => accountStatus) public balances; // Mapping with all accounts that have received an allocation - - uint256 public override totalTokens; // total tokens to be distribute - uint256 public startTime; // Instant of time in which distribution begins - uint256 public cliffTime; // Instant of time in which tokens will begin to be released - uint256 public duration; - uint256 public initialAmount; // Initial amount that will be available from startTime - uint256 public lockedAmount; // Amount that will be released over time from cliffTime - - IERC20Upgradeable public token; // Token to be distribute - bool public cancelable; // Variable that allows the ADMIN_ROLE to cancel an allocation - - /** - * @dev Emitted when the DISTRIBUTOR allocate an amount of givBack to a recipient - */ - event GivBackPaid(address distributor); - - /** - * @dev Emitted when the DISTRIBUTOR allocate an amount of praise rewards to a recipient - */ - event PraiseRewardPaid(address distributor); - - /** - * @dev Emitted when the duration is changed - */ - event DurationChanged(uint256 newDuration); - - modifier onlyDistributor() { - require(hasRole(DISTRIBUTOR_ROLE, msg.sender), 'TokenDistro::onlyDistributor: ONLY_DISTRIBUTOR_ROLE'); - - require(balances[msg.sender].claimed == 0, 'TokenDistro::onlyDistributor: DISTRIBUTOR_CANNOT_CLAIM'); - _; - } - - /** - * @dev Initially the deployer of the contract will be able to assign the tokens to one or several addresses, - * these addresses (EOA or Smart Contracts) are responsible to allocate tokens to specific addresses which can - * later claim them - * @param _totalTokens Total amount of tokens to distribute - * @param _startTime Unix time that the distribution begins - * @param _cliffPeriod Number of seconds to delay the claiming period for the tokens not initially released - * @param _duration Time it will take for all tokens to be distributed - * @param _initialPercentage Percentage of tokens initially released (2 decimals, 1/10000) - * @param _token Address of the token to distribute - * @param _cancelable In case the owner wants to have the power to cancel an assignment - */ - function initialize( - uint256 _totalTokens, - uint256 _startTime, - uint256 _cliffPeriod, - uint256 _duration, - uint256 _initialPercentage, - IERC20Upgradeable _token, - bool _cancelable - ) public initializer { - require(_duration >= _cliffPeriod, 'TokenDistro::constructor: DURATION_LESS_THAN_CLIFF'); - require(_initialPercentage <= 10000, 'TokenDistro::constructor: INITIALPERCENTAGE_GREATER_THAN_100'); - __AccessControlEnumerable_init(); - _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); - - uint256 _initialAmount = (_totalTokens * _initialPercentage) / 10000; - - token = _token; - duration = _duration; - startTime = _startTime; - totalTokens = _totalTokens; - initialAmount = _initialAmount; - cliffTime = _startTime + _cliffPeriod; - lockedAmount = _totalTokens - _initialAmount; - balances[address(this)].allocatedTokens = _totalTokens; - cancelable = _cancelable; - } - - /** - * Function that allows the DEFAULT_ADMIN_ROLE to assign set a new startTime if it hasn't started yet - * @param newStartTime new startTime - * - * Emits a {StartTimeChanged} event. - * - */ - function setStartTime(uint256 newStartTime) external override { - require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), 'TokenDistro::setStartTime: ONLY_ADMIN_ROLE'); - require( - startTime > getTimestamp() && newStartTime > getTimestamp(), - 'TokenDistro::setStartTime: IF_HAS_NOT_STARTED_YET' - ); - - uint256 _cliffPeriod = cliffTime - startTime; - startTime = newStartTime; - cliffTime = newStartTime + _cliffPeriod; - - emit StartTimeChanged(startTime, cliffTime); - } - - /** - * Function that allows the DEFAULT_ADMIN_ROLE to assign tokens to an address who later can distribute them. - * @dev It is required that the DISTRIBUTOR_ROLE is already held by the address to which an amount will be assigned - * @param distributor the address, generally a smart contract, that will determine who gets how many tokens - * @param amount Total amount of tokens to assign to that address for distributing - * - * Emits a {Assign} event. - * - */ - function assign(address distributor, uint256 amount) external override { - require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), 'TokenDistro::assign: ONLY_ADMIN_ROLE'); - require(hasRole(DISTRIBUTOR_ROLE, distributor), 'TokenDistro::assign: ONLY_TO_DISTRIBUTOR_ROLE'); - - balances[address(this)].allocatedTokens = balances[address(this)].allocatedTokens - amount; - balances[distributor].allocatedTokens = balances[distributor].allocatedTokens + amount; - - emit Assign(msg.sender, distributor, amount); - } - - /** - * Function to claim tokens for a specific address. It uses the current timestamp - * - * Emits a {claim} event. - * - */ - function claimTo(address account) external { - // This check is not necessary as it does not break anything, just changes the claimed value - // for this contract - //require(address(this) != account, "TokenDistro::claimTo: CANNOT_CLAIM_FOR_CONTRACT_ITSELF"); - _claim(account); - } - - /** - * Function to claim tokens for a specific address. It uses the current timestamp - * - * Emits a {claim} event. - * - */ - function claim() external override { - _claim(msg.sender); - } - - /** - * Function that allows to the distributor address to allocate some amount of tokens to a specific recipient - * @param recipient of token allocation - * @param amount allocated amount - * @param claim whether claim after allocate - * - * Emits a {Allocate} event. - * - */ - function _allocate(address recipient, uint256 amount, bool claim) internal { - require(!hasRole(DISTRIBUTOR_ROLE, recipient), 'TokenDistro::allocate: DISTRIBUTOR_NOT_VALID_RECIPIENT'); - balances[msg.sender].allocatedTokens = balances[msg.sender].allocatedTokens - amount; - - balances[recipient].allocatedTokens = balances[recipient].allocatedTokens + amount; - - if (claim && claimableNow(recipient) > 0) { - _claim(recipient); - } - - emit Allocate(msg.sender, recipient, amount); - } - - function allocate(address recipient, uint256 amount, bool claim) external override onlyDistributor { - _allocate(recipient, amount, claim); - } - - /** - * Function that allows to the distributor address to allocate some amounts of tokens to specific recipients - * @dev Needs to be initialized: Nobody has the DEFAULT_ADMIN_ROLE and all available tokens have been assigned - * @param recipients of token allocation - * @param amounts allocated amount - * - * Unlike allocate method it doesn't claim recipients available balance - */ - function _allocateMany(address[] memory recipients, uint256[] memory amounts) internal onlyDistributor { - uint256 length = recipients.length; - require(length == amounts.length, 'TokenDistro::allocateMany: INPUT_LENGTH_NOT_MATCH'); - - for (uint256 i = 0; i < length; i++) { - _allocate(recipients[i], amounts[i], false); - } - } - - function allocateMany(address[] memory recipients, uint256[] memory amounts) external override { - _allocateMany(recipients, amounts); - } - - function sendGIVbacks(address[] memory recipients, uint256[] memory amounts) external override { - _allocateMany(recipients, amounts); - emit GivBackPaid(msg.sender); - } - - function sendPraiseRewards(address[] memory recipients, uint256[] memory amounts) external override { - _allocateMany(recipients, amounts); - emit PraiseRewardPaid(msg.sender); - } - - /** - * Function that allows a recipient to change its address - * @dev The change can only be made to an address that has not previously received an allocation & - * the distributor cannot change its address - * - * Emits a {ChangeAddress} event. - * - */ - function changeAddress(address newAddress) external override { - _transferAllocation(msg.sender, newAddress); - } - - /** - * Function to get the current timestamp from the block - */ - function getTimestamp() public view virtual override returns (uint256) { - return block.timestamp; - } - - /** - * Function to get the total claimable tokens at some moment - * @param timestamp Unix time to check the number of tokens claimable - * @return Number of tokens claimable at that timestamp - */ - function globallyClaimableAt(uint256 timestamp) public view override returns (uint256) { - if (timestamp < startTime) return 0; - if (timestamp < cliffTime) return initialAmount; - if (timestamp > startTime + duration) return totalTokens; - - uint256 deltaTime = timestamp - startTime; - return initialAmount + (deltaTime * lockedAmount) / duration; - } - - /** - * Function to get the unlocked tokes at some moment for a specific address - * @param recipient account to query - * @param timestamp Instant of time in which the calculation is made - */ - function claimableAt(address recipient, uint256 timestamp) public view override returns (uint256) { - require(!hasRole(DISTRIBUTOR_ROLE, recipient), 'TokenDistro::claimableAt: DISTRIBUTOR_ROLE_CANNOT_CLAIM'); - require(timestamp >= getTimestamp(), 'TokenDistro::claimableAt: NOT_VALID_PAST_TIMESTAMP'); - uint256 unlockedAmount = (globallyClaimableAt(timestamp) * balances[recipient].allocatedTokens) / totalTokens; - - return unlockedAmount - balances[recipient].claimed; - } - - /** - * Function to get the unlocked tokens for a specific address. It uses the current timestamp - * @param recipient account to query - */ - function claimableNow(address recipient) public view override returns (uint256) { - return claimableAt(recipient, getTimestamp()); - } - - /** - * Function that allows the DEFAULT_ADMIN_ROLE to change a recipient in case it wants to cancel an allocation - * @dev The change can only be made when cancelable is true and to an address that has not previously received - * an allocation and the distributor cannot change its address - * - * Emits a {ChangeAddress} event. - * - * Formerly called cancelAllocation, this is an admin only function and should only be called manually - */ - function transferAllocation(address prevRecipient, address newRecipient) external override { - require(cancelable, 'TokenDistro::transferAllocation: NOT_CANCELABLE'); - - require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), 'TokenDistro::transferAllocation: ONLY_ADMIN_ROLE'); - _transferAllocation(prevRecipient, newRecipient); - } - - /** - * Function to claim tokens for a specific address. It uses the current timestamp - * - * Emits a {claim} event. - * - */ - function _claim(address recipient) private { - uint256 remainingToClaim = claimableNow(recipient); - - require(remainingToClaim > 0, 'TokenDistro::claim: NOT_ENOUGH_TOKENS_TO_CLAIM'); - - balances[recipient].claimed = balances[recipient].claimed + remainingToClaim; - - token.safeTransfer(recipient, remainingToClaim); - - emit Claim(recipient, remainingToClaim); - } - - /** - * Function to change the duration - */ - function setDuration(uint256 newDuration) public { - require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), 'TokenDistro::setDuration: ONLY_ADMIN_ROLE'); - - require(startTime > getTimestamp(), 'TokenDistro::setDuration: IF_HAS_NOT_STARTED_YET'); - - duration = newDuration; - - emit DurationChanged(newDuration); - } - - function _transferAllocation(address prevRecipient, address newRecipient) internal { - require( - balances[prevRecipient].allocatedTokens > 0, 'TokenDistro::transferAllocation: NO_ALLOCATION_TO_TRANSFER' - ); - require( - !hasRole(DISTRIBUTOR_ROLE, prevRecipient) && !hasRole(DISTRIBUTOR_ROLE, newRecipient), - 'TokenDistro::transferAllocation: DISTRIBUTOR_ROLE_NOT_A_VALID_ADDRESS' - ); - // balance adds instead of overwrites - balances[newRecipient].allocatedTokens = - balances[prevRecipient].allocatedTokens + balances[newRecipient].allocatedTokens; - balances[prevRecipient].allocatedTokens = 0; - - balances[newRecipient].claimed = balances[prevRecipient].claimed + balances[newRecipient].claimed; - - balances[prevRecipient].claimed = 0; - - emit ChangeAddress(prevRecipient, newRecipient); - } -} diff --git a/contracts/TokenDistro.sol b/contracts/TokenDistro.sol index 62d5ad2..e7a7815 100644 --- a/contracts/TokenDistro.sol +++ b/contracts/TokenDistro.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity =0.8.6; +pragma solidity ^0.8.6; import '@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol'; import '@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol'; @@ -171,7 +171,6 @@ contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeab */ function _allocate(address recipient, uint256 amount, bool claim) internal { require(!hasRole(DISTRIBUTOR_ROLE, recipient), 'TokenDistro::allocate: DISTRIBUTOR_NOT_VALID_RECIPIENT'); - balances[msg.sender].allocatedTokens = balances[msg.sender].allocatedTokens - amount; balances[recipient].allocatedTokens = balances[recipient].allocatedTokens + amount; @@ -196,9 +195,10 @@ contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeab * Unlike allocate method it doesn't claim recipients available balance */ function _allocateMany(address[] memory recipients, uint256[] memory amounts) internal onlyDistributor { - require(recipients.length == amounts.length, 'TokenDistro::allocateMany: INPUT_LENGTH_NOT_MATCH'); + uint256 length = recipients.length; + require(length == amounts.length, 'TokenDistro::allocateMany: INPUT_LENGTH_NOT_MATCH'); - for (uint256 i = 0; i < recipients.length; i++) { + for (uint256 i = 0; i < length; i++) { _allocate(recipients[i], amounts[i], false); } } @@ -226,23 +226,7 @@ contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeab * */ function changeAddress(address newAddress) external override { - require( - balances[newAddress].allocatedTokens == 0 && balances[newAddress].claimed == 0, - 'TokenDistro::changeAddress: ADDRESS_ALREADY_IN_USE' - ); - - require( - !hasRole(DISTRIBUTOR_ROLE, msg.sender) && !hasRole(DISTRIBUTOR_ROLE, newAddress), - 'TokenDistro::changeAddress: DISTRIBUTOR_ROLE_NOT_A_VALID_ADDRESS' - ); - - balances[newAddress].allocatedTokens = balances[msg.sender].allocatedTokens; - balances[msg.sender].allocatedTokens = 0; - - balances[newAddress].claimed = balances[msg.sender].claimed; - balances[msg.sender].claimed = 0; - - emit ChangeAddress(msg.sender, newAddress); + _transferAllocation(msg.sender, newAddress); } /** @@ -294,29 +278,13 @@ contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeab * * Emits a {ChangeAddress} event. * + * Formerly called cancelAllocation, this is an admin only function and should only be called manually */ - function cancelAllocation(address prevRecipient, address newRecipient) external override { - require(cancelable, 'TokenDistro::cancelAllocation: NOT_CANCELABLE'); - - require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), 'TokenDistro::cancelAllocation: ONLY_ADMIN_ROLE'); - - require( - balances[newRecipient].allocatedTokens == 0 && balances[newRecipient].claimed == 0, - 'TokenDistro::cancelAllocation: ADDRESS_ALREADY_IN_USE' - ); - - require( - !hasRole(DISTRIBUTOR_ROLE, prevRecipient) && !hasRole(DISTRIBUTOR_ROLE, newRecipient), - 'TokenDistro::cancelAllocation: DISTRIBUTOR_ROLE_NOT_A_VALID_ADDRESS' - ); + function transferAllocation(address prevRecipient, address newRecipient) external override { + require(cancelable, 'TokenDistro::transferAllocation: NOT_CANCELABLE'); - balances[newRecipient].allocatedTokens = balances[prevRecipient].allocatedTokens; - balances[prevRecipient].allocatedTokens = 0; - - balances[newRecipient].claimed = balances[prevRecipient].claimed; - balances[prevRecipient].claimed = 0; - - emit ChangeAddress(prevRecipient, newRecipient); + require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), 'TokenDistro::transferAllocation: ONLY_ADMIN_ROLE'); + _transferAllocation(prevRecipient, newRecipient); } /** @@ -349,4 +317,23 @@ contract TokenDistro is Initializable, IDistro, AccessControlEnumerableUpgradeab emit DurationChanged(newDuration); } + + function _transferAllocation(address prevRecipient, address newRecipient) internal { + require( + balances[prevRecipient].allocatedTokens > 0, 'TokenDistro::transferAllocation: NO_ALLOCATION_TO_TRANSFER' + ); + require( + !hasRole(DISTRIBUTOR_ROLE, prevRecipient) && !hasRole(DISTRIBUTOR_ROLE, newRecipient), + 'TokenDistro::transferAllocation: DISTRIBUTOR_ROLE_NOT_A_VALID_ADDRESS' + ); + // balance adds instead of overwrites + balances[newRecipient].allocatedTokens = + balances[prevRecipient].allocatedTokens + balances[newRecipient].allocatedTokens; + balances[prevRecipient].allocatedTokens = 0; + + balances[newRecipient].claimed = balances[prevRecipient].claimed + balances[newRecipient].claimed; + balances[prevRecipient].claimed = 0; + + emit ChangeAddress(prevRecipient, newRecipient); + } } diff --git a/contracts/interfaces/IDistro.sol b/contracts/interfaces/IDistro.sol index 975ef7b..bcac027 100644 --- a/contracts/interfaces/IDistro.sol +++ b/contracts/interfaces/IDistro.sol @@ -98,5 +98,7 @@ interface IDistro { */ function claimableNow(address recipient) external view returns (uint256); - function cancelAllocation(address prevRecipient, address newRecipient) external; + function transferAllocation(address prevRecipient, address newRecipient) external; + + function sendPraiseRewards(address[] memory recipients, uint256[] memory amounts) external; } diff --git a/contracts/interfaces/IDistroModified.sol b/contracts/interfaces/IDistroModified.sol deleted file mode 100644 index bcac027..0000000 --- a/contracts/interfaces/IDistroModified.sol +++ /dev/null @@ -1,104 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity ^0.8.10; - -interface IDistro { - /** - * @dev Emitted when someone makes a claim of tokens - */ - event Claim(address indexed grantee, uint256 amount); - /** - * @dev Emitted when the DISTRIBUTOR allocate an amount to a grantee - */ - event Allocate(address indexed distributor, address indexed grantee, uint256 amount); - /** - * @dev Emitted when the DEFAULT_ADMIN assign an amount to a DISTRIBUTOR - */ - event Assign(address indexed admin, address indexed distributor, uint256 amount); - /** - * @dev Emitted when someone change their reception address - */ - event ChangeAddress(address indexed oldAddress, address indexed newAddress); - - /** - * @dev Emitted when a new startTime is set - */ - event StartTimeChanged(uint256 newStartTime, uint256 newCliffTime); - - /** - * @dev Returns the total amount of tokens will be streamed - */ - function totalTokens() external view returns (uint256); - - /** - * Function that allows the DEFAULT_ADMIN_ROLE to assign set a new startTime if it hasn't started yet - * @param newStartTime new startTime - * - * Emits a {StartTimeChanged} event. - * - */ - function setStartTime(uint256 newStartTime) external; - - /** - * Function that allows the DEFAULT_ADMIN_ROLE to assign tokens to an address who later can distribute them. - * @dev It is required that the DISTRIBUTOR_ROLE is already held by the address to which an amount will be assigned - * @param distributor the address, generally a smart contract, that will determine who gets how many tokens - * @param amount Total amount of tokens to assign to that address for distributing - */ - function assign(address distributor, uint256 amount) external; - - /** - * Function to claim tokens for a specific address. It uses the current timestamp - */ - function claim() external; - - /** - * Function that allows to the distributor address to allocate some amount of tokens to a specific recipient - * @dev Needs to be initialized: Nobody has the DEFAULT_ADMIN_ROLE and all available tokens have been assigned - * @param recipient of token allocation - * @param amount allocated amount - * @param claim whether claim after allocate - */ - function allocate(address recipient, uint256 amount, bool claim) external; - - /** - * Function that allows to the distributor address to allocate some amounts of tokens to specific recipients - * @dev Needs to be initialized: Nobody has the DEFAULT_ADMIN_ROLE and all available tokens have been assigned - * @param recipients of token allocation - * @param amounts allocated amount - */ - function allocateMany(address[] memory recipients, uint256[] memory amounts) external; - - function sendGIVbacks(address[] memory recipients, uint256[] memory amounts) external; - - /** - * Function that allows a recipient to change its address - * @dev The change can only be made to an address that has not previously received an allocation & - * the distributor cannot change its address - */ - function changeAddress(address newAddress) external; - - /** - * Function to get the current timestamp from the block - */ - function getTimestamp() external view returns (uint256); - - /** - * Function to get the total unlocked tokes at some moment - */ - function globallyClaimableAt(uint256 timestamp) external view returns (uint256); - - /** - * Function to get the unlocked tokes at some moment for a specific address - */ - function claimableAt(address recipient, uint256 timestamp) external view returns (uint256); - - /** - * Function to get the unlocked tokens for a specific address. It uses the current timestamp - */ - function claimableNow(address recipient) external view returns (uint256); - - function transferAllocation(address prevRecipient, address newRecipient) external; - - function sendPraiseRewards(address[] memory recipients, uint256[] memory amounts) external; -} diff --git a/script/deployRelayerOptimism.s.sol b/script/deployRelayerOptimism.s.sol index 4ba11f2..aa120dc 100644 --- a/script/deployRelayerOptimism.s.sol +++ b/script/deployRelayerOptimism.s.sol @@ -44,7 +44,7 @@ contract deployRelayer is Script { tokenDistro.grantRole(keccak256('DISTRIBUTOR_ROLE'), address(givbacksRelayer)); tokenDistro.assign(address(givbacksRelayer), 2500000 ether); tokenDistro.revokeRole(keccak256('DISTRIBUTOR_ROLE'), address(batcherApp)); - tokenDistro.cancelAllocation(address(batcherApp), 0x0000000000000000000000000000000000000000); + tokenDistro.transferAllocation(address(batcherApp), 0x0000000000000000000000000000000000000000); console.log('proxy admin', address(givbacksRelayerProxyAdmin)); console.log('givbacks relayer', address(givbacksRelayer)); diff --git a/test/ModifyTokenDistro.t.sol b/test/TokenDistro.TransferAllocation.t.sol similarity index 97% rename from test/ModifyTokenDistro.t.sol rename to test/TokenDistro.TransferAllocation.t.sol index e6e5531..ee19d71 100644 --- a/test/ModifyTokenDistro.t.sol +++ b/test/TokenDistro.TransferAllocation.t.sol @@ -10,9 +10,9 @@ import '@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.so import '@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol'; import 'forge-std/Test.sol'; import 'forge-std/console.sol'; -import '../contracts/ModifiedTokenDistro.sol'; +import '../contracts/TokenDistro.sol'; -contract TestModifyDistro is Test { +contract TokenDistroTransferAllocation is Test { using SafeERC20Upgradeable for IERC20Upgradeable; using SafeMath for uint256; @@ -27,8 +27,8 @@ contract TestModifyDistro is Test { // deploy the token distro TransparentUpgradeableProxy tokenDistroProxy; IDistro tokenDistroInterface; - TokenDistroV1 tokenDistro; - TokenDistroV1 tokenDistroImplementation; + TokenDistro tokenDistro; + TokenDistro tokenDistroImplementation; uint256 assignedAmount = 10000000000000000000000000; uint256 forkBlock = 22501098; @@ -36,7 +36,7 @@ contract TestModifyDistro is Test { uint256 forkId = vm.createFork('https://rpc.ankr.com/gnosis', forkBlock); //https://xdai-archive.blockscout.com/ vm.selectFork(forkId); proxyAdmin = ProxyAdmin(address(0x076C250700D210e6cf8A27D1EB1Fd754FB487986)); - tokenDistro = TokenDistroV1(address(0xc0dbDcA66a0636236fAbe1B3C16B1bD4C84bB1E1)); + tokenDistro = TokenDistro(address(0xc0dbDcA66a0636236fAbe1B3C16B1bD4C84bB1E1)); tokenDistroProxy = TransparentUpgradeableProxy(payable(address(0xc0dbDcA66a0636236fAbe1B3C16B1bD4C84bB1E1))); givethMultisig = 0x4D9339dd97db55e3B9bCBE65dE39fF9c04d1C2cd; givToken = IERC20Upgradeable(address(0x4f4F9b8D5B4d0Dc10506e5551B0513B61fD59e75)); @@ -48,7 +48,7 @@ contract TestModifyDistro is Test { function setUp() public { vm.startPrank(givethMultisig); - tokenDistroImplementation = new TokenDistroV1(); + tokenDistroImplementation = new TokenDistro(); proxyAdmin.upgrade(tokenDistroProxy, address(tokenDistroImplementation)); tokenDistro.grantRole(keccak256('DISTRIBUTOR_ROLE'), distributor); tokenDistro.assign(distributor, assignedAmount); From ee655a7d2296df6dfed9a573b7b8b09b5ff45354 Mon Sep 17 00:00:00 2001 From: Amin Latifi Date: Sun, 3 Mar 2024 15:08:53 +0330 Subject: [PATCH 24/31] Reverted slither changes --- .github/workflows/slither.yml | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/.github/workflows/slither.yml b/.github/workflows/slither.yml index 73692c0..a1bf454 100644 --- a/.github/workflows/slither.yml +++ b/.github/workflows/slither.yml @@ -13,20 +13,29 @@ jobs: name: Slither check runs-on: ubuntu-latest steps: - - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 with: submodules: recursive - + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + + - name: Install deps + run: | + forge --version + forge install + - name: Run Slither - uses: crytic/slither-action@v0.3.0 + uses: crytic/slither-action@main id: slither + continue-on-error: true with: sarif: results.sarif - target: 'contracts/' - fail-on: none + target: "contracts/" - name: Upload SARIF file - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@v2 with: sarif_file: ${{ steps.slither.outputs.sarif }} From e81bd2493c1c2d7ccd458b0a926422b073bbb8d1 Mon Sep 17 00:00:00 2001 From: Amin Latifi Date: Sun, 3 Mar 2024 15:14:36 +0330 Subject: [PATCH 25/31] Upgrade dependencies --- .github/workflows/slither.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/slither.yml b/.github/workflows/slither.yml index a1bf454..565acc7 100644 --- a/.github/workflows/slither.yml +++ b/.github/workflows/slither.yml @@ -13,7 +13,7 @@ jobs: name: Slither check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive From 2b377b5643776b664410c8c8b2495faa890d6494 Mon Sep 17 00:00:00 2001 From: Amin Latifi Date: Sun, 3 Mar 2024 15:23:05 +0330 Subject: [PATCH 26/31] returned slither action back --- .github/workflows/slither.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/slither.yml b/.github/workflows/slither.yml index 565acc7..360a013 100644 --- a/.github/workflows/slither.yml +++ b/.github/workflows/slither.yml @@ -4,16 +4,14 @@ on: branches: - main pull_request: - env: FOUNDRY_PROFILE: ci - jobs: analyze: name: Slither check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 with: submodules: recursive @@ -26,7 +24,6 @@ jobs: run: | forge --version forge install - - name: Run Slither uses: crytic/slither-action@main id: slither From 2a4e88ef26bd13d444dbe7f5734d174494e0f112 Mon Sep 17 00:00:00 2001 From: Amin Latifi Date: Sun, 3 Mar 2024 15:30:25 +0330 Subject: [PATCH 27/31] Move to new slither config --- .github/workflows/slither.yml | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/.github/workflows/slither.yml b/.github/workflows/slither.yml index 360a013..069389a 100644 --- a/.github/workflows/slither.yml +++ b/.github/workflows/slither.yml @@ -11,28 +11,19 @@ jobs: name: Slither check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive - - name: Install Foundry - uses: foundry-rs/foundry-toolchain@v1 - with: - version: nightly - - - name: Install deps - run: | - forge --version - forge install - name: Run Slither - uses: crytic/slither-action@main + uses: crytic/slither-action@v0.3.0 id: slither - continue-on-error: true with: sarif: results.sarif target: "contracts/" + fail-on: none - name: Upload SARIF file - uses: github/codeql-action/upload-sarif@v2 + uses: github/codeql-action/upload-sarif@v3 with: sarif_file: ${{ steps.slither.outputs.sarif }} From 530b742b59c6276d3e6f501d344c80860b6bd772 Mon Sep 17 00:00:00 2001 From: Amin Latifi Date: Sun, 3 Mar 2024 15:46:19 +0330 Subject: [PATCH 28/31] Upgraded slither action --- .github/workflows/slither.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/slither.yml b/.github/workflows/slither.yml index 069389a..ca36bc7 100644 --- a/.github/workflows/slither.yml +++ b/.github/workflows/slither.yml @@ -16,7 +16,7 @@ jobs: submodules: recursive - name: Run Slither - uses: crytic/slither-action@v0.3.0 + uses: crytic/slither-action@v0.3.1 id: slither with: sarif: results.sarif From 64b9f2330fd9eb3c8ab60f9083993b61316a417e Mon Sep 17 00:00:00 2001 From: Amin Latifi Date: Sun, 3 Mar 2024 17:13:03 +0330 Subject: [PATCH 29/31] Modified sliter action --- .github/workflows/slither.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/slither.yml b/.github/workflows/slither.yml index ca36bc7..da80699 100644 --- a/.github/workflows/slither.yml +++ b/.github/workflows/slither.yml @@ -18,6 +18,7 @@ jobs: - name: Run Slither uses: crytic/slither-action@v0.3.1 id: slither + continue-on-error: true with: sarif: results.sarif target: "contracts/" From 579b40de6837dfaf2dba6088808b6f97316f5bbe Mon Sep 17 00:00:00 2001 From: Amin Latifi Date: Sun, 3 Mar 2024 17:15:55 +0330 Subject: [PATCH 30/31] Modified slither action --- .github/workflows/slither.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/slither.yml b/.github/workflows/slither.yml index da80699..c71d27d 100644 --- a/.github/workflows/slither.yml +++ b/.github/workflows/slither.yml @@ -18,10 +18,9 @@ jobs: - name: Run Slither uses: crytic/slither-action@v0.3.1 id: slither - continue-on-error: true with: sarif: results.sarif - target: "contracts/" + target: "./" fail-on: none - name: Upload SARIF file From 6e5b328d07a7cc375ec47b4c8d30a932d5cebd8a Mon Sep 17 00:00:00 2001 From: Amin Latifi Date: Sun, 3 Mar 2024 18:37:49 +0330 Subject: [PATCH 31/31] Removed a repetitive function definition --- contracts/interfaces/IDistro.sol | 2 -- 1 file changed, 2 deletions(-) diff --git a/contracts/interfaces/IDistro.sol b/contracts/interfaces/IDistro.sol index c31ca94..aca73cd 100644 --- a/contracts/interfaces/IDistro.sol +++ b/contracts/interfaces/IDistro.sol @@ -101,6 +101,4 @@ interface IDistro { function claimableNow(address recipient) external view returns (uint256); function transferAllocation(address prevRecipient, address newRecipient) external; - - function sendPraiseRewards(address[] memory recipients, uint256[] memory amounts) external; }