Skip to content

Commit

Permalink
TACoChildApplication: endpoint for sending penalty to the root app
Browse files Browse the repository at this point in the history
  • Loading branch information
vzotova committed Apr 21, 2024
1 parent a6211ac commit 53cb119
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 4 deletions.
2 changes: 2 additions & 0 deletions contracts/contracts/coordination/ITACoChildToRoot.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ interface ITACoChildToRoot {
event OperatorConfirmed(address indexed stakingProvider, address indexed operator);

function confirmOperatorAddress(address operator) external;

function penalize(address stakingProvider) external;
}
27 changes: 24 additions & 3 deletions contracts/contracts/coordination/TACoChildApplication.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ import "./Coordinator.sol";
* @notice TACoChildApplication
*/
contract TACoChildApplication is ITACoRootToChild, ITACoChildApplication, Initializable {
/**
* @notice Signals that the staking provider was penalized
* @param stakingProvider Staking provider address
*/
event Penalized(address indexed stakingProvider);

struct StakingProviderInfo {
address operator;
uint96 authorized;
Expand All @@ -25,6 +31,7 @@ contract TACoChildApplication is ITACoRootToChild, ITACoChildApplication, Initia

ITACoChildToRoot public immutable rootApplication;
address public coordinator;
address public adjudicator;

uint96 public immutable minimumAuthorization;

Expand Down Expand Up @@ -54,14 +61,18 @@ contract TACoChildApplication is ITACoRootToChild, ITACoChildApplication, Initia
/**
* @notice Initialize function for using with OpenZeppelin proxy
*/
function initialize(address _coordinator) external initializer {
require(coordinator == address(0), "Coordinator already set");
require(_coordinator != address(0), "Coordinator must be specified");
function initialize(address _coordinator, address _adjudicator) external initializer {
require(coordinator == address(0) || _adjudicator == address(0), "Contracts already set");
require(
_coordinator != address(0) && _adjudicator != address(0),
"Contracts must be specified"
);
require(
address(Coordinator(_coordinator).application()) == address(this),
"Invalid coordinator"
);
coordinator = _coordinator;
adjudicator = _adjudicator;
}

function authorizedStake(address _stakingProvider) external view returns (uint96) {
Expand Down Expand Up @@ -184,6 +195,16 @@ contract TACoChildApplication is ITACoRootToChild, ITACoChildApplication, Initia
rootApplication.confirmOperatorAddress(_operator);
}

/**
* @notice Penalize the staking provider's future reward
* @param _stakingProvider Staking provider address
*/
function penalize(address _stakingProvider) external override {
require(msg.sender == address(adjudicator), "Only adjudicator allowed to penalize");
rootApplication.penalize(_stakingProvider);
emit Penalized(_stakingProvider);
}

/**
* @notice Return the length of the array of staking providers
*/
Expand Down
7 changes: 7 additions & 0 deletions contracts/contracts/testnet/LynxSet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ contract MockPolygonRoot is Ownable, ITACoChildToRoot, ITACoRootToChild {
rootApplication.confirmOperatorAddress(operator);
}

function penalize(address _stakingProvider) external override onlyOwner {
rootApplication.penalize(_stakingProvider);
}

// solhint-disable-next-line no-empty-blocks
function updateOperator(address stakingProvider, address operator) external {}

Expand Down Expand Up @@ -87,6 +91,9 @@ contract MockPolygonChild is Ownable, ITACoChildToRoot, ITACoRootToChild {

// solhint-disable-next-line no-empty-blocks
function confirmOperatorAddress(address _operator) external override {}

// solhint-disable-next-line no-empty-blocks
function penalize(address _stakingProvider) external override {}
}

contract LynxRitualToken is ERC20("LynxRitualToken", "LRT") {
Expand Down
3 changes: 3 additions & 0 deletions contracts/test/CoordinatorTestSet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ contract ChildApplicationForCoordinatorMock is ITACoChildApplication {
function confirmOperatorAddress(address _operator) external {
confirmations[_operator] = true;
}

// solhint-disable-next-line no-empty-blocks
function penalize(address _stakingProvider) external {}
}

// /**
Expand Down
5 changes: 5 additions & 0 deletions contracts/test/TACoChildApplicationTestSet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ contract RootApplicationForTACoChildApplicationMock {
ITACoRootToChild public childApplication;

mapping(address => bool) public confirmations;
mapping(address => bool) public penalties;

function setChildApplication(ITACoRootToChild _childApplication) external {
childApplication = _childApplication;
Expand Down Expand Up @@ -43,6 +44,10 @@ contract RootApplicationForTACoChildApplicationMock {
confirmations[_operator] = true;
}

function penalize(address _stakingProvider) external {
penalties[_stakingProvider] = true;
}

function resetConfirmation(address _operator) external {
confirmations[_operator] = false;
}
Expand Down
18 changes: 17 additions & 1 deletion tests/test_child_application.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def coordinator(project, child_application, creator):
contract = project.CoordinatorForTACoChildApplicationMock.deploy(
child_application, sender=creator
)
child_application.initialize(contract.address, sender=creator)
child_application.initialize(contract.address, creator, sender=creator)
return contract


Expand Down Expand Up @@ -321,3 +321,19 @@ def test_confirm_address(accounts, root_application, child_application, coordina
all_locked, staking_providers = child_application.getActiveStakingProviders(0, 0)
assert all_locked == 0
assert len(staking_providers) == 0


def test_penalize(accounts, root_application, child_application, coordinator):
(
creator,
staking_provider,
*everyone_else,
) = accounts[0:]

# Penalize can be done only from adjudicator address
with ape.reverts("Only adjudicator allowed to penalize"):
child_application.penalize(staking_provider, sender=staking_provider)

tx = child_application.penalize(staking_provider, sender=creator)
assert root_application.penalties(staking_provider)
assert tx.events == [child_application.Penalized(stakingProvider=staking_provider)]

0 comments on commit 53cb119

Please sign in to comment.