-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Referral Rewards #274
Referral Rewards #274
Conversation
cf2b942
to
ed12804
Compare
@@ -166,7 +172,8 @@ contract QuestFactory is Initializable, LegacyStorage, OwnableRoles, IQuestFacto | |||
actionType_, | |||
questName_, | |||
"erc20", | |||
projectName_ | |||
projectName_, | |||
referralRewardFee_ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we going to need to update the QuestCreated
event in order to get the referral reward fee value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we consistently derive it from stuff we're already throwing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm I think we can keep the same event. We may need to update our db model in order to store the value though
@@ -419,7 +428,29 @@ contract QuestFactory is Initializable, LegacyStorage, OwnableRoles, IQuestFacto | |||
emit QuestClaimed(claimer_, quest.questAddress, questId_, rewardToken_, rewardAmountOrTokenId); | |||
} | |||
if(ref_ != address(0)){ | |||
emit QuestClaimedReferred(claimer_, quest.questAddress, questId_, rewardToken_, rewardAmountOrTokenId, ref_, 3333, mintFee); | |||
if (IQuestOwnable(quest.questAddress).startTime() > referralRewardTimestamp) { | |||
emit QuestClaimReferred( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we're only going to want to emit this on erc20 quests (that way we also won't need to emit the "empty data"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SGTM - might be easier to just emit empty data though, keeps our data shaped more consistently. I don't have a strong opinion depends a lot more on ease-of-consumption.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM - only things blocking are the fuzzed test and not doing external calls using this.
if (ref_ != address(0)) ref_.safeTransferETH(_claimFee() / 3); | ||
if (ref_ != address(0)) { | ||
ref_.safeTransferETH(_claimFee() / 3); | ||
_updateReferralTokenAmount(ref_); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels wrong to transfer some out and to account for the other internally
@@ -155,7 +167,7 @@ contract Quest is ReentrancyGuardUpgradeable, PausableUpgradeable, Ownable, IQue | |||
protocolFeeRecipient.safeTransferETH(protocolPayout); | |||
|
|||
// transfer reward tokens | |||
uint256 protocolFeeForRecipient = this.protocolFee() / 2; | |||
uint256 protocolFeeForRecipient = (this.protocolFee() / 2) - referralClaimTotal; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice approach - clean
@@ -180,6 +181,10 @@ contract Quest1155 is ERC1155Holder, ReentrancyGuardUpgradeable, PausableUpgrade | |||
return questId; | |||
} | |||
|
|||
function referralRewardAmount() external pure returns (uint256) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would confirm we wanna do 0 for these. Makes sense but let's confirm with product just so there are no surprises.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will confirm, but don't think we can give a percentage of 1155s lol
@@ -166,7 +172,8 @@ contract QuestFactory is Initializable, LegacyStorage, OwnableRoles, IQuestFacto | |||
actionType_, | |||
questName_, | |||
"erc20", | |||
projectName_ | |||
projectName_, | |||
referralRewardFee_ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we consistently derive it from stuff we're already throwing?
@@ -419,7 +428,29 @@ contract QuestFactory is Initializable, LegacyStorage, OwnableRoles, IQuestFacto | |||
emit QuestClaimed(claimer_, quest.questAddress, questId_, rewardToken_, rewardAmountOrTokenId); | |||
} | |||
if(ref_ != address(0)){ | |||
emit QuestClaimedReferred(claimer_, quest.questAddress, questId_, rewardToken_, rewardAmountOrTokenId, ref_, 3333, mintFee); | |||
if (IQuestOwnable(quest.questAddress).startTime() > referralRewardTimestamp) { | |||
emit QuestClaimReferred( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SGTM - might be easier to just emit empty data though, keeps our data shaped more consistently. I don't have a strong opinion depends a lot more on ease-of-consumption.
@@ -484,6 +515,10 @@ contract QuestFactory is Initializable, LegacyStorage, OwnableRoles, IQuestFacto | |||
defaultMintFeeRecipient = mintFeeRecipient_; | |||
} | |||
|
|||
function setReferralRewardTimestamp(uint256 timestamp_) external onlyOwner { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to remember to call this as part of the deployment. Another option is to actually just set this in the initialize call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a part of the initialize
call already, but I think we are going to need to call this function on chains where we upgrade
test/Quest.t.sol
Outdated
CLAIM REFERRAL FEES | ||
//////////////////////////////////////////////////////////////*/ | ||
|
||
function test_claimReferralFees() public { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we fuzz this test just to check edges? Preference for fuzzed tests whenever there's accounting in play.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated this to be testFuzz_claimReferralFees()
and based off the results when running forge test
, I don't think it's actually running the fuzz tests
test_fuzz_claimReferralFees()
doesn't work either -- lets sync up on this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name isn't important, you have to pass in a fuzzable arg:
function test_someFuzzableFunction(uint256 fuzzableArg) {
// ...
contract.someMutativeFunctionWithArguments(fuzzableArg);
// ...
}
But it doesn't really make sense here because the only input is an address which only enables a binary logic branch: either the address has fees to claim or it does not. The purpose of fuzz testing is mainly to catch cases off the happy path that unexpectedly break the contract's invariants.
Generally, you'd want to either mock out something the function depends on to return a fuzzed value (rather than enforcing the correct execution path by performing the "normal" operations inline as pre-assertion setup), or accept arguments which can be manipulated by the fuzz test. The only thing that seems fuzzable to me in this specific function is the time, since you're warping around and expecting certain behavior depending on the time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Less concerned with the address more concerned with the accounting around the referral payouts since this is the only test function that's covering those accounting paths.
14e515b
to
071ee85
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM - we can add fuzzing for referralRewardFee_
as a follow-on, doesn't need to be blocking.
bb209c6
to
7500d39
Compare
contracts/Quest.sol
Outdated
@@ -170,7 +170,7 @@ contract Quest is ReentrancyGuardUpgradeable, PausableUpgradeable, Ownable, IQue | |||
uint256 protocolFeeForRecipient = (this.protocolFee() / 2) - referralClaimTotal; | |||
rewardToken.safeTransfer(protocolFeeRecipient, protocolFeeForRecipient); | |||
|
|||
uint256 remainingBalanceForOwner = rewardToken.balanceOf(address(this)); | |||
uint256 remainingBalanceForOwner = rewardToken.balanceOf(address(this)) - referralClaimTotal; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't account for the fact that some claims might have gone through already.
Gonna need to update the value in the claim too. I would maintain to variables:
referralClaimTotal
and totalReferralsClaimed
or something like this.
Here we want:
uint256 remainingBalanceForOwner = rewardToken.balanceOf(address(this)) - (referralClaimTotal - totalReferralsClaimed) ;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
No description provided.