Skip to content

Commit

Permalink
Merge pull request #3 from decent-dao/claim-module-factory
Browse files Browse the repository at this point in the history
Claim module factory
  • Loading branch information
tbwebb22 authored Oct 20, 2022
2 parents 79f7a3f + d415956 commit a699cbf
Show file tree
Hide file tree
Showing 18 changed files with 1,697 additions and 389 deletions.
77 changes: 0 additions & 77 deletions contracts/ClaimSubsidiary.sol

This file was deleted.

65 changes: 65 additions & 0 deletions contracts/TokenClaim.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

import "./interfaces/ITokenClaim.sol";
import "./VotesToken.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

contract TokenClaim is FactoryFriendly, ITokenClaim {
using SafeERC20 for IERC20;

address public childToken;
address public parentToken;
uint256 public snapShotId;
uint256 public parentAllocation;
mapping(address => bool) public claimed;

/// @notice Initialize function, will be triggered when a new proxy is deployed
/// @param initializeParams Parameters of initialization encoded
function setUp(bytes memory initializeParams) public override initializer {
__Ownable_init();
(
address _childTokenFunder,
address _parentToken,
address _childToken,
uint256 _parentAllocation
) = abi.decode(initializeParams, (address, address, address, uint256));

childToken = _childToken;
parentToken = _parentToken;
parentAllocation = _parentAllocation;

snapShotId = VotesToken(_parentToken).captureSnapShot();

IERC20(_childToken).transferFrom(_childTokenFunder, address(this), _parentAllocation);

emit TokenClaimCreated(_parentToken, _childToken, _parentAllocation, snapShotId);
}

/// @notice This function allows pToken holders to claim cTokens
/// @param claimer Address which is being claimed for
function claimToken(address claimer) external {
uint256 amount = getClaimAmount(claimer); // Get user balance

if (amount == 0) revert NoAllocation();

claimed[claimer] = true;

IERC20(childToken).safeTransfer(claimer, amount); // transfer user balance

emit TokenClaimed(parentToken, childToken, claimer, amount);
}

/// @notice Gets a users child token claimable amount
/// @param claimer Address which is being claimed for
/// @return cTokenAllocation Users cToken allocation
function getClaimAmount(address claimer)
public
view
returns (uint256)
{
return claimed[claimer] ? 0 :
(VotesToken(parentToken).balanceOfAt(claimer, snapShotId) * parentAllocation) /
VotesToken(parentToken).totalSupplyAt(snapShotId);
}
}
112 changes: 22 additions & 90 deletions contracts/VetoERC20Voting.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,14 @@
pragma solidity ^0.8.0;

import "./interfaces/IVetoGuard.sol";
import "./interfaces/IVetoERC20Voting.sol";
import "./interfaces/IVetoVoting.sol";
import "./TransactionHasher.sol";
import "@gnosis.pm/safe-contracts/contracts/common/Enum.sol";
import "@gnosis.pm/zodiac/contracts/factory/FactoryFriendly.sol";
import "@openzeppelin/contracts/governance/utils/IVotes.sol";

