Skip to content

Commit

Permalink
add mocks to test bal-connector
Browse files Browse the repository at this point in the history
  • Loading branch information
defi-dev committed May 7, 2022
1 parent 16f8949 commit 0e97e84
Show file tree
Hide file tree
Showing 6 changed files with 545 additions and 0 deletions.
39 changes: 39 additions & 0 deletions contracts/test/MockBalConnector.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;

import "./MockSwapper.sol";
import "../connectors/BalPowerIndexConnector.sol";

contract MockBalConnector is BalPowerIndexConnector {
event MockWrapperCallback(uint256 withdrawAmount);
event TestMigrate(bytes migrateData);

MockSwapper immutable swapper;

constructor(
address _assetManager,
address _staking,
address _underlying,
address _rewardsToken,
address _rewardsMinter,
address _vault,
bytes32 _pId,
address _swapper
) BalPowerIndexConnector(_assetManager, _staking, _underlying, _rewardsToken, _rewardsMinter, _vault, _pId) {
swapper = MockSwapper(_swapper);
}

function _swapRewardsToUnderlying(uint256 _rewardsAmount) internal override {
swapper.swap(address(REWARDS_TOKEN), address(UNDERLYING), _rewardsAmount);
}

function getSwapperAddress() public view override returns (address) {
return address(swapper);
}

function migrate(bytes calldata _migrateData) external virtual override {
emit TestMigrate(_migrateData);
}
}
233 changes: 233 additions & 0 deletions contracts/test/crv/BalancerMinterMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

pragma solidity ^0.7.0;

import "@powerpool/balancer-v2-solidity-utils/contracts/openzeppelin/ReentrancyGuard.sol";
import "@powerpool/balancer-v2-solidity-utils/contracts/openzeppelin/SafeMath.sol";
import "@powerpool/balancer-v2-solidity-utils/contracts/openzeppelin/EIP712.sol";

import "./IBalancerMinter.sol";
import "./IBalancerToken.sol";
import "../../interfaces/ILiquidityGauge.sol";

