Redeploy staking as proxy & format all with new foundry settings

This commit is contained in:
Theo 2023-05-26 15:01:45 +03:00
parent dc1bf7e2a7
commit af38a8dcc9
30 changed files with 1256 additions and 1287 deletions

View File

@ -4,9 +4,11 @@
"prettier/prettier": [ "prettier/prettier": [
"error", "error",
{ {
"printWidth": 110 "printWidth": 110,
"bracketSpacing": true
} }
], ],
"no-console": "off",
"quotes": ["error", "double"], "quotes": ["error", "double"],
"indent": ["error", 2], "indent": ["error", 2],
"compiler-version": ["error", "^0.6.0"] "compiler-version": ["error", "^0.6.0"]

View File

@ -6,3 +6,10 @@ libs = ["node_modules", "lib"]
chain_id = 1 chain_id = 1
optimizer = true optimizer = true
optimizer-runs = 10_000_000 optimizer-runs = 10_000_000
[fmt]
line_length = 140
bracket_spacing = true
multiline_func_header = 'attributes_first'
number_underscore = 'thousands'

View File

@ -1,8 +1,8 @@
{ {
"name": "proposal-22-forge-tests", "name": "proposal-22-forge-tests",
"version": "1.0.0", "version": "1.0.0",
"repository": "https://git.tornado.ws/AlienTornadosaurusHex/proposal-22-forge-tests.git", "repository": "https://git.tornado.ws/Theo/proposal-22-forge-tests.git",
"author": "AlienTornadosaurusHex", "author": "Theo",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"test": "forge test -vvv --fork-url https://rpc.mevblocker.io --fork-block-number 17336117 --gas-report" "test": "forge test -vvv --fork-url https://rpc.mevblocker.io --fork-block-number 17336117 --gas-report"

View File

@ -29,7 +29,7 @@ contract Configuration {
function _initializeConfiguration() internal { function _initializeConfiguration() internal {
EXECUTION_DELAY = 2 days; EXECUTION_DELAY = 2 days;
EXECUTION_EXPIRATION = 3 days; EXECUTION_EXPIRATION = 3 days;
QUORUM_VOTES = 25000e18; // 0.25% of TORN QUORUM_VOTES = 25_000e18; // 0.25% of TORN
PROPOSAL_THRESHOLD = 1000e18; // 0.01% of TORN PROPOSAL_THRESHOLD = 1000e18; // 0.01% of TORN
VOTING_DELAY = 75 seconds; VOTING_DELAY = 75 seconds;
VOTING_PERIOD = 3 days; VOTING_PERIOD = 3 days;

View File

@ -29,26 +29,14 @@ abstract contract Delegation is Core {
emit Undelegated(msg.sender, previous); emit Undelegated(msg.sender, previous);
} }
function proposeByDelegate( function proposeByDelegate(address from, address target, string memory description) external returns (uint256) {
address from,
address target,
string memory description
) external returns (uint256) {
require(delegatedTo[from] == msg.sender, "Governance: not authorized"); require(delegatedTo[from] == msg.sender, "Governance: not authorized");
return _propose(from, target, description); return _propose(from, target, description);
} }
function _propose( function _propose(address proposer, address target, string memory description) internal virtual returns (uint256);
address proposer,
address target,
string memory description
) internal virtual returns (uint256);
function castDelegatedVote( function castDelegatedVote(address[] memory from, uint256 proposalId, bool support) external virtual {
address[] memory from,
uint256 proposalId,
bool support
) external virtual {
for (uint256 i = 0; i < from.length; i++) { for (uint256 i = 0; i < from.length; i++) {
require(delegatedTo[from[i]] == msg.sender, "Governance: not authorized"); require(delegatedTo[from[i]] == msg.sender, "Governance: not authorized");
_castVote(from[i], proposalId, support); _castVote(from[i], proposalId, support);
@ -58,9 +46,5 @@ abstract contract Delegation is Core {
} }
} }
function _castVote( function _castVote(address voter, uint256 proposalId, bool support) internal virtual;
address voter,
uint256 proposalId,
bool support
) internal virtual;
} }

View File

@ -14,6 +14,7 @@ import "./Configuration.sol";
contract Governance is Initializable, Configuration, Delegation, EnsResolve { contract Governance is Initializable, Configuration, Delegation, EnsResolve {
using SafeMath for uint256; using SafeMath for uint256;
/// @notice Possible states that a proposal may be in /// @notice Possible states that a proposal may be in
enum ProposalState { enum ProposalState {
Pending, Pending,
Active, Active,
@ -67,12 +68,7 @@ contract Governance is Initializable, Configuration, Delegation, EnsResolve {
/// @notice An event emitted when a new proposal is created /// @notice An event emitted when a new proposal is created
event ProposalCreated( event ProposalCreated(
uint256 indexed id, uint256 indexed id, address indexed proposer, address target, uint256 startTime, uint256 endTime, string description
address indexed proposer,
address target,
uint256 startTime,
uint256 endTime,
string description
); );
/// @notice An event emitted when a vote has been cast on a proposal /// @notice An event emitted when a vote has been cast on a proposal
@ -106,14 +102,7 @@ contract Governance is Initializable, Configuration, Delegation, EnsResolve {
_initializeConfiguration(); _initializeConfiguration();
} }
function lock( function lock(address owner, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public virtual {
address owner,
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
torn.permit(owner, address(this), amount, deadline, v, r, s); torn.permit(owner, address(this), amount, deadline, v, r, s);
_transferTokens(owner, amount); _transferTokens(owner, amount);
} }
@ -139,11 +128,12 @@ contract Governance is Initializable, Configuration, Delegation, EnsResolve {
* @param description description of the proposal * @param description description of the proposal
* @return the new proposal id * @return the new proposal id
*/ */
function _propose( function _propose(address proposer, address target, string memory description)
address proposer, internal
address target, virtual
string memory description override(Delegation)
) internal virtual override(Delegation) returns (uint256) { returns (uint256)
{
uint256 votingPower = lockedBalance[proposer]; uint256 votingPower = lockedBalance[proposer];
require(votingPower >= PROPOSAL_THRESHOLD, "Governance::propose: proposer votes below proposal threshold"); require(votingPower >= PROPOSAL_THRESHOLD, "Governance::propose: proposer votes below proposal threshold");
// target should be a contract // target should be a contract
@ -204,11 +194,7 @@ contract Governance is Initializable, Configuration, Delegation, EnsResolve {
_castVote(msg.sender, proposalId, support); _castVote(msg.sender, proposalId, support);
} }
function _castVote( function _castVote(address voter, uint256 proposalId, bool support) internal override(Delegation) {
address voter,
uint256 proposalId,
bool support
) internal override(Delegation) {
require(state(proposalId) == ProposalState.Active, "Governance::_castVote: voting is closed"); require(state(proposalId) == ProposalState.Active, "Governance::_castVote: voting is closed");
Proposal storage proposal = proposals[proposalId]; Proposal storage proposal = proposals[proposalId];
Receipt storage receipt = proposal.receipts[voter]; Receipt storage receipt = proposal.receipts[voter];

View File

@ -11,6 +11,7 @@ interface IProxy {
contract NewImplementation is MockGovernance { contract NewImplementation is MockGovernance {
uint256 public newVariable; uint256 public newVariable;
event Overriden(uint256 x); event Overriden(uint256 x);
function execute(uint256 proposalId) public payable override { function execute(uint256 proposalId) public payable override {

View File

@ -11,11 +11,10 @@ struct Recipient2 {
} }
contract TORNMock2 is TORNMock { contract TORNMock2 is TORNMock {
constructor( constructor(address _governance, uint256 _pausePeriod, Recipient2[] memory vesting)
address _governance, public
uint256 _pausePeriod, TORNMock(solve(_governance), _pausePeriod, solve2(vesting))
Recipient2[] memory vesting { }
) public TORNMock(solve(_governance), _pausePeriod, solve2(vesting)) {}
function solve(address x) private returns (bytes32) { function solve(address x) private returns (bytes32) {
return bytes32(uint256(x) << 96); return bytes32(uint256(x) << 96);

View File

@ -12,7 +12,8 @@ interface IGasCompensationVault {
/** /**
* @notice This abstract contract is used to add gas compensation functionality to a contract. * @notice This abstract contract is used to add gas compensation functionality to a contract.
* */ *
*/
abstract contract GasCompensator { abstract contract GasCompensator {
using SafeMath for uint256; using SafeMath for uint256;
@ -29,12 +30,9 @@ abstract contract GasCompensator {
* @param account address to be compensated * @param account address to be compensated
* @param eligible if the account is eligible for compensations or not * @param eligible if the account is eligible for compensations or not
* @param extra extra amount in gas to be compensated, will be multiplied by basefee * @param extra extra amount in gas to be compensated, will be multiplied by basefee
* */ *
modifier gasCompensation( */
address account, modifier gasCompensation(address account, bool eligible, uint256 extra) {
bool eligible,
uint256 extra
) {
if (eligible) { if (eligible) {
uint256 startGas = gasleft(); uint256 startGas = gasleft();
_; _;
@ -48,11 +46,13 @@ abstract contract GasCompensator {
/** /**
* @notice inheritable unimplemented function to withdraw ether from the vault * @notice inheritable unimplemented function to withdraw ether from the vault
* */ *
*/
function withdrawFromHelper(uint256 amount) external virtual; function withdrawFromHelper(uint256 amount) external virtual;
/** /**
* @notice inheritable unimplemented function to deposit ether into the vault * @notice inheritable unimplemented function to deposit ether into the vault
* */ *
*/
function setGasCompensations(uint256 _gasCompensationsLimit) external virtual; function setGasCompensations(uint256 _gasCompensationsLimit) external virtual;
} }

View File

@ -10,18 +10,16 @@ import { Math } from "@openzeppelin/contracts/math/Math.sol";
/** /**
* @notice This contract should upgrade governance to be able to compensate gas for certain actions. * @notice This contract should upgrade governance to be able to compensate gas for certain actions.
* These actions are set to castVote, castDelegatedVote in this contract. * These actions are set to castVote, castDelegatedVote in this contract.
* */ *
*/
contract GovernanceGasUpgrade is GovernanceVaultUpgrade, GasCompensator { contract GovernanceGasUpgrade is GovernanceVaultUpgrade, GasCompensator {
/** /**
* @notice constructor * @notice constructor
* @param _gasCompLogic gas compensation vault address * @param _gasCompLogic gas compensation vault address
* @param _userVault tornado vault address * @param _userVault tornado vault address
* */ *
constructor(address _gasCompLogic, address _userVault) */
public constructor(address _gasCompLogic, address _userVault) public GovernanceVaultUpgrade(_userVault) GasCompensator(_gasCompLogic) { }
GovernanceVaultUpgrade(_userVault)
GasCompensator(_gasCompLogic)
{}
/// @notice check that msg.sender is multisig /// @notice check that msg.sender is multisig
modifier onlyMultisig() { modifier onlyMultisig() {
@ -31,14 +29,16 @@ contract GovernanceGasUpgrade is GovernanceVaultUpgrade, GasCompensator {
/** /**
* @notice receive ether function, does nothing but receive ether * @notice receive ether function, does nothing but receive ether
* */ *
*/
receive() external payable { } receive() external payable { }
/** /**
* @notice function to add a certain amount of ether for gas compensations * @notice function to add a certain amount of ether for gas compensations
* @dev send ether is used in the logic as we don't expect multisig to make a reentrancy attack on governance * @dev send ether is used in the logic as we don't expect multisig to make a reentrancy attack on governance
* @param gasCompensationsLimit the amount of gas to be compensated * @param gasCompensationsLimit the amount of gas to be compensated
* */ *
*/
function setGasCompensations(uint256 gasCompensationsLimit) external virtual override onlyMultisig { function setGasCompensations(uint256 gasCompensationsLimit) external virtual override onlyMultisig {
require(payable(address(gasCompensationVault)).send(Math.min(gasCompensationsLimit, address(this).balance))); require(payable(address(gasCompensationVault)).send(Math.min(gasCompensationsLimit, address(this).balance)));
} }
@ -47,7 +47,8 @@ contract GovernanceGasUpgrade is GovernanceVaultUpgrade, GasCompensator {
* @notice function to withdraw funds from the gas compensator * @notice function to withdraw funds from the gas compensator
* @dev send ether is used in the logic as we don't expect multisig to make a reentrancy attack on governance * @dev send ether is used in the logic as we don't expect multisig to make a reentrancy attack on governance
* @param amount the amount of ether to withdraw * @param amount the amount of ether to withdraw
* */ *
*/
function withdrawFromHelper(uint256 amount) external virtual override onlyMultisig { function withdrawFromHelper(uint256 amount) external virtual override onlyMultisig {
gasCompensationVault.withdrawToGovernance(amount); gasCompensationVault.withdrawToGovernance(amount);
} }
@ -56,13 +57,14 @@ contract GovernanceGasUpgrade is GovernanceVaultUpgrade, GasCompensator {
* @notice function to cast callers votes on a proposal * @notice function to cast callers votes on a proposal
* @dev IMPORTANT: This function uses the gasCompensation modifier. * @dev IMPORTANT: This function uses the gasCompensation modifier.
* as such this function can trigger a payable fallback. * as such this function can trigger a payable fallback.
It is not possible to vote without revert more than once, * It is not possible to vote without revert more than once,
without hasAccountVoted being true, eliminating gas refunds in this case. * without hasAccountVoted being true, eliminating gas refunds in this case.
Gas compensation is also using the low level send(), forwarding 23000 gas * Gas compensation is also using the low level send(), forwarding 23000 gas
as to disallow further logic execution above that threshold. * as to disallow further logic execution above that threshold.
* @param proposalId id of proposal account is voting on * @param proposalId id of proposal account is voting on
* @param support true if yes false if no * @param support true if yes false if no
* */ *
*/
function castVote(uint256 proposalId, bool support) function castVote(uint256 proposalId, bool support)
external external
virtual virtual
@ -81,12 +83,9 @@ contract GovernanceGasUpgrade is GovernanceVaultUpgrade, GasCompensator {
* @param from array of addresses that should have delegated to voter * @param from array of addresses that should have delegated to voter
* @param proposalId id of proposal account is voting on * @param proposalId id of proposal account is voting on
* @param support true if yes false if no * @param support true if yes false if no
* */ *
function castDelegatedVote( */
address[] memory from, function castDelegatedVote(address[] memory from, uint256 proposalId, bool support) external virtual override {
uint256 proposalId,
bool support
) external virtual override {
require(from.length > 0, "Can not be empty"); require(from.length > 0, "Can not be empty");
_castDelegatedVote(from, proposalId, support, !hasAccountVoted(proposalId, msg.sender) && !checkIfQuorumReached(proposalId)); _castDelegatedVote(from, proposalId, support, !hasAccountVoted(proposalId, msg.sender) && !checkIfQuorumReached(proposalId));
} }
@ -101,7 +100,8 @@ contract GovernanceGasUpgrade is GovernanceVaultUpgrade, GasCompensator {
* @notice function to check if quorum has been reached on a given proposal * @notice function to check if quorum has been reached on a given proposal
* @param proposalId id of proposal * @param proposalId id of proposal
* @return true if quorum has been reached * @return true if quorum has been reached
* */ *
*/
function checkIfQuorumReached(uint256 proposalId) public view returns (bool) { function checkIfQuorumReached(uint256 proposalId) public view returns (bool) {
return (proposals[proposalId].forVotes + proposals[proposalId].againstVotes >= QUORUM_VOTES); return (proposals[proposalId].forVotes + proposals[proposalId].againstVotes >= QUORUM_VOTES);
} }
@ -111,7 +111,8 @@ contract GovernanceGasUpgrade is GovernanceVaultUpgrade, GasCompensator {
* @param proposalId id of proposal account should have voted on * @param proposalId id of proposal account should have voted on
* @param account address of the account * @param account address of the account
* @return true if acc has voted * @return true if acc has voted
* */ *
*/
function hasAccountVoted(uint256 proposalId, address account) public view returns (bool) { function hasAccountVoted(uint256 proposalId, address account) public view returns (bool) {
return proposals[proposalId].receipts[account].hasVoted; return proposals[proposalId].receipts[account].hasVoted;
} }
@ -121,7 +122,8 @@ contract GovernanceGasUpgrade is GovernanceVaultUpgrade, GasCompensator {
* @dev reasoning: if multisig changes we need governance to approve the next multisig address, * @dev reasoning: if multisig changes we need governance to approve the next multisig address,
* so simply inherit in a governance upgrade from this function and set the new address * so simply inherit in a governance upgrade from this function and set the new address
* @return the multisig address * @return the multisig address
* */ *
*/
function returnMultisigAddress() public pure virtual returns (address) { function returnMultisigAddress() public pure virtual returns (address) {
return 0xb04E030140b30C27bcdfaafFFA98C57d80eDa7B4; return 0xb04E030140b30C27bcdfaafFFA98C57d80eDa7B4;
} }
@ -138,13 +140,12 @@ contract GovernanceGasUpgrade is GovernanceVaultUpgrade, GasCompensator {
* @param proposalId id of proposal account is voting on * @param proposalId id of proposal account is voting on
* @param support true if yes false if no * @param support true if yes false if no
* @param gasCompensated true if gas should be compensated (given all internal checks pass) * @param gasCompensated true if gas should be compensated (given all internal checks pass)
* */ *
function _castDelegatedVote( */
address[] memory from, function _castDelegatedVote(address[] memory from, uint256 proposalId, bool support, bool gasCompensated)
uint256 proposalId, internal
bool support, gasCompensation(msg.sender, gasCompensated, (msg.sender == tx.origin ? 21e3 : 0))
bool gasCompensated {
) internal gasCompensation(msg.sender, gasCompensated, (msg.sender == tx.origin ? 21e3 : 0)) {
for (uint256 i = 0; i < from.length; i++) { for (uint256 i = 0; i < from.length; i++) {
address delegator = from[i]; address delegator = from[i];
require(delegatedTo[delegator] == msg.sender || delegator == msg.sender, "Governance: not authorized"); require(delegatedTo[delegator] == msg.sender || delegator == msg.sender, "Governance: not authorized");

View File

@ -10,7 +10,7 @@ contract MockProposal {
function executeProposal() external { function executeProposal() external {
Governance gov = Governance(GovernanceAddress); Governance gov = Governance(GovernanceAddress);
gov.setVotingPeriod(27000); gov.setVotingPeriod(27_000);
require(gov.VOTING_PERIOD() == 27000, "Voting period change failed!"); require(gov.VOTING_PERIOD() == 27_000, "Voting period change failed!");
} }
} }

View File

@ -18,11 +18,10 @@ contract GovernanceStakingUpgrade is GovernanceGasUpgrade {
event RewardUpdateSuccessful(address indexed account); event RewardUpdateSuccessful(address indexed account);
event RewardUpdateFailed(address indexed account, bytes indexed errorData); event RewardUpdateFailed(address indexed account, bytes indexed errorData);
constructor( constructor(address stakingRewardsAddress, address gasCompLogic, address userVaultAddress)
address stakingRewardsAddress, public
address gasCompLogic, GovernanceGasUpgrade(gasCompLogic, userVaultAddress)
address userVaultAddress {
) public GovernanceGasUpgrade(gasCompLogic, userVaultAddress) {
Staking = ITornadoStakingRewards(stakingRewardsAddress); Staking = ITornadoStakingRewards(stakingRewardsAddress);
} }
@ -30,7 +29,8 @@ contract GovernanceStakingUpgrade is GovernanceGasUpgrade {
* @notice This modifier should make a call to Staking to update the rewards for account without impacting logic on revert * @notice This modifier should make a call to Staking to update the rewards for account without impacting logic on revert
* @dev try / catch block to handle reverts * @dev try / catch block to handle reverts
* @param account Account to update rewards for. * @param account Account to update rewards for.
* */ *
*/
modifier updateRewards(address account) { modifier updateRewards(address account) {
try Staking.updateRewardsOnLockedBalanceChange(account, lockedBalance[account]) { try Staking.updateRewardsOnLockedBalanceChange(account, lockedBalance[account]) {
emit RewardUpdateSuccessful(account); emit RewardUpdateSuccessful(account);
@ -40,14 +40,12 @@ contract GovernanceStakingUpgrade is GovernanceGasUpgrade {
_; _;
} }
function lock( function lock(address owner, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
address owner, public
uint256 amount, virtual
uint256 deadline, override
uint8 v, updateRewards(owner)
bytes32 r, {
bytes32 s
) public virtual override updateRewards(owner) {
super.lock(owner, amount, deadline, v, r, s); super.lock(owner, amount, deadline, v, r, s);
} }

View File

@ -0,0 +1,20 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
import "@openzeppelin/contracts/proxy/TransparentUpgradeableProxy.sol";
/**
* @dev TransparentUpgradeableProxy where admin is allowed to call implementation methods.
*/
contract AdminUpgradeableProxy is TransparentUpgradeableProxy {
/**
* @dev Initializes an upgradeable proxy backed by the implementation at `_logic`.
*/
constructor(address _logic, address _admin, bytes memory _data) public payable TransparentUpgradeableProxy(_logic, _admin, _data) { }
/**
* @dev Override to allow admin access the fallback function.
*/
function _beforeFallback() internal override { }
}

View File

@ -9,11 +9,10 @@ import "../v3-relayer-registry/GovernanceStakingUpgrade.sol";
contract GovernancePatchUpgrade is GovernanceStakingUpgrade { contract GovernancePatchUpgrade is GovernanceStakingUpgrade {
mapping(uint256 => bytes32) public proposalCodehashes; mapping(uint256 => bytes32) public proposalCodehashes;
constructor( constructor(address stakingRewardsAddress, address gasCompLogic, address userVaultAddress)
address stakingRewardsAddress, public
address gasCompLogic, GovernanceStakingUpgrade(stakingRewardsAddress, gasCompLogic, userVaultAddress)
address userVaultAddress { }
) public GovernanceStakingUpgrade(stakingRewardsAddress, gasCompLogic, userVaultAddress) {}
/// @notice Return the version of the contract /// @notice Return the version of the contract
function version() external pure virtual override returns (string memory) { function version() external pure virtual override returns (string memory) {
@ -51,11 +50,12 @@ contract GovernancePatchUpgrade is GovernanceStakingUpgrade {
* @param description description of the proposal * @param description description of the proposal
* @return proposalId new proposal id * @return proposalId new proposal id
*/ */
function _propose( function _propose(address proposer, address target, string memory description)
address proposer, internal
address target, virtual
string memory description override(Governance)
) internal virtual override(Governance) returns (uint256 proposalId) { returns (uint256 proposalId)
{
// Implies all former predicates were valid // Implies all former predicates were valid
proposalId = super._propose(proposer, target, description); proposalId = super._propose(proposer, target, description);

View File

@ -5,6 +5,7 @@ pragma experimental ABIEncoderV2;
import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol"; import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
import { LoopbackProxy } from "../v1/LoopbackProxy.sol"; import { LoopbackProxy } from "../v1/LoopbackProxy.sol";
import { AdminUpgradeableProxy } from "./AdminUpgradeableProxy.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { Address } from "@openzeppelin/contracts/utils/Address.sol"; import { Address } from "@openzeppelin/contracts/utils/Address.sol";
@ -12,10 +13,6 @@ import { GovernancePatchUpgrade } from "./GovernancePatchUpgrade.sol";
import { TornadoStakingRewards } from "./TornadoStakingRewards.sol"; import { TornadoStakingRewards } from "./TornadoStakingRewards.sol";
import { RelayerRegistry } from "./RelayerRegistry.sol"; import { RelayerRegistry } from "./RelayerRegistry.sol";
interface Proxy {
function upgradeTo(address newImplementation) external;
}
/** /**
* @notice Contract which should help the proposal deploy the necessary contracts. * @notice Contract which should help the proposal deploy the necessary contracts.
*/ */
@ -27,11 +24,7 @@ contract PatchProposalContractsFactory {
* @param registry The address of the relayer registry. * @param registry The address of the relayer registry.
* @return The address of the new staking contract. * @return The address of the new staking contract.
*/ */
function createStakingRewards( function createStakingRewards(address governance, address torn, address registry) external returns (address) {
address governance,
address torn,
address registry
) external returns (address) {
return address(new TornadoStakingRewards(governance, torn, registry)); return address(new TornadoStakingRewards(governance, torn, registry));
} }
@ -43,13 +36,10 @@ contract PatchProposalContractsFactory {
* @param staking The TornadoStakingRewards contract address. * @param staking The TornadoStakingRewards contract address.
* @return The address of the new registry contract. * @return The address of the new registry contract.
*/ */
function createRegistryContract( function createRegistryContract(address torn, address governance, address ens, address staking, address feeManager)
address torn, external
address governance, returns (address)
address ens, {
address staking,
address feeManager
) external returns (address) {
return address(new RelayerRegistry(torn, governance, ens, staking, feeManager)); return address(new RelayerRegistry(torn, governance, ens, staking, feeManager));
} }
} }
@ -61,8 +51,8 @@ contract PatchProposal {
using SafeMath for uint256; using SafeMath for uint256;
using Address for address; using Address for address;
address public constant feeManagerAddress = 0x5f6c97C6AD7bdd0AE7E0Dd4ca33A4ED3fDabD4D7; address public immutable feeManagerAddress = 0x5f6c97C6AD7bdd0AE7E0Dd4ca33A4ED3fDabD4D7;
address public constant ensAddress = 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e; address public immutable ensAddress = 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e;
address public immutable registry = 0x58E8dCC13BE9780fC42E8723D8EaD4CF46943dF2; address public immutable registry = 0x58E8dCC13BE9780fC42E8723D8EaD4CF46943dF2;
IERC20 public constant TORN = IERC20(0x77777FeDdddFfC19Ff86DB637967013e6C6A116C); IERC20 public constant TORN = IERC20(0x77777FeDdddFfC19Ff86DB637967013e6C6A116C);
@ -88,22 +78,21 @@ contract PatchProposal {
// Get the small amount of TORN left // Get the small amount of TORN left
oldStaking.withdrawTorn(TORN.balanceOf(address(oldStaking))); oldStaking.withdrawTorn(TORN.balanceOf(address(oldStaking)));
// And create a new staking contract // And create a new staking logic contract
TornadoStakingRewards newStaking = TornadoStakingRewards( TornadoStakingRewards newStakingImplementation =
patchProposalContractsFactory.createStakingRewards(address(governance), address(TORN), registry) TornadoStakingRewards(patchProposalContractsFactory.createStakingRewards(address(governance), address(TORN), registry));
);
// Create new staking proxy contract (without initialization value)
bytes memory empty;
AdminUpgradeableProxy newStaking = new AdminUpgradeableProxy(address(newStakingImplementation), address(governance), empty);
// And a new registry implementation // And a new registry implementation
address newRegistryImplementationAddress = patchProposalContractsFactory.createRegistryContract( address newRegistryImplementationAddress = patchProposalContractsFactory.createRegistryContract(
address(TORN), address(TORN), address(governance), ensAddress, address(newStaking), feeManagerAddress
address(governance),
ensAddress,
address(newStaking),
feeManagerAddress
); );
// Upgrade the registry proxy // Upgrade the registry proxy
Proxy(registry).upgradeTo(newRegistryImplementationAddress); AdminUpgradeableProxy(payable(registry)).upgradeTo(newRegistryImplementationAddress);
// Now upgrade the governance to the latest stuff // Now upgrade the governance to the latest stuff
LoopbackProxy(payable(governance)).upgradeTo(address(new GovernancePatchUpgrade(address(newStaking), gasComp, vault))); LoopbackProxy(payable(governance)).upgradeTo(address(new GovernancePatchUpgrade(address(newStaking), gasComp, vault)));

View File

@ -60,11 +60,7 @@ library ENSNamehash {
return len; return len;
} }
function keccak( function keccak(bytes memory data, uint256 offset, uint256 len) private pure returns (bytes32 ret) {
bytes memory data,
uint256 offset,
uint256 len
) private pure returns (bytes32 ret) {
require(offset + len <= data.length); require(offset + len <= data.length);
assembly { assembly {
ret := keccak256(add(add(data, 32), offset), len) ret := keccak256(add(add(data, 32), offset), len)
@ -93,7 +89,8 @@ struct RelayerState {
* - if setter functions are compromised, relayer metadata would be at risk, including the noted amount of his balance * - if setter functions are compromised, relayer metadata would be at risk, including the noted amount of his balance
* - if burn function is compromised, relayers run the risk of being unable to handle withdrawals * - if burn function is compromised, relayers run the risk of being unable to handle withdrawals
* - the above risk also applies to the nullify balance function * - the above risk also applies to the nullify balance function
* */ *
*/
contract RelayerRegistry is Initializable, EnsResolve { contract RelayerRegistry is Initializable, EnsResolve {
using SafeMath for uint256; using SafeMath for uint256;
using SafeERC20 for TORN; using SafeERC20 for TORN;
@ -135,13 +132,7 @@ contract RelayerRegistry is Initializable, EnsResolve {
_; _;
} }
constructor( constructor(address _torn, address _governance, address _ens, address _staking, address _feeManager) public {
address _torn,
address _governance,
address _ens,
address _staking,
address _feeManager
) public {
torn = TORN(_torn); torn = TORN(_torn);
governance = _governance; governance = _governance;
ens = IENS(_ens); ens = IENS(_ens);
@ -153,7 +144,8 @@ contract RelayerRegistry is Initializable, EnsResolve {
* @notice initialize function for upgradeability * @notice initialize function for upgradeability
* @dev this contract will be deployed behind a proxy and should not assign values at logic address, * @dev this contract will be deployed behind a proxy and should not assign values at logic address,
* params left out because self explainable * params left out because self explainable
* */ *
*/
function initialize(bytes32 _tornadoRouter) external initializer { function initialize(bytes32 _tornadoRouter) external initializer {
tornadoRouter = resolve(_tornadoRouter); tornadoRouter = resolve(_tornadoRouter);
} }
@ -163,18 +155,16 @@ contract RelayerRegistry is Initializable, EnsResolve {
* @dev Relayer can't steal other relayers workers since they are registered, and a wallet (msg.sender check) can always unregister itself * @dev Relayer can't steal other relayers workers since they are registered, and a wallet (msg.sender check) can always unregister itself
* @param ensName ens name of the relayer * @param ensName ens name of the relayer
* @param stake the initial amount of stake in TORN the relayer is depositing * @param stake the initial amount of stake in TORN the relayer is depositing
* */ *
function register( */
string calldata ensName, function register(string calldata ensName, uint256 stake, address[] calldata workersToRegister) external {
uint256 stake,
address[] calldata workersToRegister
) external {
_register(msg.sender, ensName, stake, workersToRegister); _register(msg.sender, ensName, stake, workersToRegister);
} }
/** /**
* @dev Register function equivalent with permit-approval instead of regular approve. * @dev Register function equivalent with permit-approval instead of regular approve.
* */ *
*/
function registerPermit( function registerPermit(
string calldata ensName, string calldata ensName,
uint256 stake, uint256 stake,
@ -189,12 +179,7 @@ contract RelayerRegistry is Initializable, EnsResolve {
_register(relayer, ensName, stake, workersToRegister); _register(relayer, ensName, stake, workersToRegister);
} }
function _register( function _register(address relayer, string calldata ensName, uint256 stake, address[] calldata workersToRegister) internal {
address relayer,
string calldata ensName,
uint256 stake,
address[] calldata workersToRegister
) internal {
bytes32 ensHash = bytes(ensName).namehash(); bytes32 ensHash = bytes(ensName).namehash();
require(relayer == ens.owner(ensHash), "only ens owner"); require(relayer == ens.owner(ensHash), "only ens owner");
require(workers[relayer] == address(0), "cant register again"); require(workers[relayer] == address(0), "cant register again");
@ -222,7 +207,8 @@ contract RelayerRegistry is Initializable, EnsResolve {
* @notice This function should allow relayers to register more workeres * @notice This function should allow relayers to register more workeres
* @param relayer Relayer which should send message from any worker which is already registered * @param relayer Relayer which should send message from any worker which is already registered
* @param worker Address to register * @param worker Address to register
* */ *
*/
function registerWorker(address relayer, address worker) external onlyRelayer(msg.sender, relayer) { function registerWorker(address relayer, address worker) external onlyRelayer(msg.sender, relayer) {
_registerWorker(relayer, worker); _registerWorker(relayer, worker);
} }
@ -239,7 +225,8 @@ contract RelayerRegistry is Initializable, EnsResolve {
* - this should be followed by an action like burning relayer stake * - this should be followed by an action like burning relayer stake
* - there was an option of allowing the sender to burn relayer stake in case of malicious behaviour, this feature was not included in the end * - there was an option of allowing the sender to burn relayer stake in case of malicious behaviour, this feature was not included in the end
* - reverts if trying to unregister master, otherwise contract would break. in general, there should be no reason to unregister master at all * - reverts if trying to unregister master, otherwise contract would break. in general, there should be no reason to unregister master at all
* */ *
*/
function unregisterWorker(address worker) external { function unregisterWorker(address worker) external {
if (worker != msg.sender) require(workers[worker] == msg.sender, "only owner of worker"); if (worker != msg.sender) require(workers[worker] == msg.sender, "only owner of worker");
require(workers[worker] != worker, "cant unregister master"); require(workers[worker] != worker, "cant unregister master");
@ -251,7 +238,8 @@ contract RelayerRegistry is Initializable, EnsResolve {
* @notice This function should allow anybody to stake to a relayer more TORN * @notice This function should allow anybody to stake to a relayer more TORN
* @param relayer Relayer main address to stake to * @param relayer Relayer main address to stake to
* @param stake Stake to be added to relayer * @param stake Stake to be added to relayer
* */ *
*/
function stakeToRelayer(address relayer, uint256 stake) external { function stakeToRelayer(address relayer, uint256 stake) external {
_stakeToRelayer(msg.sender, relayer, stake); _stakeToRelayer(msg.sender, relayer, stake);
} }
@ -259,25 +247,16 @@ contract RelayerRegistry is Initializable, EnsResolve {
/** /**
* @dev stakeToRelayer function equivalent with permit-approval instead of regular approve. * @dev stakeToRelayer function equivalent with permit-approval instead of regular approve.
* @param staker address from that stake is paid * @param staker address from that stake is paid
* */ *
function stakeToRelayerPermit( */
address relayer, function stakeToRelayerPermit(address relayer, uint256 stake, address staker, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
uint256 stake, external
address staker, {
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external {
torn.permit(staker, address(this), stake, deadline, v, r, s); torn.permit(staker, address(this), stake, deadline, v, r, s);
_stakeToRelayer(staker, relayer, stake); _stakeToRelayer(staker, relayer, stake);
} }
function _stakeToRelayer( function _stakeToRelayer(address staker, address relayer, uint256 stake) internal {
address staker,
address relayer,
uint256 stake
) internal {
require(workers[relayer] == relayer, "!registered"); require(workers[relayer] == relayer, "!registered");
torn.safeTransferFrom(staker, address(staking), stake); torn.safeTransferFrom(staker, address(staking), stake);
relayers[relayer].balance = stake.add(relayers[relayer].balance); relayers[relayer].balance = stake.add(relayers[relayer].balance);
@ -294,12 +273,9 @@ contract RelayerRegistry is Initializable, EnsResolve {
* @param sender worker to check sender == relayer * @param sender worker to check sender == relayer
* @param relayer address of relayer who's stake is being burned * @param relayer address of relayer who's stake is being burned
* @param pool instance to get fee for * @param pool instance to get fee for
* */ *
function burn( */
address sender, function burn(address sender, address relayer, ITornadoInstance pool) external onlyTornadoRouter {
address relayer,
ITornadoInstance pool
) external onlyTornadoRouter {
address masterAddress = workers[sender]; address masterAddress = workers[sender];
if (masterAddress == address(0)) { if (masterAddress == address(0)) {
require(workers[relayer] == address(0), "Only custom relayer"); require(workers[relayer] == address(0), "Only custom relayer");
@ -316,7 +292,8 @@ contract RelayerRegistry is Initializable, EnsResolve {
/** /**
* @notice This function should allow governance to set the minimum stake amount * @notice This function should allow governance to set the minimum stake amount
* @param minAmount new minimum stake amount * @param minAmount new minimum stake amount
* */ *
*/
function setMinStakeAmount(uint256 minAmount) external onlyGovernance { function setMinStakeAmount(uint256 minAmount) external onlyGovernance {
minStakeAmount = minAmount; minStakeAmount = minAmount;
emit MinimumStakeAmount(minAmount); emit MinimumStakeAmount(minAmount);
@ -325,7 +302,8 @@ contract RelayerRegistry is Initializable, EnsResolve {
/** /**
* @notice This function should allow governance to set a new tornado proxy address * @notice This function should allow governance to set a new tornado proxy address
* @param tornadoRouterAddress address of the new proxy * @param tornadoRouterAddress address of the new proxy
* */ *
*/
function setTornadoRouter(address tornadoRouterAddress) external onlyGovernance { function setTornadoRouter(address tornadoRouterAddress) external onlyGovernance {
tornadoRouter = tornadoRouterAddress; tornadoRouter = tornadoRouterAddress;
emit RouterRegistered(tornadoRouterAddress); emit RouterRegistered(tornadoRouterAddress);
@ -337,7 +315,8 @@ contract RelayerRegistry is Initializable, EnsResolve {
* - Should nullify the balance * - Should nullify the balance
* - Adding nullified balance as rewards was refactored to allow for the flexibility of these funds (for gov to operate with them) * - Adding nullified balance as rewards was refactored to allow for the flexibility of these funds (for gov to operate with them)
* @param relayer address of relayer who's balance is to nullify * @param relayer address of relayer who's balance is to nullify
* */ *
*/
function nullifyBalance(address relayer) external onlyGovernance { function nullifyBalance(address relayer) external onlyGovernance {
address masterAddress = workers[relayer]; address masterAddress = workers[relayer];
require(relayer == masterAddress, "must be master"); require(relayer == masterAddress, "must be master");
@ -349,7 +328,8 @@ contract RelayerRegistry is Initializable, EnsResolve {
* @notice This function should check if a worker is associated with a relayer * @notice This function should check if a worker is associated with a relayer
* @param toResolve address to check * @param toResolve address to check
* @return true if is associated * @return true if is associated
* */ *
*/
function isRelayer(address toResolve) external view returns (bool) { function isRelayer(address toResolve) external view returns (bool) {
return workers[toResolve] != address(0); return workers[toResolve] != address(0);
} }
@ -359,7 +339,8 @@ contract RelayerRegistry is Initializable, EnsResolve {
* @param relayer relayer to check * @param relayer relayer to check
* @param toResolve address to check * @param toResolve address to check
* @return true if registered * @return true if registered
* */ *
*/
function isRelayerRegistered(address relayer, address toResolve) external view returns (bool) { function isRelayerRegistered(address relayer, address toResolve) external view returns (bool) {
return workers[toResolve] == relayer; return workers[toResolve] == relayer;
} }
@ -368,7 +349,8 @@ contract RelayerRegistry is Initializable, EnsResolve {
* @notice This function should get a relayers ensHash * @notice This function should get a relayers ensHash
* @param relayer address to fetch for * @param relayer address to fetch for
* @return relayer's ensHash * @return relayer's ensHash
* */ *
*/
function getRelayerEnsHash(address relayer) external view returns (bytes32) { function getRelayerEnsHash(address relayer) external view returns (bytes32) {
return relayers[workers[relayer]].ensHash; return relayers[workers[relayer]].ensHash;
} }
@ -377,7 +359,8 @@ contract RelayerRegistry is Initializable, EnsResolve {
* @notice This function should get a relayers balance * @notice This function should get a relayers balance
* @param relayer relayer who's balance is to fetch * @param relayer relayer who's balance is to fetch
* @return relayer's balance * @return relayer's balance
* */ *
*/
function getRelayerBalance(address relayer) external view returns (uint256) { function getRelayerBalance(address relayer) external view returns (uint256) {
return relayers[workers[relayer]].balance; return relayers[workers[relayer]].balance;
} }

View File

@ -25,7 +25,8 @@ interface ITornadoGovernance {
* and properly attribute rewards to addresses without security issues. * and properly attribute rewards to addresses without security issues.
* @dev CONTRACT RISKS: * @dev CONTRACT RISKS:
* - Relayer staked TORN at risk if contract is compromised. * - Relayer staked TORN at risk if contract is compromised.
* */ *
*/
contract TornadoStakingRewards is Initializable, EnsResolve { contract TornadoStakingRewards is Initializable, EnsResolve {
using SafeMath for uint256; using SafeMath for uint256;
using SafeERC20 for IERC20; using SafeERC20 for IERC20;
@ -52,11 +53,7 @@ contract TornadoStakingRewards is Initializable, EnsResolve {
} }
// Minor code change here we won't resolve the registry by ENS // Minor code change here we won't resolve the registry by ENS
constructor( constructor(address governanceAddress, address tornAddress, address _relayerRegistry) public {
address governanceAddress,
address tornAddress,
address _relayerRegistry
) public {
Governance = ITornadoGovernance(governanceAddress); Governance = ITornadoGovernance(governanceAddress);
torn = IERC20(tornAddress); torn = IERC20(tornAddress);
relayerRegistry = _relayerRegistry; relayerRegistry = _relayerRegistry;
@ -88,16 +85,16 @@ contract TornadoStakingRewards is Initializable, EnsResolve {
*/ */
function addBurnRewards(uint256 amount) external { function addBurnRewards(uint256 amount) external {
require(msg.sender == address(Governance) || msg.sender == relayerRegistry, "unauthorized"); require(msg.sender == address(Governance) || msg.sender == relayerRegistry, "unauthorized");
accumulatedRewardPerTorn = accumulatedRewardPerTorn.add( accumulatedRewardPerTorn =
amount.mul(ratioConstant).div(torn.balanceOf(address(Governance.userVault()))) accumulatedRewardPerTorn.add(amount.mul(ratioConstant).div(torn.balanceOf(address(Governance.userVault()))));
);
} }
/** /**
* @notice This function should allow governance to properly update the accumulated rewards rate for an account * @notice This function should allow governance to properly update the accumulated rewards rate for an account
* @param account address of account to update data for * @param account address of account to update data for
* @param amountLockedBeforehand the balance locked beforehand in the governance contract * @param amountLockedBeforehand the balance locked beforehand in the governance contract
* */ *
*/
function updateRewardsOnLockedBalanceChange(address account, uint256 amountLockedBeforehand) external onlyGovernance { function updateRewardsOnLockedBalanceChange(address account, uint256 amountLockedBeforehand) external onlyGovernance {
uint256 claimed = _updateReward(account, amountLockedBeforehand); uint256 claimed = _updateReward(account, amountLockedBeforehand);
accumulatedRewards[account] = accumulatedRewards[account].add(claimed); accumulatedRewards[account] = accumulatedRewards[account].add(claimed);
@ -105,7 +102,8 @@ contract TornadoStakingRewards is Initializable, EnsResolve {
/** /**
* @notice This function should allow governance rescue tokens from the staking rewards contract * @notice This function should allow governance rescue tokens from the staking rewards contract
* */ *
*/
function withdrawTorn(uint256 amount) external onlyGovernance { function withdrawTorn(uint256 amount) external onlyGovernance {
if (amount == type(uint256).max) amount = torn.balanceOf(address(this)); if (amount == type(uint256).max) amount = torn.balanceOf(address(this));
torn.safeTransfer(address(Governance), amount); torn.safeTransfer(address(Governance), amount);
@ -122,10 +120,10 @@ contract TornadoStakingRewards is Initializable, EnsResolve {
* @return claimed the rewards attributed to user since the last update * @return claimed the rewards attributed to user since the last update
*/ */
function _updateReward(address account, uint256 amountLockedBeforehand) private returns (uint256 claimed) { function _updateReward(address account, uint256 amountLockedBeforehand) private returns (uint256 claimed) {
if (amountLockedBeforehand != 0) if (amountLockedBeforehand != 0) {
claimed = (accumulatedRewardPerTorn.sub(accumulatedRewardRateOnLastUpdate[account])).mul(amountLockedBeforehand).div( claimed =
ratioConstant (accumulatedRewardPerTorn.sub(accumulatedRewardRateOnLastUpdate[account])).mul(amountLockedBeforehand).div(ratioConstant);
); }
accumulatedRewardRateOnLastUpdate[account] = accumulatedRewardPerTorn; accumulatedRewardRateOnLastUpdate[account] = accumulatedRewardPerTorn;
emit RewardsUpdated(account, claimed); emit RewardsUpdated(account, claimed);
} }
@ -136,8 +134,9 @@ contract TornadoStakingRewards is Initializable, EnsResolve {
*/ */
function checkReward(address account) external view returns (uint256 rewards) { function checkReward(address account) external view returns (uint256 rewards) {
uint256 amountLocked = Governance.lockedBalance(account); uint256 amountLocked = Governance.lockedBalance(account);
if (amountLocked != 0) if (amountLocked != 0) {
rewards = (accumulatedRewardPerTorn.sub(accumulatedRewardRateOnLastUpdate[account])).mul(amountLocked).div(ratioConstant); rewards = (accumulatedRewardPerTorn.sub(accumulatedRewardRateOnLastUpdate[account])).mul(amountLocked).div(ratioConstant);
}
rewards = rewards.add(accumulatedRewards[account]); rewards = rewards.add(accumulatedRewards[account]);
} }
} }