From a7d4abb0b786100b861bde24c625cce135baebca Mon Sep 17 00:00:00 2001 From: Santo Sinar Pandean Date: Fri, 18 Jun 2021 10:55:33 +0700 Subject: [PATCH] Add admin role in protocol settings Add pauser role in priceFeeds Add deployment script for transferring ownership to governance Prettier and linting contract --- contracts/farm/LiquidityMining.sol | 14 ++-- contracts/farm/LiquidityMiningConfigToken.sol | 58 +++++++------- contracts/feeds/PriceFeeds.sol | 13 +++- .../governance/Staking/WeightedStaking.sol | 1 - contracts/interfaces/ISovryn.sol | 4 + contracts/mockup/StakingMockup.sol | 5 +- contracts/mockup/VestingLogicMockup.sol | 30 ++++---- contracts/modules/ProtocolSettings.sol | 61 ++++++++++----- contracts/utils/AdminRole.sol | 68 ++++++++--------- interfaces/ISovrynBrownie.sol | 4 + .../contract_interaction.py | 76 ++++++++++++++++++- .../mainnet_contracts.json | 1 + .../testnet_contracts.json | 1 + .../Governance/GovernorAlpha/QueueTest.js | 5 +- tests-js/farm/LiquidityMining.js | 41 +++++----- tests-js/other/OracleIntegration.test.js | 34 ++++++++- tests-js/other/ProtocolSettings.test.js | 17 +++++ tests-js/staking/ExtendedStakingTest.js | 2 - tests-js/vesting/Vesting.js | 4 +- 19 files changed, 301 insertions(+), 138 deletions(-) diff --git a/contracts/farm/LiquidityMining.sol b/contracts/farm/LiquidityMining.sol index 65d661e7a..e5e007e67 100644 --- a/contracts/farm/LiquidityMining.sol +++ b/contracts/farm/LiquidityMining.sol @@ -357,7 +357,12 @@ contract LiquidityMining is LiquidityMiningStorage { * @param _user the address of user, tokens will be deposited to it * @param alreadyTransferred true if the pool tokens have already been transferred */ - function _deposit(address _poolToken, uint256 _amount, address _user, bool alreadyTransferred) internal{ + function _deposit( + address _poolToken, + uint256 _amount, + address _user, + bool alreadyTransferred + ) internal { require(poolIdList[_poolToken] != 0, "Pool token not found"); address userAddress = _user != address(0) ? _user : msg.sender; @@ -371,8 +376,7 @@ contract LiquidityMining is LiquidityMiningStorage { if (_amount > 0) { //receives pool tokens from msg.sender, it can be user or WrapperProxy contract - if(!alreadyTransferred) - pool.poolToken.safeTransferFrom(address(msg.sender), address(this), _amount); + if (!alreadyTransferred) pool.poolToken.safeTransferFrom(address(msg.sender), address(this), _amount); user.amount = user.amount.add(_amount); } _updateRewardDebt(pool, user); @@ -605,10 +609,8 @@ contract LiquidityMining is LiquidityMiningStorage { * @param _poolToken the address of pool token * @param _user the address of the user */ - function getUserPoolTokenBalance(address _poolToken, address _user) external view returns (uint256){ + function getUserPoolTokenBalance(address _poolToken, address _user) external view returns (uint256) { UserInfo memory ui = getUserInfo(_poolToken, _user); return ui.amount; } - - } diff --git a/contracts/farm/LiquidityMiningConfigToken.sol b/contracts/farm/LiquidityMiningConfigToken.sol index c314785e4..19803a528 100644 --- a/contracts/farm/LiquidityMiningConfigToken.sol +++ b/contracts/farm/LiquidityMiningConfigToken.sol @@ -8,33 +8,31 @@ import "../openzeppelin/IERC20_.sol"; * @dev We need this token for having a flexibility with LiquidityMining configuration */ contract LiquidityMiningConfigToken is IERC20_ { - - function totalSupply() external view returns (uint256) { - return 0; - } - - function balanceOf(address account) external view returns (uint256) { - return 0; - } - - function transfer(address recipient, uint256 amount) external returns (bool) { - return false; - } - - function allowance(address owner, address spender) external view returns (uint256) { - return 0; - } - - function approve(address spender, uint256 amount) external returns (bool) { - return false; - } - - function transferFrom( - address sender, - address recipient, - uint256 amount - ) external returns (bool) { - return false; - } - -} \ No newline at end of file + function totalSupply() external view returns (uint256) { + return 0; + } + + function balanceOf(address account) external view returns (uint256) { + return 0; + } + + function transfer(address recipient, uint256 amount) external returns (bool) { + return false; + } + + function allowance(address owner, address spender) external view returns (uint256) { + return 0; + } + + function approve(address spender, uint256 amount) external returns (bool) { + return false; + } + + function transferFrom( + address sender, + address recipient, + uint256 amount + ) external returns (bool) { + return false; + } +} diff --git a/contracts/feeds/PriceFeeds.sol b/contracts/feeds/PriceFeeds.sol index 7008f773d..a6e3a4714 100644 --- a/contracts/feeds/PriceFeeds.sol +++ b/contracts/feeds/PriceFeeds.sol @@ -47,6 +47,8 @@ contract PriceFeeds is Constants, Ownable { /// Flag to pause pricings. bool public globalPricingPaused = false; + address public pauser; + /* Functions */ /** @@ -69,6 +71,14 @@ contract PriceFeeds is Constants, Ownable { _setBaseToken(_baseTokenAddress); } + /** + * @notice Set pauser account. + * @param _pauser The address of the account to grant pause permissions. + * */ + function setPauser(address _pauser) public onlyOwner { + pauser = _pauser; + } + /** * @notice Calculate the price ratio between two tokens. * @@ -352,7 +362,8 @@ contract PriceFeeds is Constants, Ownable { * * @param isPaused The new status of pause (true/false). * */ - function setGlobalPricingPaused(bool isPaused) external onlyOwner { + function setGlobalPricingPaused(bool isPaused) external { + require(msg.sender == pauser, "onlyPauser"); globalPricingPaused = isPaused; emit GlobalPricingPaused(msg.sender, isPaused); diff --git a/contracts/governance/Staking/WeightedStaking.sol b/contracts/governance/Staking/WeightedStaking.sol index b8aa7ece9..9be35defd 100644 --- a/contracts/governance/Staking/WeightedStaking.sol +++ b/contracts/governance/Staking/WeightedStaking.sol @@ -444,5 +444,4 @@ contract WeightedStaking is Checkpoints { } return codeHash; } - } diff --git a/contracts/interfaces/ISovryn.sol b/contracts/interfaces/ISovryn.sol index 4d00597d6..27d7f1c2c 100644 --- a/contracts/interfaces/ISovryn.sol +++ b/contracts/interfaces/ISovryn.sol @@ -34,6 +34,10 @@ contract ISovryn is ////// Protocol Settings ////// + function setAdmin(address newAdmin) external; + + function getAdmin() external view returns (address); + function setPriceFeedContract(address newContract) external; function setSwapsImplContract(address newContract) external; diff --git a/contracts/mockup/StakingMockup.sol b/contracts/mockup/StakingMockup.sol index d13d504f9..efe303689 100644 --- a/contracts/mockup/StakingMockup.sol +++ b/contracts/mockup/StakingMockup.sol @@ -40,8 +40,8 @@ contract StakingMockup is Staking { } /** - * @dev We need this function to simulate zero delegate checkpoint value. - */ + * @dev We need this function to simulate zero delegate checkpoint value. + */ function setDelegateStake( address delegatee, uint256 lockedTS, @@ -60,5 +60,4 @@ contract StakingMockup is Staking { bytes32 codeHash = _getCodeHash(_contract); return vestingCodeHashes[codeHash]; } - } diff --git a/contracts/mockup/VestingLogicMockup.sol b/contracts/mockup/VestingLogicMockup.sol index 1aaf1ad81..cca4005e9 100644 --- a/contracts/mockup/VestingLogicMockup.sol +++ b/contracts/mockup/VestingLogicMockup.sol @@ -4,20 +4,18 @@ pragma experimental ABIEncoderV2; import "../governance/Vesting/VestingLogic.sol"; contract VestingLogicMockup is VestingLogic { + /** + * @dev we had a bug in a loop: "i < endDate" instead of "i <= endDate" + */ + function delegate(address _delegatee) public onlyTokenOwner { + require(_delegatee != address(0), "delegatee address invalid"); - /** - * @dev we had a bug in a loop: "i < endDate" instead of "i <= endDate" - */ - function delegate(address _delegatee) public onlyTokenOwner { - require(_delegatee != address(0), "delegatee address invalid"); - - /// @dev Withdraw for each unlocked position. - /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS - /// workaround found, but it doesn't work with TWO_WEEKS - for (uint256 i = startDate + cliff; i < endDate; i += FOUR_WEEKS) { - staking.delegate(_delegatee, i); - } - emit VotesDelegated(msg.sender, _delegatee); - } - -} \ No newline at end of file + /// @dev Withdraw for each unlocked position. + /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS + /// workaround found, but it doesn't work with TWO_WEEKS + for (uint256 i = startDate + cliff; i < endDate; i += FOUR_WEEKS) { + staking.delegate(_delegatee, i); + } + emit VotesDelegated(msg.sender, _delegatee); + } +} diff --git a/contracts/modules/ProtocolSettings.sol b/contracts/modules/ProtocolSettings.sol index d430b22a4..7a2dff82f 100644 --- a/contracts/modules/ProtocolSettings.sol +++ b/contracts/modules/ProtocolSettings.sol @@ -23,6 +23,13 @@ contract ProtocolSettings is State, ProtocolTokenUser, ProtocolSettingsEvents { using SafeERC20 for IERC20; using SafeMath for uint256; + address public admin; + + modifier onlyAdmin() { + require(isOwner() || msg.sender == admin, "unauthorized"); + _; + } + /** * @notice Empty public constructor. * */ @@ -67,6 +74,20 @@ contract ProtocolSettings is State, ProtocolTokenUser, ProtocolSettingsEvents { _setTarget(this.setProtocolTokenAddress.selector, target); _setTarget(this.setRolloverBaseReward.selector, target); _setTarget(this.setRebatePercent.selector, target); + _setTarget(this.setAdmin.selector, target); + _setTarget(this.getAdmin.selector, target); + } + + /** + * @notice Set admin account. + * @param _admin The address of the account to grant admin permissions. + * */ + function setAdmin(address _admin) public onlyOwner { + admin = _admin; + } + + function getAdmin() external view returns (address) { + return admin; } /** @@ -74,7 +95,7 @@ contract ProtocolSettings is State, ProtocolTokenUser, ProtocolSettingsEvents { * * @param newContract The address of the Price Feed new instance. * */ - function setPriceFeedContract(address newContract) external onlyOwner { + function setPriceFeedContract(address newContract) external onlyAdmin { address oldContract = priceFeeds; priceFeeds = newContract; @@ -86,7 +107,7 @@ contract ProtocolSettings is State, ProtocolTokenUser, ProtocolSettingsEvents { * * @param newContract The address of the asset swapper new instance. * */ - function setSwapsImplContract(address newContract) external onlyOwner { + function setSwapsImplContract(address newContract) external onlyAdmin { address oldContract = swapsImpl; swapsImpl = newContract; @@ -99,7 +120,7 @@ contract ProtocolSettings is State, ProtocolTokenUser, ProtocolSettingsEvents { * @param pools The array of addresses of new loan pool instances. * @param assets The array of addresses of the corresponding underlying tokens. * */ - function setLoanPool(address[] calldata pools, address[] calldata assets) external onlyOwner { + function setLoanPool(address[] calldata pools, address[] calldata assets) external onlyAdmin { require(pools.length == assets.length, "count mismatch"); for (uint256 i = 0; i < pools.length; i++) { @@ -128,7 +149,7 @@ contract ProtocolSettings is State, ProtocolTokenUser, ProtocolSettingsEvents { * @param toggles The array of flags indicating whether * the corresponding token is supported or not. * */ - function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles) external onlyOwner { + function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles) external onlyAdmin { require(addrs.length == toggles.length, "count mismatch"); for (uint256 i = 0; i < addrs.length; i++) { @@ -143,7 +164,7 @@ contract ProtocolSettings is State, ProtocolTokenUser, ProtocolSettingsEvents { * * @param newValue The new value for lendingFeePercent. * */ - function setLendingFeePercent(uint256 newValue) external onlyOwner { + function setLendingFeePercent(uint256 newValue) external onlyAdmin { require(newValue <= 10**20, "value too high"); uint256 oldValue = lendingFeePercent; lendingFeePercent = newValue; @@ -156,7 +177,7 @@ contract ProtocolSettings is State, ProtocolTokenUser, ProtocolSettingsEvents { * * @param newValue The new value for tradingFeePercent. * */ - function setTradingFeePercent(uint256 newValue) external onlyOwner { + function setTradingFeePercent(uint256 newValue) external onlyAdmin { require(newValue <= 10**20, "value too high"); uint256 oldValue = tradingFeePercent; tradingFeePercent = newValue; @@ -169,7 +190,7 @@ contract ProtocolSettings is State, ProtocolTokenUser, ProtocolSettingsEvents { * * @param newValue The new value for borrowingFeePercent. * */ - function setBorrowingFeePercent(uint256 newValue) external onlyOwner { + function setBorrowingFeePercent(uint256 newValue) external onlyAdmin { require(newValue <= 10**20, "value too high"); uint256 oldValue = borrowingFeePercent; borrowingFeePercent = newValue; @@ -182,7 +203,7 @@ contract ProtocolSettings is State, ProtocolTokenUser, ProtocolSettingsEvents { * * @param newValue The new value for affiliateFeePercent. * */ - function setAffiliateFeePercent(uint256 newValue) external onlyOwner { + function setAffiliateFeePercent(uint256 newValue) external onlyAdmin { require(newValue <= 10**20, "value too high"); uint256 oldValue = affiliateFeePercent; affiliateFeePercent = newValue; @@ -195,7 +216,7 @@ contract ProtocolSettings is State, ProtocolTokenUser, ProtocolSettingsEvents { * * @param newValue The new value for liquidationIncentivePercent. * */ - function setLiquidationIncentivePercent(uint256 newValue) external onlyOwner { + function setLiquidationIncentivePercent(uint256 newValue) external onlyAdmin { require(newValue <= 10**20, "value too high"); uint256 oldValue = liquidationIncentivePercent; liquidationIncentivePercent = newValue; @@ -208,7 +229,7 @@ contract ProtocolSettings is State, ProtocolTokenUser, ProtocolSettingsEvents { * * @param newValue The new value for maxDisagreement. * */ - function setMaxDisagreement(uint256 newValue) external onlyOwner { + function setMaxDisagreement(uint256 newValue) external onlyAdmin { maxDisagreement = newValue; } @@ -219,7 +240,7 @@ contract ProtocolSettings is State, ProtocolTokenUser, ProtocolSettingsEvents { * * @param newValue The new value for the maximum source buffer. * */ - function setSourceBuffer(uint256 newValue) external onlyOwner { + function setSourceBuffer(uint256 newValue) external onlyAdmin { sourceBuffer = newValue; } @@ -228,7 +249,7 @@ contract ProtocolSettings is State, ProtocolTokenUser, ProtocolSettingsEvents { * * @param newValue The new value for the maximum swap size. * */ - function setMaxSwapSize(uint256 newValue) external onlyOwner { + function setMaxSwapSize(uint256 newValue) external onlyAdmin { uint256 oldValue = maxSwapSize; maxSwapSize = newValue; @@ -244,7 +265,7 @@ contract ProtocolSettings is State, ProtocolTokenUser, ProtocolSettingsEvents { * * @param newController The new address of the feesController. * */ - function setFeesController(address newController) external onlyOwner { + function setFeesController(address newController) external onlyAdmin { address oldController = feesController; feesController = newController; @@ -415,7 +436,7 @@ contract ProtocolSettings is State, ProtocolTokenUser, ProtocolSettingsEvents { * @return The protocol token address. * @return Withdrawal success (true/false). * */ - function withdrawProtocolToken(address receiver, uint256 amount) external onlyOwner returns (address, bool) { + function withdrawProtocolToken(address receiver, uint256 amount) external onlyAdmin returns (address, bool) { return _withdrawProtocolToken(receiver, amount); } @@ -424,7 +445,7 @@ contract ProtocolSettings is State, ProtocolTokenUser, ProtocolSettingsEvents { * * @param amount The tokens of fees to send. * */ - function depositProtocolToken(uint256 amount) external onlyOwner { + function depositProtocolToken(uint256 amount) external onlyAdmin { /// @dev Update local balance protocolTokenHeld = protocolTokenHeld.add(amount); @@ -460,7 +481,7 @@ contract ProtocolSettings is State, ProtocolTokenUser, ProtocolSettingsEvents { * * @param registryAddress the address of the registry contract. * */ - function setSovrynSwapContractRegistryAddress(address registryAddress) external onlyOwner { + function setSovrynSwapContractRegistryAddress(address registryAddress) external onlyAdmin { require(Address.isContract(registryAddress), "registryAddress not a contract"); address oldSovrynSwapContractRegistryAddress = sovrynSwapContractRegistryAddress; @@ -474,7 +495,7 @@ contract ProtocolSettings is State, ProtocolTokenUser, ProtocolSettingsEvents { * * @param wrbtcTokenAddress The address of the wrBTC contract. * */ - function setWrbtcToken(address wrbtcTokenAddress) external onlyOwner { + function setWrbtcToken(address wrbtcTokenAddress) external onlyAdmin { require(Address.isContract(wrbtcTokenAddress), "wrbtcTokenAddress not a contract"); address oldwrbtcToken = address(wrbtcToken); @@ -488,7 +509,7 @@ contract ProtocolSettings is State, ProtocolTokenUser, ProtocolSettingsEvents { * * @param _protocolTokenAddress The address of the protocol token contract. * */ - function setProtocolTokenAddress(address _protocolTokenAddress) external onlyOwner { + function setProtocolTokenAddress(address _protocolTokenAddress) external onlyAdmin { require(Address.isContract(_protocolTokenAddress), "_protocolTokenAddress not a contract"); address oldProtocolTokenAddress = protocolTokenAddress; @@ -502,7 +523,7 @@ contract ProtocolSettings is State, ProtocolTokenUser, ProtocolSettingsEvents { * * @param baseRewardValue The base reward. * */ - function setRolloverBaseReward(uint256 baseRewardValue) external onlyOwner { + function setRolloverBaseReward(uint256 baseRewardValue) external onlyAdmin { require(baseRewardValue > 0, "Base reward is zero"); uint256 oldValue = rolloverBaseReward; @@ -516,7 +537,7 @@ contract ProtocolSettings is State, ProtocolTokenUser, ProtocolSettingsEvents { * * @param rebatePercent The fee rebate percent. * */ - function setRebatePercent(uint256 rebatePercent) external onlyOwner { + function setRebatePercent(uint256 rebatePercent) external onlyAdmin { require(rebatePercent <= 10**20, "Fee rebate is too high"); uint256 oldRebatePercent = feeRebatePercent; diff --git a/contracts/utils/AdminRole.sol b/contracts/utils/AdminRole.sol index 3aa357df2..b3693ad23 100644 --- a/contracts/utils/AdminRole.sol +++ b/contracts/utils/AdminRole.sol @@ -3,38 +3,36 @@ pragma solidity 0.5.17; import "../openzeppelin/Ownable.sol"; contract AdminRole is Ownable { - - /// @dev user => flag whether user has admin role. - mapping(address => bool) public admins; - - event AdminAdded(address admin); - event AdminRemoved(address admin); - - /** - * @dev Throws if called by any account other than the owner or admin. - * or on our own overriding sovrynOwnable. - */ - modifier onlyAuthorized() { - require(isOwner() || admins[msg.sender], "unauthorized"); - _; - } - - /** - * @notice Add account to ACL. - * @param _admin The addresses of the account to grant permissions. - * */ - function addAdmin(address _admin) public onlyOwner { - admins[_admin] = true; - emit AdminAdded(_admin); - } - - /** - * @notice Remove account from ACL. - * @param _admin The addresses of the account to revoke permissions. - * */ - function removeAdmin(address _admin) public onlyOwner { - admins[_admin] = false; - emit AdminRemoved(_admin); - } - -} \ No newline at end of file + /// @dev user => flag whether user has admin role. + mapping(address => bool) public admins; + + event AdminAdded(address admin); + event AdminRemoved(address admin); + + /** + * @dev Throws if called by any account other than the owner or admin. + * or on our own overriding sovrynOwnable. + */ + modifier onlyAuthorized() { + require(isOwner() || admins[msg.sender], "unauthorized"); + _; + } + + /** + * @notice Add account to ACL. + * @param _admin The addresses of the account to grant permissions. + * */ + function addAdmin(address _admin) public onlyOwner { + admins[_admin] = true; + emit AdminAdded(_admin); + } + + /** + * @notice Remove account from ACL. + * @param _admin The addresses of the account to revoke permissions. + * */ + function removeAdmin(address _admin) public onlyOwner { + admins[_admin] = false; + emit AdminRemoved(_admin); + } +} diff --git a/interfaces/ISovrynBrownie.sol b/interfaces/ISovrynBrownie.sol index 708ce1f7e..7a5071c67 100644 --- a/interfaces/ISovrynBrownie.sol +++ b/interfaces/ISovrynBrownie.sol @@ -34,6 +34,10 @@ contract ISovrynBrownie is ////// Protocol Settings ////// + function setAdmin(address newAdmin) external; + + function getAdmin() external view returns(address); + function setPriceFeedContract(address newContract) external; function setSwapsImplContract(address newContract) external; diff --git a/scripts/contractInteraction/contract_interaction.py b/scripts/contractInteraction/contract_interaction.py index e5de68404..812a02679 100644 --- a/scripts/contractInteraction/contract_interaction.py +++ b/scripts/contractInteraction/contract_interaction.py @@ -1308,4 +1308,78 @@ def readWRBTCAddressFromWrapper(wrapper): abiFile = open('./scripts/contractInteraction/RBTCWrapperProxy.json') abi = json.load(abiFile) wrapperProxy = Contract.from_abi("RBTCWrapperProxy", address=wrapper, abi=abi, owner=acct) - print(wrapperProxy.wrbtcTokenAddress()) \ No newline at end of file + print(wrapperProxy.wrbtcTokenAddress()) + +def tranfserProtocolAdminToAdminGovernance(): + governorAdmin = contracts["GovernorAdmin"] + + # Need to redeploy the protocol settings since there is additional function and logic changed + replaceProtocolSettings() + + # Set the governorAdmin as admin of the protocol + sovryn = Contract.from_abi("sovryn", address=contracts['sovrynProtocol'], abi=interface.ISovrynBrownie.abi, owner=acct) + data = sovryn.setAdmin.encode_input(governorAdmin) + multisig = Contract.from_abi("MultiSig", address=contracts['multisig'], abi=MultiSigWallet.abi, owner=acct) + tx = multisig.submitTransaction(sovryn.address,0,data) + txId = tx.events["Submission"]["transactionId"] + print("txid",txId) + +def transferProtocolOwnershipToOwnerGovernance(): + governorOwner = contracts["GovernorOwner"] + + # Need to redeploy the protocol settings since there is additional function and logic changed + replaceProtocolSettings() + + # Set the governorOwner as owner of the protocol + sovryn = Contract.from_abi("sovryn", address=contracts['sovrynProtocol'], abi=interface.ISovrynBrownie.abi, owner=acct) + data = sovryn.transferOwnership.encode_input(governorOwner) + multisig = Contract.from_abi("MultiSig", address=contracts['multisig'], abi=MultiSigWallet.abi, owner=acct) + tx = multisig.submitTransaction(sovryn.address,0,data) + txId = tx.events["Submission"]["transactionId"] + print("txid",txId) + +def transferPriceFeedOracleOwnershipToAdminGovernance(): + governorAdmin = contracts["GovernorAdmin"] + + # BProPriceFeeds --> transfer to admin governor + bProPriceFeed = Contract.from_abi("BProPriceFeed", address=contracts['BProPriceFeed'], abi=BProPriceFeed.abi, owner=acct) + data = bProPriceFeed.transferOwnership.encode_input(governorAdmin) + multisig = Contract.from_abi("MultiSig", address=contracts['multisig'], abi=MultiSigWallet.abi, owner=acct) + tx = multisig.submitTransaction(bProPriceFeed.address,0,data) + txId = tx.events["Submission"]["transactionId"] + print("txid",txId) + + # PriceFeedRSKOracle --> transfer to admin governor + priceFeedRSKOracle = Contract.from_abi("PriceFeedRSKOracle", address=contracts['PriceFeedRSKOracle'], abi=PriceFeedRSKOracle.abi, owner=acct) + data = priceFeedRSKOracle.transferOwnership.encode_input(governorAdmin) + multisig = Contract.from_abi("MultiSig", address=contracts['multisig'], abi=MultiSigWallet.abi, owner=acct) + tx = multisig.submitTransaction(priceFeedRSKOracle.address,0,data) + txId = tx.events["Submission"]["transactionId"] + print("txid",txId) + +def transferPriceFeedGatewayPauserToMultisig(): + # Need to redeploy the PriceFeeds.sol since the logic has changed (adding pauser role) + # To redeploy the priceFeeds, we need to re-register all of the assets into the pricefeeds + + # PriceFeeds --> set the pauser to our multisig -- somehow, we still need to use multisig to pause the priceFeeds, since it takes too long if pause by governance + priceFeeds = Contract.from_abi("PriceFeeds", address=contracts['PriceFeeds'], abi=PriceFeeds.abi, owner=acct) + data = priceFeeds.setPauser.encode_input(contracts['multisig']) + multisig = Contract.from_abi("MultiSig", address=contracts['multisig'], abi=MultiSigWallet.abi, owner=acct) + tx = multisig.submitTransaction(priceFeeds.address,0,data) + txId = tx.events["Submission"]["transactionId"] + print("txid",txId) + +def transferPriceFeedGatewayOwnershipToAdminGovernance(): + loadConfig() + governorAdmin = contracts["GovernorAdmin"] + + # Need to redeploy the PriceFeeds.sol since the logic has changed (adding pauser role) + # To redeploy the priceFeeds, we need to re-register all of the assets into the pricefeeds + + # PriceFeeds --> transfer to admin governor + priceFeeds = Contract.from_abi("PriceFeeds", address=contracts['PriceFeeds'], abi=PriceFeeds.abi, owner=acct) + data = priceFeeds.transferOwnership.encode_input(governorAdmin) + multisig = Contract.from_abi("MultiSig", address=contracts['multisig'], abi=MultiSigWallet.abi, owner=acct) + tx = multisig.submitTransaction(priceFeeds.address,0,data) + txId = tx.events["Submission"]["transactionId"] + print("txid",txId) \ No newline at end of file diff --git a/scripts/contractInteraction/mainnet_contracts.json b/scripts/contractInteraction/mainnet_contracts.json index 6073b43b0..a715f9c13 100644 --- a/scripts/contractInteraction/mainnet_contracts.json +++ b/scripts/contractInteraction/mainnet_contracts.json @@ -14,6 +14,7 @@ "og" : "0x81d25201D044f178883599Be1934FF53FDA98acD", "PriceFeeds": "0x437AC62769f386b2d238409B7f0a7596d36506e4", "multisig": "0x924f5ad34698Fd20c90Fe5D5A8A0abd3b42dc711", + "BProPriceFeed": "0x389e2447e1397A8e485D658a44D845a324A338Cf", "RSKOracle": "0x99eD262dbd8842442cd22d4c6885936DB38245E6", "PriceFeedRSKOracle": "0x54c33Cb8a3a32A716BeC40C3CEB5bA8B0fB92a57", "USDT":"0xEf213441a85DF4d7acBdAe0Cf78004E1e486BB96", diff --git a/scripts/contractInteraction/testnet_contracts.json b/scripts/contractInteraction/testnet_contracts.json index e1c57436f..29cbc1d3e 100644 --- a/scripts/contractInteraction/testnet_contracts.json +++ b/scripts/contractInteraction/testnet_contracts.json @@ -25,6 +25,7 @@ "BTCtoUSDTOracleAMM": "0x066ba9453e230a260c2a753d9935d91187178C29", "USDTConverter": "0x133eBE9c8bA524C9B1B601E794dF527f390729bF", "BPro": "0x4dA7997A819bb46B6758b9102234c289Dd2ad3bf", + "BProPriceFeed": "0xB7b9B10E04c36C3bB8Df34163331BBB0194d1DB4", "RSKOracle": "0xE00243Bc6912BF148302e8478996c98c22fE8739", "PriceFeedRSKOracle":"0xF2B7440C89431DF82EC6c8F3D079059847565dF0", diff --git a/tests-js/Governance/GovernorAlpha/QueueTest.js b/tests-js/Governance/GovernorAlpha/QueueTest.js index e18861ea2..db708cef7 100644 --- a/tests-js/Governance/GovernorAlpha/QueueTest.js +++ b/tests-js/Governance/GovernorAlpha/QueueTest.js @@ -94,7 +94,10 @@ contract("GovernorAlpha#queue/1", (accounts) => { const txVote2 = await gov.castVote(proposalId2, true, { from: a2 }); await advanceBlocks(30); - await expectRevert(gov.queueProposals([proposalId1, proposalId2]), "revert GovernorAlpha::_queueOrRevert: proposal action already queued at eta"); + await expectRevert( + gov.queueProposals([proposalId1, proposalId2]), + "revert GovernorAlpha::_queueOrRevert: proposal action already queued at eta" + ); await gov.queue(proposalId1); await increaseTime(60); diff --git a/tests-js/farm/LiquidityMining.js b/tests-js/farm/LiquidityMining.js index f5757a26f..eacd3c3f2 100644 --- a/tests-js/farm/LiquidityMining.js +++ b/tests-js/farm/LiquidityMining.js @@ -253,7 +253,10 @@ describe("LiquidityMining", () => { }); it("fails if unlockedImmediatelyPercent >= 10000", async () => { - await expectRevert(liquidityMining.setUnlockedImmediatelyPercent(100000), "Unlocked immediately percent has to be less than 10000."); + await expectRevert( + liquidityMining.setUnlockedImmediatelyPercent(100000), + "Unlocked immediately percent has to be less than 10000." + ); }); }); @@ -389,10 +392,10 @@ describe("LiquidityMining", () => { }); it("only owner or admin should be able to add pool token", async () => { - await expectRevert(liquidityMining.add(token2.address, new BN(1), false, {from: account1}), "unauthorized"); + await expectRevert(liquidityMining.add(token2.address, new BN(1), false, { from: account1 }), "unauthorized"); await liquidityMining.addAdmin(account1); - await liquidityMining.add(token2.address, new BN(1), false, {from: account1}); + await liquidityMining.add(token2.address, new BN(1), false, { from: account1 }); }); }); @@ -441,10 +444,10 @@ describe("LiquidityMining", () => { it("only owner or admin should be able to update pool token", async () => { await liquidityMining.add(token2.address, new BN(1), false); - await expectRevert(liquidityMining.update(token2.address, new BN(1), false, {from: account1}), "unauthorized"); + await expectRevert(liquidityMining.update(token2.address, new BN(1), false, { from: account1 }), "unauthorized"); await liquidityMining.addAdmin(account1); - await liquidityMining.update(token2.address, new BN(1), false, {from: account1}); + await liquidityMining.update(token2.address, new BN(1), false, { from: account1 }); }); }); @@ -700,7 +703,7 @@ describe("LiquidityMining", () => { user: account1, poolToken: token1.address, amount: amount, - accumulatedReward: expectedAccumulatedReward + accumulatedReward: expectedAccumulatedReward, }); }); @@ -1291,19 +1294,19 @@ describe("LiquidityMining", () => { //Maximum reward per week: 100K SOV (or 100M SOV) //Maximum reward per block: 4.9604 SOV (4.9604 * 2880 * 7 = 100001.664) - const REWARD_TOKENS_PER_BLOCK = new BN(49604).mul(new BN(10**14)).mul(new BN(1000)); + const REWARD_TOKENS_PER_BLOCK = new BN(49604).mul(new BN(10 ** 14)).mul(new BN(1000)); // const REWARD_TOKENS_PER_BLOCK = new BN(49604).mul(new BN(10**14)); //SOV/BTC pool 40K per week //ETH/BTC pool 37.5K per week (from second week) //Dummy pool 100K - SOV/BTC pool (- ETH/BTC pool) - const MAX_ALLOCATION_POINT = new BN(100000).mul(new BN(1000)); + const MAX_ALLOCATION_POINT = new BN(100000).mul(new BN(1000)); // const MAX_ALLOCATION_POINT = new BN(100000); - const ALLOCATION_POINT_SOV_BTC = new BN(40000); - const ALLOCATION_POINT_ETH_BTC = new BN(37500); + const ALLOCATION_POINT_SOV_BTC = new BN(40000); + const ALLOCATION_POINT_ETH_BTC = new BN(37500); - const ALLOCATION_POINT_SOV_BTC_2 = new BN(30000); + const ALLOCATION_POINT_SOV_BTC_2 = new BN(30000); const amount = new BN(1000); @@ -1350,7 +1353,9 @@ describe("LiquidityMining", () => { const userInfo = await liquidityMining.getUserInfo(SOVBTCpool, account1); //10 blocks passed let passedBlocks = 10; - let expectedUserReward = REWARD_TOKENS_PER_BLOCK.mul(new BN(passedBlocks)).mul(ALLOCATION_POINT_SOV_BTC).div(MAX_ALLOCATION_POINT); + let expectedUserReward = REWARD_TOKENS_PER_BLOCK.mul(new BN(passedBlocks)) + .mul(ALLOCATION_POINT_SOV_BTC) + .div(MAX_ALLOCATION_POINT); expect(userInfo.accumulatedReward).bignumber.equal(expectedUserReward); console.log(expectedUserReward.toString()); }); @@ -1388,14 +1393,16 @@ describe("LiquidityMining", () => { const userInfo = await liquidityMining.getUserInfo(SOVBTCpool, account1); //10 blocks + 5 blocks passed let passedBlocks = 10 + 1; //block should be add to calculation with old values - let expectedUserReward = REWARD_TOKENS_PER_BLOCK.mul(new BN(passedBlocks)).mul(ALLOCATION_POINT_SOV_BTC).div(MAX_ALLOCATION_POINT); + let expectedUserReward = REWARD_TOKENS_PER_BLOCK.mul(new BN(passedBlocks)) + .mul(ALLOCATION_POINT_SOV_BTC) + .div(MAX_ALLOCATION_POINT); passedBlocks = 5 - 1; //block should be removed from calculation with new values - expectedUserReward = expectedUserReward - .add(REWARD_TOKENS_PER_BLOCK.mul(new BN(passedBlocks)).mul(ALLOCATION_POINT_SOV_BTC_2).div(MAX_ALLOCATION_POINT)); + expectedUserReward = expectedUserReward.add( + REWARD_TOKENS_PER_BLOCK.mul(new BN(passedBlocks)).mul(ALLOCATION_POINT_SOV_BTC_2).div(MAX_ALLOCATION_POINT) + ); expect(userInfo.accumulatedReward).bignumber.equal(expectedUserReward); console.log(expectedUserReward.toString()); }); - }); describe("onTokensDeposited", () => { @@ -1579,7 +1586,7 @@ describe("LiquidityMining", () => { expect(rewardList[0]).bignumber.equal("0"); }); - it("getUserPoolTokenBalance", async()=>{ + it("getUserPoolTokenBalance", async () => { await liquidityMining.deposit(token1.address, new BN(500), ZERO_ADDRESS, { from: account1 }); let poolTokenBalance = await liquidityMining.getUserPoolTokenBalance(token1.address, account1); expect(poolTokenBalance).bignumber.equal(new BN(500)); diff --git a/tests-js/other/OracleIntegration.test.js b/tests-js/other/OracleIntegration.test.js index d1b69448b..4c44f0039 100644 --- a/tests-js/other/OracleIntegration.test.js +++ b/tests-js/other/OracleIntegration.test.js @@ -8,6 +8,7 @@ const PriceFeedRSKOracleMockup = artifacts.require("PriceFeedRSKOracleMockup"); const SwapsImplSovrynSwap = artifacts.require("SwapsImplSovrynSwap"); const { getSUSD, getRBTC, getWRBTC, getBZRX, getSovryn, getPriceFeeds } = require("../Utils/initializer.js"); +const wei = web3.utils.toWei; contract("OracleIntegration", (accounts) => { let sovryn, SUSD, WRBTC, RBTC, BZRX, priceFeeds, swapsImpl; @@ -54,10 +55,39 @@ contract("OracleIntegration", (accounts) => { }; describe("OracleIntegration Tests", () => { + it("Test pause price feed should revert if not set by pauser", async () => { + const price_feeds = await PriceFeeds.new(WRBTC.address, BZRX.address, SUSD.address); + await expectRevert(price_feeds.setGlobalPricingPaused(true), "onlyPauser"); + expect((await price_feeds.globalPricingPaused()) == false).to.be.true; + }); + + it("Test pause price feed", async () => { + const newPauser = accounts[9]; + + const price_feeds = await PriceFeeds.new(WRBTC.address, BZRX.address, SUSD.address); + await price_feeds.setPauser(newPauser); + + expect((await price_feeds.pauser()) == newPauser).to.be.true; + + await price_feeds.setGlobalPricingPaused(true, { from: newPauser }); + expect((await price_feeds.globalPricingPaused()) == true).to.be.true; + + expect((await price_feeds.queryReturn(WRBTC.address, BZRX.address, wei("1", "ether"))) == 0).to.be.true; + + await expectRevert( + price_feeds.checkPriceDisagreement(WRBTC.address, BZRX.address, wei("1", "ether"), wei("1", "ether"), wei("1", "ether")), + "pricing is paused" + ); + }); + it("Test moc oracle integration", async () => { const [price_feeds, price_feeds_moc] = await set_oracle( - (await price_feed_rsk_mockup()).address, - (await price_feed_moc_mockup()).address + ( + await price_feed_rsk_mockup() + ).address, + ( + await price_feed_moc_mockup() + ).address ); let res = await price_feeds.queryPrecision(BZRX.address, WRBTC.address); diff --git a/tests-js/other/ProtocolSettings.test.js b/tests-js/other/ProtocolSettings.test.js index 566eff686..72877ce82 100644 --- a/tests-js/other/ProtocolSettings.test.js +++ b/tests-js/other/ProtocolSettings.test.js @@ -38,6 +38,23 @@ contract("ProtocolSettings", (accounts) => { }); describe("ProtocolSettings Tests", () => { + it("Set admin", async () => { + const dest = sovryn.address; + const val = 0; + const newAdmin = accounts[9]; + let data = sovryn.contract.methods.setAdmin(newAdmin).encodeABI(); + let tx = await multisig.submitTransaction(dest, val, data, { from: accounts[0] }); + let txId = tx.logs.filter((item) => item.event == "Submission")[0].args["transactionId"]; + await multisig.confirmTransaction(txId, { from: accounts[1] }); + + expect((await sovryn.getAdmin()) == newAdmin).to.be.true; + }); + + it("Set admin will revert if set by not an owner", async () => { + const newAdmin = accounts[9]; + await expectRevert(sovryn.setAdmin(newAdmin), "unauthorized"); + }); + it("Test setCoreParams", async () => { const dest = sovryn.address; const val = 0; diff --git a/tests-js/staking/ExtendedStakingTest.js b/tests-js/staking/ExtendedStakingTest.js index 7bebf0e7f..28a57919c 100644 --- a/tests-js/staking/ExtendedStakingTest.js +++ b/tests-js/staking/ExtendedStakingTest.js @@ -663,7 +663,6 @@ contract("Staking", (accounts) => { }); describe("withdraw", () => { - it("Amount of tokens to be withdrawn needs to be bigger than 0", async () => { let amount = "1000"; let duration = new BN(TWO_WEEKS).mul(new BN(2)); @@ -999,7 +998,6 @@ contract("Staking", (accounts) => { balance = await staking.balanceOf_MultipliedByTwo.call(root); expect(balance.toNumber()).to.be.equal(amount * 2); }); - }); async function getTimeFromKickoff(delay) { diff --git a/tests-js/vesting/Vesting.js b/tests-js/vesting/Vesting.js index c57025e04..01fce947a 100644 --- a/tests-js/vesting/Vesting.js +++ b/tests-js/vesting/Vesting.js @@ -864,7 +864,7 @@ contract("Vesting", (accounts) => { await staking.addAdmin(a1); //governance withdraw until duration must withdraw all staked tokens without fees - let tx = await staking.governanceWithdrawVesting(vesting.address, root, {from: a1}); + let tx = await staking.governanceWithdrawVesting(vesting.address, root, { from: a1 }); expectEvent(tx, "VestingTokensWithdrawn", { vesting: vesting.address, @@ -880,7 +880,6 @@ contract("Vesting", (accounts) => { let vestingBalance = await staking.balanceOf(vesting.address); expect(vestingBalance).to.be.bignumber.equal(new BN(0)); }); - }); describe("collectDividends", async () => { @@ -1002,5 +1001,4 @@ contract("Vesting", (accounts) => { await vesting.migrateToNewStakingContract({ from: a1 }); }); }); - });