/// @notice A contract for casting veto votes with an ERC20 votes token
contract VetoERC20Voting is
IVetoERC20Voting,
TransactionHasher,
FactoryFriendly
{
contract VetoERC20Voting is IVetoVoting, TransactionHasher, FactoryFriendly {
uint256 public vetoVotesThreshold; // Number of votes required to veto a transaction
uint256 public freezeVotesThreshold; // Number of freeze votes required to activate a freeze
uint256 public freezeProposalCreatedBlock; // Block number the freeze proposal was created at
Expand All @@ -31,14 +27,17 @@ contract VetoERC20Voting is
function setUp(bytes memory initializeParams) public override initializer {
__Ownable_init();
(
address _owner,
uint256 _vetoVotesThreshold,
uint256 _freezeVotesThreshold,
uint256 _freezeProposalBlockDuration,
uint256 _freezeBlockDuration,
address _votesToken,
address _vetoGuard
) = abi.decode(initializeParams, (address, uint256, uint256, uint256, uint256, address, address));
address _owner,
uint256 _vetoVotesThreshold,
uint256 _freezeVotesThreshold,
uint256 _freezeProposalBlockDuration,
uint256 _freezeBlockDuration,
address _votesToken,
address _vetoGuard
) = abi.decode(
initializeParams,
(address, uint256, uint256, uint256, uint256, address, address)
);

_transferOwnership(_owner);
vetoVotesThreshold = _vetoVotesThreshold;
Expand Down Expand Up @@ -88,8 +87,7 @@ contract VetoERC20Voting is
emit VetoVoteCast(msg.sender, _transactionHash, vetoVotes, _freeze);
}

/// @notice Allows a user to cast a freeze vote if there is an active freeze proposal
/// @notice If there isn't an active freeze proposal, it is created and the user's votes are cast
/// @notice Allows user to cast a freeze vote, creating a freeze proposal if necessary
function castFreezeVote() public {
uint256 userVotes;

Expand Down Expand Up @@ -132,7 +130,6 @@ contract VetoERC20Voting is

/// @notice Unfreezes the DAO, only callable by the owner
function defrost() public onlyOwner {
require(isFrozen(), "DAO is not already frozen");
freezeProposalCreatedBlock = 0;
freezeProposalVoteCount = 0;
}
Expand Down Expand Up @@ -173,82 +170,17 @@ contract VetoERC20Voting is
}

/// @notice Returns whether the specified transaction has been vetoed
/// @param to Destination address.
/// @param value Ether value.
/// @param data Data payload.
/// @param operation Operation type.
/// @param safeTxGas Gas that should be used for the safe transaction.
/// @param baseGas Gas costs for that are independent of the transaction execution(e.g. base transaction fee, signature check, payment of the refund)
/// @param gasPrice Maximum gas price that should be used for this transaction.
/// @param gasToken Token address (or 0 if ETH) that is used for the payment.
/// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
/// @param _transactionHash The hash of the transaction data
/// @return bool True if the transaction is vetoed
function getIsVetoed(
address to,
uint256 value,
bytes memory data,
Enum.Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address payable refundReceiver
) external view returns (bool) {
return
transactionVetoVotes[
getTransactionHash(
to,
value,
data,
operation,
safeTxGas,
baseGas,
gasPrice,
gasToken,
refundReceiver
)
] > vetoVotesThreshold;
}

/// @notice Returns the number of votes that have been cast to veto the specified transaction
/// @param to Destination address.
/// @param value Ether value.
/// @param data Data payload.
/// @param operation Operation type.
/// @param safeTxGas Gas that should be used for the safe transaction.
/// @param baseGas Gas costs for that are independent of the transaction execution(e.g. base transaction fee, signature check, payment of the refund)
/// @param gasPrice Maximum gas price that should be used for this transaction.
/// @param gasToken Token address (or 0 if ETH) that is used for the payment.
/// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
/// @return uint256 The number of veto votes that have been cast
function getVetoVotes(
address to,
uint256 value,
bytes memory data,
Enum.Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address payable refundReceiver
) external view returns (uint256) {
return
transactionVetoVotes[
getTransactionHash(
to,
value,
data,
operation,
safeTxGas,
baseGas,
gasPrice,
gasToken,
refundReceiver
)
];
function getIsVetoed(bytes32 _transactionHash)
external
view
returns (bool)
{
return transactionVetoVotes[_transactionHash] > vetoVotesThreshold;
}

/// @notice Returns true if the DAO is currently frozen
/// @notice Returns true if the DAO is currently frozen, false otherwise
/// @return bool Indicates whether the DAO is currently frozen
function isFrozen() public view returns (bool) {
if (
Expand Down
49 changes: 31 additions & 18 deletions contracts/VetoGuard.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pragma solidity ^0.8.0;

import "./interfaces/IVetoGuard.sol";
import "./interfaces/IVetoERC20Voting.sol";
import "./interfaces/IVetoVoting.sol";
import "./interfaces/IGnosisSafe.sol";
import "./TransactionHasher.sol";
import "./FractalBaseGuard.sol";
Expand All @@ -17,7 +17,7 @@ contract VetoGuard is
IVetoGuard
{
uint256 public executionDelayBlocks;
IVetoERC20Voting public vetoERC20Voting;
IVetoVoting public vetoVoting;
IGnosisSafe public gnosisSafe;
mapping(bytes32 => uint256) transactionQueuedBlock;

Expand All @@ -28,20 +28,22 @@ contract VetoGuard is
(
uint256 _executionDelayBlocks,
address _owner,
address _vetoERC20Voting,
address _gnosisSafe
address _vetoVoting,
address _gnosisSafe // Address(0) == msg.sender
) = abi.decode(initializeParams, (uint256, address, address, address));

executionDelayBlocks = _executionDelayBlocks;
transferOwnership(_owner);
vetoERC20Voting = IVetoERC20Voting(_vetoERC20Voting);
gnosisSafe = IGnosisSafe(_gnosisSafe);
vetoVoting = IVetoVoting(_vetoVoting);
gnosisSafe = IGnosisSafe(
_gnosisSafe == address(0) ? msg.sender : _gnosisSafe
);

emit VetoGuardSetup(
msg.sender,
_executionDelayBlocks,
_owner,
_vetoERC20Voting
_vetoVoting
);
}

Expand Down Expand Up @@ -110,6 +112,15 @@ contract VetoGuard is
emit TransactionQueued(msg.sender, transactionHash, signatures);
}

/// @notice Updates the execution delay blocks, only callable by the owner
/// @param _executionDelayBlocks The number of blocks between when a transaction is queued and can be executed
function updateExecutionDelayBlocks(uint256 _executionDelayBlocks)
external
onlyOwner
{
executionDelayBlocks = _executionDelayBlocks;
}

/// @notice This function is called by the Gnosis Safe to check if the transaction should be able to be executed
/// @notice Reverts if this transaction cannot be executed
/// @param to Destination address.
Expand Down Expand Up @@ -158,21 +169,23 @@ contract VetoGuard is
);

require(
!vetoERC20Voting.getIsVetoed(
to,
value,
data,
operation,
safeTxGas,
baseGas,
gasPrice,
gasToken,
refundReceiver
!vetoVoting.getIsVetoed(
getTransactionHash(
to,
value,
data,
operation,
safeTxGas,
baseGas,
gasPrice,
gasToken,
refundReceiver
)
),
"Transaction has been vetoed"
);

require(!vetoERC20Voting.isFrozen(), "DAO is frozen");
require(!vetoVoting.isFrozen(), "DAO is frozen");
}

/// @notice Does checks after transaction is executed on the Gnosis Safe
Expand Down
Loading

0 comments on commit a699cbf

Please sign in to comment.