Skip to content

Conversation

abarmat
Copy link
Contributor

@abarmat abarmat commented Feb 15, 2021

  • Indexer can set a rewards destination for indexing rewards after closing an allocation and for rebate claims
  • If rewards destination is set to zero, indexing rewards are restaked

Copy link

@pi0neerpat pi0neerpat left a comment

Choose a reason for hiding this comment

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

  1. call setRewardsDestination(address _destination) from your indexer.
  2. close allocation, which will call _distributeRewards and then _sendRewards

Clean and simple, I like it!

@@ -82,3 +82,7 @@ contract StakingV1Storage is Managed {
// Allowed AssetHolders: assetHolder => is allowed
mapping(address => bool) public assetHolders;
}

contract StakingV2Storage is StakingV1Storage {

Choose a reason for hiding this comment

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

Nice proxy skillz

require(graphToken.transfer(alloc.indexer, tokensToClaim), "!transfer");
}
}
_sendRewards(graphToken, tokensToClaim, alloc.indexer, restake);

Choose a reason for hiding this comment

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

This means the indexer agent has to be updated too right? Since this is only for query fees, I think its ok to not have this feature in the agent for now

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So to not change the current claim() interface, if you pass this method restake=true it will restake if restake=false it will send rewards out.

@pi0neerpat
Copy link

Any tests planned to be added?

@abarmat
Copy link
Contributor Author

abarmat commented Feb 15, 2021

Any tests planned to be added?

Yes, I'm pushing them in a minute

Copy link
Contributor

@davekay100 davekay100 left a comment

Choose a reason for hiding this comment

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

In general looks good, looking forward to see the tests

* @param _destination Rewards destination address. If set to zero, rewards will be restaked
*/
function setRewardsDestination(address _destination) public override {
rewardsDestination[msg.sender] = _destination;
Copy link
Contributor

Choose a reason for hiding this comment

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

Ariel slacked me saying he will add an event here, good idea

Copy link
Contributor

Choose a reason for hiding this comment

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

Can we make it external? This is what the interface shows, seems we are no using it within the contract

Copy link
Contributor

Choose a reason for hiding this comment

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

event added :)

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'll change it to be external. An event was added to this function too.

Choose a reason for hiding this comment

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

Will _destination be set up via Remix or some key in Agent config?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

setRewardsDestination() is a function that needs to be called by the indexer address (the one that staked), in the case of an indexer through a TokenLock it needs be called initially through Remix. The feature can be potentially integrated in the frontend too.

@@ -82,3 +82,7 @@ contract StakingV1Storage is Managed {
// Allowed AssetHolders: assetHolder => is allowed
mapping(address => bool) public assetHolders;
}

contract StakingV2Storage is StakingV1Storage {
mapping(address => address) public rewardsDestination;
Copy link
Contributor

Choose a reason for hiding this comment

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

We could add a comment here to describe what rewardsDestination is

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea

@@ -717,6 +717,14 @@ contract Staking is StakingV1Storage, GraphUpgradeable, IStaking {
_withdraw(msg.sender);
}

/**
* @dev Set the destination where to send rewards.
* @param _destination Rewards destination address. If set to zero, rewards will be restaked
Copy link
Contributor

Choose a reason for hiding this comment

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

great idea that set to 0 = restaked. this way, when the upgrade happens, it will automatically be set so that everyone is re-staking. we won't run into any breaks

address destination = rewardsDestination[_beneficiary];
require(
_graphToken.transfer(
destination == address(0) ? _beneficiary : destination,
Copy link
Contributor

Choose a reason for hiding this comment

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

I believe this ternary is not needed. If we got this far, we already know that rewardsDestination[_beneficiary] != 0

this would work:

require(_graphToken.transfer(rewardsDestination[beneficiary]), _amount, "!transfer");

wdyt?

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 depends, when the function is called from _claim() it might not be the case.

Copy link
Contributor

Choose a reason for hiding this comment

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

you are right ! there is nothing wrong with this code

Copy link
Contributor

@davekay100 davekay100 left a comment

Choose a reason for hiding this comment

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

Tests added look good!

expect(toRound(afterIndexer1Balance)).eq(
toRound(beforeIndexer1Balance.add(expectedIndexingRewards)),
)
// Check indexing rewards are sent from the staking contract
Copy link
Contributor

Choose a reason for hiding this comment

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

is it more accurate to say check indexing rewards were not sent to the staking contract ? (basically they get minted and send directly to the indexer AFAICT)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, what I tried to say is that rewards are out of the staking contract

const afterStakingBalance = await grt.balanceOf(staking.address)

// Check that rewards are put into indexer stake
// NOTE: calculated manually on a spreadsheet
Copy link
Contributor

Choose a reason for hiding this comment

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

Note sure what this note really means

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 is an outdated comment from the test I used as base for this one, I'll update it

@abarmat
Copy link
Contributor Author

abarmat commented Feb 16, 2021

I did some benchmark of gas usage for the solution that send rewards directly and the one that uses a rewards pool:

            |  Contract      ·  Method                 ·  Min        ·  Max        ·  Avg        ·  # calls    ·  usd (avg)   │
RewardPool: |  Staking       ·  closeAllocation        ·          -  ·          -  ·     256898  ·          1  ·           -  │
DirectTx:   |  Staking       ·  closeAllocation        ·          -  ·          -  ·     269114  ·          1  ·           -  │

Sending directly to the beneficiary on close is about 4% more expensive. So it might be a good idea to have a rewards pool where multiple rewards across many closeAllocations() and claim() are accumulated before calling withdrawRewards(), this will be only more efficient in the cases an indexer waits to call withdraw.

@davekaj wdyt?

Copy link
Contributor

@davekay100 davekay100 left a comment

Choose a reason for hiding this comment

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

changes look good to me

Copy link
Contributor

@davekay100 davekay100 left a comment

Choose a reason for hiding this comment

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

Looks good to me. It would be nice to run some tests before actually merging to master.

which makes me think - what should our strategy be for merging to master?

My first thought is that we should only merge to master when the changes are actually deployed to mainnet. Meaning we could create a dev branch or something right now.

I am open to other suggestions!

@pi0neerpat
Copy link

pi0neerpat commented Feb 19, 2021

Just a suggestion, but you're welcome to copy some of what we do here https://github.com/superfluid-finance/protocol-monorepo

  • Set up a canary branch ("main" or "dev")
  • Set this as default branch when people land on the repo, or make any PRs
  • Every time a PR is merged to master, the new contracts are deployed (upgraded) to testnet
  • When things are upgraded/deployed to mainnet then we merge to "master" to reflect this as you mentioned @davekaj

Patch versions are updated on releasing to canary
Minor versions are updated on merging to master

@abarmat abarmat changed the title staking: set rewards destination Set indexing rewards destination Feb 21, 2021
@abarmat abarmat changed the title Set indexing rewards destination Set indexer rewards destination Feb 21, 2021
@abarmat abarmat merged commit f1fa480 into master Mar 29, 2021
@abarmat abarmat deleted the ariel/rewards-pool branch November 10, 2021 06:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants