diff --git a/packages/faucets/contracts/FaucetsERC1155.md b/packages/faucets/contracts/FaucetsERC1155.md index 8bcc82ed12..82a4009d2e 100644 --- a/packages/faucets/contracts/FaucetsERC1155.md +++ b/packages/faucets/contracts/FaucetsERC1155.md @@ -87,6 +87,14 @@ event Withdrawn(address indexed faucet, address indexed receiver, uint256[] toke modifier exists(address faucet) ``` +Modifier to check if the faucet exists. + + +Parameters: + +| Name | Type | Description | +| :----- | :------ | :------------------------- | +| faucet | address | The address of the faucet. | ## Functions info @@ -183,6 +191,40 @@ Parameters: | faucet | address | The address of the faucet. | | newLimit | uint256 | The new maximum amount of tokens a user can claim at once. | +### faucetExists (0x860ddec0) + +```solidity +function faucetExists(address faucet) public view returns (bool) +``` + +External function to check the existence of a given faucet. + + +Parameters: + +| Name | Type | Description | +| :----- | :------ | :------------------------- | +| faucet | address | The address of the faucet. | + +### tokenExistsInFaucet (0xab9a7f86) + +```solidity +function tokenExistsInFaucet( + address faucet, + uint256 tokenId +) public view exists(faucet) returns (bool) +``` + +External function to check the existence of a given faucet and token. + + +Parameters: + +| Name | Type | Description | +| :------ | :------ | :-------------------------- | +| faucet | address | The address of the faucet. | +| tokenId | uint256 | The id of the token. | + ### addFaucet (0xe2337fa8) ```solidity @@ -253,6 +295,23 @@ Parameters: | :----- | :------ | :------------------------------------ | | faucet | address | Address of the faucet to be disabled. | +### isFaucetEnabled (0xfc490550) + +```solidity +function isFaucetEnabled( + address faucet +) public view exists(faucet) returns (bool) +``` + +Determines whether a faucet is enabled. + + +Parameters: + +| Name | Type | Description | +| :----- | :------ | :--------------------- | +| faucet | address | Address of the faucet. | + ### removeTokens (0xecae5383) ```solidity diff --git a/packages/faucets/contracts/FaucetsERC1155.sol b/packages/faucets/contracts/FaucetsERC1155.sol index c11172d353..59d44ef08c 100644 --- a/packages/faucets/contracts/FaucetsERC1155.sol +++ b/packages/faucets/contracts/FaucetsERC1155.sol @@ -88,12 +88,40 @@ contract FaucetsERC1155 is Ownable, ERC1155Holder, ReentrancyGuard { emit LimitUpdated(faucet, newLimit); } - // Modifier to check if the faucet exists. + /** + * @dev Internal function to check the existence of a given faucet. + * @param faucet The address of the faucet. + */ + function _exists(address faucet) internal view returns (bool) { + return faucets[faucet].isFaucet; + } + + /** + * @dev External function to check the existence of a given faucet. + * @param faucet The address of the faucet. + */ + function faucetExists(address faucet) public view returns (bool) { + return _exists(faucet); + } + + /** + * @dev Modifier to check if the faucet exists. + * @param faucet The address of the faucet. + */ modifier exists(address faucet) { - require(faucets[faucet].isFaucet, "Faucets: FAUCET_DOES_NOT_EXIST"); + require(_exists(faucet), "Faucets: FAUCET_DOES_NOT_EXIST"); _; } + /** + * @dev External function to check the existence of a given faucet and token. + * @param faucet The address of the faucet. + * @param tokenId The id of the token. + */ + function tokenExistsInFaucet(address faucet, uint256 tokenId) public view exists(faucet) returns (bool) { + return faucets[faucet].tokenIdExists[tokenId]; + } + /** * @dev Add a new faucet to the system. * @param faucet The address of the ERC1155 token contract to be used as faucet. @@ -102,7 +130,7 @@ contract FaucetsERC1155 is Ownable, ERC1155Holder, ReentrancyGuard { * @param tokenIds List of token IDs that this faucet will distribute. */ function addFaucet(address faucet, uint256 period, uint256 limit, uint256[] memory tokenIds) public onlyOwner { - require(!faucets[faucet].isFaucet, "Faucets: FAUCET_ALREADY_EXISTS"); + require(!_exists(faucet), "Faucets: FAUCET_ALREADY_EXISTS"); require(limit > 0, "Faucets: LIMIT_ZERO"); require(tokenIds.length > 0, "Faucets: TOKENS_CANNOT_BE_EMPTY"); @@ -155,6 +183,15 @@ contract FaucetsERC1155 is Ownable, ERC1155Holder, ReentrancyGuard { emit FaucetStatusChanged(faucet, false); } + /** + * @dev Determines whether a faucet is enabled. + * @param faucet Address of the faucet. + */ + function isFaucetEnabled(address faucet) public view exists(faucet) returns (bool) { + FaucetInfo storage faucetInfo = faucets[faucet]; + return faucetInfo.isEnabled; + } + /** * @dev Remove specific tokens from a faucet. * @param faucet Address of the faucet. @@ -173,6 +210,7 @@ contract FaucetsERC1155 is Ownable, ERC1155Holder, ReentrancyGuard { bool shouldSkip = false; for (uint256 j = 0; j < tokenIds.length; j++) { if (currentTokenIds[i] == tokenIds[j]) { + faucetInfo.tokenIdExists[currentTokenIds[i]] = false; shouldSkip = true; break; } diff --git a/packages/faucets/test/faucetsERC1155.ts b/packages/faucets/test/faucetsERC1155.ts index 5f2eecb936..1eed9310f3 100644 --- a/packages/faucets/test/faucetsERC1155.ts +++ b/packages/faucets/test/faucetsERC1155.ts @@ -2,359 +2,526 @@ import {expect} from 'chai'; import {loadFixture} from '@nomicfoundation/hardhat-network-helpers'; import {setupFaucetERC1155} from './fixtures'; import {mine, time} from '@nomicfoundation/hardhat-network-helpers'; +import {ethers} from 'hardhat'; describe('FaucetsERC1155', function () { - it('Should allow a user to claim ERC1155 tokens', async function () { - const { - otherAccount, - mockAssetERC1155, - faucetsERC1155, - fakeAssets, - faucetLimit, - } = await loadFixture(setupFaucetERC1155); - - const otherAccountAddress = await otherAccount.getAddress(); - const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); - await faucetsERC1155 - .connect(otherAccount) - .claim(mockAssetERC1155Address, fakeAssets[0].id, faucetLimit); - const otherAccountBalance = await mockAssetERC1155.balanceOf( - otherAccountAddress, - fakeAssets[0].id - ); - expect(otherAccountBalance).to.equal(faucetLimit); + describe('Deployment', function () { + it('Should set the right owner', async function () { + const {faucetsERC1155, owner} = await loadFixture(setupFaucetERC1155); + const ownerAddress = await owner.getAddress(); + expect(await faucetsERC1155.owner()).to.equal(ownerAddress); + }); }); - it('Should not allow a user to claim more than the limit', async function () { - const { - otherAccount, - mockAssetERC1155, - faucetsERC1155, - faucetLimit, - fakeAssets, - } = await loadFixture(setupFaucetERC1155); - const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); - - await expect( - faucetsERC1155 - .connect(otherAccount) - .claim(mockAssetERC1155Address, fakeAssets[0].id, faucetLimit + 1) - ).to.be.revertedWith('Faucets: AMOUNT_TOO_HIGH'); - }); - - it('Should not allow a user to claim before the faucet period expires', async function () { - const { - otherAccount, - mockAssetERC1155, - faucetsERC1155, - faucetLimit, - fakeAssets, - } = await loadFixture(setupFaucetERC1155); - const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); - - await faucetsERC1155 - .connect(otherAccount) - .claim(mockAssetERC1155Address, fakeAssets[0].id, faucetLimit); - await expect( - faucetsERC1155 - .connect(otherAccount) - .claim(mockAssetERC1155Address, fakeAssets[0].id, faucetLimit) - ).to.be.revertedWith('Faucets: CLAIM_PERIOD_NOT_PASSED'); - }); - - it('Should allow a user to claim after the faucet period expires', async function () { - const { - otherAccount, - mockAssetERC1155, - faucetsERC1155, - faucetLimit, - fakeAssets, - faucetPeriod, - } = await loadFixture(setupFaucetERC1155); - const otherAccountAddress = await otherAccount.getAddress(); - const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); - - await faucetsERC1155 - .connect(otherAccount) - .claim(mockAssetERC1155Address, fakeAssets[0].id, faucetLimit); - - await time.increase(faucetPeriod); - await mine(); - - await faucetsERC1155 - .connect(otherAccount) - .claim(mockAssetERC1155Address, fakeAssets[0].id, faucetLimit); - const otherAccountBalance = await mockAssetERC1155.balanceOf( - otherAccountAddress, - fakeAssets[0].id - ); - expect(otherAccountBalance).to.equal(faucetLimit * 2); - }); + describe('Limit', function () { + it('Should set and get limit correctly', async function () { + const {owner, mockAssetERC1155, faucetsERC1155, faucetLimit} = + await loadFixture(setupFaucetERC1155); - it("Should not allow a user to claim if the faucet doesn't have enough tokens", async function () { - const {otherAccount, mockAssetERC1155, faucetsERC1155, fakeAssets} = - await loadFixture(setupFaucetERC1155); - const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); + const mockAssetAddress = mockAssetERC1155.getAddress(); - const highAmount = fakeAssets[1].supply + 1; - await expect( - faucetsERC1155 - .connect(otherAccount) - .claim(mockAssetERC1155Address, fakeAssets[1].id, highAmount) - ).to.be.revertedWith('Faucets: BALANCE_IS_NOT_ENOUGH'); - }); + let limit = await faucetsERC1155.getLimit(mockAssetAddress); + expect(limit).to.equal(faucetLimit); - it("Should correctly get the faucet's period", async function () { - const {mockAssetERC1155, faucetsERC1155, faucetPeriod} = await loadFixture( - setupFaucetERC1155 - ); - const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); + const newLimit = faucetLimit * 2; + await faucetsERC1155.connect(owner).setLimit(mockAssetAddress, newLimit); - const period = await faucetsERC1155.getPeriod(mockAssetERC1155Address); - expect(period).to.equal(faucetPeriod); + limit = await faucetsERC1155.getLimit(mockAssetAddress); + expect(limit).to.equal(newLimit); + }); }); - it('Should allow the owner to set a new faucet period', async function () { - const {owner, mockAssetERC1155, faucetsERC1155} = await loadFixture( - setupFaucetERC1155 - ); - const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); - - const newPeriod = 7200; - await faucetsERC1155 - .connect(owner) - .setPeriod(mockAssetERC1155Address, newPeriod); - - const updatedPeriod = await faucetsERC1155.getPeriod( - mockAssetERC1155Address - ); - expect(updatedPeriod).to.equal(newPeriod); - }); + describe('Claim', function () { + it('Should allow a user to claim ERC1155 tokens', async function () { + const { + otherAccount, + mockAssetERC1155, + faucetsERC1155, + fakeAssets, + faucetLimit, + } = await loadFixture(setupFaucetERC1155); + + const otherAccountAddress = await otherAccount.getAddress(); + const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); + await faucetsERC1155 + .connect(otherAccount) + .claim(mockAssetERC1155Address, fakeAssets[0].id, faucetLimit); + const otherAccountBalance = await mockAssetERC1155.balanceOf( + otherAccountAddress, + fakeAssets[0].id + ); + expect(otherAccountBalance).to.equal(faucetLimit); + }); + + it('Should not allow a user to claim more than the limit', async function () { + const { + otherAccount, + mockAssetERC1155, + faucetsERC1155, + faucetLimit, + fakeAssets, + } = await loadFixture(setupFaucetERC1155); + const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); + + await expect( + faucetsERC1155 + .connect(otherAccount) + .claim(mockAssetERC1155Address, fakeAssets[0].id, faucetLimit + 1) + ).to.be.revertedWith('Faucets: AMOUNT_TOO_HIGH'); + }); + + it('Should correctly determine if a user can claim tokens or not', async function () { + const { + otherAccount, + mockAssetERC1155, + faucetsERC1155, + fakeAssets, + faucetLimit, + faucetPeriod, + } = await loadFixture(setupFaucetERC1155); + + const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); + const otherAccountAddress = await otherAccount.getAddress(); + + let canClaim = await faucetsERC1155.canClaim( + mockAssetERC1155Address, + fakeAssets[0].id, + otherAccountAddress + ); + expect(canClaim).to.equal(true); + + await faucetsERC1155 + .connect(otherAccount) + .claim(mockAssetERC1155Address, fakeAssets[0].id, faucetLimit); + + canClaim = await faucetsERC1155.canClaim( + mockAssetERC1155Address, + fakeAssets[0].id, + otherAccountAddress + ); + expect(canClaim).to.equal(false); + + await time.increase(faucetPeriod); + await mine(); + + canClaim = await faucetsERC1155.canClaim( + mockAssetERC1155Address, + fakeAssets[0].id, + otherAccountAddress + ); + expect(canClaim).to.equal(true); + }); + + it('Should not allow a user to claim before the faucet period expires', async function () { + const { + otherAccount, + mockAssetERC1155, + faucetsERC1155, + faucetLimit, + fakeAssets, + } = await loadFixture(setupFaucetERC1155); + const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); + + await faucetsERC1155 + .connect(otherAccount) + .claim(mockAssetERC1155Address, fakeAssets[0].id, faucetLimit); + await expect( + faucetsERC1155 + .connect(otherAccount) + .claim(mockAssetERC1155Address, fakeAssets[0].id, faucetLimit) + ).to.be.revertedWith('Faucets: CLAIM_PERIOD_NOT_PASSED'); + }); + + it('Should allow a user to claim after the faucet period expires', async function () { + const { + otherAccount, + mockAssetERC1155, + faucetsERC1155, + faucetLimit, + fakeAssets, + faucetPeriod, + } = await loadFixture(setupFaucetERC1155); + const otherAccountAddress = await otherAccount.getAddress(); + const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); + + await faucetsERC1155 + .connect(otherAccount) + .claim(mockAssetERC1155Address, fakeAssets[0].id, faucetLimit); - it('Should not allow a non-owner to set a new faucet period', async function () { - const {otherAccount, mockAssetERC1155, faucetsERC1155} = await loadFixture( - setupFaucetERC1155 - ); - const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); + await time.increase(faucetPeriod); + await mine(); - const newPeriod = 7200; - await expect( - faucetsERC1155 + await faucetsERC1155 .connect(otherAccount) - .setPeriod(mockAssetERC1155Address, newPeriod) - ).to.be.revertedWith('Ownable: caller is not the owner'); + .claim(mockAssetERC1155Address, fakeAssets[0].id, faucetLimit); + const otherAccountBalance = await mockAssetERC1155.balanceOf( + otherAccountAddress, + fakeAssets[0].id + ); + expect(otherAccountBalance).to.equal(faucetLimit * 2); + }); + + it("Should not allow a user to claim if the faucet doesn't have enough tokens", async function () { + const {otherAccount, mockAssetERC1155, faucetsERC1155, fakeAssets} = + await loadFixture(setupFaucetERC1155); + const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); + + const highAmount = fakeAssets[1].supply + 1; + await expect( + faucetsERC1155 + .connect(otherAccount) + .claim(mockAssetERC1155Address, fakeAssets[1].id, highAmount) + ).to.be.revertedWith('Faucets: BALANCE_IS_NOT_ENOUGH'); + }); }); - it("Should allow the owner to withdraw all the faucet's tokens", async function () { - const {owner, mockAssetERC1155, faucetsERC1155, fakeAssets} = - await loadFixture(setupFaucetERC1155); - const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); - const faucetsERC1155Address = await faucetsERC1155.getAddress(); - const ownerAddress = await owner.getAddress(); - const erc1155TokenIds = [fakeAssets[0].id, fakeAssets[1].id]; - - const faucetBalanceBefore = await mockAssetERC1155.balanceOf( - faucetsERC1155Address, - fakeAssets[0].id - ); - expect(faucetBalanceBefore).to.be.gt(0); - - await faucetsERC1155 - .connect(owner) - .withdraw(mockAssetERC1155Address, ownerAddress, erc1155TokenIds); - - const faucetBalanceAfter = await mockAssetERC1155.balanceOf( - faucetsERC1155Address, - fakeAssets[0].id - ); - const ownerBalanceAfter = await mockAssetERC1155.balanceOf( - ownerAddress, - fakeAssets[0].id - ); - - expect(faucetBalanceAfter).to.equal(0); - expect(ownerBalanceAfter).to.equal(faucetBalanceBefore); - }); + describe('Claim Batch', function () { + it('Should allow a user to batch claim multiple ERC1155 tokens from a single faucet', async function () { + const { + otherAccount, + mockAssetERC1155, + faucetsERC1155, + fakeAssets, + faucetLimit, + } = await loadFixture(setupFaucetERC1155); + const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); + const otherAccountAddress = await otherAccount.getAddress(); + const erc1155TokenIds = [fakeAssets[0].id, fakeAssets[1].id]; + + const claimAmounts = [faucetLimit, fakeAssets[1].supply - 1]; + + await faucetsERC1155 + .connect(otherAccount) + .claimBatch(mockAssetERC1155Address, erc1155TokenIds, claimAmounts); + + const balanceTokenA = await mockAssetERC1155.balanceOf( + otherAccountAddress, + erc1155TokenIds[0] + ); + const balanceTokenB = await mockAssetERC1155.balanceOf( + otherAccountAddress, + erc1155TokenIds[1] + ); + + expect(balanceTokenA).to.equal(claimAmounts[0]); + expect(balanceTokenB).to.equal(claimAmounts[1]); + }); + + it('Should not allow a user to batch claim amounts greater than the set limits', async function () { + const { + otherAccount, + mockAssetERC1155, + faucetsERC1155, + fakeAssets, + faucetLimit, + } = await loadFixture(setupFaucetERC1155); + const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); + const erc1155TokenIds = [fakeAssets[0].id, fakeAssets[1].id]; + const excessiveAmounts = [faucetLimit + 1, fakeAssets[1].supply + 1]; + + await expect( + faucetsERC1155 + .connect(otherAccount) + .claimBatch( + mockAssetERC1155Address, + erc1155TokenIds, + excessiveAmounts + ) + ).to.be.revertedWith('Faucets: AMOUNT_TOO_HIGH'); + }); + + it('Should not allow a user to batch claim before the faucet period expires', async function () { + const { + otherAccount, + mockAssetERC1155, + faucetsERC1155, + fakeAssets, + faucetLimit, + } = await loadFixture(setupFaucetERC1155); + const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); + const erc1155TokenIds = [fakeAssets[0].id, fakeAssets[1].id]; + + await faucetsERC1155 + .connect(otherAccount) + .claimBatch(mockAssetERC1155Address, erc1155TokenIds, [ + faucetLimit, + 10, + ]); + + await expect( + faucetsERC1155 + .connect(otherAccount) + .claimBatch(mockAssetERC1155Address, erc1155TokenIds, [ + faucetLimit, + 10, + ]) + ).to.be.revertedWith('Faucets: CLAIM_PERIOD_NOT_PASSED'); + }); + + it('Should allow a user to batch claim after the faucet period expires', async function () { + const { + otherAccount, + mockAssetERC1155, + faucetsERC1155, + fakeAssets, + faucetLimit, + faucetPeriod, + } = await loadFixture(setupFaucetERC1155); + const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); + const otherAccountAddress = await otherAccount.getAddress(); + const erc1155TokenIds = [fakeAssets[0].id, fakeAssets[1].id]; + + await faucetsERC1155 + .connect(otherAccount) + .claimBatch(mockAssetERC1155Address, erc1155TokenIds, [ + faucetLimit, + 10, + ]); - it("Should not allow a non-owner to withdraw the faucet's tokens", async function () { - const {otherAccount, mockAssetERC1155, faucetsERC1155, fakeAssets} = - await loadFixture(setupFaucetERC1155); - const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); - const otherAccountAddress = await otherAccount.getAddress(); - const erc1155TokenIds = [fakeAssets[0].id, fakeAssets[1].id]; + await time.increase(faucetPeriod); + await mine(); - await expect( - faucetsERC1155 + await faucetsERC1155 .connect(otherAccount) - .withdraw(mockAssetERC1155Address, otherAccountAddress, erc1155TokenIds) - ).to.be.revertedWith('Ownable: caller is not the owner'); + .claimBatch(mockAssetERC1155Address, erc1155TokenIds, [ + faucetLimit, + 10, + ]); + + const balanceTokenA = await mockAssetERC1155.balanceOf( + otherAccountAddress, + erc1155TokenIds[0] + ); + const balanceTokenB = await mockAssetERC1155.balanceOf( + otherAccountAddress, + erc1155TokenIds[1] + ); + + expect(balanceTokenA).to.equal(faucetLimit * 2); + expect(balanceTokenB).to.equal(20); + }); + + it('Should revert if trying to batch claim for tokens not in the faucet', async function () { + const {otherAccount, mockAssetERC1155, faucetsERC1155, faucetLimit} = + await loadFixture(setupFaucetERC1155); + const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); + const notInFaucetTokenId = 9999; + + await expect( + faucetsERC1155 + .connect(otherAccount) + .claimBatch( + mockAssetERC1155Address, + [notInFaucetTokenId], + [faucetLimit] + ) + ).to.be.revertedWith('Faucets: TOKEN_DOES_NOT_EXIST'); + }); }); - it('Should allow a user to batch claim multiple ERC1155 tokens from a single faucet', async function () { - const { - otherAccount, - mockAssetERC1155, - faucetsERC1155, - fakeAssets, - faucetLimit, - } = await loadFixture(setupFaucetERC1155); - const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); - const otherAccountAddress = await otherAccount.getAddress(); - const erc1155TokenIds = [fakeAssets[0].id, fakeAssets[1].id]; - - const claimAmounts = [faucetLimit, fakeAssets[1].supply - 1]; - - await faucetsERC1155 - .connect(otherAccount) - .claimBatch(mockAssetERC1155Address, erc1155TokenIds, claimAmounts); - - const balanceTokenA = await mockAssetERC1155.balanceOf( - otherAccountAddress, - erc1155TokenIds[0] - ); - const balanceTokenB = await mockAssetERC1155.balanceOf( - otherAccountAddress, - erc1155TokenIds[1] - ); - - expect(balanceTokenA).to.equal(claimAmounts[0]); - expect(balanceTokenB).to.equal(claimAmounts[1]); + describe('Period', function () { + it("Should correctly get the faucet's period", async function () { + const {mockAssetERC1155, faucetsERC1155, faucetPeriod} = + await loadFixture(setupFaucetERC1155); + const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); + + const period = await faucetsERC1155.getPeriod(mockAssetERC1155Address); + expect(period).to.equal(faucetPeriod); + }); + + it('Should allow the owner to set a new faucet period', async function () { + const {owner, mockAssetERC1155, faucetsERC1155} = await loadFixture( + setupFaucetERC1155 + ); + const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); + + const newPeriod = 7200; + await faucetsERC1155 + .connect(owner) + .setPeriod(mockAssetERC1155Address, newPeriod); + + const updatedPeriod = await faucetsERC1155.getPeriod( + mockAssetERC1155Address + ); + expect(updatedPeriod).to.equal(newPeriod); + }); + + it('Should not allow a non-owner to set a new faucet period', async function () { + const {otherAccount, mockAssetERC1155, faucetsERC1155} = + await loadFixture(setupFaucetERC1155); + const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); + + const newPeriod = 7200; + await expect( + faucetsERC1155 + .connect(otherAccount) + .setPeriod(mockAssetERC1155Address, newPeriod) + ).to.be.revertedWith('Ownable: caller is not the owner'); + }); }); - it('Should not allow a user to batch claim amounts greater than the set limits', async function () { - const { - otherAccount, - mockAssetERC1155, - faucetsERC1155, - fakeAssets, - faucetLimit, - } = await loadFixture(setupFaucetERC1155); - const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); - const erc1155TokenIds = [fakeAssets[0].id, fakeAssets[1].id]; - const excessiveAmounts = [faucetLimit + 1, fakeAssets[1].supply + 1]; - - await expect( - faucetsERC1155 - .connect(otherAccount) - .claimBatch(mockAssetERC1155Address, erc1155TokenIds, excessiveAmounts) - ).to.be.revertedWith('Faucets: AMOUNT_TOO_HIGH'); + describe('Withdraw', function () { + it("Should allow the owner to withdraw all the faucet's tokens", async function () { + const {owner, mockAssetERC1155, faucetsERC1155, fakeAssets} = + await loadFixture(setupFaucetERC1155); + const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); + const faucetsERC1155Address = await faucetsERC1155.getAddress(); + const ownerAddress = await owner.getAddress(); + const erc1155TokenIds = [fakeAssets[0].id, fakeAssets[1].id]; + + const faucetBalanceBefore = await mockAssetERC1155.balanceOf( + faucetsERC1155Address, + fakeAssets[0].id + ); + expect(faucetBalanceBefore).to.be.gt(0); + + await faucetsERC1155 + .connect(owner) + .withdraw(mockAssetERC1155Address, ownerAddress, erc1155TokenIds); + + const faucetBalanceAfter = await mockAssetERC1155.balanceOf( + faucetsERC1155Address, + fakeAssets[0].id + ); + const ownerBalanceAfter = await mockAssetERC1155.balanceOf( + ownerAddress, + fakeAssets[0].id + ); + + expect(faucetBalanceAfter).to.equal(0); + expect(ownerBalanceAfter).to.equal(faucetBalanceBefore); + }); + + it("Should not allow a non-owner to withdraw the faucet's tokens", async function () { + const {otherAccount, mockAssetERC1155, faucetsERC1155, fakeAssets} = + await loadFixture(setupFaucetERC1155); + const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); + const otherAccountAddress = await otherAccount.getAddress(); + const erc1155TokenIds = [fakeAssets[0].id, fakeAssets[1].id]; + + await expect( + faucetsERC1155 + .connect(otherAccount) + .withdraw( + mockAssetERC1155Address, + otherAccountAddress, + erc1155TokenIds + ) + ).to.be.revertedWith('Ownable: caller is not the owner'); + }); }); - it('Should not allow a user to batch claim before the faucet period expires', async function () { - const { - otherAccount, - mockAssetERC1155, - faucetsERC1155, - fakeAssets, - faucetLimit, - } = await loadFixture(setupFaucetERC1155); - const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); - const erc1155TokenIds = [fakeAssets[0].id, fakeAssets[1].id]; - - await faucetsERC1155 - .connect(otherAccount) - .claimBatch(mockAssetERC1155Address, erc1155TokenIds, [faucetLimit, 10]); - - await expect( - faucetsERC1155 - .connect(otherAccount) - .claimBatch(mockAssetERC1155Address, erc1155TokenIds, [faucetLimit, 10]) - ).to.be.revertedWith('Faucets: CLAIM_PERIOD_NOT_PASSED'); + describe('Enable/Disable Faucet', function () { + it('Should allow the owner to enable a disabled faucet', async function () { + const {owner, mockAssetERC1155, faucetsERC1155} = await loadFixture( + setupFaucetERC1155 + ); + const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); + + await faucetsERC1155.connect(owner).enableFaucet(mockAssetERC1155Address); + expect( + await faucetsERC1155.isFaucetEnabled(mockAssetERC1155Address) + ).to.equal(true); + }); + + it('Should not allow non-owner to enable a disabled faucet', async function () { + const {otherAccount, mockAssetERC1155, faucetsERC1155} = + await loadFixture(setupFaucetERC1155); + const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); + + await expect( + faucetsERC1155 + .connect(otherAccount) + .enableFaucet(mockAssetERC1155Address) + ).to.be.revertedWith('Ownable: caller is not the owner'); + }); + + it('Should allow the owner to disable an enabled faucet', async function () { + const {owner, mockAssetERC1155, faucetsERC1155} = await loadFixture( + setupFaucetERC1155 + ); + const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); + + await faucetsERC1155 + .connect(owner) + .disableFaucet(mockAssetERC1155Address); + expect( + await faucetsERC1155.isFaucetEnabled(mockAssetERC1155Address) + ).to.equal(false); + }); + + it('Should not allow non-owner to disable an enabled faucet', async function () { + const {otherAccount, mockAssetERC1155, faucetsERC1155} = + await loadFixture(setupFaucetERC1155); + const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); + + await expect( + faucetsERC1155 + .connect(otherAccount) + .disableFaucet(mockAssetERC1155Address) + ).to.be.revertedWith('Ownable: caller is not the owner'); + }); }); - it('Should allow a user to batch claim after the faucet period expires', async function () { - const { - otherAccount, - mockAssetERC1155, - faucetsERC1155, - fakeAssets, - faucetLimit, - faucetPeriod, - } = await loadFixture(setupFaucetERC1155); - const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); - const otherAccountAddress = await otherAccount.getAddress(); - const erc1155TokenIds = [fakeAssets[0].id, fakeAssets[1].id]; - - await faucetsERC1155 - .connect(otherAccount) - .claimBatch(mockAssetERC1155Address, erc1155TokenIds, [faucetLimit, 10]); - - await time.increase(faucetPeriod); - await mine(); - - await faucetsERC1155 - .connect(otherAccount) - .claimBatch(mockAssetERC1155Address, erc1155TokenIds, [faucetLimit, 10]); - - const balanceTokenA = await mockAssetERC1155.balanceOf( - otherAccountAddress, - erc1155TokenIds[0] - ); - const balanceTokenB = await mockAssetERC1155.balanceOf( - otherAccountAddress, - erc1155TokenIds[1] - ); - - expect(balanceTokenA).to.equal(faucetLimit * 2); - expect(balanceTokenB).to.equal(20); + describe('Remove Faucet', function () { + it('Should allow the owner to remove a faucet', async function () { + const {owner, mockAssetERC1155, faucetsERC1155} = await loadFixture( + setupFaucetERC1155 + ); + + const mockAssetAddress = await mockAssetERC1155.getAddress(); + expect(await faucetsERC1155.faucetExists(mockAssetAddress)).to.equal( + true + ); + await faucetsERC1155.connect(owner).removeFaucet(mockAssetAddress); + expect(await faucetsERC1155.faucetExists(mockAssetAddress)).to.equal( + false + ); + }); + + it('Should not allow a non-owner to remove a faucet', async function () { + const {otherAccount, mockAssetERC1155, faucetsERC1155} = + await loadFixture(setupFaucetERC1155); + + const mockAssetAddress = await mockAssetERC1155.getAddress(); + await expect( + faucetsERC1155.connect(otherAccount).removeFaucet(mockAssetAddress) + ).to.be.revertedWith('Ownable: caller is not the owner'); + }); + + it('Should revert if trying to remove a non-existent faucet', async function () { + const {owner, faucetsERC1155} = await loadFixture(setupFaucetERC1155); + + const nonExistentFaucetAddress = ethers.getAddress( + '0x000000000000000000000000000000000000dead' + ); + await expect( + faucetsERC1155.connect(owner).removeFaucet(nonExistentFaucetAddress) + ).to.be.revertedWith('Faucets: FAUCET_DOES_NOT_EXIST'); + }); }); - it('Should revert if trying to batch claim for tokens not in the faucet', async function () { - const {otherAccount, mockAssetERC1155, faucetsERC1155, faucetLimit} = - await loadFixture(setupFaucetERC1155); - const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); - const notInFaucetTokenId = 9999; - - await expect( - faucetsERC1155 - .connect(otherAccount) - .claimBatch( - mockAssetERC1155Address, - [notInFaucetTokenId], - [faucetLimit] + describe('Remove Tokens', function () { + it('Should remove tokens and adjust tokenIds array correctly', async function () { + const {owner, faucetsERC1155, mockAssetERC1155, fakeAssets} = + await loadFixture(setupFaucetERC1155); + + const tokenToKeep = fakeAssets[1].id; + const tokenToRemove = fakeAssets[0].id; + const mockAssetAddress = mockAssetERC1155.getAddress(); + + await faucetsERC1155 + .connect(owner) + .removeTokens(mockAssetAddress, [tokenToRemove]); + expect( + await faucetsERC1155.tokenExistsInFaucet( + mockAssetAddress, + tokenToRemove ) - ).to.be.revertedWith('Faucets: TOKEN_DOES_NOT_EXIST'); - }); - - it('Should correctly determine if a user can claim tokens or not', async function () { - const { - otherAccount, - mockAssetERC1155, - faucetsERC1155, - fakeAssets, - faucetLimit, - faucetPeriod, - } = await loadFixture(setupFaucetERC1155); - - const mockAssetERC1155Address = await mockAssetERC1155.getAddress(); - const otherAccountAddress = await otherAccount.getAddress(); - - let canClaim = await faucetsERC1155.canClaim( - mockAssetERC1155Address, - fakeAssets[0].id, - otherAccountAddress - ); - expect(canClaim).to.equal(true); - - await faucetsERC1155 - .connect(otherAccount) - .claim(mockAssetERC1155Address, fakeAssets[0].id, faucetLimit); - - canClaim = await faucetsERC1155.canClaim( - mockAssetERC1155Address, - fakeAssets[0].id, - otherAccountAddress - ); - expect(canClaim).to.equal(false); - - await time.increase(faucetPeriod); - await mine(); - - canClaim = await faucetsERC1155.canClaim( - mockAssetERC1155Address, - fakeAssets[0].id, - otherAccountAddress - ); - expect(canClaim).to.equal(true); + ).to.be.false; + expect( + await faucetsERC1155.tokenExistsInFaucet(mockAssetAddress, tokenToKeep) + ).to.be.true; + }); }); });