diff --git a/contracts/QuestBudget.sol b/contracts/QuestBudget.sol index 1221bf75..3a6aa150 100644 --- a/contracts/QuestBudget.sol +++ b/contracts/QuestBudget.sol @@ -145,6 +145,7 @@ contract QuestBudget is Budget, IERC1155Receiver, ReentrancyGuard { /// @param actionType_ The action type for the quest /// @param questName_ The name of the quest /// @param projectName_ The name of the project/protocol used for the quest + /// @param referralRewardFee_ The fee amount for referrals. The value is counted against the `rewardAmount` /// @return address the quest contract address function createERC20Quest( uint32 txHashChainId_, @@ -156,7 +157,8 @@ contract QuestBudget is Budget, IERC1155Receiver, ReentrancyGuard { string memory questId_, string memory actionType_, string memory questName_, - string memory projectName_ + string memory projectName_, + uint256 referralRewardFee_ ) public virtual onlyAuthorized returns (address) { uint256 maxTotalRewards = totalParticipants_ * rewardAmount_; uint256 questFee = uint256(IQuestFactory(questFactory).questFee()); @@ -173,7 +175,8 @@ contract QuestBudget is Budget, IERC1155Receiver, ReentrancyGuard { questId_, actionType_, questName_, - projectName_ + projectName_, + referralRewardFee_ ); } diff --git a/contracts/QuestFactory.sol b/contracts/QuestFactory.sol index 38add0b5..4302a78c 100644 --- a/contracts/QuestFactory.sol +++ b/contracts/QuestFactory.sol @@ -146,7 +146,7 @@ contract QuestFactory is Initializable, LegacyStorage, OwnableRoles, IQuestFacto /// @param questName_ The name of the quest /// @param projectName_ The name of the project/protocol used for the quest /// @return address the quest contract address - function createERC20Quest( + function createERC20Boost( uint32 txHashChainId_, address rewardTokenAddress_, uint256 endTime_, @@ -175,6 +175,49 @@ contract QuestFactory is Initializable, LegacyStorage, OwnableRoles, IQuestFacto ); } + /// @dev Create an erc20 quest and start it at the same time. The function will transfer the reward amount to the quest contract + /// @param txHashChainId_ The chain id of the chain the txHash is on + /// @param rewardTokenAddress_ The contract address of the reward token + /// @param endTime_ The end time of the quest + /// @param startTime_ The start time of the quest + /// @param totalParticipants_ The total amount of participants (accounts) the quest will have + /// @param rewardAmount_ The reward amount for an erc20 quest + /// @param questId_ The id of the quest + /// @param actionType_ The action type for the quest + /// @param questName_ The name of the quest + /// @param projectName_ The name of the project/protocol used for the quest + /// @param referralRewardFee_ The fee amount for referrals -- this is no longer used since we now have a flat 2.5% fee + /// @return address the quest contract address + function createERC20Quest( + uint32 txHashChainId_, + address rewardTokenAddress_, + uint256 endTime_, + uint256 startTime_, + uint256 totalParticipants_, + uint256 rewardAmount_, + string memory questId_, + string memory actionType_, + string memory questName_, + string memory projectName_, + uint256 referralRewardFee_ + ) external checkQuest(questId_) returns (address) { + return createERC20QuestInternal( + ERC20QuestData( + txHashChainId_, + rewardTokenAddress_, + endTime_, + startTime_, + totalParticipants_, + rewardAmount_, + questId_, + actionType_, + questName_, + "erc20", + projectName_ + ) + ); + } + /// @dev Create an erc1155 quest and start it at the same time. The function will transfer the reward amount to the quest contract /// @param txHashChainId_ The chain id of the chain the txHash is on /// @param rewardTokenAddress_ The contract address of the reward token diff --git a/contracts/interfaces/IQuestFactory.sol b/contracts/interfaces/IQuestFactory.sol index c1eaf5ac..d0358e84 100644 --- a/contracts/interfaces/IQuestFactory.sol +++ b/contracts/interfaces/IQuestFactory.sol @@ -196,7 +196,7 @@ interface IQuestFactory { function questFee() external view returns (uint16); // Create - function createERC20Quest( + function createERC20Boost( uint32 txHashChainId_, address rewardTokenAddress_, uint256 endTime_, @@ -208,6 +208,19 @@ interface IQuestFactory { string memory questName_, string memory projectName_ ) external returns (address); + function createERC20Quest( + uint32 txHashChainId_, + address rewardTokenAddress_, + uint256 endTime_, + uint256 startTime_, + uint256 totalParticipants_, + uint256 rewardAmount_, + string memory questId_, + string memory actionType_, + string memory questName_, + string memory projectName_, + uint256 referralRewardFee_ + ) external returns (address); function create1155QuestAndQueue( address rewardTokenAddress_, diff --git a/test/QuestBudget.t.sol b/test/QuestBudget.t.sol index 63face66..7f90f61a 100644 --- a/test/QuestBudget.t.sol +++ b/test/QuestBudget.t.sol @@ -383,6 +383,7 @@ contract QuestBudgetTest is Test, TestUtils, IERC1155Receiver { string memory actionType_ = "testAction"; string memory questName_ = "Test Quest"; string memory projectName_ = "Test Project"; + uint256 referralRewardFee_ = 10 ether; uint256 maxTotalRewards = totalParticipants_ * rewardAmount_; uint256 questFee = uint256(mockQuestFactory.questFee()); @@ -406,7 +407,8 @@ contract QuestBudgetTest is Test, TestUtils, IERC1155Receiver { questId_, actionType_, questName_, - projectName_ + projectName_, + referralRewardFee_ ); // Ensure the returned quest address is not the zero address @@ -432,6 +434,7 @@ contract QuestBudgetTest is Test, TestUtils, IERC1155Receiver { string memory actionType_ = "testAction"; string memory questName_ = "Test Quest"; string memory projectName_ = "Test Project"; + uint256 referralRewardFee_ = 10 ether; uint256 maxTotalRewards = totalParticipants_ * rewardAmount_; uint256 questFee = uint256(mockQuestFactory.questFee()); @@ -455,7 +458,8 @@ contract QuestBudgetTest is Test, TestUtils, IERC1155Receiver { questId_, actionType_, questName_, - projectName_ + projectName_, + referralRewardFee_ ); // Ensure the returned quest address is not the zero address diff --git a/test/QuestClaimable.t.sol b/test/QuestClaimable.t.sol index a0dd6696..f26eb1d9 100644 --- a/test/QuestClaimable.t.sol +++ b/test/QuestClaimable.t.sol @@ -73,7 +73,7 @@ contract TestQuestClaimable is Test, Errors, Events, TestUtils { function test_claim_with_referrer() public { vm.startPrank(questCreator); sampleERC20.approve(address(questFactory), calculateTotalRewardsPlusFee(TOTAL_PARTICIPANTS, REWARD_AMOUNT, QUEST_FEE, REFERRAL_REWARD_FEE)); - address questAddress = questFactory.createERC20Quest( + address questAddress = questFactory.createERC20Boost( 101, address(sampleERC20), END_TIME, @@ -109,7 +109,7 @@ contract TestQuestClaimable is Test, Errors, Events, TestUtils { referrer = address(0); vm.startPrank(questCreator); sampleERC20.approve(address(questFactory), calculateTotalRewardsPlusFee(TOTAL_PARTICIPANTS, REWARD_AMOUNT, QUEST_FEE, REFERRAL_REWARD_FEE)); - address questAddress = questFactory.createERC20Quest( + address questAddress = questFactory.createERC20Boost( 101, address(sampleERC20), END_TIME, diff --git a/test/QuestFactory.t.sol b/test/QuestFactory.t.sol index 3121b8f2..69d7a2d0 100644 --- a/test/QuestFactory.t.sol +++ b/test/QuestFactory.t.sol @@ -116,14 +116,14 @@ contract TestQuestFactory is Test, Errors, Events, TestUtils { vm.stopPrank(); } - function test_createERC20Quest() public{ + function test_createERC20Boost() public{ vm.startPrank(questCreator); sampleERC20.approve(address(questFactory), calculateTotalRewardsPlusFee(QUEST.TOTAL_PARTICIPANTS, QUEST.REWARD_AMOUNT, QUEST_FEE, REFERRAL_FEE)); vm.expectEmit(true,false,true,true); emit QuestCreated(questCreator, address(0), QUEST.PROJECT_NAME, QUEST.QUEST_NAME, QUEST.QUEST_ID_STRING, "erc20", QUEST.ACTION_TYPE, QUEST.CHAIN_ID, address(sampleERC20), QUEST.END_TIME, QUEST.START_TIME, QUEST.TOTAL_PARTICIPANTS, QUEST.REWARD_AMOUNT); - address questAddress = questFactory.createERC20Quest( + address questAddress = questFactory.createERC20Boost( QUEST.CHAIN_ID, address(sampleERC20), QUEST.END_TIME, @@ -144,10 +144,10 @@ contract TestQuestFactory is Test, Errors, Events, TestUtils { vm.stopPrank(); } - function test_RevertIf_createERC20Quest_QuestIdUsed() public{ + function test_RevertIf_createERC20Boost_QuestIdUsed() public{ vm.startPrank(questCreator); sampleERC20.approve(address(questFactory), calculateTotalRewardsPlusFee(QUEST.TOTAL_PARTICIPANTS, QUEST.REWARD_AMOUNT, QUEST_FEE, REFERRAL_FEE)); - questFactory.createERC20Quest( + questFactory.createERC20Boost( QUEST.CHAIN_ID, address(sampleERC20), QUEST.END_TIME, @@ -161,7 +161,7 @@ contract TestQuestFactory is Test, Errors, Events, TestUtils { ); vm.expectRevert(abi.encodeWithSelector(QuestIdUsed.selector)); - questFactory.createERC20Quest( + questFactory.createERC20Boost( QUEST.CHAIN_ID, address(sampleERC20), QUEST.END_TIME, @@ -175,7 +175,7 @@ contract TestQuestFactory is Test, Errors, Events, TestUtils { ); } - function test_RevertIf_createERC20Quest_Erc20QuestAddressNotSet() public{ + function test_RevertIf_createERC20Boost_Erc20QuestAddressNotSet() public{ vm.startPrank(owner); questFactory.setErc20QuestAddress(address(0)); @@ -183,7 +183,7 @@ contract TestQuestFactory is Test, Errors, Events, TestUtils { sampleERC20.approve(address(questFactory), calculateTotalRewardsPlusFee(QUEST.TOTAL_PARTICIPANTS, QUEST.REWARD_AMOUNT, QUEST_FEE, REFERRAL_FEE)); vm.expectRevert(abi.encodeWithSelector(Erc20QuestAddressNotSet.selector)); - questFactory.createERC20Quest( + questFactory.createERC20Boost( QUEST.CHAIN_ID, address(sampleERC20), QUEST.END_TIME, @@ -248,7 +248,7 @@ contract TestQuestFactory is Test, Errors, Events, TestUtils { vm.deal(participant, 1000000); vm.startPrank(questCreator); sampleERC20.approve(address(questFactory), calculateTotalRewardsPlusFee(QUEST.TOTAL_PARTICIPANTS, QUEST.REWARD_AMOUNT, QUEST_FEE, REFERRAL_FEE)); - address questAddress = questFactory.createERC20Quest( + address questAddress = questFactory.createERC20Boost( QUEST.CHAIN_ID, address(sampleERC20), QUEST.END_TIME, @@ -287,7 +287,7 @@ contract TestQuestFactory is Test, Errors, Events, TestUtils { vm.startPrank(questCreator); sampleERC20.approve(address(questFactory), calculateTotalRewardsPlusFee(QUEST.TOTAL_PARTICIPANTS, QUEST.REWARD_AMOUNT, QUEST_FEE, REFERRAL_FEE)); - address questAddress = questFactory.createERC20Quest( + address questAddress = questFactory.createERC20Boost( QUEST.CHAIN_ID, address(sampleERC20), QUEST.END_TIME, @@ -318,7 +318,7 @@ contract TestQuestFactory is Test, Errors, Events, TestUtils { function test_claimCompressed_erc20_with_ref() public{ vm.startPrank(questCreator); sampleERC20.approve(address(questFactory), calculateTotalRewardsPlusFee(QUEST.TOTAL_PARTICIPANTS, QUEST.REWARD_AMOUNT, QUEST_FEE, REFERRAL_FEE)); - address questAddress = questFactory.createERC20Quest( + address questAddress = questFactory.createERC20Boost( QUEST.CHAIN_ID, address(sampleERC20), QUEST.END_TIME, @@ -384,7 +384,7 @@ contract TestQuestFactory is Test, Errors, Events, TestUtils { function test_claimOptimized_revert_deprecated() public{ vm.startPrank(questCreator); sampleERC20.approve(address(questFactory), calculateTotalRewardsPlusFee(QUEST.TOTAL_PARTICIPANTS, QUEST.REWARD_AMOUNT, QUEST_FEE, REFERRAL_FEE)); - questFactory.createERC20Quest( + questFactory.createERC20Boost( QUEST.CHAIN_ID, address(sampleERC20), QUEST.END_TIME, @@ -415,7 +415,7 @@ contract TestQuestFactory is Test, Errors, Events, TestUtils { function test_cancelQuest() public { vm.startPrank(questCreator); sampleERC20.approve(address(questFactory), calculateTotalRewardsPlusFee(QUEST.TOTAL_PARTICIPANTS, QUEST.REWARD_AMOUNT, QUEST_FEE, REFERRAL_FEE)); - address questAddress = questFactory.createERC20Quest( + address questAddress = questFactory.createERC20Boost( QUEST.CHAIN_ID, address(sampleERC20), QUEST.END_TIME, @@ -439,7 +439,7 @@ contract TestQuestFactory is Test, Errors, Events, TestUtils { function test_cancelQuest_alreadyStarted() public { vm.startPrank(questCreator); sampleERC20.approve(address(questFactory), calculateTotalRewardsPlusFee(QUEST.TOTAL_PARTICIPANTS, QUEST.REWARD_AMOUNT, QUEST_FEE, REFERRAL_FEE)); - address questAddress = questFactory.createERC20Quest( + address questAddress = questFactory.createERC20Boost( QUEST.CHAIN_ID, address(sampleERC20), QUEST.END_TIME, @@ -464,7 +464,7 @@ contract TestQuestFactory is Test, Errors, Events, TestUtils { function test_cancelQuest_unauthorized() public { vm.startPrank(questCreator); sampleERC20.approve(address(questFactory), calculateTotalRewardsPlusFee(QUEST.TOTAL_PARTICIPANTS, QUEST.REWARD_AMOUNT, QUEST_FEE, REFERRAL_FEE)); - address questAddress = questFactory.createERC20Quest( + address questAddress = questFactory.createERC20Boost( QUEST.CHAIN_ID, address(sampleERC20), QUEST.END_TIME, @@ -488,7 +488,7 @@ contract TestQuestFactory is Test, Errors, Events, TestUtils { function test_questData() public { vm.startPrank(questCreator); sampleERC20.approve(address(questFactory), calculateTotalRewardsPlusFee(QUEST.TOTAL_PARTICIPANTS, QUEST.REWARD_AMOUNT, QUEST_FEE, REFERRAL_FEE)); - address questAddress = questFactory.createERC20Quest( + address questAddress = questFactory.createERC20Boost( QUEST.CHAIN_ID, address(sampleERC20), QUEST.END_TIME, diff --git a/test/mocks/QuestFactoryMock.sol b/test/mocks/QuestFactoryMock.sol index 507c6d87..2e066b1e 100644 --- a/test/mocks/QuestFactoryMock.sol +++ b/test/mocks/QuestFactoryMock.sol @@ -19,6 +19,7 @@ contract QuestFactoryMock { string questName; string questType; string projectName; + uint256 referralRewardFee; } QuestData public questData; @@ -71,7 +72,8 @@ contract QuestFactoryMock { string memory questId_, string memory actionType_, string memory questName_, - string memory projectName_ + string memory projectName_, + uint256 referralRewardFee_ ) external returns (address) { uint256 maxTotalRewards = totalParticipants_ * rewardAmount_; uint256 maxProtocolReward = (maxTotalRewards * 2000) / 10_000; // Assuming questFee is 2000 @@ -87,7 +89,8 @@ contract QuestFactoryMock { actionType: actionType_, questName: questName_, questType: "erc20", - projectName: projectName_ + projectName: projectName_, + referralRewardFee: referralRewardFee_ }); // Transfer rewardAmount_ tokens from the caller to this contract