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

feat: add getSharesFromQueuedWithdrawal #1078

Open
wants to merge 5 commits into
base: slashing-magnitudes-fixes
Choose a base branch
from

Conversation

0xClandestine
Copy link
Member

@0xClandestine 0xClandestine commented Feb 10, 2025

Motivation:

Users want a cost effective way to query withdrawable shares.

Modifications:

  • added getSharesFromQueuedWithdrawal(bytes32 withdrawalRoot)
  • renamed getQueuedWithdrawals to getSharesFromQueuedWithdrawals.

Result:

Users can query withdrawable shares with withdrawalRoot alone.

@0xClandestine 0xClandestine changed the base branch from dev to slashing-magnitudes-fixes February 10, 2025 17:59
@0xClandestine 0xClandestine changed the title Feat: queued withdrawal shares alias feat: add getSharesFromQueuedWithdrawal Feb 10, 2025
src/contracts/interfaces/IDelegationManager.sol Outdated Show resolved Hide resolved
src/test/unit/DelegationUnit.t.sol Outdated Show resolved Hide resolved
src/contracts/core/DelegationManager.sol Outdated Show resolved Hide resolved
Comment on lines +783 to +812
withdrawal = queuedWithdrawals[withdrawalRoot];
shares = new uint256[](withdrawal.strategies.length);

address operator = delegatedTo[withdrawal.staker];
uint32 slashableUntil = withdrawal.startBlock + MIN_WITHDRAWAL_DELAY_BLOCKS;

uint256[] memory slashingFactors;
// If slashableUntil block is in the past, read the slashing factors at that block
// Otherwise read the current slashing factors. Note that if the slashableUntil block is the current block
// or in the future then the slashing factors are still subject to change before the withdrawal is completable
// and the shares withdrawn to be less
if (slashableUntil < uint32(block.number)) {
slashingFactors = _getSlashingFactorsAtBlock({
staker: withdrawal.staker,
operator: operator,
strategies: withdrawal.strategies,
blockNumber: slashableUntil
});
} else {
slashingFactors =
_getSlashingFactors({staker: withdrawal.staker, operator: operator, strategies: withdrawal.strategies});
}

for (uint256 j; j < withdrawal.strategies.length; ++j) {
shares[j] = SlashingLib.scaleForCompleteWithdrawal({
scaledShares: withdrawal.scaledShares[j],
slashingFactor: slashingFactors[j]
});
}
}
Copy link
Member

@bowenli86 bowenli86 Feb 10, 2025

Choose a reason for hiding this comment

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

my concern is that this view function is essentially doing some heavy computing on the fly, which is
1/ really inefficient, eg consecutive read with same root would require it to compute again and again
2/ it's essentially not "view" function anymore. view function IMHO should be an read only operation that expose an already existance state, to make it vieweable by others. But in this case, the state to be read does not exist at all and have to be computed on the fly, so it's more like a write operation

Whereas a more proper way is to precompute everything and the view function only does a quick lookup read

is there a way to make it the 2nd pattern?

Copy link
Member Author

Choose a reason for hiding this comment

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

Are you suggesting tracking this in storage?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ya, a bit confused on the ask here @bowenli86? This value can't be stored because its dynamic (slashing while in the queue)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Remember, not all view functions need to be called on-chain, some are designed to be called off-chain too, where the gas limit is not the same

Copy link
Member

Choose a reason for hiding this comment

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

yea the concern is this seems not to be a view function for either onchain or offchain, b/c it's doing a bunch of complex logic rather than just get sth out of shelf.

but i see your point of it being dynamic, especially it's expensive to update the value every block

not sure what's the best design pattern for such cases.
not a blocker

function _getSharesFromQueuedWithdrawal(
bytes32 withdrawalRoot
) internal view returns (Withdrawal memory withdrawal, uint256[] memory shares) {
withdrawal = queuedWithdrawals[withdrawalRoot];
Copy link
Member

Choose a reason for hiding this comment

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

what happens if the withdrawal is already completed or does not exist in queue?

Comment on lines +783 to +812
withdrawal = queuedWithdrawals[withdrawalRoot];
shares = new uint256[](withdrawal.strategies.length);

address operator = delegatedTo[withdrawal.staker];
uint32 slashableUntil = withdrawal.startBlock + MIN_WITHDRAWAL_DELAY_BLOCKS;

uint256[] memory slashingFactors;
// If slashableUntil block is in the past, read the slashing factors at that block
// Otherwise read the current slashing factors. Note that if the slashableUntil block is the current block
// or in the future then the slashing factors are still subject to change before the withdrawal is completable
// and the shares withdrawn to be less
if (slashableUntil < uint32(block.number)) {
slashingFactors = _getSlashingFactorsAtBlock({
staker: withdrawal.staker,
operator: operator,
strategies: withdrawal.strategies,
blockNumber: slashableUntil
});
} else {
slashingFactors =
_getSlashingFactors({staker: withdrawal.staker, operator: operator, strategies: withdrawal.strategies});
}

for (uint256 j; j < withdrawal.strategies.length; ++j) {
shares[j] = SlashingLib.scaleForCompleteWithdrawal({
scaledShares: withdrawal.scaledShares[j],
slashingFactor: slashingFactors[j]
});
}
}
Copy link
Member

Choose a reason for hiding this comment

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

yea the concern is this seems not to be a view function for either onchain or offchain, b/c it's doing a bunch of complex logic rather than just get sth out of shelf.

but i see your point of it being dynamic, especially it's expensive to update the value every block

not sure what's the best design pattern for such cases.
not a blocker

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