Skip to content

Commit

Permalink
Merge pull request #8 from powerpool-finance/torn-connector-audit-fixes
Browse files Browse the repository at this point in the history
Torn connector audit fixes
  • Loading branch information
defi-lead authored Apr 27, 2022
2 parents 0500ec1 + cd80fac commit fd46a61
Show file tree
Hide file tree
Showing 10 changed files with 132 additions and 102 deletions.
37 changes: 29 additions & 8 deletions contracts/PowerIndexRouter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ contract PowerIndexRouter is PowerIndexRouterInterface, PowerIndexNaiveRouter {
bool indexed isNewConnector
);
event SetConnectorClaimParams(address connector, bytes claimParams);
event SetConnectorStakeParams(address connector, bytes stakeParams);

struct BasicConfig {
address poolRestrictions;
Expand Down Expand Up @@ -78,6 +79,7 @@ contract PowerIndexRouter is PowerIndexRouterInterface, PowerIndexNaiveRouter {
uint256 lastChangeStakeAt;
bytes stakeData;
bytes pokeData;
bytes stakeParams;
bytes claimParams;
}

Expand Down Expand Up @@ -197,7 +199,17 @@ contract PowerIndexRouter is PowerIndexRouterInterface, PowerIndexNaiveRouter {

if (c.newConnector) {
connectors.push(
Connector(c.connector, c.share, c.callBeforeAfterPoke, 0, 0, new bytes(0), new bytes(0), new bytes(0))
Connector(
c.connector,
c.share,
c.callBeforeAfterPoke,
0,
0,
new bytes(0),
new bytes(0),
new bytes(0),
new bytes(0)
)
);
c.connectorIndex = connectors.length - 1;
} else {
Expand All @@ -221,6 +233,16 @@ contract PowerIndexRouter is PowerIndexRouterInterface, PowerIndexNaiveRouter {
emit SetConnectorClaimParams(address(connectors[_connectorIndex].connector), _claimParams);
}

/**
* @notice Set connector stake params to pass it to connector.
* @param _connectorIndex Index of connector
* @param _stakeParams Claim params
*/
function setStakeParams(uint256 _connectorIndex, bytes memory _stakeParams) external onlyOwner {
connectors[_connectorIndex].stakeParams = _stakeParams;
emit SetConnectorStakeParams(address(connectors[_connectorIndex].connector), _stakeParams);
}

/**
* @notice Set piERC20 noFee config for account address.
* @param _for Account address.
Expand Down Expand Up @@ -417,14 +439,14 @@ contract PowerIndexRouter is PowerIndexRouterInterface, PowerIndexNaiveRouter {
* @notice Call redeem in the connector with delegatecall, save result stakeData if not null.
*/
function _redeem(Connector storage _c, uint256 _diff) internal {
_callStakeRedeem("redeem(uint256,(bytes,uint256,address))", _c, _diff);
_callStakeRedeem("redeem(uint256,(bytes,bytes,uint256,address))", _c, _diff);
}

/**
* @notice Call stake in the connector with delegatecall, save result `stakeData` if not null.
*/
function _stake(Connector storage _c, uint256 _diff) internal {
_callStakeRedeem("stake(uint256,(bytes,uint256,address))", _c, _diff);
_callStakeRedeem("stake(uint256,(bytes,bytes,uint256,address))", _c, _diff);
}

function _callStakeRedeem(
Expand Down Expand Up @@ -571,10 +593,9 @@ contract PowerIndexRouter is PowerIndexRouterInterface, PowerIndexNaiveRouter {

if (shouldClaim && _c.claimParams.length != 0) {
shouldClaim = _c.connector.isClaimAvailable(_c.claimParams, _c.lastClaimRewardsAt, _c.lastChangeStakeAt);
}

if (status == StakeStatus.EQUILIBRIUM && shouldClaim) {
forceRebalance = true;
if (shouldClaim && !forceRebalance) {
forceRebalance = true;
}
}
}

Expand Down Expand Up @@ -787,7 +808,7 @@ contract PowerIndexRouter is PowerIndexRouterInterface, PowerIndexNaiveRouter {
}

function _getDistributeData(Connector storage c) internal view returns (IRouterConnector.DistributeData memory) {
return IRouterConnector.DistributeData(c.stakeData, performanceFee, performanceFeeReceiver);
return IRouterConnector.DistributeData(c.stakeData, c.stakeParams, performanceFee, performanceFeeReceiver);
}

function _checkConnectorsTotalShare() internal view {
Expand Down
12 changes: 6 additions & 6 deletions contracts/WrappedPiErc20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,25 @@ import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "./interfaces/PowerIndexNaiveRouterInterface.sol";
import "./interfaces/PowerIndexRouterInterface.sol";
import "./interfaces/WrappedPiErc20Interface.sol";
import "./interfaces/IPermitERC20.sol";
import "./interfaces/IERC20Permit.sol";

contract WrappedPiErc20 is ERC20, ReentrancyGuard, WrappedPiErc20Interface {
using SafeMath for uint256;
using SafeERC20 for IPermitERC20;
using SafeERC20 for IERC20Permit;

bytes32 public constant PERMIT_TYPEHASH =
keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
bytes public constant EIP712_REVISION = bytes("1");
bytes32 internal constant EIP712_DOMAIN =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");

IPermitERC20 public immutable underlying;
bytes32 public immutable DOMAIN_SEPARATOR;
IERC20Permit public immutable underlying;
bytes32 public immutable override DOMAIN_SEPARATOR;
address public router;
bool public routerCallbackEnabled;
uint256 public ethFee;
mapping(address => bool) public noFeeWhitelist;
mapping(address => uint256) public nonces;
mapping(address => uint256) public override nonces;

event Deposit(address indexed account, uint256 undelyingDeposited, uint256 piMinted);
event Withdraw(address indexed account, uint256 underlyingWithdrawn, uint256 piBurned);
Expand All @@ -51,7 +51,7 @@ contract WrappedPiErc20 is ERC20, ReentrancyGuard, WrappedPiErc20Interface {
string memory _name,
string memory _symbol
) public ERC20(_name, _symbol) {
underlying = IPermitERC20(_token);
underlying = IERC20Permit(_token);
router = _router;

uint256 chainId;
Expand Down
54 changes: 12 additions & 42 deletions contracts/connectors/TornPowerIndexConnector.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ contract TornPowerIndexConnector is AbstractConnector {
address _underlying,
address _piToken,
address _governance
) public AbstractConnector(46e14) {
)
public
// 1e18 for 100% / (6 hours * 60 * 60) seconds ~= 46e12 degradation per 1 second
AbstractConnector(46e12)
{
STAKING = _staking;
UNDERLYING = IERC20(_underlying);
PI_TOKEN = WrappedPiErc20Interface(_piToken);
Expand Down Expand Up @@ -84,26 +88,10 @@ contract TornPowerIndexConnector is AbstractConnector {

/*** VIEWERS ***/

function getPendingRewards() public view returns (uint256) {
function getPendingRewards() external view returns (uint256) {
return ITornStaking(STAKING).checkReward(address(PI_TOKEN));
}

function accumulatedRewardPerTorn() public view returns (uint256) {
return ITornStaking(STAKING).accumulatedRewardPerTorn();
}

function accumulatedReward() public view returns (uint256) {
return ITornStaking(STAKING).accumulatedRewards(address(PI_TOKEN));
}

function accumulatedRewardRateOnLastUpdate() public view returns (uint256) {
return ITornStaking(STAKING).accumulatedRewardRateOnLastUpdate(address(PI_TOKEN));
}

function accumulatedRewardRateDiffForLastUpdate() public view returns (uint256) {
return accumulatedRewardPerTorn().sub(accumulatedRewardRateOnLastUpdate());
}

/**
* @notice Calculate pending rewards of TornStaking
* @param _accRewardPerTorn TornStaking variable, getting by accumulatedRewardPerTorn()
Expand All @@ -117,7 +105,7 @@ contract TornPowerIndexConnector is AbstractConnector {
) public view returns (uint256) {
return
_lockedBalance.mul(_accRewardPerTorn.sub(_accRewardRateOnLastUpdate)).div(RATIO_CONSTANT).add(
accumulatedReward()
ITornStaking(STAKING).accumulatedRewards(address(PI_TOKEN))
);
}

Expand Down Expand Up @@ -165,8 +153,8 @@ contract TornPowerIndexConnector is AbstractConnector {
{
uint256 lastUpdate = _lastClaimRewardsAt > _lastChangeStakeAt ? _lastClaimRewardsAt : _lastChangeStakeAt;
uint256 lockedBalance = getUnderlyingStaked();
uint256 accRewardPerTorn = accumulatedRewardPerTorn();
uint256 accRewardOnLastUpdate = accumulatedRewardRateOnLastUpdate();
uint256 accRewardPerTorn = ITornStaking(STAKING).accumulatedRewardPerTorn();
uint256 accRewardOnLastUpdate = ITornStaking(STAKING).accumulatedRewardRateOnLastUpdate(address(PI_TOKEN));
pending = pendingReward(accRewardPerTorn, accRewardOnLastUpdate, lockedBalance);

return (
Expand Down Expand Up @@ -226,39 +214,21 @@ contract TornPowerIndexConnector is AbstractConnector {
* @param _tornAmountIn TORN amount to convert
*/
function calcWethOutByTornIn(uint256 _tornAmountIn) external view returns (uint256) {
return calcWethOutByTornInWithRatio(_tornAmountIn, getTornPriceRatio());
}

/**
* @notice Convert TORN amount to WETH amount by provided rario
* @param _tornAmount TORN amount to convert
* @param _ratio Uniswap V3 ratio
*/
function calcWethOutByTornInWithRatio(uint256 _tornAmount, uint256 _ratio) public pure returns (uint256) {
return _tornAmount.mul(_ratio).div(UniswapV3OracleHelper.RATIO_DIVIDER);
return _tornAmountIn.mul(getTornPriceRatio()).div(UniswapV3OracleHelper.RATIO_DIVIDER);
}

/**
* @notice Convert WETH amount to TORN amount with built in ratio
* @param _wethAmount WETH amount to convert
*/
function calcTornOutByWethIn(uint256 _wethAmount) public view returns (uint256) {
return calcTornOutByWethInWithRatio(_wethAmount, getTornPriceRatio());
}

/**
* @notice Convert WETH amount to TORN amount with provided ratio
* @param _wethAmount WETH amount to convert
* @param _ratio Uniswap V3 ratio
*/
function calcTornOutByWethInWithRatio(uint256 _wethAmount, uint256 _ratio) public pure returns (uint256) {
return _wethAmount.mul(UniswapV3OracleHelper.RATIO_DIVIDER).div(_ratio);
return _wethAmount.mul(UniswapV3OracleHelper.RATIO_DIVIDER).div(getTornPriceRatio());
}

/**
* @notice Pack claim params to bytes.
*/
function packClaimParams(uint256 paybackDuration, uint256 gasToReinvest) public pure returns (bytes memory) {
function packClaimParams(uint256 paybackDuration, uint256 gasToReinvest) external pure returns (bytes memory) {
return abi.encode(paybackDuration, gasToReinvest);
}

Expand Down
60 changes: 60 additions & 0 deletions contracts/interfaces/IERC20Permit.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: MIT
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

pragma solidity >=0.6.0 <0.8.0;

/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit is IERC20 {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;

/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);

/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
19 changes: 0 additions & 19 deletions contracts/interfaces/IPermitERC20.sol

This file was deleted.

1 change: 1 addition & 0 deletions contracts/interfaces/IRouterConnector.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import "../interfaces/PowerIndexRouterInterface.sol";
interface IRouterConnector {
struct DistributeData {
bytes stakeData;
bytes stakeParams;
uint256 performanceFee;
address performanceFeeReceiver;
}
Expand Down
14 changes: 2 additions & 12 deletions contracts/interfaces/WrappedPiErc20Interface.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,9 @@
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface WrappedPiErc20Interface is IERC20 {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
import "./IERC20Permit.sol";

interface WrappedPiErc20Interface is IERC20Permit {
function deposit(uint256 _amount) external payable returns (uint256);

function withdraw(uint256 _amount) external payable returns (uint256);
Expand Down
6 changes: 3 additions & 3 deletions hardhat.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const config = {
mainnet: {
url: 'https://mainnet-eth.compound.finance',
accounts: getAccounts('mainnet'),
gasPrice: 36 * 10 ** 9,
gasPrice: process.env.GAS_PRICE ? parseInt(process.env.GAS_PRICE) * 10 ** 9 : 20 * 10 ** 9,
gasMultiplier: 1.2,
timeout: 2000000,
},
Expand All @@ -80,7 +80,7 @@ const config = {
kovan: {
url: 'https://kovan-eth.compound.finance',
accounts: getAccounts('kovan'),
gasPrice: 10 ** 9,
gasPrice: process.env.GAS_PRICE ? parseInt(process.env.GAS_PRICE) * 10 ** 9 : 20 * 10 ** 9,
gasMultiplier: 2,
},
coverage: {
Expand All @@ -93,7 +93,7 @@ const config = {
coverage: './coverage',
coverageJson: './coverage.json',
root: './',
sources: './contracts',
sources: process.env.FLAT ? './flatten' : './contracts',
tests: './test',
},
solidity: {
Expand Down
Loading

0 comments on commit fd46a61

Please sign in to comment.