Skip to content

Commit

Permalink
merge main
Browse files Browse the repository at this point in the history
  • Loading branch information
Mike committed Oct 13, 2023
2 parents 0a7edb0 + 545ec42 commit 65be9c1
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 23 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ build :; forge clean && forge build --optimize --optimizer-runs 1000000
# Tests
tests :; forge clean && forge test --mt test --optimize --optimizer-runs 1000000 -v # --ffi # enable if you need the `ffi` cheat code on HEVM
test-with-gas-report :; forge clean && forge build && forge test --mt test --optimize --optimizer-runs 1000000 -v --gas-report # --ffi # enable if you need the `ffi` cheat code on HEVM
test-unit :; forge clean && forge test --no-match-test invariant --optimize --optimizer-runs 1000000 -v # --ffi # enable if you need the `ffi` cheat code on HEVM
test-invariant :; ./test/invariants/test-invariant.sh ${SCENARIO} ${NUM_ACTORS} ${NUM_PROPOSALS} ${PER_ADDRESS_TOKEN_REQ_CAP}
test-invariant-all :; forge clean && forge t --mt invariant
test-invariant-multiple-distribution :; forge clean && ./test/invariants/test-invariant.sh MultipleDistribution 2 25 200
Expand Down
2 changes: 1 addition & 1 deletion script/GrantFund.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ contract DeployGrantFund is Script {
vm.stopBroadcast();

console.log("GrantFund deployed to %s", grantFund);
console.log("Please transfer %s AJNA (%s WAD) into the treasury", treasury / 1e18, treasury);
console.log("Please transfer %s AJNA (%s WAD) to the treasury using the fundTreasury() method found in GrantFund.sol", treasury / 1e18, treasury);
}
}
11 changes: 7 additions & 4 deletions src/grants/GrantFund.sol
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ contract GrantFund is IGrantFund, Storage, ReentrancyGuard {

uint24 distributionId = proposal.distributionId;

// check that the distribution period has ended, and one week has passed to enable competing slates to be checked
// check that the distribution period has ended
if (block.number <= _distributions[distributionId].endBlock) revert ExecuteProposalInvalid();

// check proposal is successful and hasn't already been executed
Expand Down Expand Up @@ -307,8 +307,8 @@ contract GrantFund is IGrantFund, Storage, ReentrancyGuard {

DistributionPeriod storage currentDistribution = _distributions[_currentDistributionId];

// cannot add new proposal after end of screening period
// screening period ends 72000 blocks before end of distribution period, ~ 80 days.
// cannot add new proposal after the screening period ends
// screening period ends 525_600 blocks after the start of the distribution period, ~73 days.
if (block.number > _getScreeningStageEndBlock(currentDistribution.startBlock)) revert ScreeningPeriodEnded();

// store new proposal information
Expand Down Expand Up @@ -732,7 +732,7 @@ contract GrantFund is IGrantFund, Storage, ReentrancyGuard {
* @dev Votes can be allocated to multiple proposals, quadratically, for or against.
* @param currentDistribution_ The current distribution period.
* @param proposal_ The current proposal being voted upon.
* @param voter_ The voter data struct tracking available votes.
* @param voter_ The VoterInfo struct tracking votes.
* @param voteParams_ The amount of votes being allocated to the proposal. Not squared. If less than 0, vote is against.
* @return incrementalVotesUsed_ The amount of funding stage votes allocated to the proposal.
*/
Expand Down Expand Up @@ -825,6 +825,7 @@ contract GrantFund is IGrantFund, Storage, ReentrancyGuard {
/**
* @notice Vote on a proposal in the screening stage of the Distribution Period.
* @param proposal_ The current proposal being voted upon.
* @param voter_ The VoterInfo struct tracking votes.
* @param votes_ The amount of votes being cast.
*/
function _screeningVote(
Expand Down Expand Up @@ -1098,6 +1099,8 @@ contract GrantFund is IGrantFund, Storage, ReentrancyGuard {
DistributionPeriod storage currentDistribution = _distributions[distributionId_];
VoterInfo storage voter = _voterInfo[distributionId_][voter_];

if (voter.screeningVotesCast == 0) return 0;

rewards_ = _getDelegateReward(currentDistribution, voter);
}

Expand Down
19 changes: 9 additions & 10 deletions src/grants/interfaces/IGrantFundActions.sol
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ interface IGrantFundActions is IGrantFundState {
* @param targets_ The addresses of the contracts to call.
* @param values_ The amounts of ETH to send to each target.
* @param calldatas_ The calldata to send to each target.
* @param descriptionHash_ The hash of the proposal's description string. Generated by `abi.encode(DESCRIPTION_PREFIX_HASH, keccak256(bytes(description_))`.
* The `DESCRIPTION_PREFIX_HASH` is unique for each funding mechanism: `keccak256(bytes("Standard Funding: "))` for standard funding
* @param descriptionHash_ The hash of the proposal's description string. Generated by `keccak256(bytes(description_))` or by calling `getDescriptionHash`.
* @return proposalId_ The hashed proposalId created from the provided params.
*/
function hashProposal(
Expand All @@ -81,7 +80,7 @@ interface IGrantFundActions is IGrantFundState {

/**
* @notice Submit a new proposal to the Grant Coordination Fund Standard Funding mechanism.
* @dev All proposals can be submitted by anyone. There can only be one value in each array. Interface is compliant with OZ.propose().
* @dev Proposals can be submitted by anyone. Interface is compliant with OZ.propose().
* @param targets_ List of contracts the proposal calldata will interact with. Should be the Ajna token contract for all proposals.
* @param values_ List of values to be sent with the proposal calldata. Should be 0 for all proposals.
* @param calldatas_ List of calldata to be executed. Should be the transfer() method.
Expand All @@ -97,7 +96,7 @@ interface IGrantFundActions is IGrantFundState {

/**
* @notice Find the status of a given proposal.
* @dev Check proposal status based upon Grant Fund specific logic.
* @dev Proposal status depends on the stage of the distribution period in which it was submitted, and vote counts on the proposal.
* @param proposalId_ The id of the proposal to query the status of.
* @return ProposalState of the given proposal.
*/
Expand All @@ -106,7 +105,7 @@ interface IGrantFundActions is IGrantFundState {
) external view returns (ProposalState);

/**
* @notice Check if a slate of proposals meets requirements, and maximizes votes. If so, update DistributionPeriod.
* @notice Check if a slate of proposals meets requirements, and maximizes votes. If so, set the provided proposal slate as the new top slate of proposals.
* @param proposalIds_ Array of proposal Ids to check.
* @param distributionId_ Id of the current distribution period.
* @return newTopSlate_ Boolean indicating whether the new proposal slate was set as the new top slate for distribution.
Expand All @@ -122,7 +121,7 @@ interface IGrantFundActions is IGrantFundState {

/**
* @notice Cast an array of funding votes in one transaction.
* @dev Calls out to StandardFunding._fundingVote().
* @dev Calls StandardFunding._fundingVote().
* @dev Only iterates through a maximum of 10 proposals that made it through the screening round.
* @dev Counters incremented in an unchecked block due to being bounded by array length.
* @param voteParams_ The array of votes on proposals to cast.
Expand All @@ -134,7 +133,7 @@ interface IGrantFundActions is IGrantFundState {

/**
* @notice Cast an array of screening votes in one transaction.
* @dev Calls out to StandardFunding._screeningVote().
* @dev Calls StandardFunding._screeningVote().
* @dev Counters incremented in an unchecked block due to being bounded by array length.
* @param voteParams_ The array of votes on proposals to cast.
* @return votesCast_ The total number of votes cast across all of the proposals.
Expand Down Expand Up @@ -167,9 +166,9 @@ interface IGrantFundActions is IGrantFundState {

/**
* @notice Calculate the description hash of a proposal.
* @dev The description hash is used as a unique identifier for a proposal. It is created by hashing the description string with a prefix.
* @dev The description hash is used as a unique identifier for a proposal. It is created by hashing the description string.
* @param description_ The proposal's description string.
* @return The hash of the proposal's prefix and description string.
* @return The hash of the proposal's description string.
*/
function getDescriptionHash(string memory description_) external pure returns (bytes32);

Expand Down Expand Up @@ -204,7 +203,7 @@ interface IGrantFundActions is IGrantFundState {

/**
* @notice Get the block number at which this distribution period's funding stage ends.
* @param startBlock_ The end block of a distribution period to get the funding stage end block for.
* @param startBlock_ The start block of a distribution period to get the funding stage end block for.
* @return The block number at which this distribution period's funding stage ends.
*/
function getFundingStageEndBlock(uint256 startBlock_) external pure returns (uint256);
Expand Down
5 changes: 0 additions & 5 deletions src/grants/interfaces/IGrantFundErrors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,6 @@ interface IGrantFundErrors {
/*** Errors ***/
/**************/

/**
* @notice Voter has already voted on a proposal in the screening stage in a quarter.
*/
error AlreadyVoted();

/**
* @notice User attempted to start a new distribution or claim delegation rewards before the distribution period ended.
*/
Expand Down
38 changes: 38 additions & 0 deletions src/token/BurnWrapper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,32 @@ import { ERC20Permit } from "@oz/token/ERC20/extensions/draft-ERC20Permit.sol
import { ERC20Wrapper } from "@oz/token/ERC20/extensions/ERC20Wrapper.sol";
import { IERC20Metadata } from "@oz/token/ERC20/extensions/IERC20Metadata.sol";

/**
* @title Ajna Token `ERC20` token interface.
* @dev Ajna Token `ERC20` token interface, including the following functions:
* - `burnFrom()`
* @dev Used by the `BurnWrappedAjna` contract to burn Ajna tokens on wrapping.
*/
interface IERC20Token {
/**
* @notice Burns `amount` tokens from `account`, deducting from the caller's allowance and balance.
* @param account Account to burn tokens from.
* @param amount Amount of tokens to burn.
*/
function burnFrom(address account, uint256 amount) external;
}


/**
* @title BurnWrappedAjna Contract
* @notice Entrypoint of BurnWrappedAjna actions for Ajna token holders looking to migrate their tokens to a sidechain:
* - `TokenHolders`: Approve the BurnWrappedAjna contract to burn a specified amount of Ajna tokens, and call `depositFor()` to mint them a corresponding amount of bwAJNA tokens.
* @dev This contract is intended for usage in cases where users are attempting to migrate their Ajna to a sidechain that lacks a permissionless bridge.
* Usage of this contract protects holders from the risk of a compromised sidechain bridge.
* @dev Contract inherits from OpenZeppelin ERC20Burnable and ERC20Wrapper extensions.
* @dev Only mainnet Ajna token can be wrapped. Tokens that have been wrapped cannot be unwrapped, as they are burned on wrapping.
* @dev Holders must call `depositFor()` to wrap their tokens. Transferring Ajna tokens to the wrapper contract directly results in loss of tokens.
*/
contract BurnWrappedAjna is ERC20, ERC20Burnable, ERC20Permit, ERC20Wrapper {

/**
Expand Down Expand Up @@ -50,6 +76,18 @@ contract BurnWrappedAjna is ERC20, ERC20Burnable, ERC20Permit, ERC20Wrapper {
return 18;
}

/**
* @notice Override wrap method to burn Ajna tokens on wrapping instead of transferring to the wrapper contract.
*/
function depositFor(address account, uint256 amount) public override returns (bool) {
// burn the existing ajna tokens
IERC20Token(AJNA_TOKEN_ADDRESS).burnFrom(account, amount);

// mint the new wrapped tokens
_mint(account, amount);
return true;
}

/**
* @notice Override unwrap method to ensure burn wrapped tokens can't be unwrapped.
*/
Expand Down
Loading

0 comments on commit 65be9c1

Please sign in to comment.