Skip to content

Commit

Permalink
feat: implements partial slashing (#402)
Browse files Browse the repository at this point in the history
* feat: adds logic to mitigate against insufficent funds bug

* feat: adds testing for edge cases of penatly and residual balance slashing

* chore: newline

* chore: remove whitespace

* chore: constructs the provider registry abi

* feat: start reducing storage reads

Co-authored-by: Mikhail Wall <[email protected]>

* feat: reduce storage reads

* feat: fixes bug around not slashing the provider balance.

* chore: remove empty line

---------

Co-authored-by: Mikhail Wall <[email protected]>
  • Loading branch information
ckartik and Mikelle authored Sep 17, 2024
1 parent 4605509 commit 8eb78b9
Show file tree
Hide file tree
Showing 5 changed files with 243 additions and 5 deletions.
31 changes: 31 additions & 0 deletions contracts-abi/abi/ProviderRegistry.abi
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,37 @@
],
"anonymous": false
},
{
"type": "event",
"name": "InsufficientFundsToSlash",
"inputs": [
{
"name": "provider",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "providerStake",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "residualAmount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "penaltyFee",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"type": "event",
"name": "OwnershipTransferStarted",
Expand Down
149 changes: 148 additions & 1 deletion contracts-abi/clients/ProviderRegistry/ProviderRegistry.go

Large diffs are not rendered by default.

10 changes: 9 additions & 1 deletion contracts/contracts/core/ProviderRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,15 @@ contract ProviderRegistry is
) external nonReentrant onlyPreConfirmationEngine whenNotPaused {
uint256 residualAmt = (amt * residualBidPercentAfterDecay * PRECISION) / PERCENT;
uint256 penaltyFee = (residualAmt * uint256(feePercent) * PRECISION) / PERCENT;
require(providerStakes[provider] >= residualAmt + penaltyFee, "Insufficient funds to slash");
uint256 providerStake = providerStakes[provider];

if (providerStake < residualAmt + penaltyFee) {
emit InsufficientFundsToSlash(provider, providerStake, residualAmt, penaltyFee);
if (providerStake < residualAmt) {
residualAmt = providerStake;
}
penaltyFee = providerStake - residualAmt;
}
providerStakes[provider] -= residualAmt + penaltyFee;

penaltyFeeTracker.accumulatedAmount += penaltyFee;
Expand Down
8 changes: 8 additions & 0 deletions contracts/contracts/interfaces/IProviderRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ interface IProviderRegistry {
/// @dev Event emitted when the fee payout period in blocks is updated
event FeePayoutPeriodBlocksUpdated(uint256 indexed newFeePayoutPeriodBlocks);

/// @dev Event emitted when there are insufficient funds to slash
event InsufficientFundsToSlash(
address indexed provider,
uint256 providerStake,
uint256 residualAmount,
uint256 penaltyFee
);

function registerAndStake(bytes calldata blsPublicKey) external payable;

function stake() external payable;
Expand Down
50 changes: 47 additions & 3 deletions contracts/test/core/ProviderRegistryTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ contract ProviderRegistryTest is Test {
event FeeTransfer(uint256 amount, address indexed recipient);
event PenaltyFeeRecipientUpdated(address indexed newPenaltyFeeRecipient);
event FeePayoutPeriodBlocksUpdated(uint256 indexed newFeePayoutPeriodBlocks);
event InsufficientFundsToSlash(
address indexed provider,
uint256 providerStake,
uint256 residualAmt,
uint256 penaltyFee
);

function setUp() public {
testNumber = 42;
Expand Down Expand Up @@ -257,21 +263,59 @@ contract ProviderRegistryTest is Test {
vm.expectRevert(bytes(""));
providerRegistry.slash(1 ether, provider, payable(bidder),100);
}

function testFail_ShouldRetrieveFundsGreaterThanStake() public {
function test_ShouldRetrieveFundsWhenSlashIsGreaterThanStake() public {
vm.prank(address(this));
providerRegistry.setPreconfirmationsContract(address(this));

vm.deal(provider, 3 ether);
vm.prank(provider);
providerRegistry.registerAndStake{value: 2 ether}(validBLSPubkey);
address bidder = vm.addr(4);
vm.expectRevert(bytes(""));
vm.prank(address(this));

vm.expectEmit(true, true, true, true);
emit InsufficientFundsToSlash(provider, 2 ether, 3 ether, 0.3 ether);
providerRegistry.slash(3 ether, provider, payable(bidder), 100);

assertEq(providerRegistry.getAccumulatedPenaltyFee(), 0);
assertEq(providerRegistry.providerStakes(provider), 0 ether);
}

function test_ShouldRetrieveFundsWhenSlashIsGreaterThanStakePenaltyNotCovered() public {
vm.prank(address(this));
providerRegistry.setPreconfirmationsContract(address(this));

vm.deal(provider, 3 ether);
vm.prank(provider);
providerRegistry.registerAndStake{value: 3 ether}(validBLSPubkey);
address bidder = vm.addr(4);
vm.prank(address(this));

vm.expectEmit(true, true, true, true);
emit InsufficientFundsToSlash(provider, 3 ether, 3 ether, 0.3 ether);
providerRegistry.slash(3 ether, provider, payable(bidder), 100);

assertEq(providerRegistry.getAccumulatedPenaltyFee(), 0);
assertEq(providerRegistry.providerStakes(provider), 0 ether);
}

function test_ShouldRetrieveFundsWhenSlashIsGreaterThanStakePenaltyNotFullyCovered() public {
vm.prank(address(this));
providerRegistry.setPreconfirmationsContract(address(this));

vm.deal(provider, 3.1 ether);
vm.prank(provider);
providerRegistry.registerAndStake{value: 3.1 ether}(validBLSPubkey);
address bidder = vm.addr(4);
vm.prank(address(this));

vm.expectEmit(true, true, true, true);
emit InsufficientFundsToSlash(provider, 3.1 ether, 3 ether, 0.3 ether);
providerRegistry.slash(3 ether, provider, payable(bidder), 100);

assertEq(providerRegistry.getAccumulatedPenaltyFee(), 0.1 ether);
assertEq(providerRegistry.providerStakes(provider), 0 ether);
}
function test_PenaltyFeeBehavior() public {
providerRegistry.setNewPenaltyFeeRecipient(vm.addr(6));
vm.deal(provider, 3 ether);
Expand Down

0 comments on commit 8eb78b9

Please sign in to comment.