diff --git a/contracts/airdrop/MerkleDistributor.sol b/contracts/airdrop/MerkleDistributor.sol deleted file mode 100644 index fad1e8c8..00000000 --- a/contracts/airdrop/MerkleDistributor.sol +++ /dev/null @@ -1,252 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.15; - -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; -import "@openzeppelin/contracts/access/Ownable.sol"; - -/** - * @title MerkleDistributor - * @notice Handles token airdrops from an unlimited amount of token rewards - * @dev Based on https://github.com/Uniswap/merkle-distributor but modified to handle multiple airdrops concurrently - */ -contract MerkleDistributor is Ownable { - using SafeERC20 for IERC20; - - struct Distribution { - address token; - bool isPaused; - uint256 expiryTimestamp; - bytes32 merkleRoot; - uint256 totalAmount; - mapping(address => uint256) claimed; - } - address[] public tokens; - mapping(address => Distribution) public distributions; - - event Claimed(address indexed token, uint256 index, address indexed account, uint256 amount); - event DistributionAdded(uint256 indexed tokenIndex, address indexed token, uint256 totalAmount, uint256 expiryTimestamp); - event DistributionUpdated(address indexed token, uint256 additionalAmount, uint256 expiryTimestamp); - event SetExpiryTimestamp(address indexed token, uint256 expiryTimestamp); - - modifier distributionExists(address _token) { - require(distributions[_token].token != address(0), "MerkleDistributor: Distribution does not exist."); - _; - } - - /** - * @notice returns the total amount that an account has claimed from a distribution - * @param _token token address - * @param _account address of the account to return claimed amount for - **/ - function getClaimed(address _token, address _account) external view distributionExists(_token) returns (uint256) { - return distributions[_token].claimed[_account]; - } - - /** - * @notice add multiple token distributions - * @param _tokens the list of token addresses to add - * @param _merkleRoots list of merkle roots for each distribution - * @param _totalAmounts list of total distribution amounts for each token - * @param _expiryTimestamps list of expiry timestamps for each distribution - **/ - function addDistributions( - address[] calldata _tokens, - bytes32[] calldata _merkleRoots, - uint256[] calldata _totalAmounts, - uint256[] calldata _expiryTimestamps - ) external onlyOwner { - require( - _tokens.length == _merkleRoots.length && _tokens.length == _totalAmounts.length, - "MerkleDistributor: Array lengths need to match." - ); - - for (uint256 i = 0; i < _tokens.length; i++) { - addDistribution(_tokens[i], _merkleRoots[i], _totalAmounts[i], _expiryTimestamps[i]); - } - } - - /** - * @notice add a token distribution - * @param _token token address - * @param _merkleRoot merkle root for token distribution - * @param _totalAmount total distribution amount - * @param _expiryTimestamp timestamp when unclaimed tokens can be withdrawn - **/ - function addDistribution( - address _token, - bytes32 _merkleRoot, - uint256 _totalAmount, - uint256 _expiryTimestamp - ) public onlyOwner { - require(distributions[_token].token == address(0), "MerkleDistributor: Distribution is already added."); - require(IERC20(_token).balanceOf(address(this)) >= _totalAmount, "MerkleDistributor: Insufficient balance."); - - tokens.push(_token); - distributions[_token].token = _token; - distributions[_token].merkleRoot = _merkleRoot; - distributions[_token].totalAmount = _totalAmount; - distributions[_token].expiryTimestamp = _expiryTimestamp; - - emit DistributionAdded(tokens.length - 1, _token, _totalAmount, _expiryTimestamp); - } - - /** - * @notice update multiple token distributions - * @param _tokens the list of token addresses to update - * @param _merkleRoots list of updated merkle roots for the distributions - * @param _additionalAmounts list of total additional distribution amounts for each token - * @param _expiryTimestamps list of updated expiry timestamps for each distribution - **/ - function updateDistributions( - address[] calldata _tokens, - bytes32[] calldata _merkleRoots, - uint256[] calldata _additionalAmounts, - uint256[] calldata _expiryTimestamps - ) external onlyOwner { - require( - _tokens.length == _merkleRoots.length && _tokens.length == _additionalAmounts.length, - "MerkleDistributor: Array lengths need to match." - ); - - for (uint256 i = 0; i < _tokens.length; i++) { - updateDistribution(_tokens[i], _merkleRoots[i], _additionalAmounts[i], _expiryTimestamps[i]); - } - } - - /** - * @notice update a token distribution - * @dev merkle root should be updated to reflect additional amount - the amount for each - * account should be incremented by any additional allocation and any new accounts should be added - * to the tree - * @param _token token address - * @param _merkleRoot updated merkle root for token distribution - * @param _additionalAmount total additional distribution amount - * @param _expiryTimestamp timestamp when unclaimed tokens can be withdrawn - **/ - function updateDistribution( - address _token, - bytes32 _merkleRoot, - uint256 _additionalAmount, - uint256 _expiryTimestamp - ) public onlyOwner distributionExists(_token) { - require(!distributions[_token].isPaused, "MerkleDistributor: Distribution is paused."); - require(IERC20(_token).balanceOf(address(this)) >= _additionalAmount, "MerkleDistributor: Insufficient balance."); - require(_expiryTimestamp >= distributions[_token].expiryTimestamp, "MerkleDistributor: Invalid expiry timestamp."); - - distributions[_token].merkleRoot = _merkleRoot; - distributions[_token].totalAmount += _additionalAmount; - distributions[_token].expiryTimestamp = _expiryTimestamp; - - emit DistributionUpdated(_token, _additionalAmount, _expiryTimestamp); - } - - /** - * @notice claim multiple token distributions - * @param _tokens list of token address - * @param _indexes list of indexes of the claims within the distributions - * @param _account address of the account to claim for - * @param _amounts list of lifetime amounts of the tokens allocated to account - * @param _merkleProofs list of merkle proofs for the token claims - **/ - function claimDistributions( - address[] calldata _tokens, - uint256[] calldata _indexes, - address _account, - uint256[] calldata _amounts, - bytes32[][] calldata _merkleProofs - ) external { - require( - _tokens.length == _indexes.length && _tokens.length == _amounts.length && _tokens.length == _merkleProofs.length, - "MerkleDistributor: Array lengths need to match." - ); - - for (uint256 i = 0; i < _tokens.length; i++) { - claimDistribution(_tokens[i], _indexes[i], _account, _amounts[i], _merkleProofs[i]); - } - } - - /** - * @notice claim a token distribution - * @param _token token address - * @param _index index of the claim within the distribution - * @param _account address of the account to claim for - * @param _amount lifetime amount of the token allocated to account - * @param _merkleProof the merkle proof for the token claim - **/ - function claimDistribution( - address _token, - uint256 _index, - address _account, - uint256 _amount, - bytes32[] calldata _merkleProof - ) public distributionExists(_token) { - require(!distributions[_token].isPaused, "MerkleDistributor: Distribution is paused."); - Distribution storage distribution = distributions[_token]; - - bytes32 node = keccak256(abi.encodePacked(_index, _account, _amount)); - require(MerkleProof.verify(_merkleProof, distribution.merkleRoot, node), "MerkleDistributor: Invalid proof."); - - require(distribution.claimed[_account] < _amount, "MerkleDistributor: No claimable tokens."); - - uint256 amount = _amount - distribution.claimed[_account]; - distribution.claimed[_account] = _amount; - IERC20(_token).safeTransfer(_account, amount); - - emit Claimed(_token, _index, _account, amount); - } - - /** - * @notice withdraws unclaimed tokens - * @dev merkle root should be updated to reflect current state of claims - the amount for each - * account should be equal to it's claimed amount - * @param _token token address - * @param _merkleRoot updated merkle root - * @param _totalAmount updated total amount - **/ - function withdrawUnclaimedTokens( - address _token, - bytes32 _merkleRoot, - uint256 _totalAmount - ) external onlyOwner distributionExists(_token) { - require(distributions[_token].isPaused, "MerkleDistributor: Distribution is not paused."); - - IERC20 token = IERC20(_token); - uint256 balance = token.balanceOf(address(this)); - if (balance > 0) { - token.safeTransfer(msg.sender, balance); - } - - distributions[_token].merkleRoot = _merkleRoot; - distributions[_token].totalAmount = _totalAmount; - distributions[_token].isPaused = false; - } - - /** - * @notice pauses a token distribution for withdrawal of unclaimed tokens - * @dev must be called before withdrawUnlclaimedTokens to ensure state doesn't change - * while the new merkle root is calculated - * @param _token token address - **/ - function pauseForWithdrawal(address _token) external onlyOwner distributionExists(_token) { - require( - distributions[_token].expiryTimestamp <= block.timestamp, - "MerkleDistributor: Expiry timestamp not reached." - ); - require(!distributions[_token].isPaused, "MerkleDistributor: Already paused."); - distributions[_token].isPaused = true; - } - - /** - * @notice sets the timestamp when unclaimed tokens can be withdrawn for a token distribution - * @param _token token address - * @param _expiryTimestamp expiry timestamp - **/ - function setExpiryTimestamp(address _token, uint256 _expiryTimestamp) external onlyOwner distributionExists(_token) { - require(!distributions[_token].isPaused, "MerkleDistributor: Distribution is paused."); - require(_expiryTimestamp >= distributions[_token].expiryTimestamp, "MerkleDistributor: Invalid expiry timestamp."); - distributions[_token].expiryTimestamp = _expiryTimestamp; - emit SetExpiryTimestamp(_token, _expiryTimestamp); - } -} diff --git a/deployments/mainnet.json b/deployments/mainnet.json index a082f1c1..4db39e46 100644 --- a/deployments/mainnet.json +++ b/deployments/mainnet.json @@ -51,10 +51,6 @@ "address": "0xae78736Cd615f374D3085123A210448E74Fc6393", "artifact": "ERC20" }, - "MerkleDistributor": { - "address": "0xe7Dd77d408920c000C40C35c4c111318Ba8B4767", - "artifact": "MerkleDistributor" - }, "ixETH_WrappedSDToken": { "address": "0x1A72bE10F6E6CF0CA100a407352E50d0ed653dEc", "artifact": "WrappedSDToken" diff --git a/scripts/airdrop/deploy-merkle-distributor.ts b/scripts/airdrop/deploy-merkle-distributor.ts deleted file mode 100644 index 765b4512..00000000 --- a/scripts/airdrop/deploy-merkle-distributor.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { updateDeployments, deploy } from '../utils/deployment' - -async function main() { - const merkleDistributor = await deploy('MerkleDistributor') - console.log('MerkleDistributor deployed: ', merkleDistributor.address) - - updateDeployments({ - MerkleDistributor: merkleDistributor.address, - }) -} - -main() - .then(() => process.exit(0)) - .catch((error) => { - console.error(error) - process.exit(1) - }) diff --git a/test/airdrop/merkle-distributor.test.ts b/test/airdrop/merkle-distributor.test.ts deleted file mode 100644 index 38b54f5b..00000000 --- a/test/airdrop/merkle-distributor.test.ts +++ /dev/null @@ -1,391 +0,0 @@ -import { ethers } from 'hardhat' -import { BigNumber } from 'ethers' -import { expect } from 'chai' -import { time } from '@nomicfoundation/hardhat-network-helpers' -import BalanceTree from '../utils/merkle/balance-tree' -import { deploy, getAccounts } from '../utils/helpers' -import { ERC677, MerkleDistributor } from '../../typechain-types' - -// Copied and modified from: https://github.com/Uniswap/merkle-distributor/blob/master/test/MerkleDistributor.spec.ts -// to test contract changes. -// Most tests have been removed as core functionality has not changed, focus on testing multiple distributions - -const ZERO_BYTES32 = '0x0000000000000000000000000000000000000000000000000000000000000000' - -describe('MerkleDistributor', () => { - let accounts: string[] - let wallet0: string - let wallet1: string - let token: ERC677 - - before(async () => { - ;({ accounts } = await getAccounts()) - }) - - beforeEach('deploy token', async () => { - wallet0 = accounts[1] - wallet1 = accounts[2] - - token = (await deploy('contracts/core/tokens/base/ERC677.sol:ERC677', [ - 'Token', - 'TKN', - 1000000, - ])) as ERC677 - }) - - describe('#claim', () => { - it('fails for empty proof', async () => { - const distributor = (await deploy('MerkleDistributor')) as MerkleDistributor - await distributor.addDistribution(token.address, ZERO_BYTES32, BigNumber.from(0), 0) - await expect( - distributor.claimDistribution(token.address, 0, wallet0, 10, []) - ).to.be.revertedWith('MerkleDistributor: Invalid proof.') - }) - - describe('two account tree', () => { - let distributor: MerkleDistributor - let tree: BalanceTree - beforeEach('deploy', async () => { - tree = new BalanceTree([ - { account: wallet0, amount: BigNumber.from(100) }, - { account: wallet1, amount: BigNumber.from(101) }, - ]) - distributor = (await deploy('MerkleDistributor')) as MerkleDistributor - await token.transfer(distributor.address, BigNumber.from(201)) - await distributor.addDistribution(token.address, tree.getHexRoot(), BigNumber.from(201), 0) - }) - - it('successful claim', async () => { - const proof0 = tree.getProof(0, wallet0, BigNumber.from(100)) - await expect(distributor.claimDistribution(token.address, 0, wallet0, 100, proof0)) - .to.emit(distributor, 'Claimed') - .withArgs(token.address, 0, wallet0, 100) - const proof1 = tree.getProof(1, wallet1, BigNumber.from(101)) - await expect(distributor.claimDistribution(token.address, 1, wallet1, 101, proof1)) - .to.emit(distributor, 'Claimed') - .withArgs(token.address, 1, wallet1, 101) - }) - - it('transfers the token', async () => { - const proof0 = tree.getProof(0, wallet0, BigNumber.from(100)) - expect(await token.balanceOf(wallet0)).to.eq(0) - await distributor.claimDistribution(token.address, 0, wallet0, 100, proof0) - expect(await token.balanceOf(wallet0)).to.eq(100) - }) - - it('increments claimed amount', async () => { - const proof0 = tree.getProof(0, wallet0, BigNumber.from(100)) - expect(await distributor.getClaimed(token.address, wallet0)).to.eq(0) - expect(await distributor.getClaimed(token.address, wallet1)).to.eq(0) - await distributor.claimDistribution(token.address, 0, wallet0, 100, proof0) - expect(await distributor.getClaimed(token.address, wallet0)).to.eq(100) - expect(await distributor.getClaimed(token.address, wallet1)).to.eq(0) - }) - - it('cannot allow two claims', async () => { - const proof0 = tree.getProof(0, wallet0, BigNumber.from(100)) - await distributor.claimDistribution(token.address, 0, wallet0, 100, proof0) - await expect( - distributor.claimDistribution(token.address, 0, wallet0, 100, proof0) - ).to.be.revertedWith('MerkleDistributor: No claimable tokens') - }) - - it('cannot claim more than once: 0 and then 1', async () => { - await distributor.claimDistribution( - token.address, - 0, - wallet0, - 100, - tree.getProof(0, wallet0, BigNumber.from(100)) - ) - await distributor.claimDistribution( - token.address, - 1, - wallet1, - 101, - tree.getProof(1, wallet1, BigNumber.from(101)) - ) - - await expect( - distributor.claimDistribution( - token.address, - 0, - wallet0, - 100, - tree.getProof(0, wallet0, BigNumber.from(100)) - ) - ).to.be.revertedWith('MerkleDistributor: No claimable tokens.') - }) - - it('cannot claim more than once: 1 and then 0', async () => { - await distributor.claimDistribution( - token.address, - 1, - wallet1, - 101, - tree.getProof(1, wallet1, BigNumber.from(101)) - ) - await distributor.claimDistribution( - token.address, - 0, - wallet0, - 100, - tree.getProof(0, wallet0, BigNumber.from(100)) - ) - - await expect( - distributor.claimDistribution( - token.address, - 1, - wallet1, - 101, - tree.getProof(1, wallet1, BigNumber.from(101)) - ) - ).to.be.revertedWith('MerkleDistributor: No claimable tokens.') - }) - - it('cannot claim for address other than proof', async () => { - const proof0 = tree.getProof(0, wallet0, BigNumber.from(100)) - await expect( - distributor.claimDistribution(token.address, 1, wallet1, 101, proof0) - ).to.be.revertedWith('MerkleDistributor: Invalid proof.') - }) - - it('cannot claim more than proof', async () => { - const proof0 = tree.getProof(0, wallet0, BigNumber.from(100)) - await expect( - distributor.claimDistribution(token.address, 0, wallet0, 101, proof0) - ).to.be.revertedWith('MerkleDistributor: Invalid proof.') - }) - - it('cannot claim distribution that does not exist', async () => { - const proof0 = tree.getProof(0, wallet0, BigNumber.from(100)) - await expect( - distributor.claimDistribution(wallet1, 0, wallet0, 101, proof0) - ).to.be.revertedWith('MerkleDistributor: Distribution does not exist.') - }) - - it('can set expiryTimestamp', async () => { - await distributor.setExpiryTimestamp(token.address, 100000) - expect((await distributor.distributions(token.address))[2]).to.eq(100000) - await expect(distributor.setExpiryTimestamp(token.address, 99999)).to.be.revertedWith( - 'MerkleDistributor: Invalid expiry timestamp.' - ) - await distributor.setExpiryTimestamp(token.address, 101000) - expect((await distributor.distributions(token.address))[2]).to.eq(101000) - }) - - it('can pause for withdrawal', async () => { - let ts = (await ethers.provider.getBlock(await ethers.provider.getBlockNumber())).timestamp - await distributor.setExpiryTimestamp(token.address, ts + 10000) - await expect(distributor.pauseForWithdrawal(token.address)).to.be.revertedWith( - 'Expiry timestamp not reached.' - ) - await time.increase(10000) - await distributor.pauseForWithdrawal(token.address) - expect((await distributor.distributions(token.address))[1]).to.eq(true) - }) - - it('can withdraw unclaimed tokens', async () => { - await expect( - distributor.withdrawUnclaimedTokens(token.address, tree.getHexRoot(), 0) - ).to.be.revertedWith('MerkleDistributor: Distribution is not paused.') - await distributor.claimDistribution( - token.address, - 1, - wallet1, - 101, - tree.getProof(1, wallet1, BigNumber.from(101)) - ) - await distributor.pauseForWithdrawal(token.address) - await distributor.withdrawUnclaimedTokens(token.address, tree.getHexRoot(), 101) - let distribution = await distributor.distributions(token.address) - expect(distribution[1]).to.eq(false) - expect(distribution[3]).to.eq(tree.getHexRoot()) - expect(distribution[4]).to.eq(101) - expect(await token.balanceOf(distributor.address)).to.eq(BigNumber.from(0)) - }) - }) - - describe('multiple distributions', () => { - let distributor: MerkleDistributor - let tree: BalanceTree - let token2: ERC677 - let token3: ERC677 - beforeEach('deploy', async () => { - token2 = (await deploy('contracts/core/tokens/base/ERC677.sol:ERC677', [ - 'Token', - 'TKN', - 1000000, - ])) as ERC677 - token3 = (await deploy('contracts/core/tokens/base/ERC677.sol:ERC677', [ - 'Token', - 'TKN', - 1000000, - ])) as ERC677 - tree = new BalanceTree([ - { account: wallet0, amount: BigNumber.from(100) }, - { account: wallet1, amount: BigNumber.from(101) }, - ]) - distributor = (await deploy('MerkleDistributor')) as MerkleDistributor - await token.approve(distributor.address, ethers.constants.MaxUint256) - await token2.approve(distributor.address, ethers.constants.MaxUint256) - await token3.approve(distributor.address, ethers.constants.MaxUint256) - const proof0 = tree.getProof(0, wallet0, BigNumber.from(100)) - await expect( - distributor.claimDistribution(wallet1, 0, wallet0, 101, proof0) - ).to.be.revertedWith('MerkleDistributor: Distribution does not exist.') - await token.transfer(distributor.address, BigNumber.from(201)) - await token2.transfer(distributor.address, BigNumber.from(201)) - await token3.transfer(distributor.address, BigNumber.from(201)) - await distributor.addDistributions( - [token.address, token2.address, token3.address], - [tree.getHexRoot(), tree.getHexRoot(), tree.getHexRoot()], - [BigNumber.from(201), BigNumber.from(201), BigNumber.from(201)], - [0, 0, 0] - ) - }) - - it('successful claim', async () => { - const proof0 = tree.getProof(0, wallet0, BigNumber.from(100)) - await expect(distributor.claimDistribution(token.address, 0, wallet0, 100, proof0)) - .to.emit(distributor, 'Claimed') - .withArgs(token.address, 0, wallet0, 100) - await expect(distributor.claimDistribution(token2.address, 0, wallet0, 100, proof0)) - .to.emit(distributor, 'Claimed') - .withArgs(token2.address, 0, wallet0, 100) - const proof1 = tree.getProof(1, wallet1, BigNumber.from(101)) - await expect(distributor.claimDistribution(token.address, 1, wallet1, 101, proof1)) - .to.emit(distributor, 'Claimed') - .withArgs(token.address, 1, wallet1, 101) - await expect(distributor.claimDistribution(token3.address, 1, wallet1, 101, proof1)) - .to.emit(distributor, 'Claimed') - .withArgs(token3.address, 1, wallet1, 101) - }) - - it('transfers the token', async () => { - const proof0 = tree.getProof(0, wallet0, BigNumber.from(100)) - expect(await token.balanceOf(wallet0)).to.eq(0) - await distributor.claimDistribution(token.address, 0, wallet0, 100, proof0) - expect(await token.balanceOf(wallet0)).to.eq(100) - await distributor.claimDistribution(token2.address, 0, wallet0, 100, proof0) - expect(await token2.balanceOf(wallet0)).to.eq(100) - await distributor.claimDistribution(token3.address, 0, wallet0, 100, proof0) - expect(await token3.balanceOf(wallet0)).to.eq(100) - }) - - it('increments claimed amount', async () => { - const proof0 = tree.getProof(0, wallet0, BigNumber.from(100)) - expect(await distributor.getClaimed(token.address, wallet0)).to.eq(0) - expect(await distributor.getClaimed(token.address, wallet1)).to.eq(0) - await distributor.claimDistribution(token.address, 0, wallet0, 100, proof0) - expect(await distributor.getClaimed(token.address, wallet0)).to.eq(100) - expect(await distributor.getClaimed(token.address, wallet1)).to.eq(0) - - expect(await distributor.getClaimed(token2.address, wallet0)).to.eq(0) - expect(await distributor.getClaimed(token2.address, wallet1)).to.eq(0) - await distributor.claimDistribution(token2.address, 0, wallet0, 100, proof0) - expect(await distributor.getClaimed(token2.address, wallet0)).to.eq(100) - expect(await distributor.getClaimed(token2.address, wallet1)).to.eq(0) - }) - - it('cannot allow two claims', async () => { - const proof0 = tree.getProof(0, wallet0, BigNumber.from(100)) - await distributor.claimDistribution(token.address, 0, wallet0, 100, proof0) - await expect( - distributor.claimDistribution(token.address, 0, wallet0, 100, proof0) - ).to.be.revertedWith('MerkleDistributor: No claimable tokens.') - - await distributor.claimDistribution(token2.address, 0, wallet0, 100, proof0) - await expect( - distributor.claimDistribution(token2.address, 0, wallet0, 100, proof0) - ).to.be.revertedWith('MerkleDistributor: No claimable tokens.') - }) - - it('cannot add distributions of unequal length', async () => { - await expect( - distributor.addDistributions( - [token.address, token2.address, token2.address], - [tree.getHexRoot(), tree.getHexRoot()], - [BigNumber.from(201), BigNumber.from(201)], - [0, 0] - ) - ).to.be.revertedWith('MerkleDistributor: Array lengths need to match.') - }) - - it('can update distributions', async () => { - const newTree = new BalanceTree([ - { account: wallet0, amount: BigNumber.from(200) }, - { account: wallet1, amount: BigNumber.from(201) }, - ]) - let proof0 = tree.getProof(0, wallet0, BigNumber.from(100)) - - await distributor.claimDistribution(token.address, 0, wallet0, 100, proof0) - await token.transfer(distributor.address, BigNumber.from(200)) - await token3.transfer(distributor.address, BigNumber.from(200)) - await distributor.updateDistributions( - [token.address, token3.address], - [newTree.getHexRoot(), newTree.getHexRoot()], - [BigNumber.from(200), BigNumber.from(200)], - [100, 0] - ) - - expect((await distributor.distributions(token.address))[2]).to.eq(100) - expect((await distributor.distributions(token.address))[4]).to.eq(401) - - proof0 = newTree.getProof(0, wallet0, BigNumber.from(200)) - let proof1 = newTree.getProof(1, wallet1, BigNumber.from(201)) - - await distributor.claimDistribution(token.address, 0, wallet0, 200, proof0) - await distributor.claimDistribution(token.address, 1, wallet1, 201, proof1) - await distributor.claimDistribution(token3.address, 0, wallet0, 200, proof0) - await distributor.claimDistribution(token3.address, 1, wallet1, 201, proof1) - expect(await distributor.getClaimed(token.address, wallet0)).to.eq(200) - expect(await distributor.getClaimed(token.address, wallet1)).to.eq(201) - expect(await distributor.getClaimed(token3.address, wallet0)).to.eq(200) - expect(await distributor.getClaimed(token3.address, wallet1)).to.eq(201) - expect(await token.balanceOf(wallet0)).to.eq(200) - expect(await token.balanceOf(wallet1)).to.eq(201) - expect(await token3.balanceOf(wallet0)).to.eq(200) - expect(await token3.balanceOf(wallet1)).to.eq(201) - }) - - it('cannot update distributions of unequal length', async () => { - await expect( - distributor.updateDistributions( - [token.address, token2.address, token2.address], - [tree.getHexRoot(), tree.getHexRoot()], - [BigNumber.from(201), BigNumber.from(201)], - [0, 0] - ) - ).to.be.revertedWith('MerkleDistributor: Array lengths need to match.') - }) - - it('cannot update distribution that does not exist', async () => { - await token.transfer(distributor.address, BigNumber.from(201)) - await expect( - distributor.updateDistributions( - [token.address, wallet1], - [tree.getHexRoot(), tree.getHexRoot()], - [BigNumber.from(201), BigNumber.from(201)], - [0, 0] - ) - ).to.be.revertedWith('MerkleDistributor: Distribution does not exist.') - }) - - it('can claim multiple distributions', async () => { - const proof0 = tree.getProof(0, wallet0, BigNumber.from(100)) - - await distributor.claimDistributions( - [token.address, token3.address], - [0, 0], - wallet0, - [100, 100], - [proof0, proof0] - ) - expect(await distributor.getClaimed(token.address, wallet0)).to.eq(100) - expect(await distributor.getClaimed(token3.address, wallet0)).to.eq(100) - }) - }) - }) -}) diff --git a/test/foundry/Base.t.sol b/test/foundry/Base.t.sol index 50bd3812..9582f42f 100644 --- a/test/foundry/Base.t.sol +++ b/test/foundry/Base.t.sol @@ -4,18 +4,16 @@ pragma solidity ^0.8.15; import {Test, console2} from "forge-std/Test.sol"; import {Users} from "./utils/Types.sol"; import {Utils} from "./utils/Utils.sol"; -import {MerkleDistributor} from "../../contracts/airdrop/MerkleDistributor.sol"; abstract contract BaseTest is Test, Utils { Users internal users; uint256 internal network; - MerkleDistributor public merkleDistributor; function init(bool _fork) public { if (_fork) { network = vm.createSelectFork(vm.rpcUrl("ethereum")); } else { - merkleDistributor = new MerkleDistributor(); + //merkleDistributor = new MerkleDistributor(); } } } diff --git a/test/foundry/fork/MerkleDistributorFork.t.sol b/test/foundry/fork/MerkleDistributorFork.t.sol deleted file mode 100644 index 496d58ce..00000000 --- a/test/foundry/fork/MerkleDistributorFork.t.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.15; - -import {MerkleDistributor} from "../../../contracts/airdrop/MerkleDistributor.sol"; -import {BaseTest} from "../Base.t.sol"; -import {ERC677} from "../../../contracts/core/tokens/base/ERC677.sol"; - -contract MerkleDistributorForkTest is BaseTest { - bool internal _fork = true; - - function setUp() public { - BaseTest.init(_fork); - } -} diff --git a/test/foundry/unit/MerkleDistributor.t.sol b/test/foundry/unit/MerkleDistributor.t.sol deleted file mode 100644 index 4a9e15e6..00000000 --- a/test/foundry/unit/MerkleDistributor.t.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.15; - -import {MerkleDistributor} from "../../../contracts/airdrop/MerkleDistributor.sol"; -import {BaseTest} from "../Base.t.sol"; -import {ERC677} from "../../../contracts/core/tokens/base/ERC677.sol"; - -contract MerkleDistributorTest is BaseTest { - bool internal _fork = false; - - function setUp() public { - BaseTest.init(_fork); - } - - function test_claimDistribution_EmptyProof() public { - ERC677 _testToken = new ERC677("Token", "TKN", 1000000); - merkleDistributor.addDistribution(address(_testToken), bytes32(""), 0, 0); - bytes32[] memory _proof = new bytes32[](0); - vm.expectRevert("MerkleDistributor: Invalid proof."); - merkleDistributor.claimDistribution(address(_testToken), 0, users.user1, 10, _proof); - } -}