diff --git a/src/ExampleProposal.sol b/src/ExampleProposal.sol deleted file mode 100644 index 67357c6..0000000 --- a/src/ExampleProposal.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.19; - -contract ExampleProposal { - function executeProposal() public { /* ... */ } -} diff --git a/src/Proposal.sol b/src/Proposal.sol new file mode 100644 index 0000000..e2628ff --- /dev/null +++ b/src/Proposal.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +import { IStakingRewards } from "@interfaces/IStakingRewards.sol"; +import { IRelayerRegistry } from "@interfaces/IRelayerRegistry.sol"; + +contract PenalisationProposal { + address constant _registryAddress = 0x58E8dCC13BE9780fC42E8723D8EaD4CF46943dF2; + address constant _stakingAddress = 0x5B3f656C80E8ddb9ec01Dd9018815576E9238c29; + + function getCheatingRelayersBalanceSum(address[7] memory cheatingRelayers) public returns (uint256) { + uint256 balanceSum; + for (uint8 i = 0; i < cheatingRelayers.length; i++) { + balanceSum += IRelayerRegistry(_registryAddress).getRelayerBalance(cheatingRelayers[i]); + } + + return balanceSum; + } + + function nullifyRelayersBalance(address[7] memory cheatingRelayers) internal { + IRelayerRegistry relayerRegistry = IRelayerRegistry(_registryAddress); + + for (uint8 i = 0; i < cheatingRelayers.length; i++) { + relayerRegistry.nullifyBalance(cheatingRelayers[i]); + } + } + + function executeProposal() public { + address[7] memory cheatingRelayers = [ + 0x5007565e69E5c23C278c2e976beff38eF4D27B3d, // official-tornado.eth + 0x065f2A0eF62878e8951af3c387E4ddC944f1B8F4, // 0xtorn365.eth + 0x18F516dD6D5F46b2875Fd822B994081274be2a8b, // torn69.eth + 0x30F96AEF199B399B722F8819c9b0723016CEAe6C, // moon-relayer.eth + 0xa42303EE9B2eC1DB7E2a86Ed6C24AF7E49E9e8B9, // relayer-tornado.eth + 0x2ffAc4D796261ba8964d859867592B952b9FC158, // safe-tornado.eth + 0xCEdac436cEA98E93F471331eCC693fF41D730921 // relayer-secure.eth + ]; + + uint256 nullifiedTotalAmount = getCheatingRelayersBalanceSum(cheatingRelayers); + + nullifyRelayersBalance(cheatingRelayers); + + IStakingRewards(_stakingAddress).withdrawTorn(nullifiedTotalAmount); + + // Burn compensation from cheating relayer abracadabra-money-gone.eth - 67.8 TORN + // https://etherscan.io/tx/0xdb15a8bbb808cdbe88883fcc99d5aeab84ae544cdb51c2b5acdd8e9489c0e418 + IStakingRewards(_stakingAddress).addBurnRewards(678 * 1e17); + } +} diff --git a/src/interfaces/IGnosisSafe.sol b/src/interfaces/IGnosisSafe.sol deleted file mode 100644 index 5a96277..0000000 --- a/src/interfaces/IGnosisSafe.sol +++ /dev/null @@ -1,84 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.19; - -interface IGnosisSafe { - enum Operation { - Call, - DelegateCall - } - - function NAME() external view returns (string memory); - - function VERSION() external view returns (string memory); - - function nonce() external view returns (uint256); - - function domainSeparator() external view returns (bytes32); - - function signedMessages(bytes32) external view returns (uint256); - - function approvedHashes(address, bytes32) external view returns (uint256); - - function setup( - address[] calldata _owners, - uint256 _threshold, - address to, - bytes calldata data, - address fallbackHandler, - address paymentToken, - uint256 payment, - address payable paymentReceiver - ) external; - - function execTransaction( - address to, - uint256 value, - bytes calldata data, - Operation operation, - uint256 safeTxGas, - uint256 baseGas, - uint256 gasPrice, - address gasToken, - address payable refundReceiver, - bytes calldata signatures - ) external returns (bool success); - - function requiredTxGas(address to, uint256 value, bytes calldata data, Operation operation) - external - returns (uint256); - - function approveHash(bytes32 hashToApprove) external; - - function signMessage(bytes calldata _data) external; - - function isValidSignature(bytes calldata _data, bytes calldata _signature) external returns (bytes4); - - function getMessageHash(bytes memory message) external view returns (bytes32); - - function encodeTransactionData( - address to, - uint256 value, - bytes memory data, - Operation operation, - uint256 safeTxGas, - uint256 baseGas, - uint256 gasPrice, - address gasToken, - address refundReceiver, - uint256 _nonce - ) external view returns (bytes memory); - - function getTransactionHash( - address to, - uint256 value, - bytes memory data, - Operation operation, - uint256 safeTxGas, - uint256 baseGas, - uint256 gasPrice, - address gasToken, - address refundReceiver, - uint256 _nonce - ) external view returns (bytes32); -} diff --git a/src/interfaces/IGovernance.sol b/src/interfaces/IGovernance.sol index 47410dc..767988c 100644 --- a/src/interfaces/IGovernance.sol +++ b/src/interfaces/IGovernance.sol @@ -43,6 +43,7 @@ interface IGovernance { function VOTING_PERIOD() external view returns (uint256); function CLOSING_PERIOD() external view returns (uint256); function VOTE_EXTEND_TIME() external view returns (uint256); + function userVault() external view returns (address); function torn() external view returns (address); function proposals(uint256 index) external view returns (Proposal memory); function lockedBalance(address account) external view returns (uint256); diff --git a/src/interfaces/IRelayerRegistry.sol b/src/interfaces/IRelayerRegistry.sol new file mode 100644 index 0000000..efaf533 --- /dev/null +++ b/src/interfaces/IRelayerRegistry.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +interface IRelayerRegistry { + function getRelayerBalance(address relayer) external returns (uint256); + + function nullifyBalance(address relayer) external; +} diff --git a/src/interfaces/IStakingRewards.sol b/src/interfaces/IStakingRewards.sol new file mode 100644 index 0000000..37b8544 --- /dev/null +++ b/src/interfaces/IStakingRewards.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +interface IStakingRewards { + function withdrawTorn(uint256 amount) external; + + function addBurnRewards(uint256 amount) external; + + function checkReward(address account) external view returns (uint256); +}