Skip to content

Commit

Permalink
feat: support withdraw of excess RPL
Browse files Browse the repository at this point in the history
  • Loading branch information
dmccartney committed Dec 6, 2023
1 parent 35bf289 commit 09baede
Show file tree
Hide file tree
Showing 9 changed files with 601 additions and 26 deletions.
9 changes: 2 additions & 7 deletions web/src/components/ClaimAndStakeForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,7 @@ export function ClaimButtonTooltip({
currency="eth"
placeholder="0"
/>
<CurrencyValue
value={rplTotal.sub(stakeAmountRpl)}
currency="rpl"
placeholder="0"
/>
<CurrencyValue value={rplTotal} currency="rpl" placeholder="0" />
</Stack>
<FormHelperText sx={{ m: 0 }}>
approximate receipts (after gas)
Expand Down Expand Up @@ -183,8 +179,7 @@ export default function ClaimAndStakeForm({
<ClaimButtonTooltip
gasAmount={gasAmount}
ethTotal={ethTotal}
rplTotal={rplTotal}
stakeAmountRpl={stakeAmountRpl}
rplTotal={rplTotal.sub(stakeAmountRpl)}
/>
}
>
Expand Down
6 changes: 3 additions & 3 deletions web/src/components/NodeRewardsSummaryCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ function SummaryCardHeader({ asLink, nodeAddress }) {
let { rplStake } = details || {
rplStake: ethers.constants.Zero,
};
const rplStatus = useNodeRplStatus({ nodeAddress });
const { rplStatus } = useNodeRplStatus({ nodeAddress });
const depositEth = bnSum(
(minipools || [])
.filter((mp) => !mp.isFinalized)
Expand Down Expand Up @@ -653,7 +653,7 @@ function RplStakeEthRangeAxis({ sx, nodeAddress }) {
const theme = useTheme();
const minipools = useMinipoolDetails(nodeAddress);
const { data: details } = useNodeDetails({ nodeAddress });
let rplStatus = useNodeRplStatus({ nodeAddress });
let { rplStatus } = useNodeRplStatus({ nodeAddress });
let { ethMatched } = details || {
ethMatched: ethers.constants.Zero,
minipoolCount: ethers.constants.Zero,
Expand Down Expand Up @@ -785,7 +785,7 @@ function RplStakeChart({ sx, nodeAddress }) {
const theme = useTheme();
const { data: details } = useNodeDetails({ nodeAddress });
const rplEthPrice = useRplEthPrice();
let rplStatus = useNodeRplStatus({ nodeAddress });
let { rplStatus } = useNodeRplStatus({ nodeAddress });
let { rplStake, minimumRPLStake, maximumRPLStake } = details || {
rplStake: ethers.constants.Zero,
minimumRPLStake: ethers.constants.Zero,
Expand Down
172 changes: 162 additions & 10 deletions web/src/components/SafeSweepCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import {
estimateDistributeConsensusBatchGas,
estimateFinalizeGas,
estimateTipsMevGas,
estimateWithdrawRplGas,
MinipoolStatus,
safeAppUrl,
} from "../utils";
Expand All @@ -58,6 +59,7 @@ import useNodeFinalizedRewardSnapshots from "../hooks/useNodeFinalizedRewardSnap
import contracts from "../contracts";
import useNodeDetails from "../hooks/useNodeDetails";
import { ClaimButtonTooltip } from "./ClaimAndStakeForm";
import useNodeRplStatus from "../hooks/useNodeRplStatus";

function ConsensusConfigurationCard({
sx,
Expand Down Expand Up @@ -361,6 +363,8 @@ function SafeAlert({ sx, nodeAddress }) {

function useSweeper({ nodeAddress }) {
let { data: details } = useNodeDetails({ nodeAddress });
let { rplOver } = useNodeRplStatus({ nodeAddress });

let { feeDistributorAddress } = details || {};

// Intervals configuration
Expand Down Expand Up @@ -447,6 +451,14 @@ function useSweeper({ nodeAddress }) {
(finalizableMinipools || []).map(({ nodeBalance }) => nodeBalance)
);

let [isWithdrawingRpl, setIsWithdrawingRpl] = useState(rplOver.gt(0));
// If we get an updated `rplOver` later, we want to use it as the default.
useEffect(
() => setIsWithdrawingRpl(rplOver.gt(0)),
// eslint-disable-next-line react-hooks/exhaustive-deps
[rplOver?.toString()]
);

let beforeGas = {
intervalsEth: totalEth,
tipsMevEth: executionNodeTotal,
Expand All @@ -463,6 +475,7 @@ function useSweeper({ nodeAddress }) {
tipsMev: estimateTipsMevGas(),
consensus: estimateDistributeConsensusBatchGas((currentBatch || []).length),
finalize: estimateFinalizeGas(finalizableMinipools.length),
withdrawRpl: estimateWithdrawRplGas(),
};
let overall = {
eth: bnSum([
Expand All @@ -471,14 +484,16 @@ function useSweeper({ nodeAddress }) {
isDistributingConsensus ? beforeGas.consensusEth : ethers.constants.Zero,
isFinalizing ? beforeGas.finalizeEth : ethers.constants.Zero,
]),
rpl: isClaimingInterval
? totalRpl.sub(stakeAmountRpl)
: ethers.constants.Zero,
rpl: bnSum([
isClaimingInterval ? totalRpl.sub(stakeAmountRpl) : ethers.constants.Zero,
isWithdrawingRpl ? rplOver : ethers.constants.Zero,
]),
gas: bnSum([
isClaimingInterval ? gas.intervals : ethers.constants.Zero,
isDistributingTipsMev ? gas.tipsMev : ethers.constants.Zero,
isDistributingConsensus ? gas.consensus : ethers.constants.Zero,
isFinalizing ? gas.finalize : ethers.constants.Zero,
isWithdrawingRpl ? gas.withdrawRpl : ethers.constants.Zero,
]),
};
if (!overall.gas.isZero()) {
Expand Down Expand Up @@ -537,6 +552,18 @@ function useSweeper({ nodeAddress }) {
}))
);
}
if (isWithdrawingRpl) {
txs = txs.concat([
{
operation: "0x00",
to: contracts.RocketNodeStaking.address,
value: "0",
data: new ethers.utils.Interface(
contracts.RocketNodeStaking.abi
).encodeFunctionData("withdrawRPL", [rplOver]),
},
]);
}
return sdk.txs.send({
txs,
});
Expand Down Expand Up @@ -578,6 +605,11 @@ function useSweeper({ nodeAddress }) {
finalizableMinipools,
finalizeAmount,

// Excess RPL config
isWithdrawingRpl,
setIsWithdrawingRpl,
rplOver,

// Analysis
beforeGas,
gas,
Expand Down Expand Up @@ -612,6 +644,10 @@ function SweepCardContent({ sx, nodeAddress, sweeper }) {
setFinalizing,
finalizableMinipools,

isWithdrawingRpl,
setIsWithdrawingRpl,
rplOver,

beforeGas,
gas,
overall,
Expand Down Expand Up @@ -952,6 +988,82 @@ function SweepCardContent({ sx, nodeAddress, sweeper }) {
</Stack>
}
/>
<IconRow Icon={Add} />
<TransactionRow
lhs={
<Grid
sx={{ pt: 0, pr: 3 }}
container
rowSpacing={2}
columnSpacing={2}
alignItems="center"
>
<Grid item xs={5} sx={{ textAlign: "right" }}>
<Tooltip
arrow
sx={{ cursor: "help" }}
title="Withdraw your staked RPL beyond the maximum effective stake."
>
<Stack
direction={"row"}
spacing={1}
justifyContent="end"
alignItems={"center"}
>
<HelpOutline fontSize="inherit" color="disabled" />
<Typography color={"text.primary"} variant={"subtitle2"}>
Excess RPL
</Typography>
</Stack>
</Tooltip>
</Grid>
<Grid item xs={7}>
<FormControlLabel
control={
<Checkbox
checked={isWithdrawingRpl}
onChange={(e) => setIsWithdrawingRpl(e.target.checked)}
/>
}
color="text.secondary"
slotProps={{
typography: {
variant: "caption",
color: "text.secondary",
},
}}
disableTypography
label={
<Stack spacing={0} direction="column">
<CurrencyValue
size="xsmall"
value={rplOver}
currency="rpl"
/>
<FormHelperText sx={{ m: 0 }}>
{isWithdrawingRpl ? "Withdrawing" : "Not Withdrawing"}
</FormHelperText>
</Stack>
}
/>
</Grid>
</Grid>
}
rhs={
<Stack direction="column" sx={{ pl: 2, pr: 2 }} spacing={2}>
{!isWithdrawingRpl ? null : (
<ReceiptsInfo amountRpl={rplOver} amountGas={gas.withdrawRpl} />
)}
<TransactionDescription
title={
!isWithdrawingRpl
? "Don't withdraw excess RPL"
: "Withdraw excess RPL"
}
/>
</Stack>
}
/>
<IconRow
Icon={Merge}
iconProps={{
Expand Down Expand Up @@ -1027,6 +1139,8 @@ export default function SafeSweepCard({ sx, nodeAddress }) {
isDistributingTipsMev,
isDistributingConsensus,
isFinalizing,
isWithdrawingRpl,
rplOver,
totalRpl,
totalEth,
rewardIndexes,
Expand Down Expand Up @@ -1077,7 +1191,7 @@ export default function SafeSweepCard({ sx, nodeAddress }) {
<ClaimButtonTooltip
gasAmount={overall.gas}
ethTotal={overall.eth}
rplTotal={isClaimingInterval ? totalRpl : ethers.constants.Zero}
rplTotal={overall.rpl}
stakeAmountRpl={
isClaimingInterval ? stakeAmountRpl : ethers.constants.Zero
}
Expand Down Expand Up @@ -1227,6 +1341,35 @@ export default function SafeSweepCard({ sx, nodeAddress }) {
</Grid>
</>
)}
{!isWithdrawingRpl ? null : (
<>
<Grid item xs={4.5}>
<Stack direction="row" justifyContent="flex-end">
<Typography
component="span"
variant="caption"
color="text.secondary"
>
excess RPL
</Typography>
</Stack>
</Grid>
<Grid item xs={7.5}>
<Stack
direction="row"
spacing={1}
justifyContent="flex-start"
>
<CurrencyValue
size="xsmall"
value={rplOver}
currency="rpl"
placeholder="0"
/>
</Stack>
</Grid>
</>
)}
</Grid>
</Stack>
</ClaimButtonTooltip>
Expand Down Expand Up @@ -1267,12 +1410,21 @@ export default function SafeSweepCard({ sx, nodeAddress }) {
color={color}
disabled={!canWithdraw}
endIcon={
<CurrencyValue
value={overall.eth}
size="xsmall"
currency="eth"
placeholder="0"
/>
<>
<CurrencyValue
value={overall.eth}
size="xsmall"
currency="eth"
placeholder="0"
/>
<CurrencyValue
sx={{ ml: 1 }}
value={overall.rpl}
size="xsmall"
currency="rpl"
placeholder="0"
/>
</>
}
>
Sweep
Expand Down
5 changes: 5 additions & 0 deletions web/src/contracts.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import RocketMinipoolManager from "./generated/contracts/RocketMinipoolManager.j
import RocketNetworkPrices from "./generated/contracts/RocketNetworkPrices.json";
import RocketNodeDistributorInterface from "./generated/contracts/RocketNodeDistributorInterface.json";
import RocketNodeManager from "./generated/contracts/RocketNodeManager.json";
import RocketNodeStaking from "./generated/contracts/RocketNodeStaking.json";
import RocketRewardsPool from "./generated/contracts/RocketRewardsPool.json";
import RocketStorageK from "./generated/contracts/RocketStorage.json";

Expand Down Expand Up @@ -39,6 +40,10 @@ const contracts = {
address: "0x89F478E6Cc24f052103628f36598D4C14Da3D287",
abi: RocketNodeManager.abi,
},
RocketNodeStaking: {
address: "0x0d8D8f8541B12A0e1194B7CC4b6D954b90AB82ec",
abi: RocketNodeStaking.abi,
},
RocketRewardsPool: {
address: [
"0xA805d68b61956BC92d556F2bE6d18747adAeEe82",
Expand Down
Loading

0 comments on commit 09baede

Please sign in to comment.