Skip to content

Instantly share code, notes, and snippets.

@xrchz
Last active June 22, 2024 23:08
Show Gist options
  • Save xrchz/d173403003ed4097b8e1873bd27096f1 to your computer and use it in GitHub Desktop.
Save xrchz/d173403003ed4097b8e1873bd27096f1 to your computer and use it in GitHub Desktop.
Ways of getting Rocket Pool Rewards
import { ethers } from 'ethers'
// tested using a fork of mainnet (where we can impersonate the signers)
// e.g. anvil -f http://localhost:8545@20143000 -p 8549
const provider = new ethers.JsonRpcProvider('http://localhost:8549')
const rocketStorage = new ethers.Contract('rocketstorage.eth',
[
'function getAddress(bytes32) view returns (address)',
'function getNodeWithdrawalAddress(address) view returns (address)'
],
provider)
const getRocketContract = async (name, abi) =>
new ethers.Contract(await rocketStorage['getAddress(bytes32)'](ethers.id(`contract.address${name}`)), abi, provider)
// We will use this node as our test subject
const nodeEns = '🎉️👯‍♀️🥳️.eth'
const nodeAddress = await provider.resolveName(nodeEns)
await provider.send("anvil_impersonateAccount", [nodeAddress])
const signer = await provider.getSigner(nodeAddress)
const withdrawalAddress = await rocketStorage.getNodeWithdrawalAddress(nodeAddress)
const RPL = await getRocketContract('rocketTokenRPL', ['function balanceOf(address) view returns (uint256)'])
const printBalances = async (msg) => {
console.log(msg)
console.log(`Withdrawal address ETH: ${ethers.formatEther(await provider.getBalance(withdrawalAddress))}`)
console.log(`Withdrawal address RPL: ${ethers.formatEther(await RPL.balanceOf(withdrawalAddress))}`)
console.log()
}
// Claim minipool rewards
const rocketMinipoolManager = await getRocketContract('rocketMinipoolManager', ['function getNodeMinipoolAt(address node,uint256 index) view returns (address)'])
const minipoolAddress = await rocketMinipoolManager.getNodeMinipoolAt(nodeAddress, 0)
const minipool = new ethers.Contract(minipoolAddress, ['function distributeBalance(bool rewardsOnly)'], provider)
await printBalances('Before distributeBalance')
await minipool.connect(signer).distributeBalance(true).then(t => t.wait())
await printBalances('After distributeBalance')
// N.B.: minipools also have refund() and close() methods that might be needed for retrieving funds from them. Since they are not primarily about rewards I haven't looked into how to use them in this file
// Claim fee distributor rewards
const feeDistributorManager = await getRocketContract('rocketNodeDistributorFactory', ['function getProxyAddress(address node) view returns (address)'])
const feeDistributorAddress = await feeDistributorManager.getProxyAddress(nodeAddress)
const feeDistributor = new ethers.Contract(feeDistributorAddress, ['function distribute()'])
await printBalances('Before distribute')
await feeDistributor.connect(signer).distribute().then(t => t.wait())
await printBalances('After distribute')
// Claim interval rewards (RPL + smoothing pool)
import { existsSync, readFileSync, createWriteStream } from 'node:fs'
import { Readable } from 'node:stream'
const rocketRewardsPool = await getRocketContract('rocketRewardsPool', [
'function getRewardIndex() view returns (uint256)'
])
const merkleDistributor = await getRocketContract('rocketMerkleDistributorMainnet', [
'function isClaimed(uint256 index, address node) view returns (bool)',
'function claimAndStake(address node, uint256[] index, uint256[] amountRPL, uint256[] amountETH,' +
' bytes32[][] merkleProof, uint256 stakeAmount)'
])
const latestIndex = await rocketRewardsPool.getRewardIndex()
const unclaimedIntervals = []
for (let i = 0; i < latestIndex; i++)
if (!(await merkleDistributor.isClaimed(i, nodeAddress)))
unclaimedIntervals.push(i)
console.log(`Got unclaimed intervals: ${unclaimedIntervals}`)
const rewardFileUrl = 'https://github.com/rocket-pool/rewards-trees/raw/main/mainnet/'
const intervalRewards = []
for (const i of unclaimedIntervals) {
const filename = `rp-rewards-mainnet-${i}.json`
if (!existsSync(filename)) {
const response = await fetch(`${rewardFileUrl}${filename}`)
const readStream = Readable.fromWeb(response.body)
const promise = new Promise(resolve => readStream.on('end', resolve))
readStream.pipe(createWriteStream(filename))
await promise
}
const {nodeRewards} = JSON.parse(readFileSync(filename))
const {smoothingPoolEth, collateralRpl, merkleProof} = nodeRewards[nodeAddress.toLowerCase()] ?? {}
intervalRewards.push({
ETH: BigInt(smoothingPoolEth || 0),
RPL: BigInt(collateralRpl || 0),
proof: merkleProof
})
}
let totalRPL = 0n
const claimIndices = []
const amountRPL = []
const amountETH = []
const proofs = []
for (const [i, {ETH, RPL, proof}] of intervalRewards.entries()) {
if (typeof proof === 'undefined') continue
claimIndices.push(unclaimedIntervals[i])
amountRPL.push(RPL)
amountETH.push(ETH)
proofs.push(proof)
totalRPL += RPL
console.log(`Available rewards for Interval ${claimIndices.at(-1)}:`)
console.log(`ETH: ${ethers.formatEther(ETH)}`)
console.log(`RPL: ${ethers.formatEther(RPL)}`)
console.log()
}
// restake 10% of the total RPL, retrieve the rest
const restakeAmount = totalRPL / 10n
const rocketNodeStaking = await getRocketContract('rocketNodeStaking',
['function getNodeRPLStake(address node) view returns (uint256)'])
const printStake = async () => {
const amount = await rocketNodeStaking.getNodeRPLStake(nodeAddress)
console.log(`RPL staked: ${ethers.formatEther(amount)}`)
}
await printBalances('Before claimAndStake')
await printStake()
await merkleDistributor.connect(signer).claimAndStake(
nodeAddress,
claimIndices,
amountRPL,
amountETH,
proofs,
restakeAmount
)
await printBalances('After claimAndStake')
await printStake()
/* expected output:
Before distributeBalance
Withdrawal address ETH: 0.0
Withdrawal address RPL: 0.0
After distributeBalance
Withdrawal address ETH: 0.04920901867
Withdrawal address RPL: 0.0
Before distribute
Withdrawal address ETH: 0.04920901867
Withdrawal address RPL: 0.0
After distribute
Withdrawal address ETH: 0.06033272080216608
Withdrawal address RPL: 0.0
Got unclaimed intervals: 0,1,2,3,4,5,23
Available rewards for Interval 23:
ETH: 0.0
RPL: 21.106327077063228527
Before claimAndStake
Withdrawal address ETH: 0.06033272080216608
Withdrawal address RPL: 0.0
RPL staked: 2569.00000000000001149
After claimAndStake
Withdrawal address ETH: 0.06033272080216608
Withdrawal address RPL: 18.995694369356905675
RPL staked: 2571.110632707706334342
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment