Skip to content
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

Merged
merged 14 commits into from
Apr 29, 2024
Merged

Referral Rewards #274

merged 14 commits into from
Apr 29, 2024

Conversation

jonathandiep
Copy link
Contributor

No description provided.

@jonathandiep jonathandiep force-pushed the jon/referral-rewards branch from cf2b942 to ed12804 Compare April 5, 2024 08:38
@jonathandiep jonathandiep marked this pull request as ready for review April 5, 2024 08:40
@jonathandiep jonathandiep requested a review from a team as a code owner April 5, 2024 08:40
@@ -166,7 +172,8 @@ contract QuestFactory is Initializable, LegacyStorage, OwnableRoles, IQuestFacto
actionType_,
questName_,
"erc20",
projectName_
projectName_,
referralRewardFee_
Copy link
Contributor Author

@jonathandiep jonathandiep Apr 5, 2024

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?

Copy link
Member

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?

Copy link
Contributor Author

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(
Copy link
Contributor Author

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"

Copy link
Member

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.

Copy link
Member

@Quazia Quazia left a 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_);
Copy link
Member

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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice approach - clean

contracts/Quest.sol Outdated Show resolved Hide resolved
contracts/Quest.sol Outdated Show resolved Hide resolved
@@ -180,6 +181,10 @@ contract Quest1155 is ERC1155Holder, ReentrancyGuardUpgradeable, PausableUpgrade
return questId;
}

function referralRewardAmount() external pure returns (uint256) {
Copy link
Member

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.

Copy link
Contributor Author

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_
Copy link
Member

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(
Copy link
Member

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 {
Copy link
Member

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.

Copy link
Contributor Author

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 {
Copy link
Member

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.

Copy link
Contributor Author

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

Copy link
Contributor

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.

Copy link
Member

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.

@jonathandiep jonathandiep requested a review from Quazia April 5, 2024 23:40
@jonathandiep jonathandiep force-pushed the jon/referral-rewards branch from 14e515b to 071ee85 Compare April 9, 2024 16:58
Copy link
Member

@Quazia Quazia left a 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.

@jonathandiep jonathandiep force-pushed the jon/referral-rewards branch from bb209c6 to 7500d39 Compare April 16, 2024 19:18
@@ -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;
Copy link
Member

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) ;

Copy link
Member

@Quazia Quazia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@jonathandiep jonathandiep merged commit d0e7c24 into main Apr 29, 2024
2 checks passed
@jonathandiep jonathandiep deleted the jon/referral-rewards branch April 29, 2024 20:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants