diff --git a/contracts/test/TestMysoOracle.sol b/contracts/test/TestnetMysoOracle.sol similarity index 100% rename from contracts/test/TestMysoOracle.sol rename to contracts/test/TestnetMysoOracle.sol diff --git a/contracts/test/TestnetTokenManager.sol b/contracts/test/TestnetTokenManager.sol index f009355d..4c2cfc95 100644 --- a/contracts/test/TestnetTokenManager.sol +++ b/contracts/test/TestnetTokenManager.sol @@ -2,36 +2,46 @@ pragma solidity 0.8.19; -import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol"; import {DataTypesPeerToPeer} from "../peer-to-peer/DataTypesPeerToPeer.sol"; import {DataTypesPeerToPool} from "../peer-to-pool/DataTypesPeerToPool.sol"; import {Errors} from "../Errors.sol"; import {IMysoTokenManager} from "../interfaces/IMysoTokenManager.sol"; +import {ILenderVaultImpl} from "../peer-to-peer/interfaces/ILenderVaultImpl.sol"; -contract TestnetTokenManager is ERC20, Ownable2Step, IMysoTokenManager { - uint8 internal _decimals; - address internal _vaultCompartmentVictim; - address internal _vaultAddr; - uint256 internal _borrowerReward; - uint256 internal _lenderReward; - uint256 internal _vaultCreationReward; - uint256 internal constant MAX_SUPPLY = 100_000_000 ether; +contract TestnetTokenManager is Ownable2Step, IMysoTokenManager { + using SafeERC20 for IERC20; + struct RewardInfo { + uint128 collThreshold; + uint128 mysoTokenMultiplier; + } address internal constant MYSO_TOKEN = - 0x6B175474E89094C44Da98b954EedeAC495271d0F; - //0x00000000000000000000000000000000DeaDBeef; - + //0x8fF1307ba7e5FDc3A411d259bAe641e2B1d897c4; // sepolia dev-token + 0x6B175474E89094C44Da98b954EedeAC495271d0F; // Dai testnet stand-in + address internal constant STAKED_MYSO_TOKEN = + 0x0A6cBCB5Ac7Fc6B47f06c2cE3E828b6EEBf37B06; + mapping(address => RewardInfo) public rewardInfos; + bool public mysoRewardsActive; uint256 public totalMysoLoanAmount; + uint256 public minMysoStakingRequirement; address public mysoIOOVault; + event RewardInfoSet( + address indexed collToken, + uint128 collThreshold, + uint128 mysoTokenMultiplier + ); + event MysoRewardsToggled(bool active); + event MinMysoStakingRequirementSet(uint256 minStakingRequirement); + event IOOVaultSet(address indexed mysoIOOVault); + // TODO: mapping oracleAddr -> vaultAddr -> tokenAddr -> loanAmount + flag for being turned tracked // This will allow for other IOOs to use a custom oracle with auto-updating price for loan amount if desired - constructor() ERC20("TYSO", "TYSO") { - _decimals = 18; - _borrowerReward = 1 ether; - _lenderReward = 1 ether; - _vaultCreationReward = 1 ether; + constructor() { + minMysoStakingRequirement = 10_000 * 1e18; _transferOwnership(msg.sender); } @@ -43,22 +53,38 @@ contract TestnetTokenManager is ERC20, Ownable2Step, IMysoTokenManager { address lenderVault ) external returns (uint128[2] memory applicableProtocolFeeParams) { applicableProtocolFeeParams = currProtocolFeeParams; - if (totalSupply() + _borrowerReward + _lenderReward < MAX_SUPPLY) { - _mint(loan.borrower, _borrowerReward); - _mint(lenderVault, _lenderReward); - } if (loan.loanToken == MYSO_TOKEN && lenderVault == mysoIOOVault) { totalMysoLoanAmount += loan.initLoanAmount; } + if ( + mysoRewardsActive && + IERC20(STAKED_MYSO_TOKEN).balanceOf(loan.borrower) > + minMysoStakingRequirement + ) { + RewardInfo memory rewardInfo = rewardInfos[loan.collToken]; + uint256 rewardAmount = loan.initCollAmount * + rewardInfo.mysoTokenMultiplier; + uint256 bal = IERC20(MYSO_TOKEN).balanceOf(address(this)); + rewardAmount = rewardAmount > bal ? bal : rewardAmount; + if ( + loan.initCollAmount > rewardInfo.collThreshold && + rewardAmount > 0 + ) { + SafeERC20.safeTransfer( + IERC20(MYSO_TOKEN), + ILenderVaultImpl(lenderVault).owner(), + rewardAmount + ); + } + } } + // solhint-disable no-empty-blocks function processP2PCreateVault( uint256 /*numRegisteredVaults*/, address /*vaultCreator*/, - address newLenderVaultAddr - ) external { - _mint(newLenderVaultAddr, _vaultCreationReward); - } + address /*newLenderVaultAddr*/ + ) external {} // solhint-disable no-empty-blocks function processP2PCreateWrappedTokenForERC721s( @@ -115,20 +141,41 @@ contract TestnetTokenManager is ERC20, Ownable2Step, IMysoTokenManager { uint256 /*numLoanProposals*/ ) external {} - function setRewards( - uint256 borrowerReward, - uint256 lenderReward, - uint256 vaultCreationReward + function withdraw(address token, address to, uint256 amount) external { + _checkOwner(); + SafeERC20.safeTransfer(IERC20(token), to, amount); + } + + function setRewardInfo( + address collToken, + uint128 collThreshold, + uint128 mysoTokenMultiplier ) external { _checkOwner(); - _borrowerReward = borrowerReward; - _lenderReward = lenderReward; - _vaultCreationReward = vaultCreationReward; + RewardInfo storage rewardInfo = rewardInfos[collToken]; + rewardInfo.collThreshold = collThreshold; + rewardInfo.mysoTokenMultiplier = mysoTokenMultiplier; + emit RewardInfoSet(collToken, collThreshold, mysoTokenMultiplier); + } + + function toggleMysoRewards() external { + _checkOwner(); + mysoRewardsActive = !mysoRewardsActive; + emit MysoRewardsToggled(mysoRewardsActive); + } + + function setMinMysoStakingRequirement( + uint256 _minMysoStakingRequirement + ) external { + _checkOwner(); + minMysoStakingRequirement = _minMysoStakingRequirement; + emit MinMysoStakingRequirementSet(_minMysoStakingRequirement); } function setIOOVault(address _mysoIOOVault) external { _checkOwner(); mysoIOOVault = _mysoIOOVault; + emit IOOVaultSet(_mysoIOOVault); } function transferOwnership(address _newOwnerProposal) public override { @@ -143,8 +190,4 @@ contract TestnetTokenManager is ERC20, Ownable2Step, IMysoTokenManager { } super._transferOwnership(_newOwnerProposal); } - - function decimals() public view override returns (uint8) { - return _decimals; - } } diff --git a/hardhat.config.ts b/hardhat.config.ts index 82dc26f1..2a3caa70 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -156,6 +156,11 @@ const config: HardhatUserConfig = { }, gasReporter: { enabled: true + }, + etherscan: { + apiKey: { + sepolia: process.env.ETHERSCAN_API_KEY + } } } diff --git a/scripts/peer-to-peer/dao/manageAddressRegistry.json b/scripts/peer-to-peer/dao/manageAddressRegistry.json index bf2badda..8ce00f9c 100644 --- a/scripts/peer-to-peer/dao/manageAddressRegistry.json +++ b/scripts/peer-to-peer/dao/manageAddressRegistry.json @@ -20,12 +20,12 @@ ] }, "sepolia": { - "addressRegistry": "0x5EdDDFCAB93b4637b3365E4BB8c69aa1806AE46f", + "addressRegistry": "0x028A90c9834E5e52dB31886D9E05c592b6173F21", "actions": [ { "type": "setWhitelistState", - "addresses": ["0x45b5B91b2f507F881aD42cCb8446bE88BaAfcDAE"], - "state": 1 + "addresses": ["0xC71dBB6b1a9735F3259F0CF746C1c000BF02615c"], + "state": 9 } ] }, diff --git a/scripts/peer-to-peer/utils/configTestMysoOracle.ts b/scripts/peer-to-peer/utils/configTestMysoOracle.ts new file mode 100644 index 00000000..3c2a1b29 --- /dev/null +++ b/scripts/peer-to-peer/utils/configTestMysoOracle.ts @@ -0,0 +1,42 @@ +import { ethers } from 'hardhat' +import { Logger } from '../../helpers/misc' + +const hre = require('hardhat') +const path = require('path') +const scriptName = path.parse(__filename).name +const logger = new Logger(__dirname, scriptName) + +async function main() { + logger.log(`Starting ${scriptName}...`) + logger.log('Loading signer info (check hardhat.config.ts)...') + + const [deployer] = await ethers.getSigners() + const deployerBal = await ethers.provider.getBalance(deployer.address) + const network = await ethers.getDefaultProvider().getNetwork() + const hardhatNetworkName = hre.network.name + const hardhatChainId = hre.network.config.chainId + + logger.log('Running script with the following deployer:', deployer.address) + logger.log('Deployer ETH balance:', ethers.utils.formatEther(deployerBal.toString())) + logger.log(`Deploying to network '${hardhatNetworkName}' (default provider network name '${network.name}')`) + logger.log(`Configured chain id '${hardhatChainId}' (default provider config chain id '${network.chainId}')`) + const TestnetMysoOracle = await ethers.getContractFactory('TestnetMysoOracle') + const testnetMysoOracleAddr = "0x16B67F0dc94e0fAd995d4dFAB77170d30848c277" + const testnetMysoOracle = await TestnetMysoOracle.attach(testnetMysoOracleAddr) + const mysoTestnetTokenManager = "0xC71dBB6b1a9735F3259F0CF746C1c000BF02615c" + await testnetMysoOracle.connect(deployer).setMysoTokenManager(mysoTestnetTokenManager) + + /* + const maxPrice = "55000000" // 8 decimals + const k = "660000000000000000" // 18 decimals + const a = "1350" // scaled by 1000 + const b = "600" // scaled by 1000 + await testnetMysoOracle.connect(deployer).setMysoPriceParams(maxPrice, k, a, b) + logger.log('testnetMysoOracle deployed at:', testnetMysoOracle.address) + */ +} + +main().catch(error => { + console.error(error) + process.exitCode = 1 +}) diff --git a/scripts/peer-to-peer/utils/deployTestMysoOracle.ts b/scripts/peer-to-peer/utils/deployTestMysoOracle.ts new file mode 100644 index 00000000..e632188a --- /dev/null +++ b/scripts/peer-to-peer/utils/deployTestMysoOracle.ts @@ -0,0 +1,39 @@ +import { ethers } from 'hardhat' +import { Logger } from '../../helpers/misc' + +const hre = require('hardhat') +const path = require('path') +const scriptName = path.parse(__filename).name +const logger = new Logger(__dirname, scriptName) + +async function main() { + logger.log(`Starting ${scriptName}...`) + logger.log('Loading signer info (check hardhat.config.ts)...') + + const [deployer] = await ethers.getSigners() + const deployerBal = await ethers.provider.getBalance(deployer.address) + const network = await ethers.getDefaultProvider().getNetwork() + const hardhatNetworkName = hre.network.name + const hardhatChainId = hre.network.config.chainId + + logger.log('Running script with the following deployer:', deployer.address) + logger.log('Deployer ETH balance:', ethers.utils.formatEther(deployerBal.toString())) + logger.log(`Deploying to network '${hardhatNetworkName}' (default provider network name '${network.name}')`) + logger.log(`Configured chain id '${hardhatChainId}' (default provider config chain id '${network.chainId}')`) + const TestnetMysoOracle = await ethers.getContractFactory('TestnetMysoOracle') + const owner = deployer.address + const mysoTokenManager = ethers.constants.AddressZero + const maxPrice = "55000000" // 8 decimals + const k = "66000000000000000000" // 18 decimals + const a = "1350" // scaled by 1000 + const b = "600" // scaled by 1000 + const testnetMysoOracle = await TestnetMysoOracle.connect(deployer).deploy(owner, mysoTokenManager, maxPrice, k, a, b) + await testnetMysoOracle.deployed() + logger.log('testnetMysoOracle deployed at:', testnetMysoOracle.address) + // npx hardhat verify 0x16B67F0dc94e0fAd995d4dFAB77170d30848c277 "0xcE3d0e78c15C30ecf631ef529581Af3de0478895" "0x0000000000000000000000000000000000000000" "5500000000000000" "66000000000000000000" "1350" "600" --network sepolia +} + +main().catch(error => { + console.error(error) + process.exitCode = 1 +}) diff --git a/scripts/peer-to-peer/utils/deployTestnetTokenManager.ts b/scripts/peer-to-peer/utils/deployTestnetTokenManager.ts new file mode 100644 index 00000000..ecc738b7 --- /dev/null +++ b/scripts/peer-to-peer/utils/deployTestnetTokenManager.ts @@ -0,0 +1,32 @@ +import { ethers } from 'hardhat' +import { Logger } from '../../helpers/misc' + +const hre = require('hardhat') +const path = require('path') +const scriptName = path.parse(__filename).name +const logger = new Logger(__dirname, scriptName) + +async function main() { + logger.log(`Starting ${scriptName}...`) + logger.log('Loading signer info (check hardhat.config.ts)...') + + const [deployer] = await ethers.getSigners() + const deployerBal = await ethers.provider.getBalance(deployer.address) + const network = await ethers.getDefaultProvider().getNetwork() + const hardhatNetworkName = hre.network.name + const hardhatChainId = hre.network.config.chainId + + logger.log('Running script with the following deployer:', deployer.address) + logger.log('Deployer ETH balance:', ethers.utils.formatEther(deployerBal.toString())) + logger.log(`Deploying to network '${hardhatNetworkName}' (default provider network name '${network.name}')`) + logger.log(`Configured chain id '${hardhatChainId}' (default provider config chain id '${network.chainId}')`) + const TestnetTokenManager = await ethers.getContractFactory('TestnetTokenManager') + const testnetTokenManager = await TestnetTokenManager.connect(deployer).deploy() + await testnetTokenManager.deployed() + logger.log('testnetTokenManager deployed at:', testnetTokenManager.address) +} + +main().catch(error => { + console.error(error) + process.exitCode = 1 +})