diff --git a/multisig/proposals/ethereum/vip-054/index.ts b/multisig/proposals/ethereum/vip-054/index.ts new file mode 100644 index 000000000..5f14558f3 --- /dev/null +++ b/multisig/proposals/ethereum/vip-054/index.ts @@ -0,0 +1,159 @@ +import { BigNumber } from "ethers"; +import { parseUnits } from "ethers/lib/utils"; +import { ethers } from "hardhat"; + +import { makeProposal } from "../../../../src/utils"; + +interface CASE_COMMAND { + name: string; + rewardsDistributorOld: string; + address: string; + oldSupplySpeed: BigNumber; + oldBorrowSpeed: BigNumber; +} + +export const REWARDS_DISTRIBUTOR_CORE_OLD = "0x134bfDEa7e68733921Bc6A87159FB0d68aBc6Cf8"; +export const REWARDS_DISTRIBUTOR_CORE_NEW = "0x886767B62C7ACD601672607373048FFD96Cf27B2"; +export const REWARDS_DISTRIBUTOR_LST_OLD = "0x7A91bEd36D96E4e644d3A181c287E0fcf9E9cc98"; +export const REWARDS_DISTRIBUTOR_LST_NEW = "0x1e25CF968f12850003Db17E0Dba32108509C4359"; +export const XVS = "0xd3CC9d8f3689B83c91b7B59cAB4946B063EB894A"; + +export const VFRAX_CORE = "0x4fAfbDc4F2a9876Bd1764827b26fb8dc4FD1dB95"; +export const VSFRAX_CORE = "0x17142a05fe678e9584FA1d88EfAC1bF181bF7ABe"; +export const VDAI_CORE = "0xd8AdD9B41D4E1cd64Edad8722AB0bA8D35536657"; +export const VTUSD_CORE = "0x13eB80FDBe5C5f4a7039728E258A6f05fb3B912b"; + +export const VSFRXETH_LST = "0xF9E9Fe17C00a8B96a8ac20c4E344C8688D7b947E"; + +/* +REFERENCE VIP +https://github.com/VenusProtocol/vips/pull/277 - CASE A +https://github.com/VenusProtocol/vips/pull/301 - CASE B +https://github.com/VenusProtocol/vips/pull/302 - (PAUSED) +*/ + +export const XVS_TRANSFERRED_FRAX_SFRAX_CASE_A = parseUnits("4800", 18); +export const XVS_TRANSFERRED_FRAX_SFRAX_CASE_B = parseUnits("3600", 18); +export const XVS_TRANSFERRED_DAI_TUSD_OLD_CASE_B = parseUnits("2100", 18); +export const XVS_TRANSFERRED_LST_OLD = parseUnits("2400", 18); +export const XVS_AMOUNT_CORE_OLD = parseUnits("19946630223281754045521", 0); +export const XVS_AMOUNT_LST_OLD = parseUnits("19256300979232439022849", 0); + +// https://etherscan.io/tx/0x261395084b5f1a51d331c72ab2f836d10479b6fbb76b6b8b3094ec440e7de032 +export const REWARD_START_BLOCK_CASE_A = parseUnits("19861441", 0); + +// https://etherscan.io/tx/0x8eea38407bed27ae0acafd3bce96aefe0f28d4eaed39eef1fe8309daced86e08 +export const REWARD_START_BLOCK_CASE_B = parseUnits("20063791", 0); + +// https://etherscan.io/tx/0xd20a77569af4004f85a88de6cd49f7f288f8c412bca66620b8a88c131102b864 +export const PAUSED_BLOCK_NUMBER = parseUnits("20435458", 0); + +// https://etherscan.io/tx/0x8dfd2bf80e8485f5c8a98f908f6e0d47594ed99bea487d362317f45ea0442133 +export const START_REWARDING_BLOCK_LST_OLD = parseUnits("20185343", 0); + +export const LAST_REWARDING_BLOCK_CASE_D = parseUnits("20509441", 0); + +// 4,800 XVS transferred +export const CASE_A_SPEEDS = [ + { + name: "vFRAX", + rewardsDistributorOld: REWARDS_DISTRIBUTOR_CORE_OLD, + address: VFRAX_CORE, + oldSupplySpeed: parseUnits("1481481481481481", 0), + oldBorrowSpeed: parseUnits("2222222222222222", 0), + }, + { + name: "vsFRAX", + rewardsDistributorOld: REWARDS_DISTRIBUTOR_CORE_OLD, + address: VSFRAX_CORE, + oldSupplySpeed: parseUnits("2222222222222222", 0), + oldBorrowSpeed: parseUnits("1481481481481481", 0), + }, +]; + +// 3,600 XVS transferred +export const CASE_B_SPEEDS = [ + { + name: "vFRAX", + rewardsDistributorOld: REWARDS_DISTRIBUTOR_CORE_OLD, + address: VFRAX_CORE, + oldSupplySpeed: parseUnits("1111111111111111", 0), + oldBorrowSpeed: parseUnits("1666666666666666", 0), + }, + { + name: "vsFRAX", + rewardsDistributorOld: REWARDS_DISTRIBUTOR_CORE_OLD, + address: VSFRAX_CORE, + oldSupplySpeed: parseUnits("1111111111111111", 0), + oldBorrowSpeed: parseUnits("1666666666666666", 0), + }, +]; + +// 2,100 XVS transferred +export const CORE_SPEEDS = [ + { + name: "vDAI", + rewardsDistributorOld: REWARDS_DISTRIBUTOR_CORE_OLD, + address: VDAI_CORE, + oldSupplySpeed: parseUnits("925925925925925", 0), + oldBorrowSpeed: parseUnits("1388888888888888", 0), + }, + { + name: "vTUSD", + rewardsDistributorOld: REWARDS_DISTRIBUTOR_CORE_OLD, + address: VTUSD_CORE, + oldSupplySpeed: parseUnits("370370370370370", 0), + oldBorrowSpeed: parseUnits("555555555555555", 0), + }, +]; + +// 2,400 XVS transferred +export const LST_SPEEDS = [ + { + name: "vSFRXETH", + rewardsDistributorOld: REWARDS_DISTRIBUTOR_LST_OLD, + address: VSFRXETH_LST, + oldSupplySpeed: parseUnits("3703703703703703", 0), + oldBorrowSpeed: parseUnits("0", 0), + }, +]; + +const calculateXVSReward = (startBlock: BigNumber, endBlock: BigNumber, CASE: CASE_COMMAND[]) => { + const blockDelta = endBlock.sub(startBlock); + let totalXVS = ethers.BigNumber.from(0); + for (const config of CASE) { + totalXVS = totalXVS.add(blockDelta.mul(config.oldBorrowSpeed.add(config.oldSupplySpeed))); + } + return totalXVS; +}; + +const XVS_FRAX_SFRAX_CASE_A = calculateXVSReward(REWARD_START_BLOCK_CASE_A, REWARD_START_BLOCK_CASE_B, CASE_A_SPEEDS); +const XVS_FRAX_SFRAX_CASE_B = calculateXVSReward(REWARD_START_BLOCK_CASE_B, PAUSED_BLOCK_NUMBER, CASE_B_SPEEDS); +const XVS_FOR_DAI_TUSD = XVS_TRANSFERRED_DAI_TUSD_OLD_CASE_B.sub( + calculateXVSReward(REWARD_START_BLOCK_CASE_B, PAUSED_BLOCK_NUMBER, CORE_SPEEDS), +); + +// Total XVS transferred - (REWARD_START_BLOCK_CASE_B - REWARD_START_BLOCK_CASE_A + PAUSED_BLOCK_NUMBER - REWARD_START_BLOCK_CASE_B) * (perBlockReward) +export const TOTAL_XVS_FOR_CORE_NEW = XVS_TRANSFERRED_FRAX_SFRAX_CASE_A.add(XVS_TRANSFERRED_FRAX_SFRAX_CASE_B) + .sub(XVS_FRAX_SFRAX_CASE_A.add(XVS_FRAX_SFRAX_CASE_B)) + .add(XVS_FOR_DAI_TUSD); + +export const TOTAL_XVS_FOR_LST_NEW = XVS_TRANSFERRED_LST_OLD.sub( + calculateXVSReward(START_REWARDING_BLOCK_LST_OLD, PAUSED_BLOCK_NUMBER, LST_SPEEDS), +); + +export const vip054 = () => { + return makeProposal([ + { + target: REWARDS_DISTRIBUTOR_CORE_OLD, + signature: "grantRewardToken(address,uint256)", + params: [REWARDS_DISTRIBUTOR_CORE_NEW, TOTAL_XVS_FOR_CORE_NEW], + }, + { + target: REWARDS_DISTRIBUTOR_LST_OLD, + signature: "grantRewardToken(address,uint256)", + params: [REWARDS_DISTRIBUTOR_LST_NEW, TOTAL_XVS_FOR_LST_NEW], + }, + ]); +}; +export default vip054; diff --git a/multisig/simulations/ethereum/vip-054/abi/RewardsDistributor.json b/multisig/simulations/ethereum/vip-054/abi/RewardsDistributor.json new file mode 100644 index 000000000..5f8bac784 --- /dev/null +++ b/multisig/simulations/ethereum/vip-054/abi/RewardsDistributor.json @@ -0,0 +1,458 @@ +[ + { "inputs": [], "stateMutability": "nonpayable", "type": "constructor" }, + { + "inputs": [ + { "internalType": "uint256", "name": "loopsLimit", "type": "uint256" }, + { "internalType": "uint256", "name": "requiredLoops", "type": "uint256" } + ], + "name": "MaxLoopsLimitExceeded", + "type": "error" + }, + { + "inputs": [ + { "internalType": "address", "name": "sender", "type": "address" }, + { "internalType": "address", "name": "calledContract", "type": "address" }, + { "internalType": "string", "name": "methodSignature", "type": "string" } + ], + "name": "Unauthorized", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "vToken", "type": "address" }, + { "indexed": false, "internalType": "uint32", "name": "newBlock", "type": "uint32" } + ], + "name": "BorrowLastRewardingBlockUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "contributor", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "newSpeed", "type": "uint256" } + ], + "name": "ContributorRewardTokenSpeedUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "contributor", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "rewardAccrued", "type": "uint256" } + ], + "name": "ContributorRewardsUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "contract VToken", "name": "vToken", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "borrower", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "rewardTokenDelta", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "rewardTokenTotal", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "rewardTokenBorrowIndex", "type": "uint256" } + ], + "name": "DistributedBorrowerRewardToken", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "contract VToken", "name": "vToken", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "supplier", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "rewardTokenDelta", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "rewardTokenTotal", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "rewardTokenSupplyIndex", "type": "uint256" } + ], + "name": "DistributedSupplierRewardToken", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "uint8", "name": "version", "type": "uint8" }], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": true, "internalType": "address", "name": "vToken", "type": "address" }], + "name": "MarketInitialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "oldMaxLoopsLimit", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newmaxLoopsLimit", "type": "uint256" } + ], + "name": "MaxLoopsLimitUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "oldAccessControlManager", "type": "address" }, + { "indexed": false, "internalType": "address", "name": "newAccessControlManager", "type": "address" } + ], + "name": "NewAccessControlManager", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } + ], + "name": "OwnershipTransferStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "vToken", "type": "address" }, + { + "components": [{ "internalType": "uint256", "name": "mantissa", "type": "uint256" }], + "indexed": false, + "internalType": "struct ExponentialNoError.Exp", + "name": "marketBorrowIndex", + "type": "tuple" + } + ], + "name": "RewardTokenBorrowIndexUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "contract VToken", "name": "vToken", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "newSpeed", "type": "uint256" } + ], + "name": "RewardTokenBorrowSpeedUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "recipient", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "RewardTokenGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": true, "internalType": "address", "name": "vToken", "type": "address" }], + "name": "RewardTokenSupplyIndexUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "contract VToken", "name": "vToken", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "newSpeed", "type": "uint256" } + ], + "name": "RewardTokenSupplySpeedUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "vToken", "type": "address" }, + { "indexed": false, "internalType": "uint32", "name": "newBlock", "type": "uint32" } + ], + "name": "SupplyLastRewardingBlockUpdated", + "type": "event" + }, + { + "inputs": [], + "name": "INITIAL_INDEX", + "outputs": [{ "internalType": "uint224", "name": "", "type": "uint224" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "acceptOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "accessControlManager", + "outputs": [{ "internalType": "contract IAccessControlManagerV8", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "holder", "type": "address" }, + { "internalType": "contract VToken[]", "name": "vTokens", "type": "address[]" } + ], + "name": "claimRewardToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "holder", "type": "address" }], + "name": "claimRewardToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "vToken", "type": "address" }, + { "internalType": "address", "name": "borrower", "type": "address" }, + { + "components": [{ "internalType": "uint256", "name": "mantissa", "type": "uint256" }], + "internalType": "struct ExponentialNoError.Exp", + "name": "marketBorrowIndex", + "type": "tuple" + } + ], + "name": "distributeBorrowerRewardToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "vToken", "type": "address" }, + { "internalType": "address", "name": "supplier", "type": "address" } + ], + "name": "distributeSupplierRewardToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getBlockNumber", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "recipient", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "grantRewardToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "contract Comptroller", "name": "comptroller_", "type": "address" }, + { "internalType": "contract IERC20Upgradeable", "name": "rewardToken_", "type": "address" }, + { "internalType": "uint256", "name": "loopsLimit_", "type": "uint256" }, + { "internalType": "address", "name": "accessControlManager_", "type": "address" } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "vToken", "type": "address" }], + "name": "initializeMarket", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "lastContributorBlock", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxLoopsLimit", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingOwner", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "rewardToken", + "outputs": [{ "internalType": "contract IERC20Upgradeable", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "rewardTokenAccrued", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "rewardTokenBorrowSpeeds", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "rewardTokenBorrowState", + "outputs": [ + { "internalType": "uint224", "name": "index", "type": "uint224" }, + { "internalType": "uint32", "name": "block", "type": "uint32" }, + { "internalType": "uint32", "name": "lastRewardingBlock", "type": "uint32" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "address", "name": "", "type": "address" } + ], + "name": "rewardTokenBorrowerIndex", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "rewardTokenContributorSpeeds", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "address", "name": "", "type": "address" } + ], + "name": "rewardTokenSupplierIndex", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "rewardTokenSupplySpeeds", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "rewardTokenSupplyState", + "outputs": [ + { "internalType": "uint224", "name": "index", "type": "uint224" }, + { "internalType": "uint32", "name": "block", "type": "uint32" }, + { "internalType": "uint32", "name": "lastRewardingBlock", "type": "uint32" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "accessControlManager_", "type": "address" }], + "name": "setAccessControlManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "contributor", "type": "address" }, + { "internalType": "uint256", "name": "rewardTokenSpeed", "type": "uint256" } + ], + "name": "setContributorRewardTokenSpeed", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "contract VToken[]", "name": "vTokens", "type": "address[]" }, + { "internalType": "uint32[]", "name": "supplyLastRewardingBlocks", "type": "uint32[]" }, + { "internalType": "uint32[]", "name": "borrowLastRewardingBlocks", "type": "uint32[]" } + ], + "name": "setLastRewardingBlocks", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "limit", "type": "uint256" }], + "name": "setMaxLoopsLimit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "contract VToken[]", "name": "vTokens", "type": "address[]" }, + { "internalType": "uint256[]", "name": "supplySpeeds", "type": "uint256[]" }, + { "internalType": "uint256[]", "name": "borrowSpeeds", "type": "uint256[]" } + ], + "name": "setRewardTokenSpeeds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "contributor", "type": "address" }], + "name": "updateContributorRewards", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "vToken", "type": "address" }, + { + "components": [{ "internalType": "uint256", "name": "mantissa", "type": "uint256" }], + "internalType": "struct ExponentialNoError.Exp", + "name": "marketBorrowIndex", + "type": "tuple" + } + ], + "name": "updateRewardTokenBorrowIndex", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "vToken", "type": "address" }], + "name": "updateRewardTokenSupplyIndex", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/multisig/simulations/ethereum/vip-054/abi/xvs.json b/multisig/simulations/ethereum/vip-054/abi/xvs.json new file mode 100644 index 000000000..8a2713887 --- /dev/null +++ b/multisig/simulations/ethereum/vip-054/abi/xvs.json @@ -0,0 +1,683 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "accessControlManager_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "MintLimitExceed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "MintNotAllowed", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddressNotAllowed", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "value", + "type": "bool" + } + ], + "name": "BlacklistUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "MintCapChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newLimit", + "type": "uint256" + } + ], + "name": "MintLimitDecreased", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newLimit", + "type": "uint256" + } + ], + "name": "MintLimitIncreased", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldAccessControlManager", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newAccessControlManager", + "type": "address" + } + ], + "name": "NewAccessControlManager", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "_blacklist", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "accessControlManager", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount_", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user_", + "type": "address" + } + ], + "name": "isBlackListed", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount_", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "minterToCap", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "minterToMintedAmount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAccessControlAddress_", + "type": "address" + } + ], + "name": "setAccessControlManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "minter_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount_", + "type": "uint256" + } + ], + "name": "setMintCap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user_", + "type": "address" + }, + { + "internalType": "bool", + "name": "value_", + "type": "bool" + } + ], + "name": "updateBlacklist", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/multisig/simulations/ethereum/vip-054/index.ts b/multisig/simulations/ethereum/vip-054/index.ts new file mode 100644 index 000000000..e2ff5f203 --- /dev/null +++ b/multisig/simulations/ethereum/vip-054/index.ts @@ -0,0 +1,73 @@ +import { expect } from "chai"; +import { BigNumber, Contract } from "ethers"; +import { parseUnits } from "ethers/lib/utils"; +import { ethers } from "hardhat"; + +import { forking, pretendExecutingVip } from "../../../../src/vip-framework"; +import vip054, { + REWARDS_DISTRIBUTOR_CORE_NEW, + REWARDS_DISTRIBUTOR_CORE_OLD, + REWARDS_DISTRIBUTOR_LST_NEW, + REWARDS_DISTRIBUTOR_LST_OLD, + TOTAL_XVS_FOR_CORE_NEW, + TOTAL_XVS_FOR_LST_NEW, + XVS, + XVS_AMOUNT_CORE_OLD, + XVS_AMOUNT_LST_OLD, +} from "../../../proposals/ethereum/vip-054"; +import REWARDS_DISTRIBUTOR_ABI from "./abi/RewardsDistributor.json"; +import XVS_ABI from "./abi/xvs.json"; + +forking(20484269, async () => { + let xvs: Contract; + const provider = ethers.provider; + xvs = new ethers.Contract(XVS, XVS_ABI, provider); + const TOTAL_XVS_CORE = parseUnits("5731818055555557437136", 0); + const TOTAL_XVS_LST = parseUnits("1473648148148148324155", 0); + + describe("Pre-VIP behaviour", () => { + it("should have old XVS token in original reward distributor ", async () => { + const rewardsDistributorCoreOld = await ethers.getContractAt( + REWARDS_DISTRIBUTOR_ABI, + REWARDS_DISTRIBUTOR_CORE_OLD, + ); + + const rewardDistributorLSTOld = await ethers.getContractAt(REWARDS_DISTRIBUTOR_ABI, REWARDS_DISTRIBUTOR_LST_OLD); + expect(await xvs.balanceOf(rewardsDistributorCoreOld.address)).to.be.equal(XVS_AMOUNT_CORE_OLD); + expect(await xvs.balanceOf(rewardDistributorLSTOld.address)).to.be.equal(XVS_AMOUNT_LST_OLD); + }); + }); + describe("Post-VIP behavior", async () => { + let newCoreDistributorBalance: BigNumber, + newLstDistributorBalance: BigNumber, + oldCoreDistributorBalance: BigNumber, + oldLstDistributorBalance: BigNumber; + before(async () => { + xvs = await ethers.getContractAt(XVS_ABI, XVS); + oldCoreDistributorBalance = await xvs.balanceOf(REWARDS_DISTRIBUTOR_CORE_OLD); + oldLstDistributorBalance = await xvs.balanceOf(REWARDS_DISTRIBUTOR_LST_OLD); + newCoreDistributorBalance = await xvs.balanceOf(REWARDS_DISTRIBUTOR_CORE_NEW); + newLstDistributorBalance = await xvs.balanceOf(REWARDS_DISTRIBUTOR_LST_NEW); + await pretendExecutingVip(await vip054()); + }); + it("should transfer correct values", async () => { + expect(TOTAL_XVS_FOR_CORE_NEW).to.be.equal(TOTAL_XVS_CORE); + expect(TOTAL_XVS_FOR_LST_NEW).to.be.equal(TOTAL_XVS_LST); + }); + + it("should have correct balance left in old rewarder and new rewarder", async () => { + expect(await xvs.balanceOf(REWARDS_DISTRIBUTOR_CORE_OLD)).to.be.equal( + oldCoreDistributorBalance.sub(TOTAL_XVS_FOR_CORE_NEW), + ); + expect(await xvs.balanceOf(REWARDS_DISTRIBUTOR_LST_OLD)).to.be.equal( + oldLstDistributorBalance.sub(TOTAL_XVS_FOR_LST_NEW), + ); + expect(await xvs.balanceOf(REWARDS_DISTRIBUTOR_CORE_NEW)).to.be.equal( + TOTAL_XVS_FOR_CORE_NEW.add(newCoreDistributorBalance), + ); + expect(await xvs.balanceOf(REWARDS_DISTRIBUTOR_LST_NEW)).to.be.equal( + TOTAL_XVS_FOR_LST_NEW.add(newLstDistributorBalance), + ); + }); + }); +}); diff --git a/simulations/vip-352/simulations.ts b/simulations/vip-352/simulations.ts new file mode 100644 index 000000000..7140f607e --- /dev/null +++ b/simulations/vip-352/simulations.ts @@ -0,0 +1,7 @@ +import { forking, testVip } from "src/vip-framework"; + +import vip352 from "../../vips/vip-352/bscmainnet"; + +forking(41186665, async () => { + testVip("VIP-352", await vip352(), {}); +}); diff --git a/vips/vip-352/bscmainnet.ts b/vips/vip-352/bscmainnet.ts new file mode 100644 index 000000000..4a5307fce --- /dev/null +++ b/vips/vip-352/bscmainnet.ts @@ -0,0 +1,57 @@ +import { ProposalType } from "../../src/types"; +import { makeProposal } from "../../src/utils"; + +const NORMAL_TIMELOCK = "0x939bD8d64c0A9583A7Dcea9933f7b21697ab6396"; + +const vip352 = () => { + const meta = { + version: "v2", + title: "VIP-352 [Ethereum] Unification of XVS rewards for DAI, TUSD, FRAX, sFRAX and sfrxETH", + description: `#### Summary + +If passed, this VIP will perform the following actions: + +- Transfer 5,731.81 XVS from [RewardsDistributor_Core_0](https://etherscan.io/address/0x134bfDEa7e68733921Bc6A87159FB0d68aBc6Cf8) to [RewardsDistributor_Core_2](https://etherscan.io/address/0x886767B62C7ACD601672607373048FFD96Cf27B2) +- Transfer 1,473.64 XVS from [RewardsDistributor_Liquid Staked ETH_0](https://etherscan.io/address/0x7A91bEd36D96E4e644d3A181c287E0fcf9E9cc98) to [RewardsDistributor_Liquid Staked ETH_3](https://etherscan.io/address/0x1e25CF968f12850003Db17E0Dba32108509C4359) + +#### Description + +In the [VIP-348](https://app.venus.io/#/governance/proposal/348?chainId=56), the rewards for the Ethereum markets of [DAI](https://app.venus.io/#/core-pool/market/0xd8AdD9B41D4E1cd64Edad8722AB0bA8D35536657?chainId=1), [TUSD](https://app.venus.io/#/core-pool/market/0x13eB80FDBe5C5f4a7039728E258A6f05fb3B912b?chainId=1), [FRAX](https://app.venus.io/#/core-pool/market/0x4fAfbDc4F2a9876Bd1764827b26fb8dc4FD1dB95?chainId=1), [sFRAX](https://app.venus.io/#/core-pool/market/0x17142a05fe678e9584FA1d88EfAC1bF181bF7ABe?chainId=1) and [sfrxETH](https://app.venus.io/#/isolated-pools/pool/0xF522cd0360EF8c2FF48B648d53EA1717Ec0F3Ac3/market/0xF9E9Fe17C00a8B96a8ac20c4E344C8688D7b947E?chainId=1) were stopped in the original RewardsDistributor contracts ([RewardsDistributor_Core_0](https://etherscan.io/address/0x134bfDEa7e68733921Bc6A87159FB0d68aBc6Cf8) and [RewardsDistributor_Liquid Staked ETH_0](https://etherscan.io/address/0x7A91bEd36D96E4e644d3A181c287E0fcf9E9cc98)) and enabled in the new ones ([RewardsDistributor_Core_2](https://etherscan.io/address/0x886767B62C7ACD601672607373048FFD96Cf27B2) and [RewardsDistributor_Liquid Staked ETH_3](https://etherscan.io/address/0x1e25CF968f12850003Db17E0Dba32108509C4359)), aiming to unify the XVS rewards in one contract per pool. + +This VIP will transfer the non-allocated XVS tokens from the original RewardsDistributor contracts to the new ones. This transfer doesn’t have any impact on the users, who will continue accruing rewards as usual. + +#### References + +- [VIP simulation](https://github.com/VenusProtocol/vips/pull/338) +- [VIP-302 Ethereum: new FRAX and sFRAX markets in the Core pool](https://app.venus.io/#/governance/proposal/302?chainId=56) ([PR](https://github.com/VenusProtocol/vips/pull/277)): 4,800 XVS were transferred to the RewardsDistributor_Core_0, to be distributed for 90 days among the FRAX and sFRAX market users +- [VIP-322: [Ethereum] Market Emission Adjustment](https://app.venus.io/#/governance/proposal/322?chainId=56) ([PR](https://github.com/VenusProtocol/vips/pull/301/files)): 112,000 XVS were transferred for the rewards of the following markets: + - Core pool: WETH, WBTC, USDT, USDC, crvUSD, FRAX, sFRAX, TUSD, DAI + - Curve pool: CRV, crvUSD + - LST pool: wstETH +- [VIP-329 Ethereum: new sfrxETH market in the Liquid Staked ETH pool](https://app.venus.io/#/governance/proposal/329?chainId=56) ([PR](https://github.com/VenusProtocol/vips/pull/302)): 2,400 XVS were transferred to the RewardsDistributor_Core_0, to be distributed for 90 days among the sfrxETH market users +- [VIP-335 [Ethereum] Resume Market Incentives](https://app.venus.io/#/governance/proposal/335?chainId=1) ([PR](https://github.com/VenusProtocol/vips/pull/314)): 82,180 XVS were transferred from the old RewardsDistributor contracts to the new ones. These are the rewards associated to every market except FRAX, sFRAX, sfrxETH, DAI, TUSD +- [VIP-348 [Ethereum] Market Emission Adjustment](https://app.venus.io/#/governance/proposal/348?chainId=56) ([PR](https://github.com/VenusProtocol/vips/pull/331)): speeds for FRAX, sFRAX, sfrxETH, DAI, TUSD are set to zero in the old RewardsDistributor contracts and the new speeds are set in the new RewardsDistributor contracts + +#### Disclaimer for Ethereum VIPs + +Privilege commands on Ethereum will be executed by the [Guardian wallet](https://etherscan.io/address/0x285960C5B22fD66A736C7136967A3eB15e93CC67), until the [Multichain Governance](https://docs-v4.venus.io/technical-reference/reference-technical-articles/multichain-governance) contracts are fully enabled. If this VIP passes, [this](https://app.safe.global/transactions/tx?safe=eth:0x285960C5B22fD66A736C7136967A3eB15e93CC67&id=multisig_0x285960C5B22fD66A736C7136967A3eB15e93CC67_0x717fa100138a66aa5ca51cba4880a9448e6b18d87c3d2c3b41bfb91e7f27e8c8) multisig transaction will be executed. Otherwise, it will be rejected.`, + forDescription: "I agree that Venus Protocol should proceed with this proposal", + againstDescription: "I do not think that Venus Protocol should proceed with this proposal", + abstainDescription: "I am indifferent to whether Venus Protocol proceeds or not", + }; + + return makeProposal( + [ + { + target: NORMAL_TIMELOCK, + signature: "", + params: [], + value: "1", + }, + ], + meta, + ProposalType.REGULAR, + ); +}; + +export default vip352;