contract BalancerMinterMock is ReentrancyGuard, EIP712 {
using SafeMath for uint256;

IBalancerToken private immutable _token;

// user -> gauge -> value
mapping(address => mapping(address => uint256)) private _minted;
// minter -> user -> can mint?
mapping(address => mapping(address => bool)) private _allowedMinter;

// Signature replay attack prevention for each user.
mapping(address => uint256) internal _nextNonce;

// solhint-disable-next-line var-name-mixedcase
bytes32 private immutable _SET_MINTER_APPROVAL_TYPEHASH = keccak256(
"SetMinterApproval(address minter,bool approval,uint256 nonce,uint256 deadline)"
);

event MinterApprovalSet(address indexed user, address indexed minter, bool approval);

constructor(IBalancerToken token) EIP712("Balancer Minter", "1") {
_token = token;
}

function getDomainSeparator() external view returns (bytes32) {
return _domainSeparatorV4();
}

function getNextNonce(address user) external view returns (uint256) {
return _nextNonce[user];
}

/**
* @notice Returns the address of the Balancer Governance Token
*/
function getBalancerToken() external view returns (IERC20) {
return _token;
}

/**
* @notice Mint everything which belongs to `msg.sender` and send to them
* @param gauge `LiquidityGauge` address to get mintable amount from
*/
function mint(address gauge) external nonReentrant returns (uint256) {
return _mintFor(gauge, msg.sender);
}

/**
* @notice Mint everything which belongs to `msg.sender` across multiple gauges
* @param gauges List of `LiquidityGauge` addresses
*/
function mintMany(address[] calldata gauges) external nonReentrant returns (uint256) {
return _mintForMany(gauges, msg.sender);
}

/**
* @notice Mint tokens for `user`
* @dev Only possible when `msg.sender` has been approved by `user` to mint on their behalf
* @param gauge `LiquidityGauge` address to get mintable amount from
* @param user Address to mint to
*/
function mintFor(address gauge, address user) external nonReentrant returns (uint256) {
require(_allowedMinter[msg.sender][user], "Caller not allowed to mint for user");
return _mintFor(gauge, user);
}

/**
* @notice Mint tokens for `user` across multiple gauges
* @dev Only possible when `msg.sender` has been approved by `user` to mint on their behalf
* @param gauges List of `LiquidityGauge` addresses
* @param user Address to mint to
*/
function mintManyFor(address[] calldata gauges, address user) external nonReentrant returns (uint256) {
require(_allowedMinter[msg.sender][user], "Caller not allowed to mint for user");
return _mintForMany(gauges, user);
}

/**
* @notice The total number of tokens minted for `user` from `gauge`
*/
function minted(address user, address gauge) external view returns (uint256) {
return _minted[user][gauge];
}

/**
* @notice Whether `minter` is approved to mint tokens for `user`
*/
function getMinterApproval(address minter, address user) external view returns (bool) {
return _allowedMinter[minter][user];
}

/**
* @notice Set whether `minter` is approved to mint tokens on your behalf
*/
function setMinterApproval(address minter, bool approval) public {
_setMinterApproval(minter, msg.sender, approval);
}

/**
* @notice Set whether `minter` is approved to mint tokens on behalf of `user`, who has signed a message authorizing
* them.
*/
function setMinterApprovalWithSignature(
address minter,
bool approval,
address user,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external {
// solhint-disable-next-line not-rely-on-time
require(deadline > block.timestamp, "Signature expired");

uint256 nonce = _nextNonce[user]++;

bytes32 structHash = keccak256(abi.encode(_SET_MINTER_APPROVAL_TYPEHASH, minter, approval, nonce, deadline));
bytes32 digest = _hashTypedDataV4(structHash);

address recoveredAddress = ecrecover(digest, v, r, s);

// ecrecover returns the zero address on recover failure, so we need to handle that explicitly.
require(recoveredAddress != address(0) && recoveredAddress == user, "Invalid signature");

_setMinterApproval(minter, user, approval);
}

function _setMinterApproval(
address minter,
address user,
bool approval
) private {
_allowedMinter[minter][user] = approval;
emit MinterApprovalSet(user, minter, approval);
}

// Internal functions
function _updateGauge(address gauge, address user) internal returns (uint256 tokensToMint) {
ILiquidityGauge(gauge).user_checkpoint(user);
uint256 totalMint = ILiquidityGauge(gauge).integrate_fraction(user);
tokensToMint = totalMint.sub(_minted[user][gauge]);

if (tokensToMint > 0) {
_minted[user][gauge] = totalMint;
}
}

function _mintFor(address gauge, address user) internal returns (uint256 tokensToMint) {
tokensToMint = _updateGauge(gauge, user);
if (tokensToMint > 0) {
_token.mint(user, tokensToMint);
}
}

function _mintForMany(address[] calldata gauges, address user) internal returns (uint256 tokensToMint) {
uint256 length = gauges.length;
for (uint256 i = 0; i < length; ++i) {
tokensToMint = tokensToMint.add(_updateGauge(gauges[i], user));
}

if (tokensToMint > 0) {
_token.mint(user, tokensToMint);
}
}

// The below functions are near-duplicates of functions available above.
// They are included for ABI compatibility with snake_casing as used in vyper contracts.
// solhint-disable func-name-mixedcase

/**
* @notice Whether `minter` is approved to mint tokens for `user`
*/
function allowed_to_mint_for(address minter, address user) external view returns (bool) {
return _allowedMinter[minter][user];
}

/**
* @notice Mint everything which belongs to `msg.sender` across multiple gauges
* @dev This function is not recommended as `mintMany()` is more flexible and gas efficient
* @param gauges List of `LiquidityGauge` addresses
*/
function mint_many(address[8] calldata gauges) external nonReentrant {
for (uint256 i = 0; i < 8; ++i) {
if (gauges[i] == address(0)) {
break;
}
_mintFor(gauges[i], msg.sender);
}
}

/**
* @notice Mint tokens for `user`
* @dev Only possible when `msg.sender` has been approved by `user` to mint on their behalf
* @param gauge `LiquidityGauge` address to get mintable amount from
* @param user Address to mint to
*/
function mint_for(address gauge, address user) external nonReentrant {
if (_allowedMinter[msg.sender][user]) {
_mintFor(gauge, user);
}
}

/**
* @notice Toggle whether `minter` is approved to mint tokens for `user`
*/
function toggle_approve_mint(address minter) external {
setMinterApproval(minter, !_allowedMinter[minter][msg.sender]);
}
}
117 changes: 117 additions & 0 deletions contracts/test/crv/IBalancerMinter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

pragma solidity ^0.7.0;

import "./IBalancerTokenAdmin.sol";

interface IBalancerMinter {
event Minted(address indexed recipient, address gauge, uint256 minted);

/**
* @notice Returns the address of the Balancer Governance Token
*/
function getBalancerToken() external view returns (IERC20);

/**
* @notice Returns the address of the Balancer Token Admin contract
*/
function getBalancerTokenAdmin() external view returns (IBalancerTokenAdmin);

/**
* @notice Mint everything which belongs to `msg.sender` and send to them
* @param gauge `LiquidityGauge` address to get mintable amount from
*/
function mint(address gauge) external returns (uint256);

/**
* @notice Mint everything which belongs to `msg.sender` across multiple gauges
* @param gauges List of `LiquidityGauge` addresses
*/
function mintMany(address[] calldata gauges) external returns (uint256);

/**
* @notice Mint tokens for `user`
* @dev Only possible when `msg.sender` has been approved by `user` to mint on their behalf
* @param gauge `LiquidityGauge` address to get mintable amount from
* @param user Address to mint to
*/
function mintFor(address gauge, address user) external returns (uint256);

/**
* @notice Mint tokens for `user` across multiple gauges
* @dev Only possible when `msg.sender` has been approved by `user` to mint on their behalf
* @param gauges List of `LiquidityGauge` addresses
* @param user Address to mint to
*/
function mintManyFor(address[] calldata gauges, address user) external returns (uint256);

/**
* @notice The total number of tokens minted for `user` from `gauge`
*/
function minted(address user, address gauge) external view returns (uint256);

/**
* @notice Whether `minter` is approved to mint tokens for `user`
*/
function getMinterApproval(address minter, address user) external view returns (bool);

/**
* @notice Set whether `minter` is approved to mint tokens on your behalf
*/
function setMinterApproval(address minter, bool approval) external;

/**
* @notice Set whether `minter` is approved to mint tokens on behalf of `user`, who has signed a message authorizing
* them.
*/
function setMinterApprovalWithSignature(
address minter,
bool approval,
address user,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;

// The below functions are near-duplicates of functions available above.
// They are included for ABI compatibility with snake_casing as used in vyper contracts.
// solhint-disable func-name-mixedcase

/**
* @notice Whether `minter` is approved to mint tokens for `user`
*/
function allowed_to_mint_for(address minter, address user) external view returns (bool);

/**
* @notice Mint everything which belongs to `msg.sender` across multiple gauges
* @dev This function is not recommended as `mintMany()` is more flexible and gas efficient
* @param gauges List of `LiquidityGauge` addresses
*/
function mint_many(address[8] calldata gauges) external;

/**
* @notice Mint tokens for `user`
* @dev Only possible when `msg.sender` has been approved by `user` to mint on their behalf
* @param gauge `LiquidityGauge` address to get mintable amount from
* @param user Address to mint to
*/
function mint_for(address gauge, address user) external;

/**
* @notice Toggle whether `minter` is approved to mint tokens for `user`
*/
function toggle_approve_mint(address minter) external;
}
Loading

0 comments on commit 0e97e84

Please sign in to comment.