From cbabbd8716ef3a8021609c75e56c666619c7bf15 Mon Sep 17 00:00:00 2001 From: Sebastian Camacho Date: Thu, 28 Sep 2023 21:00:09 +0200 Subject: [PATCH] add external function canClaim --- packages/faucets/contracts/FaucetsERC1155.md | 72 ++++++++---- packages/faucets/contracts/FaucetsERC1155.sol | 105 +++++++++++------- packages/faucets/test/faucetsERC1155.ts | 44 +++++++- 3 files changed, 160 insertions(+), 61 deletions(-) diff --git a/packages/faucets/contracts/FaucetsERC1155.md b/packages/faucets/contracts/FaucetsERC1155.md index 373becbe90..8bcc82ed12 100644 --- a/packages/faucets/contracts/FaucetsERC1155.md +++ b/packages/faucets/contracts/FaucetsERC1155.md @@ -272,47 +272,56 @@ Parameters: | faucet | address | Address of the faucet. | | tokenIds | uint256[] | List of token IDs to remove. | -### claim (0x2bc43fd9) +### canClaim (0xb178e559) ```solidity -function claim( +function canClaim( address faucet, uint256 tokenId, - uint256 amount -) external exists(faucet) nonReentrant + address walletAddress +) external view exists(faucet) returns (bool) ``` -Claim tokens from a faucet. +Determines whether a wallet address can claim a token from a specific faucet. + +Calls the internal function _canClaim to get the result. Parameters: -| Name | Type | Description | -| :------ | :------ | :------------------------------------ | -| faucet | address | Address of the faucet to claim from. | -| tokenId | uint256 | ID of the token to be claimed. | -| amount | uint256 | Amount of tokens to be claimed. | +| Name | Type | Description | +| :------------ | :------ | :---------------------------------------------- | +| faucet | address | The address of the faucet contract. | +| tokenId | uint256 | The ID of the token being claimed. | +| walletAddress | address | The address of the wallet attempting to claim. | -### withdraw (0x893bd7c8) + +Return values: + +| Name | Type | Description | +| :--- | :--- | :---------------------------------------------------------------------------- | +| [0] | bool | bool Returns true if the wallet address can claim the token, false otherwise. | + +### claim (0x2bc43fd9) ```solidity -function withdraw( +function claim( address faucet, - address receiver, - uint256[] memory tokenIds -) external onlyOwner exists(faucet) nonReentrant + uint256 tokenId, + uint256 amount +) external exists(faucet) nonReentrant ``` -Function to withdraw the total balance of tokens from the contract to a specified address. +Claim tokens from a faucet. Parameters: -| Name | Type | Description | -| :------- | :-------- | :----------------------------------------------------------------------------------------------------------------------------- | -| faucet | address | - The address of the ERC1155 contract (faucet) containing the tokens to be withdrawn. | -| receiver | address | - The address to which the tokens will be sent. | -| tokenIds | uint256[] | - An array of token IDs to be withdrawn. Emits a {Withdrawn} event. Requirements: - The `tokenIds` must exist in the faucet. | +| Name | Type | Description | +| :------ | :------ | :------------------------------------ | +| faucet | address | Address of the faucet to claim from. | +| tokenId | uint256 | ID of the token to be claimed. | +| amount | uint256 | Amount of tokens to be claimed. | ### claimBatch (0xe59e53c2) @@ -334,3 +343,24 @@ Parameters: | faucet | address | - The address of the ERC1155 contract (faucet) to claim from. | | tokenIds | uint256[] | - An array of token IDs to be claimed from the faucet. | | amounts | uint256[] | - An array of amounts of tokens to be claimed for respective token IDs. Emits multiple {Claimed} events for each claim. Requirements: - The lengths of `tokenIds` and `amounts` arrays should be the same. - Each tokenId must exist in the faucet. | + +### withdraw (0x893bd7c8) + +```solidity +function withdraw( + address faucet, + address receiver, + uint256[] memory tokenIds +) external onlyOwner exists(faucet) nonReentrant +``` + +Function to withdraw the total balance of tokens from the contract to a specified address. + + +Parameters: + +| Name | Type | Description | +| :------- | :-------- | :----------------------------------------------------------------------------------------------------------------------------- | +| faucet | address | - The address of the ERC1155 contract (faucet) containing the tokens to be withdrawn. | +| receiver | address | - The address to which the tokens will be sent. | +| tokenIds | uint256[] | - An array of token IDs to be withdrawn. Emits a {Withdrawn} event. Requirements: - The `tokenIds` must exist in the faucet. | diff --git a/packages/faucets/contracts/FaucetsERC1155.sol b/packages/faucets/contracts/FaucetsERC1155.sol index 2c9881508f..c11172d353 100644 --- a/packages/faucets/contracts/FaucetsERC1155.sol +++ b/packages/faucets/contracts/FaucetsERC1155.sol @@ -186,6 +186,36 @@ contract FaucetsERC1155 is Ownable, ERC1155Holder, ReentrancyGuard { faucetInfo.tokenIds = newTokenIds; } + /** + * @notice (Internal) Checks if the wallet address is eligible to claim the token from the faucet. + * @dev Calculates based on the lastTimestamp and the period in the faucetInfo, whether the walletAddress can currently claim the tokenId from the faucet. + * @param faucet The address of the faucet contract. + * @param tokenId The ID of the token being claimed. + * @param walletAddress The address of the wallet attempting to claim. + * @return bool Returns true if the wallet address can claim the token, false otherwise. + */ + function _canClaim(address faucet, uint256 tokenId, address walletAddress) internal view returns (bool) { + FaucetInfo storage faucetInfo = faucets[faucet]; + uint256 lastTimestamp = faucetInfo.lastTimestamps[tokenId][walletAddress]; + return block.timestamp >= (lastTimestamp + faucetInfo.period); + } + + /** + * @notice Determines whether a wallet address can claim a token from a specific faucet. + * @dev Calls the internal function _canClaim to get the result. + * @param faucet The address of the faucet contract. + * @param tokenId The ID of the token being claimed. + * @param walletAddress The address of the wallet attempting to claim. + * @return bool Returns true if the wallet address can claim the token, false otherwise. + */ + function canClaim( + address faucet, + uint256 tokenId, + address walletAddress + ) external view exists(faucet) returns (bool) { + return _canClaim(faucet, tokenId, walletAddress); + } + /** * @dev Claim tokens from a faucet. * @param faucet Address of the faucet to claim from. @@ -197,17 +227,50 @@ contract FaucetsERC1155 is Ownable, ERC1155Holder, ReentrancyGuard { require(faucetInfo.isEnabled, "Faucets: FAUCET_DISABLED"); require(faucetInfo.tokenIdExists[tokenId], "Faucets: TOKEN_DOES_NOT_EXIST"); require(amount > 0 && amount <= faucetInfo.limit, "Faucets: AMOUNT_TOO_HIGH"); - - uint256 lastTimestamp = faucetInfo.lastTimestamps[tokenId][msg.sender]; - require(block.timestamp >= (lastTimestamp + faucetInfo.period), "Faucets: CLAIM_PERIOD_NOT_PASSED"); + require(_canClaim(faucet, tokenId, msg.sender), "Faucets: CLAIM_PERIOD_NOT_PASSED"); uint256 balance = IERC1155(faucet).balanceOf(address(this), tokenId); require(balance >= amount, "Faucets: BALANCE_IS_NOT_ENOUGH"); + faucetInfo.lastTimestamps[tokenId][msg.sender] = block.timestamp; IERC1155(faucet).safeTransferFrom(address(this), msg.sender, tokenId, amount, ""); emit Claimed(faucet, msg.sender, tokenId, amount); } + /** + * @notice Function to claim multiple tokens from a single faucet. + * @param faucet - The address of the ERC1155 contract (faucet) to claim from. + * @param tokenIds - An array of token IDs to be claimed from the faucet. + * @param amounts - An array of amounts of tokens to be claimed for respective token IDs. + * + * Emits multiple {Claimed} events for each claim. + * + * Requirements: + * - The lengths of `tokenIds` and `amounts` arrays should be the same. + * - Each tokenId must exist in the faucet. + */ + function claimBatch(address faucet, uint256[] memory tokenIds, uint256[] memory amounts) external nonReentrant { + require(tokenIds.length == amounts.length, "Faucets: ARRAY_LENGTH_MISMATCH"); + + for (uint256 i = 0; i < tokenIds.length; i++) { + uint256 tokenId = tokenIds[i]; + uint256 amount = amounts[i]; + + FaucetInfo storage faucetInfo = faucets[faucet]; + require(faucetInfo.isEnabled, "Faucets: FAUCET_DISABLED"); + require(faucetInfo.tokenIdExists[tokenId], "Faucets: TOKEN_DOES_NOT_EXIST"); + require(amount > 0 && amount <= faucetInfo.limit, "Faucets: AMOUNT_TOO_HIGH"); + require(_canClaim(faucet, tokenId, msg.sender), "Faucets: CLAIM_PERIOD_NOT_PASSED"); + + uint256 balance = IERC1155(faucet).balanceOf(address(this), tokenId); + require(balance >= amount, "Faucets: BALANCE_IS_NOT_ENOUGH"); + + faucetInfo.lastTimestamps[tokenId][msg.sender] = block.timestamp; + IERC1155(faucet).safeTransferFrom(address(this), msg.sender, tokenId, amount, ""); + emit Claimed(faucet, msg.sender, tokenId, amount); + } + } + /** * @notice Function to withdraw the total balance of tokens from the contract to a specified address. * @param faucet - The address of the ERC1155 contract (faucet) containing the tokens to be withdrawn. @@ -253,40 +316,4 @@ contract FaucetsERC1155 is Ownable, ERC1155Holder, ReentrancyGuard { IERC1155(faucet).safeBatchTransferFrom(address(this), receiver, tokenIds, balances, ""); emit Withdrawn(faucet, receiver, tokenIds, balances); } - - /** - * @notice Function to claim multiple tokens from a single faucet. - * @param faucet - The address of the ERC1155 contract (faucet) to claim from. - * @param tokenIds - An array of token IDs to be claimed from the faucet. - * @param amounts - An array of amounts of tokens to be claimed for respective token IDs. - * - * Emits multiple {Claimed} events for each claim. - * - * Requirements: - * - The lengths of `tokenIds` and `amounts` arrays should be the same. - * - Each tokenId must exist in the faucet. - */ - function claimBatch(address faucet, uint256[] memory tokenIds, uint256[] memory amounts) external nonReentrant { - require(tokenIds.length == amounts.length, "Faucets: ARRAY_LENGTH_MISMATCH"); - - for (uint256 i = 0; i < tokenIds.length; i++) { - uint256 tokenId = tokenIds[i]; - uint256 amount = amounts[i]; - - // Using the existing logic of the `claim` function but without the `nonReentrant` modifier. - FaucetInfo storage faucetInfo = faucets[faucet]; - require(faucetInfo.isEnabled, "Faucets: FAUCET_DISABLED"); - require(faucetInfo.tokenIdExists[tokenId], "Faucets: TOKEN_DOES_NOT_EXIST"); - require(amount > 0 && amount <= faucetInfo.limit, "Faucets: AMOUNT_TOO_HIGH"); - - uint256 lastTimestamp = faucetInfo.lastTimestamps[tokenId][msg.sender]; - require(block.timestamp >= (lastTimestamp + faucetInfo.period), "Faucets: CLAIM_PERIOD_NOT_PASSED"); - - uint256 balance = IERC1155(faucet).balanceOf(address(this), tokenId); - require(balance >= amount, "Faucets: BALANCE_IS_NOT_ENOUGH"); - faucetInfo.lastTimestamps[tokenId][msg.sender] = block.timestamp; - IERC1155(faucet).safeTransferFrom(address(this), msg.sender, tokenId, amount, ""); - emit Claimed(faucet, msg.sender, tokenId, amount); - } - } } diff --git a/packages/faucets/test/faucetsERC1155.ts b/packages/faucets/test/faucetsERC1155.ts index 5d250789e1..5f2eecb936 100644 --- a/packages/faucets/test/faucetsERC1155.ts +++ b/packages/faucets/test/faucetsERC1155.ts @@ -279,7 +279,7 @@ describe('FaucetsERC1155', function () { .connect(otherAccount) .claimBatch(mockAssetERC1155Address, erc1155TokenIds, [faucetLimit, 10]); - await time.increase(faucetPeriod + 1); + await time.increase(faucetPeriod); await mine(); await faucetsERC1155 @@ -315,4 +315,46 @@ describe('FaucetsERC1155', function () { ) ).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); + }); });