Signed-off-by: AlienTornadosaurusHex <>
This commit is contained in:
AlienTornadosaurusHex 2023-05-27 15:29:13 +00:00
parent 7cc789f48f
commit 2aabdc4bbe
25 changed files with 671 additions and 6437 deletions

1
.gitignore vendored
View File

@ -16,3 +16,4 @@ docs/
# yarn # yarn
yarn-error* yarn-error*
yarn.lock

View File

@ -9,7 +9,7 @@ optimizer-runs = 10_000_000
[fmt] [fmt]
line_length = 140 line_length = 110
bracket_spacing = true bracket_spacing = true
multiline_func_header = 'attributes_first' multiline_func_header = 'attributes_first'
number_underscore = 'thousands' number_underscore = 'thousands'

View File

@ -1,5 +1,5 @@
@proprietary/=src/proprietary/ @proprietary/=test/proprietary/
@interfaces/=src/interfaces/ @interfaces/=test/interfaces/
@root/=src/ @root/=src/
@forge-std/=lib/forge-std/src/ @forge-std/=lib/forge-std/src/

View File

@ -13,7 +13,10 @@ abstract contract Delegation is Core {
function delegate(address to) external { function delegate(address to) external {
address previous = delegatedTo[msg.sender]; address previous = delegatedTo[msg.sender];
require(to != msg.sender && to != address(this) && to != address(0) && to != previous, "Governance: invalid delegatee"); require(
to != msg.sender && to != address(this) && to != address(0) && to != previous,
"Governance: invalid delegatee"
);
if (previous != address(0)) { if (previous != address(0)) {
emit Undelegated(msg.sender, previous); emit Undelegated(msg.sender, previous);
} }
@ -29,12 +32,18 @@ abstract contract Delegation is Core {
emit Undelegated(msg.sender, previous); emit Undelegated(msg.sender, previous);
} }
function proposeByDelegate(address from, address target, string memory description) external returns (uint256) { function proposeByDelegate(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(address proposer, address target, string memory description) internal virtual returns (uint256); function _propose(address proposer, address target, string memory description)
internal
virtual
returns (uint256);
function castDelegatedVote(address[] memory from, uint256 proposalId, bool support) external virtual { function castDelegatedVote(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++) {

View File

@ -68,7 +68,12 @@ 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, address indexed proposer, address target, uint256 startTime, uint256 endTime, string description uint256 indexed id,
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
@ -102,7 +107,10 @@ contract Governance is Initializable, Configuration, Delegation, EnsResolve {
_initializeConfiguration(); _initializeConfiguration();
} }
function lock(address owner, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public virtual { function lock(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);
} }
@ -135,7 +143,9 @@ contract Governance is Initializable, Configuration, Delegation, EnsResolve {
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
require(Address.isContract(target), "Governance::propose: not a contract"); require(Address.isContract(target), "Governance::propose: not a contract");
@ -143,7 +153,8 @@ contract Governance is Initializable, Configuration, Delegation, EnsResolve {
if (latestProposalId != 0) { if (latestProposalId != 0) {
ProposalState proposersLatestProposalState = state(latestProposalId); ProposalState proposersLatestProposalState = state(latestProposalId);
require( require(
proposersLatestProposalState != ProposalState.Active && proposersLatestProposalState != ProposalState.Pending, proposersLatestProposalState != ProposalState.Active
&& proposersLatestProposalState != ProposalState.Pending,
"Governance::propose: one live proposal per proposer, found an already active proposal" "Governance::propose: one live proposal per proposer, found an already active proposal"
); );
} }
@ -172,7 +183,10 @@ contract Governance is Initializable, Configuration, Delegation, EnsResolve {
} }
function execute(uint256 proposalId) public payable virtual { function execute(uint256 proposalId) public payable virtual {
require(state(proposalId) == ProposalState.AwaitingExecution, "Governance::execute: invalid proposal state"); require(
state(proposalId) == ProposalState.AwaitingExecution,
"Governance::execute: invalid proposal state"
);
Proposal storage proposal = proposals[proposalId]; Proposal storage proposal = proposals[proposalId];
proposal.executed = true; proposal.executed = true;
@ -226,7 +240,9 @@ contract Governance is Initializable, Configuration, Delegation, EnsResolve {
receipt.hasVoted = true; receipt.hasVoted = true;
receipt.support = support; receipt.support = support;
receipt.votes = votes; receipt.votes = votes;
_lockTokens(voter, proposal.endTime.add(VOTE_EXTEND_TIME).add(EXECUTION_EXPIRATION).add(EXECUTION_DELAY)); _lockTokens(
voter, proposal.endTime.add(VOTE_EXTEND_TIME).add(EXECUTION_EXPIRATION).add(EXECUTION_DELAY)
);
emit Voted(proposalId, voter, support, votes); emit Voted(proposalId, voter, support, votes);
} }
@ -252,7 +268,10 @@ contract Governance is Initializable, Configuration, Delegation, EnsResolve {
return ProposalState.Pending; return ProposalState.Pending;
} else if (getBlockTimestamp() <= proposal.endTime) { } else if (getBlockTimestamp() <= proposal.endTime) {
return ProposalState.Active; return ProposalState.Active;
} else if (proposal.forVotes <= proposal.againstVotes || proposal.forVotes + proposal.againstVotes < QUORUM_VOTES) { } else if (
proposal.forVotes <= proposal.againstVotes
|| proposal.forVotes + proposal.againstVotes < QUORUM_VOTES
) {
return ProposalState.Defeated; return ProposalState.Defeated;
} else if (proposal.executed) { } else if (proposal.executed) {
return ProposalState.Executed; return ProposalState.Executed;

View File

@ -13,7 +13,11 @@ contract LoopbackProxy is TransparentUpgradeableProxy, EnsResolve {
/** /**
* @dev Initializes an upgradeable proxy backed by the implementation at `_logic`. * @dev Initializes an upgradeable proxy backed by the implementation at `_logic`.
*/ */
constructor(address _logic, bytes memory _data) public payable TransparentUpgradeableProxy(_logic, address(this), _data) { } constructor(address _logic, bytes memory _data)
public
payable
TransparentUpgradeableProxy(_logic, address(this), _data)
{ }
/** /**
* @dev Override to allow admin (itself) access the fallback function. * @dev Override to allow admin (itself) access the fallback function.

View File

@ -1,13 +1 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import "../LoopbackProxy.sol";
contract MockProxy is LoopbackProxy {
constructor(address _logic, bytes memory _data) public payable LoopbackProxy(_logic, _data) { }
function resolve(bytes32 addr) public view override returns (address) {
return address(uint160(uint256(addr) >> (12 * 8)));
}
}

View File

@ -1,31 +1 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "torn-token/contracts/mocks/TORNMock.sol";
struct Recipient2 {
address to;
uint256 amount;
}
contract TORNMock2 is TORNMock {
constructor(address _governance, uint256 _pausePeriod, Recipient2[] memory vesting)
public
TORNMock(solve(_governance), _pausePeriod, solve2(vesting))
{ }
function solve(address x) private returns (bytes32) {
return bytes32(uint256(x) << 96);
}
function solve2(Recipient2[] memory vesting) private returns (Recipient[] memory) {
Recipient[] memory realVesting = new Recipient[](vesting.length);
for (uint256 i = 0; i < vesting.length; i++) {
realVesting[i].to = solve(vesting[i].to);
realVesting[i].amount = vesting[i].amount;
}
return realVesting;
}
}

View File

@ -19,7 +19,11 @@ contract GovernanceGasUpgrade is GovernanceVaultUpgrade, GasCompensator {
* @param _userVault tornado vault address * @param _userVault tornado vault address
* *
*/ */
constructor(address _gasCompLogic, address _userVault) public GovernanceVaultUpgrade(_userVault) GasCompensator(_gasCompLogic) { } constructor(address _gasCompLogic, address _userVault)
public
GovernanceVaultUpgrade(_userVault)
GasCompensator(_gasCompLogic)
{ }
/// @notice check that msg.sender is multisig /// @notice check that msg.sender is multisig
modifier onlyMultisig() { modifier onlyMultisig() {
@ -40,7 +44,11 @@ contract GovernanceGasUpgrade is GovernanceVaultUpgrade, GasCompensator {
* *
*/ */
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)
)
);
} }
/** /**
@ -85,9 +93,18 @@ contract GovernanceGasUpgrade is GovernanceVaultUpgrade, GasCompensator {
* @param support true if yes false if no * @param support true if yes false if no
* *
*/ */
function castDelegatedVote(address[] memory from, uint256 proposalId, bool support) external virtual override { function castDelegatedVote(address[] memory from, 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)
);
} }
/// @notice checker for success on deployment /// @notice checker for success on deployment
@ -148,7 +165,9 @@ contract GovernanceGasUpgrade is GovernanceVaultUpgrade, GasCompensator {
{ {
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"
);
require(!gasCompensated || !hasAccountVoted(proposalId, delegator), "Governance: voted already"); require(!gasCompensated || !hasAccountVoted(proposalId, delegator), "Governance: voted already");
_castVote(delegator, proposalId, support); _castVote(delegator, proposalId, support);
} }

View File

@ -1,16 +1 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
import "../../v1/Governance.sol";
contract MockProposal {
address public constant GovernanceAddress = 0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce;
function executeProposal() external {
Governance gov = Governance(GovernanceAddress);
gov.setVotingPeriod(27_000);
require(gov.VOTING_PERIOD() == 27_000, "Voting period change failed!");
}
}

View File

@ -11,7 +11,11 @@ contract AdminUpgradeableProxy is TransparentUpgradeableProxy {
/** /**
* @dev Initializes an upgradeable proxy backed by the implementation at `_logic`. * @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) { } constructor(address _logic, address _admin, bytes memory _data)
public
payable
TransparentUpgradeableProxy(_logic, _admin, _data)
{ }
/** /**
* @dev Override to allow admin access the fallback function. * @dev Override to allow admin access the fallback function.

View File

@ -37,7 +37,10 @@ contract GovernancePatchUpgrade is GovernanceStakingUpgrade {
proposalCodehash := extcodehash(target) proposalCodehash := extcodehash(target)
} }
require(proposalCodehash == proposalCodehashes[proposalId], "Governance::propose: metamorphic contracts not allowed"); require(
proposalCodehash == proposalCodehashes[proposalId],
"Governance::propose: metamorphic contracts not allowed"
);
super.execute(proposalId); super.execute(proposalId);
} }

View File

@ -24,7 +24,10 @@ 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(address governance, address torn, address registry) external returns (address) { function createStakingRewards(address governance, address torn, address registry)
external
returns (address)
{
return address(new TornadoStakingRewards(governance, torn, registry)); return address(new TornadoStakingRewards(governance, torn, registry));
} }
@ -36,10 +39,13 @@ 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(address torn, address governance, address ens, address staking, address feeManager) function createRegistryContract(
external address torn,
returns (address) address governance,
{ 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));
} }
} }
@ -51,9 +57,9 @@ contract PatchProposal {
using SafeMath for uint256; using SafeMath for uint256;
using Address for address; using Address for address;
address public immutable feeManagerAddress = 0x5f6c97C6AD7bdd0AE7E0Dd4ca33A4ED3fDabD4D7; address public immutable feeManagerProxyAddress = 0x5f6c97C6AD7bdd0AE7E0Dd4ca33A4ED3fDabD4D7;
address public immutable registryProxyAddress = 0x58E8dCC13BE9780fC42E8723D8EaD4CF46943dF2;
address public immutable ensAddress = 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e; address public immutable ensAddress = 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e;
address public immutable registry = 0x58E8dCC13BE9780fC42E8723D8EaD4CF46943dF2;
IERC20 public constant TORN = IERC20(0x77777FeDdddFfC19Ff86DB637967013e6C6A116C); IERC20 public constant TORN = IERC20(0x77777FeDdddFfC19Ff86DB637967013e6C6A116C);
@ -73,31 +79,39 @@ contract PatchProposal {
address vault = address(GovernancePatchUpgrade(governance).userVault()); address vault = address(GovernancePatchUpgrade(governance).userVault());
// Get the old staking contract // Get the old staking contract
TornadoStakingRewards oldStaking = TornadoStakingRewards(address(GovernancePatchUpgrade(governance).Staking())); TornadoStakingRewards oldStaking =
TornadoStakingRewards(address(GovernancePatchUpgrade(governance).Staking()));
// 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 logic contract // And create a new staking logic contract
TornadoStakingRewards newStakingImplementation = TornadoStakingRewards newStakingImplementation = TornadoStakingRewards(
TornadoStakingRewards(patchProposalContractsFactory.createStakingRewards(address(governance), address(TORN), registry)); patchProposalContractsFactory.createStakingRewards(
address(governance), address(TORN), registryProxyAddress
)
);
// Create new staking proxy contract (without initialization value) // Create new staking proxy contract (without initialization value)
bytes memory empty; bytes memory empty;
AdminUpgradeableProxy newStaking = new AdminUpgradeableProxy(address(newStakingImplementation), address(governance), empty);
address newStaking =
address(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(governance), ensAddress, address(newStaking), feeManagerAddress address(TORN), address(governance), ensAddress, newStaking, feeManagerProxyAddress
); );
// Upgrade the registry proxy // Upgrade the registry proxy
AdminUpgradeableProxy(payable(registry)).upgradeTo(newRegistryImplementationAddress); AdminUpgradeableProxy(payable(registryProxyAddress)).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(newStaking, gasComp, vault))
);
// Return TORNs, which were withdrawn by bug, to Governance Staking contract // Compensate TORN for staking
TORN.transfer(address(newStaking), 94_092 ether); TORN.transfer(newStaking, 94_092 ether);
} }
} }

View File

@ -132,7 +132,9 @@ contract RelayerRegistry is Initializable, EnsResolve {
_; _;
} }
constructor(address _torn, address _governance, address _ens, address _staking, address _feeManager) public { constructor(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);
@ -157,7 +159,9 @@ contract RelayerRegistry is Initializable, EnsResolve {
* @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, uint256 stake, address[] calldata workersToRegister) external { function register(string calldata ensName, uint256 stake, address[] calldata workersToRegister)
external
{
_register(msg.sender, ensName, stake, workersToRegister); _register(msg.sender, ensName, stake, workersToRegister);
} }
@ -179,7 +183,12 @@ contract RelayerRegistry is Initializable, EnsResolve {
_register(relayer, ensName, stake, workersToRegister); _register(relayer, ensName, stake, workersToRegister);
} }
function _register(address relayer, string calldata ensName, uint256 stake, address[] calldata workersToRegister) internal { function _register(
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");
@ -249,9 +258,15 @@ contract RelayerRegistry is Initializable, EnsResolve {
* @param staker address from that stake is paid * @param staker address from that stake is paid
* *
*/ */
function stakeToRelayerPermit(address relayer, uint256 stake, address staker, uint256 deadline, uint8 v, bytes32 r, bytes32 s) function stakeToRelayerPermit(
external address relayer,
{ uint256 stake,
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);
} }

View File

@ -85,8 +85,9 @@ 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 = accumulatedRewardPerTorn.add(
accumulatedRewardPerTorn.add(amount.mul(ratioConstant).div(torn.balanceOf(address(Governance.userVault())))); amount.mul(ratioConstant).div(torn.balanceOf(address(Governance.userVault())))
);
} }
/** /**
@ -95,7 +96,10 @@ contract TornadoStakingRewards is Initializable, EnsResolve {
* @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);
} }
@ -119,10 +123,14 @@ contract TornadoStakingRewards is Initializable, EnsResolve {
* @param amountLockedBeforehand the balance locked beforehand in the governance contract * @param amountLockedBeforehand the balance locked beforehand in the governance contract
* @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 = claimed = (accumulatedRewardPerTorn.sub(accumulatedRewardRateOnLastUpdate[account])).mul(
(accumulatedRewardPerTorn.sub(accumulatedRewardRateOnLastUpdate[account])).mul(amountLockedBeforehand).div(ratioConstant); amountLockedBeforehand
).div(ratioConstant);
} }
accumulatedRewardRateOnLastUpdate[account] = accumulatedRewardPerTorn; accumulatedRewardRateOnLastUpdate[account] = accumulatedRewardPerTorn;
emit RewardsUpdated(account, claimed); emit RewardsUpdated(account, claimed);
@ -135,7 +143,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]);
} }

View File

@ -3,7 +3,10 @@
pragma solidity 0.6.12; pragma solidity 0.6.12;
interface IMetamorphicContractFactory { interface IMetamorphicContractFactory {
function findMetamorphicContractAddress(bytes32 salt) external view returns (address metamorphicContractAddress); function findMetamorphicContractAddress(bytes32 salt)
external
view
returns (address metamorphicContractAddress);
function deployMetamorphicContractFromExistingImplementation( function deployMetamorphicContractFromExistingImplementation(
bytes32 salt, bytes32 salt,

View File

@ -7,8 +7,10 @@ contract Mock {
address public constant TEST_REAL_ADDRESS_WITH_BALANCE = 0x9Ff3C1Bea9ffB56a78824FE29f457F066257DD58; address public constant TEST_REAL_ADDRESS_WITH_BALANCE = 0x9Ff3C1Bea9ffB56a78824FE29f457F066257DD58;
address public constant TEST_RELAYER_ADDRESS = 0x30F96AEF199B399B722F8819c9b0723016CEAe6C; // moon-relayer.eth (just for testing) address public constant TEST_RELAYER_ADDRESS = 0x30F96AEF199B399B722F8819c9b0723016CEAe6C; // moon-relayer.eth (just for testing)
uint256 public constant TEST_PRIVATE_KEY_ONE = 0x66ddbd7cbe4a566df405f6ded0b908c669f88cdb1656380c050e3a457bd21df0; uint256 public constant TEST_PRIVATE_KEY_ONE =
uint256 public constant TEST_PRIVATE_KEY_TWO = 0xa4c8c98120e77741a87a116074a2df4ddb20d1149069290fd4a3d7ee65c55064; 0x66ddbd7cbe4a566df405f6ded0b908c669f88cdb1656380c050e3a457bd21df0;
uint256 public constant TEST_PRIVATE_KEY_TWO =
0xa4c8c98120e77741a87a116074a2df4ddb20d1149069290fd4a3d7ee65c55064;
address public constant TEST_ADDRESS_ONE = 0x118251976c65AFAf291f5255450ddb5b6A4d8B88; address public constant TEST_ADDRESS_ONE = 0x118251976c65AFAf291f5255450ddb5b6A4d8B88;
address public constant TEST_ADDRESS_TWO = 0x63aE7d90Eb37ca39FC62dD9991DbEfeE70673a20; address public constant TEST_ADDRESS_TWO = 0x63aE7d90Eb37ca39FC62dD9991DbEfeE70673a20;

View File

@ -4,6 +4,8 @@ pragma experimental ABIEncoderV2;
import { Test } from "@forge-std/Test.sol"; import { Test } from "@forge-std/Test.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { ERC20Permit } from "torn-token/contracts/ERC20Permit.sol";
import { console2 } from "@forge-std/console2.sol";
import { Mock } from "./Mock.sol"; import { Mock } from "./Mock.sol";
import { Proposal, IGovernance } from "@interfaces/IGovernance.sol"; import { Proposal, IGovernance } from "@interfaces/IGovernance.sol";
@ -53,12 +55,15 @@ contract ProposalUtils is Mock, Parameters, Test {
function retrieveAndLockBalance(uint256 privateKey, address voter, uint256 amount) internal { function retrieveAndLockBalance(uint256 privateKey, address voter, uint256 amount) internal {
uint256 lockTimestamp = block.timestamp + PROPOSAL_DURATION; uint256 lockTimestamp = block.timestamp + PROPOSAL_DURATION;
uint256 accountNonce = ERC20Permit(_tokenAddress).nonces(voter);
console2.log("Account nonce: %s", accountNonce);
bytes32 messageHash = keccak256( bytes32 messageHash = keccak256(
abi.encodePacked( abi.encodePacked(
PERMIT_FUNC_SELECTOR, PERMIT_FUNC_SELECTOR,
EIP712_DOMAIN, EIP712_DOMAIN,
keccak256(abi.encode(PERMIT_TYPEHASH, voter, _governanceAddress, amount, 0, lockTimestamp)) keccak256(abi.encode(PERMIT_TYPEHASH, voter, _governanceAddress, amount, accountNonce, lockTimestamp))
) )
); );

View File

@ -18,14 +18,22 @@ contract TestContractsState is MockProposal {
uint256 lockedBalanceAfterExecution = governance.lockedBalance(TEST_REAL_ADDRESS_WITH_BALANCE); uint256 lockedBalanceAfterExecution = governance.lockedBalance(TEST_REAL_ADDRESS_WITH_BALANCE);
console2.log("User locked balance before execution: %s TORN", lockedBalanceAfterExecution / 10 ** 18); console2.log("User locked balance before execution: %s TORN", lockedBalanceAfterExecution / 10 ** 18);
require(lockedBalanceBeforeExecution == lockedBalanceAfterExecution, "Wrong locked balance after execution"); require(
lockedBalanceBeforeExecution == lockedBalanceAfterExecution,
"Wrong locked balance after execution"
);
} }
function testGovernanceStakingStateChanged() public { function testGovernanceStakingStateChanged() public {
TornadoStakingRewards oldStaking = TornadoStakingRewards(getStakingProxyAddress()); TornadoStakingRewards oldStaking = TornadoStakingRewards(getStakingProxyAddress());
uint256 accumulatedRewardsBeforeExecution = oldStaking.checkReward(TEST_REAL_ADDRESS_WITH_BALANCE); uint256 accumulatedRewardsBeforeExecution = oldStaking.checkReward(TEST_REAL_ADDRESS_WITH_BALANCE);
console2.log("User rewards balance (bugged) before execution: %s TORN", accumulatedRewardsBeforeExecution / 10 ** 18); console2.log(
console2.log("Bugged value of accumulated rewards per TORN: %s", oldStaking.accumulatedRewardPerTorn()); "User rewards balance (bugged) before execution: %s TORN",
accumulatedRewardsBeforeExecution / 10 ** 18
);
console2.log(
"Bugged value of accumulated rewards per TORN: %s", oldStaking.accumulatedRewardPerTorn()
);
createAndExecuteProposal(); createAndExecuteProposal();
@ -33,8 +41,13 @@ contract TestContractsState is MockProposal {
uint256 accumulatedRewardsPerTORNAfterExecution = newStaking.accumulatedRewardPerTorn(); uint256 accumulatedRewardsPerTORNAfterExecution = newStaking.accumulatedRewardPerTorn();
uint256 accumulatedRewardsAfterExecution = newStaking.checkReward(TEST_REAL_ADDRESS_WITH_BALANCE); uint256 accumulatedRewardsAfterExecution = newStaking.checkReward(TEST_REAL_ADDRESS_WITH_BALANCE);
console2.log("User rewards balance before execution: %s TORN", accumulatedRewardsAfterExecution / 10 ** 18); console2.log(
console2.log("Value of accumulated rewards per TORN after contract redeployment: %s", accumulatedRewardsPerTORNAfterExecution); "User rewards balance before execution: %s TORN", accumulatedRewardsAfterExecution / 10 ** 18
);
console2.log(
"Value of accumulated rewards per TORN after contract redeployment: %s",
accumulatedRewardsPerTORNAfterExecution
);
require(accumulatedRewardsBeforeExecution >= accumulatedRewardsAfterExecution, "Wtf"); require(accumulatedRewardsBeforeExecution >= accumulatedRewardsAfterExecution, "Wtf");
require(accumulatedRewardsAfterExecution == 0, "Accumulated rewards isn't nullified"); require(accumulatedRewardsAfterExecution == 0, "Accumulated rewards isn't nullified");
@ -59,10 +72,14 @@ contract TestContractsState is MockProposal {
uint256 relayerStakedBalanceAfterExecution = registry.getRelayerBalance(TEST_RELAYER_ADDRESS); uint256 relayerStakedBalanceAfterExecution = registry.getRelayerBalance(TEST_RELAYER_ADDRESS);
console2.log( console2.log(
"Relayer balance in relayer registry contract after proposal execution: %s TORN", relayerStakedBalanceAfterExecution / 10 ** 18 "Relayer balance in relayer registry contract after proposal execution: %s TORN",
relayerStakedBalanceAfterExecution / 10 ** 18
); );
require(isRelayerRegisteredAfterExecution, "Relayer isn't registered after proposal execution"); require(isRelayerRegisteredAfterExecution, "Relayer isn't registered after proposal execution");
require(relayerStakedBalanceBeforeExecution == relayerStakedBalanceAfterExecution, "Relayer stake balance differs after execution"); require(
relayerStakedBalanceBeforeExecution == relayerStakedBalanceAfterExecution,
"Relayer stake balance differs after execution"
);
} }
} }

View File

@ -21,7 +21,8 @@ contract TestProxyUpdating is MockProposal {
} }
function getUpgradeableProxyImplementationAddress(address proxy) internal view returns (address) { function getUpgradeableProxyImplementationAddress(address proxy) internal view returns (address) {
bytes32 proxyImplementationSlot = bytes32(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc); bytes32 proxyImplementationSlot =
bytes32(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc);
return getAddressFromSlot(proxy, proxyImplementationSlot); return getAddressFromSlot(proxy, proxyImplementationSlot);
} }
@ -36,25 +37,36 @@ contract TestProxyUpdating is MockProposal {
function testGovernanceStakingProxyUpdated() public { function testGovernanceStakingProxyUpdated() public {
address stakingProxyAddressBeforeExecution = getStakingProxyAddress(); address stakingProxyAddressBeforeExecution = getStakingProxyAddress();
console2.log("Staking proxy address before proposal execution: %s", stakingProxyAddressBeforeExecution); console2.log(
"Staking proxy address before proposal execution: %s", stakingProxyAddressBeforeExecution
);
createAndExecuteProposal(); createAndExecuteProposal();
address stakingProxyAddressAfterExecution = getStakingProxyAddress(); address stakingProxyAddressAfterExecution = getStakingProxyAddress();
console2.log("Staking proxy address after proposal execution: %s", stakingProxyAddressAfterExecution); console2.log("Staking proxy address after proposal execution: %s", stakingProxyAddressAfterExecution);
require(stakingProxyAddressBeforeExecution != stakingProxyAddressAfterExecution, "Staking proxy address didn't changed"); require(
stakingProxyAddressBeforeExecution != stakingProxyAddressAfterExecution,
"Staking proxy address didn't changed"
);
require(isContract(stakingProxyAddressAfterExecution)); require(isContract(stakingProxyAddressAfterExecution));
} }
function testGovernanceStakingImplementationUpdated() public { function testGovernanceStakingImplementationUpdated() public {
address stakingImplementationAddressBeforeExecution = getStakingImplementationAddress(); address stakingImplementationAddressBeforeExecution = getStakingImplementationAddress();
console2.log("Staking implementation address before proposal execution: %s", stakingImplementationAddressBeforeExecution); console2.log(
"Staking implementation address before proposal execution: %s",
stakingImplementationAddressBeforeExecution
);
createAndExecuteProposal(); createAndExecuteProposal();
address stakingImplementationAddressAfterExecution = getStakingImplementationAddress(); address stakingImplementationAddressAfterExecution = getStakingImplementationAddress();
console2.log("Staking implementation address after proposal execution: %s", stakingImplementationAddressAfterExecution); console2.log(
"Staking implementation address after proposal execution: %s",
stakingImplementationAddressAfterExecution
);
require( require(
stakingImplementationAddressBeforeExecution != stakingImplementationAddressAfterExecution, stakingImplementationAddressBeforeExecution != stakingImplementationAddressAfterExecution,
@ -64,33 +76,45 @@ contract TestProxyUpdating is MockProposal {
} }
function testRelayerRegistryImplementationUpdated() public { function testRelayerRegistryImplementationUpdated() public {
address relayerRegistryImplementationAddressBeforeExecution = getRelayerRegistryImplementationAddress(); address relayerRegistryImplementationAddressBeforeExecution =
getRelayerRegistryImplementationAddress();
console2.log( console2.log(
"Relayer registry implementation address before proposal execution: %s", relayerRegistryImplementationAddressBeforeExecution "Relayer registry implementation address before proposal execution: %s",
relayerRegistryImplementationAddressBeforeExecution
); );
createAndExecuteProposal(); createAndExecuteProposal();
address relayerRegistryImplementationAddressAfterExecution = getRelayerRegistryImplementationAddress(); address relayerRegistryImplementationAddressAfterExecution = getRelayerRegistryImplementationAddress();
console2.log( console2.log(
"Relayer registry implementation address after proposal execution: %s", relayerRegistryImplementationAddressAfterExecution "Relayer registry implementation address after proposal execution: %s",
relayerRegistryImplementationAddressAfterExecution
); );
require( require(
relayerRegistryImplementationAddressBeforeExecution != relayerRegistryImplementationAddressAfterExecution, relayerRegistryImplementationAddressBeforeExecution
!= relayerRegistryImplementationAddressAfterExecution,
"Relayer registry implementation address didn't changed" "Relayer registry implementation address didn't changed"
); );
require(isContract(relayerRegistryImplementationAddressAfterExecution)); require(isContract(relayerRegistryImplementationAddressAfterExecution));
} }
function testGovernanceImplementationUpdated() public { function testGovernanceImplementationUpdated() public {
address governanceImplementationAddressBeforeExecution = getUpgradeableProxyImplementationAddress(_governanceAddress); address governanceImplementationAddressBeforeExecution =
console2.log("Governance implementation address before proposal execution: %s", governanceImplementationAddressBeforeExecution); getUpgradeableProxyImplementationAddress(_governanceAddress);
console2.log(
"Governance implementation address before proposal execution: %s",
governanceImplementationAddressBeforeExecution
);
createAndExecuteProposal(); createAndExecuteProposal();
address governanceImplementationAddressAfterExecution = getUpgradeableProxyImplementationAddress(_governanceAddress); address governanceImplementationAddressAfterExecution =
console2.log("Governance implementation address after proposal execution: %s", governanceImplementationAddressAfterExecution); getUpgradeableProxyImplementationAddress(_governanceAddress);
console2.log(
"Governance implementation address after proposal execution: %s",
governanceImplementationAddressAfterExecution
);
require( require(
governanceImplementationAddressBeforeExecution != governanceImplementationAddressAfterExecution, governanceImplementationAddressBeforeExecution != governanceImplementationAddressAfterExecution,
@ -101,12 +125,16 @@ contract TestProxyUpdating is MockProposal {
function testRelayerRegistryProxyNotUpdated() public { function testRelayerRegistryProxyNotUpdated() public {
address relayerRegistryProxyAddressBeforeExecution = getRelayerRegistryProxyAddress(); address relayerRegistryProxyAddressBeforeExecution = getRelayerRegistryProxyAddress();
console2.log("Relayer registry proxy before proposal execution: %s", relayerRegistryProxyAddressBeforeExecution); console2.log(
"Relayer registry proxy before proposal execution: %s", relayerRegistryProxyAddressBeforeExecution
);
createAndExecuteProposal(); createAndExecuteProposal();
address relayerRegistryProxyAddressAfterExecution = getRelayerRegistryProxyAddress(); address relayerRegistryProxyAddressAfterExecution = getRelayerRegistryProxyAddress();
console2.log("Relayer registry proxyafter proposal execution: %s", relayerRegistryProxyAddressAfterExecution); console2.log(
"Relayer registry proxyafter proposal execution: %s", relayerRegistryProxyAddressAfterExecution
);
require( require(
relayerRegistryProxyAddressBeforeExecution == relayerRegistryProxyAddressAfterExecution, relayerRegistryProxyAddressBeforeExecution == relayerRegistryProxyAddressAfterExecution,

View File

@ -113,10 +113,14 @@ contract TestRelayerBalance is MockProposal {
for (uint256 i = 0; i < allRelayersAddresses.length; i++) { for (uint256 i = 0; i < allRelayersAddresses.length; i++) {
uint256 currentRelayerBalance = registry.getRelayerBalance(allRelayersAddresses[i]); uint256 currentRelayerBalance = registry.getRelayerBalance(allRelayersAddresses[i]);
relayersBalancesSum += currentRelayerBalance; relayersBalancesSum += currentRelayerBalance;
console2.log("Relayer %s, relayer balance: %s TORN", allRelayersAddresses[i], currentRelayerBalance / 10e17); console2.log(
"Relayer %s, relayer balance: %s TORN", allRelayersAddresses[i], currentRelayerBalance / 10e17
);
} }
console2.log("\nSum of relayer balances on block %s: %s TORN", block.number, relayersBalancesSum / 10e17); console2.log(
"\nSum of relayer balances on block %s: %s TORN", block.number, relayersBalancesSum / 10e17
);
require(relayersBalancesSum > 0); require(relayersBalancesSum > 0);
} }

View File

@ -24,20 +24,34 @@ contract TestGovernanceStakingRewards is MockProposal {
vm.stopPrank(); vm.stopPrank();
} }
function testAccumulatedRewardCanBeUpdated() public executeAttackerProposalBefore executeCurrentProposalBefore { function testAccumulatedRewardCanBeUpdated()
public
executeAttackerProposalBefore
executeCurrentProposalBefore
{
TornadoStakingRewards staking = TornadoStakingRewards(getStakingProxyAddress()); TornadoStakingRewards staking = TornadoStakingRewards(getStakingProxyAddress());
uint256 accumulatedRewardPerTornBeforeBurning = staking.accumulatedRewardPerTorn() / _tornMaximumSupply; uint256 accumulatedRewardPerTornBeforeBurning =
staking.accumulatedRewardPerTorn() / _tornMaximumSupply;
console2.log("Accumulated reward per TORN right after proposal execution: %s TORN", accumulatedRewardPerTornBeforeBurning / 10e17); console2.log(
"Accumulated reward per TORN right after proposal execution: %s TORN",
accumulatedRewardPerTornBeforeBurning / 10e17
);
burnTokens(_governanceAddress, 10_000_000 ether, staking); burnTokens(_governanceAddress, 10_000_000 ether, staking);
uint256 accumulatedRewardPerTornAfterBurning = staking.accumulatedRewardPerTorn() / _tornMaximumSupply; uint256 accumulatedRewardPerTornAfterBurning = staking.accumulatedRewardPerTorn() / _tornMaximumSupply;
console2.log("Accumulated reward per TORN after burning 10 000 000 TORN: ~ %s TORN", accumulatedRewardPerTornAfterBurning / 10e17); console2.log(
"Accumulated reward per TORN after burning 10 000 000 TORN: ~ %s TORN",
accumulatedRewardPerTornAfterBurning / 10e17
);
require(accumulatedRewardPerTornAfterBurning > accumulatedRewardPerTornBeforeBurning, "Staking rewards isn't updated"); require(
accumulatedRewardPerTornAfterBurning > accumulatedRewardPerTornBeforeBurning,
"Staking rewards isn't updated"
);
} }
function testStakerCanGetRewards() function testStakerCanGetRewards()
@ -75,16 +89,25 @@ contract TestGovernanceStakingRewards is MockProposal {
require(receivedReward == expectedRewards, "Expected and received rewards don't match"); require(receivedReward == expectedRewards, "Expected and received rewards don't match");
uint256 stakerTORNbalanceBeforeGettingRewards = TORN.balanceOf(TEST_ADDRESS_ONE); uint256 stakerTORNbalanceBeforeGettingRewards = TORN.balanceOf(TEST_ADDRESS_ONE);
console2.log("Staker balance before getting (withdrawal) collected rewards: %s TORN", stakerTORNbalanceBeforeGettingRewards / 10e17); console2.log(
"Staker balance before getting (withdrawal) collected rewards: %s TORN",
stakerTORNbalanceBeforeGettingRewards / 10e17
);
vm.startPrank(TEST_ADDRESS_ONE); vm.startPrank(TEST_ADDRESS_ONE);
staking.getReward(); staking.getReward();
vm.stopPrank(); vm.stopPrank();
uint256 stakerTORNbalanceAfterGettingRewards = TORN.balanceOf(TEST_ADDRESS_ONE); uint256 stakerTORNbalanceAfterGettingRewards = TORN.balanceOf(TEST_ADDRESS_ONE);
console2.log("Staker balance after getting (withdrawal) collected rewards: %s TORN", stakerTORNbalanceAfterGettingRewards / 10e17); console2.log(
"Staker balance after getting (withdrawal) collected rewards: %s TORN",
stakerTORNbalanceAfterGettingRewards / 10e17
);
require(stakerTORNbalanceAfterGettingRewards > stakerTORNbalanceBeforeGettingRewards, "Rewards isn't withdrawed"); require(
stakerTORNbalanceAfterGettingRewards > stakerTORNbalanceBeforeGettingRewards,
"Rewards isn't withdrawed"
);
require( require(
stakerTORNbalanceAfterGettingRewards - stakerTORNbalanceBeforeGettingRewards == receivedReward, stakerTORNbalanceAfterGettingRewards - stakerTORNbalanceBeforeGettingRewards == receivedReward,
"Incorrect rewards amount withdrawed" "Incorrect rewards amount withdrawed"
@ -99,6 +122,9 @@ contract TestGovernanceStakingRewards is MockProposal {
burnTokens(relayerRegistryAddress, 10_000 ether, staking); burnTokens(relayerRegistryAddress, 10_000 ether, staking);
require(staking.accumulatedRewardPerTorn() > accumulatedRewardPerTornBeforeBurning, "Burn from relayer registry failed"); require(
staking.accumulatedRewardPerTorn() > accumulatedRewardPerTornBeforeBurning,
"Burn from relayer registry failed"
);
} }
} }

View File

@ -7,4 +7,5 @@ contract Parameters {
address constant _governanceAddress = 0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce; address constant _governanceAddress = 0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce;
address constant _governanceVaultAddress = 0x2F50508a8a3D323B91336FA3eA6ae50E55f32185; address constant _governanceVaultAddress = 0x2F50508a8a3D323B91336FA3eA6ae50E55f32185;
address constant _tokenAddress = 0x77777FeDdddFfC19Ff86DB637967013e6C6A116C; address constant _tokenAddress = 0x77777FeDdddFfC19Ff86DB637967013e6C6A116C;
uint256 constant _tornMaximumSupply = 10_000_000;
} }

5893
yarn.lock

File diff suppressed because it is too large Load Diff