From 7dad9e06a917a3bcee059ad2cd6e5100e42f326c Mon Sep 17 00:00:00 2001 From: Filip Malachowicz Date: Mon, 28 Jul 2025 13:46:31 +0200 Subject: [PATCH 1/3] feat: TreasuryConverter configured --- simulations/vip-515/abi/ConverterNetwork.json | 2 +- .../vip-536/abi/AccessControlManager.json | 360 +++++ .../vip-536/abi/singletokenconverter.json | 1381 +++++++++++++++++ simulations/vip-536/arbitrumone.ts | 176 ++- simulations/vip-536/bscmainnet.ts | 177 ++- simulations/vip-536/ethereum.ts | 176 ++- src/networkAddresses.ts | 2 + vips/vip-536/bscmainnet.ts | 236 +++ 8 files changed, 2503 insertions(+), 7 deletions(-) create mode 100644 simulations/vip-536/abi/AccessControlManager.json create mode 100644 simulations/vip-536/abi/singletokenconverter.json diff --git a/simulations/vip-515/abi/ConverterNetwork.json b/simulations/vip-515/abi/ConverterNetwork.json index 0fa27deec..3bf045b3b 100644 --- a/simulations/vip-515/abi/ConverterNetwork.json +++ b/simulations/vip-515/abi/ConverterNetwork.json @@ -445,4 +445,4 @@ "stateMutability": "nonpayable", "type": "function" } -] +] \ No newline at end of file diff --git a/simulations/vip-536/abi/AccessControlManager.json b/simulations/vip-536/abi/AccessControlManager.json new file mode 100644 index 000000000..4a118fcc4 --- /dev/null +++ b/simulations/vip-536/abi/AccessControlManager.json @@ -0,0 +1,360 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "string", + "name": "functionSig", + "type": "string" + } + ], + "name": "PermissionGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "string", + "name": "functionSig", + "type": "string" + } + ], + "name": "PermissionRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "accountToPermit", + "type": "address" + } + ], + "name": "giveCallPermission", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + } + ], + "name": "hasPermission", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + } + ], + "name": "isAllowedToCall", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "accountToRevoke", + "type": "address" + } + ], + "name": "revokeCallPermission", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/simulations/vip-536/abi/singletokenconverter.json b/simulations/vip-536/abi/singletokenconverter.json new file mode 100644 index 000000000..c8d0f7077 --- /dev/null +++ b/simulations/vip-536/abi/singletokenconverter.json @@ -0,0 +1,1381 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountInMantissa", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMaxMantissa", + "type": "uint256" + } + ], + "name": "AmountInHigherThanMax", + "type": "error" + }, + { + "inputs": [], + "name": "AmountInMismatched", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMantissa", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMinMantissa", + "type": "uint256" + } + ], + "name": "AmountOutLowerThanMinRequired", + "type": "error" + }, + { + "inputs": [], + "name": "AmountOutMismatched", + "type": "error" + }, + { + "inputs": [], + "name": "ConversionConfigNotEnabled", + "type": "error" + }, + { + "inputs": [], + "name": "ConversionEnabledOnlyForPrivateConversions", + "type": "error" + }, + { + "inputs": [], + "name": "ConversionTokensActive", + "type": "error" + }, + { + "inputs": [], + "name": "ConversionTokensPaused", + "type": "error" + }, + { + "inputs": [], + "name": "DeflationaryTokenNotSupported", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "incentive", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxIncentive", + "type": "uint256" + } + ], + "name": "IncentiveTooHigh", + "type": "error" + }, + { + "inputs": [], + "name": "InputLengthMisMatch", + "type": "error" + }, + { + "inputs": [], + "name": "InsufficientInputAmount", + "type": "error" + }, + { + "inputs": [], + "name": "InsufficientOutputAmount", + "type": "error" + }, + { + "inputs": [], + "name": "InsufficientPoolLiquidity", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidConverterNetwork", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidMinimumAmountToConvert", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidToAddress", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidTokenConfigAddresses", + "type": "error" + }, + { + "inputs": [], + "name": "NonZeroIncentiveForPrivateConversion", + "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" + }, + { + "inputs": [], + "name": "ZeroAddressNotAllowed", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroValueNotAllowed", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "comptroller", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "asset", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "AssetTransferredToDestination", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldBaseAsset", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newBaseAsset", + "type": "address" + } + ], + "name": "BaseAssetUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "tokenAddressIn", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "tokenAddressOut", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "oldIncentive", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newIncentive", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "enum IAbstractTokenConverter.ConversionAccessibility", + "name": "oldAccess", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "enum IAbstractTokenConverter.ConversionAccessibility", + "name": "newAccess", + "type": "uint8" + } + ], + "name": "ConversionConfigUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "ConversionPaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "ConversionResumed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "tokenAddressIn", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "tokenAddressOut", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "name": "ConvertedExactTokens", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "tokenAddressIn", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "tokenAddressOut", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "name": "ConvertedExactTokensSupportingFeeOnTransferTokens", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "tokenAddressIn", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "tokenAddressOut", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "name": "ConvertedForExactTokens", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "tokenAddressIn", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "tokenAddressOut", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "name": "ConvertedForExactTokensSupportingFeeOnTransferTokens", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldConverterNetwork", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "converterNetwork", + "type": "address" + } + ], + "name": "ConverterNetworkAddressUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldDestinationAddress", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "destinationAddress", + "type": "address" + } + ], + "name": "DestinationAddressUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldMinAmountToConvert", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newMinAmountToConvert", + "type": "uint256" + } + ], + "name": "MinAmountToConvertUpdated", + "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": "contract ResilientOracle", + "name": "oldPriceOracle", + "type": "address" + }, + { + "indexed": true, + "internalType": "contract ResilientOracle", + "name": "priceOracle", + "type": "address" + } + ], + "name": "PriceOracleUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "SweepToken", + "type": "event" + }, + { + "inputs": [], + "name": "MAX_INCENTIVE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "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": "tokenAddress", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "tokenBalance", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "baseAsset", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "conversionConfigurations", + "outputs": [ + { + "internalType": "uint256", + "name": "incentive", + "type": "uint256" + }, + { + "internalType": "enum IAbstractTokenConverter.ConversionAccessibility", + "name": "conversionAccess", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "conversionPaused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountInMantissa", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMinMantissa", + "type": "uint256" + }, + { + "internalType": "address", + "name": "tokenAddressIn", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenAddressOut", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "convertExactTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "actualAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actualAmountOut", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountInMantissa", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMinMantissa", + "type": "uint256" + }, + { + "internalType": "address", + "name": "tokenAddressIn", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenAddressOut", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "convertExactTokensSupportingFeeOnTransferTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "actualAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actualAmountOut", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountInMaxMantissa", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMantissa", + "type": "uint256" + }, + { + "internalType": "address", + "name": "tokenAddressIn", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenAddressOut", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "convertForExactTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "actualAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actualAmountOut", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountInMaxMantissa", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMantissa", + "type": "uint256" + }, + { + "internalType": "address", + "name": "tokenAddressIn", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenAddressOut", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "convertForExactTokensSupportingFeeOnTransferTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "actualAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actualAmountOut", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "converterNetwork", + "outputs": [ + { + "internalType": "contract IConverterNetwork", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "destinationAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMantissa", + "type": "uint256" + }, + { + "internalType": "address", + "name": "tokenAddressIn", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenAddressOut", + "type": "address" + } + ], + "name": "getAmountIn", + "outputs": [ + { + "internalType": "uint256", + "name": "amountConvertedMantissa", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMantissa", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountInMantissa", + "type": "uint256" + }, + { + "internalType": "address", + "name": "tokenAddressIn", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenAddressOut", + "type": "address" + } + ], + "name": "getAmountOut", + "outputs": [ + { + "internalType": "uint256", + "name": "amountConvertedMantissa", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMantissa", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMantissa", + "type": "uint256" + }, + { + "internalType": "address", + "name": "tokenAddressIn", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenAddressOut", + "type": "address" + } + ], + "name": "getUpdatedAmountIn", + "outputs": [ + { + "internalType": "uint256", + "name": "amountConvertedMantissa", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMantissa", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountInMantissa", + "type": "uint256" + }, + { + "internalType": "address", + "name": "tokenAddressIn", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenAddressOut", + "type": "address" + } + ], + "name": "getUpdatedAmountOut", + "outputs": [ + { + "internalType": "uint256", + "name": "amountConvertedMantissa", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMantissa", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "accessControlManager_", + "type": "address" + }, + { + "internalType": "contract ResilientOracle", + "name": "priceOracle_", + "type": "address" + }, + { + "internalType": "address", + "name": "destinationAddress_", + "type": "address" + }, + { + "internalType": "address", + "name": "baseAsset_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "minAmountToConvert_", + "type": "uint256" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "minAmountToConvert", + "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": "pauseConversion", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "pendingOwner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "priceOracle", + "outputs": [ + { + "internalType": "contract ResilientOracle", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "resumeConversion", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "accessControlManager_", + "type": "address" + } + ], + "name": "setAccessControlManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "baseAsset_", + "type": "address" + } + ], + "name": "setBaseAsset", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenAddressIn", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenAddressOut", + "type": "address" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "incentive", + "type": "uint256" + }, + { + "internalType": "enum IAbstractTokenConverter.ConversionAccessibility", + "name": "conversionAccess", + "type": "uint8" + } + ], + "internalType": "struct IAbstractTokenConverter.ConversionConfig", + "name": "conversionConfig", + "type": "tuple" + } + ], + "name": "setConversionConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenAddressIn", + "type": "address" + }, + { + "internalType": "address[]", + "name": "tokenAddressesOut", + "type": "address[]" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "incentive", + "type": "uint256" + }, + { + "internalType": "enum IAbstractTokenConverter.ConversionAccessibility", + "name": "conversionAccess", + "type": "uint8" + } + ], + "internalType": "struct IAbstractTokenConverter.ConversionConfig[]", + "name": "conversionConfigs", + "type": "tuple[]" + } + ], + "name": "setConversionConfigs", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IConverterNetwork", + "name": "converterNetwork_", + "type": "address" + } + ], + "name": "setConverterNetwork", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "destinationAddress_", + "type": "address" + } + ], + "name": "setDestination", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "minAmountToConvert_", + "type": "uint256" + } + ], + "name": "setMinAmountToConvert", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract ResilientOracle", + "name": "priceOracle_", + "type": "address" + } + ], + "name": "setPriceOracle", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "sweepToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "comptroller", + "type": "address" + }, + { + "internalType": "address", + "name": "asset", + "type": "address" + } + ], + "name": "updateAssetsState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/simulations/vip-536/arbitrumone.ts b/simulations/vip-536/arbitrumone.ts index ac8b446fe..4bd1ce301 100644 --- a/simulations/vip-536/arbitrumone.ts +++ b/simulations/vip-536/arbitrumone.ts @@ -1,34 +1,58 @@ import { expect } from "chai"; import { Contract } from "ethers"; import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; import { expectEvents } from "src/utils"; import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; import vip536, { + ARBITRUM_CONVERSION_INCENTIVE, + ConversionAccessibility, NEW_SINGLE_TOKEN_CONVERTER_IMP_ARBITRUM, SINGLE_TOKEN_CONVERTER_BEACON_ARBITRUM, + TREASURY_CONVERTER, + TREASURY_CONVERTER_ARBITRUM, } from "../../vips/vip-536/bscmainnet"; +import ACCESS_CONTROLL_MANAGER_ABI from "./abi/AccessControlManager.json"; import BEACON_ABI from "./abi/Beacon.json"; +import CONVERTER_ABI from "./abi/singletokenconverter.json"; + +const { arbitrumone } = NETWORK_ADDRESSES; const OLD_SINGLE_TOKEN_CONVERTER_IMP_ARBITRUM = "0x07801d54906Be49517DfDEd26c89A81fb94e504B"; -forking(356227715, async () => { +forking(362442798, async () => { const provider = ethers.provider; let beacon: Contract; + let treasuryConverter: Contract; + let acm: Contract; before(async () => { beacon = new ethers.Contract(SINGLE_TOKEN_CONVERTER_BEACON_ARBITRUM, BEACON_ABI, provider); + treasuryConverter = new ethers.Contract(TREASURY_CONVERTER_ARBITRUM, CONVERTER_ABI, provider); + acm = new ethers.Contract(arbitrumone.ACCESS_CONTROL_MANAGER, ACCESS_CONTROLL_MANAGER_ABI, provider); }); describe("Pre-VIP behavior", () => { it("SingleTokenConverter should have old implementation", async () => { expect(await beacon.implementation()).to.equal(OLD_SINGLE_TOKEN_CONVERTER_IMP_ARBITRUM); }); + + describe("TreasuryConverter", () => { + it("should have a correct pending owner", async () => { + expect(await treasuryConverter.pendingOwner()).to.equal(arbitrumone.NORMAL_TIMELOCK); + }); + }); }); testForkedNetworkVipCommands("VIP-536", await vip536(), { callbackAfterExecution: async (txResponse: any) => { - await expectEvents(txResponse, [BEACON_ABI], ["Upgraded"], [1]); + await expectEvents( + txResponse, + [BEACON_ABI, CONVERTER_ABI], + ["Upgraded", "ConverterNetworkAddressUpdated", "OwnershipTransferred", "ConversionConfigUpdated"], + [1, 1, 2, 3], + ); }, }); @@ -36,5 +60,153 @@ forking(356227715, async () => { it("SingleTokenConverter should have new implementation", async () => { expect(await beacon.implementation()).to.equal(NEW_SINGLE_TOKEN_CONVERTER_IMP_ARBITRUM); }); + describe("TreasuryConverter", () => { + it("should not be paused", async () => { + expect(await treasuryConverter.conversionPaused()).to.be.false; + }); + + it("should have Treasury as destination for conversion", async () => { + expect(await treasuryConverter.destinationAddress()).to.equal(arbitrumone.VTREASURY); + }); + + it("should have correct owner", async () => { + expect(await treasuryConverter.owner()).to.equal(arbitrumone.NORMAL_TIMELOCK); + }); + + it("should have correct converters network address", async () => { + expect(await treasuryConverter.converterNetwork()).to.equal(TREASURY_CONVERTER.arbitrumone.converterNetwork); + }); + + it("should have correct conversion configuration", async () => { + const { tokenIn, tokenOuts } = TREASURY_CONVERTER.arbitrumone; + + for (const tokenOut of tokenOuts) { + const config = await treasuryConverter.conversionConfigurations(tokenIn, tokenOut); + + expect(config.incentive).to.equal(ARBITRUM_CONVERSION_INCENTIVE); + expect(config.conversionAccess).to.equal(ConversionAccessibility.ALL); + } + }); + + it("guardian should have all permissions to call TreasuryConverter", async () => { + const pauseConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ARBITRUM, "pauseConversion()"], + ); + const pauseConversionRoleHash = ethers.utils.keccak256(pauseConversionRole); + expect(await acm.hasRole(pauseConversionRoleHash, arbitrumone.GUARDIAN)).to.be.true; + + const resumeConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ARBITRUM, "resumeConversion()"], + ); + const resumeConversionRoleHash = ethers.utils.keccak256(resumeConversionRole); + expect(await acm.hasRole(resumeConversionRoleHash, arbitrumone.GUARDIAN)).to.be.true; + + const setMinAmountToConvertRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ARBITRUM, "setMinAmountToConvert(uint256)"], + ); + const setMinAmountToConvertRoleHash = ethers.utils.keccak256(setMinAmountToConvertRole); + expect(await acm.hasRole(setMinAmountToConvertRoleHash, arbitrumone.GUARDIAN)).to.be.true; + + const setConversionConfigRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ARBITRUM, "setConversionConfig(address,address,ConversionConfig)"], + ); + const setConversionConfigRoleHash = ethers.utils.keccak256(setConversionConfigRole); + expect(await acm.hasRole(setConversionConfigRoleHash, arbitrumone.GUARDIAN)).to.be.true; + }); + + it("Regular timelock should have true permissions to call TreasuryConverter", async () => { + const pauseConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ARBITRUM, "pauseConversion()"], + ); + const pauseConversionRoleHash = ethers.utils.keccak256(pauseConversionRole); + expect(await acm.hasRole(pauseConversionRoleHash, arbitrumone.NORMAL_TIMELOCK)).to.be.true; + + const resumeConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ARBITRUM, "resumeConversion()"], + ); + const resumeConversionRoleHash = ethers.utils.keccak256(resumeConversionRole); + expect(await acm.hasRole(resumeConversionRoleHash, arbitrumone.NORMAL_TIMELOCK)).to.be.true; + + const setMinAmountToConvertRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ARBITRUM, "setMinAmountToConvert(uint256)"], + ); + const setMinAmountToConvertRoleHash = ethers.utils.keccak256(setMinAmountToConvertRole); + expect(await acm.hasRole(setMinAmountToConvertRoleHash, arbitrumone.NORMAL_TIMELOCK)).to.be.true; + + const setConversionConfigRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ARBITRUM, "setConversionConfig(address,address,ConversionConfig)"], + ); + const setConversionConfigRoleHash = ethers.utils.keccak256(setConversionConfigRole); + expect(await acm.hasRole(setConversionConfigRoleHash, arbitrumone.NORMAL_TIMELOCK)).to.be.true; + }); + + it("Fast Track timelock should have true permissions to call TreasuryConverter", async () => { + const pauseConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ARBITRUM, "pauseConversion()"], + ); + const pauseConversionRoleHash = ethers.utils.keccak256(pauseConversionRole); + expect(await acm.hasRole(pauseConversionRoleHash, arbitrumone.FAST_TRACK_TIMELOCK)).to.be.true; + + const resumeConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ARBITRUM, "resumeConversion()"], + ); + const resumeConversionRoleHash = ethers.utils.keccak256(resumeConversionRole); + expect(await acm.hasRole(resumeConversionRoleHash, arbitrumone.FAST_TRACK_TIMELOCK)).to.be.true; + + const setMinAmountToConvertRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ARBITRUM, "setMinAmountToConvert(uint256)"], + ); + const setMinAmountToConvertRoleHash = ethers.utils.keccak256(setMinAmountToConvertRole); + expect(await acm.hasRole(setMinAmountToConvertRoleHash, arbitrumone.FAST_TRACK_TIMELOCK)).to.be.true; + + const setConversionConfigRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ARBITRUM, "setConversionConfig(address,address,ConversionConfig)"], + ); + const setConversionConfigRoleHash = ethers.utils.keccak256(setConversionConfigRole); + expect(await acm.hasRole(setConversionConfigRoleHash, arbitrumone.FAST_TRACK_TIMELOCK)).to.be.true; + }); + + it("Critical timelock should have true permissions to call TreasuryConverter", async () => { + const pauseConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ARBITRUM, "pauseConversion()"], + ); + const pauseConversionRoleHash = ethers.utils.keccak256(pauseConversionRole); + expect(await acm.hasRole(pauseConversionRoleHash, arbitrumone.CRITICAL_TIMELOCK)).to.be.true; + + const resumeConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ARBITRUM, "resumeConversion()"], + ); + const resumeConversionRoleHash = ethers.utils.keccak256(resumeConversionRole); + expect(await acm.hasRole(resumeConversionRoleHash, arbitrumone.CRITICAL_TIMELOCK)).to.be.true; + + const setMinAmountToConvertRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ARBITRUM, "setMinAmountToConvert(uint256)"], + ); + const setMinAmountToConvertRoleHash = ethers.utils.keccak256(setMinAmountToConvertRole); + expect(await acm.hasRole(setMinAmountToConvertRoleHash, arbitrumone.CRITICAL_TIMELOCK)).to.be.true; + + const setConversionConfigRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ARBITRUM, "setConversionConfig(address,address,ConversionConfig)"], + ); + const setConversionConfigRoleHash = ethers.utils.keccak256(setConversionConfigRole); + expect(await acm.hasRole(setConversionConfigRoleHash, arbitrumone.CRITICAL_TIMELOCK)).to.be.true; + }); + }); }); }); diff --git a/simulations/vip-536/bscmainnet.ts b/simulations/vip-536/bscmainnet.ts index 3cfb132ce..6e0551218 100644 --- a/simulations/vip-536/bscmainnet.ts +++ b/simulations/vip-536/bscmainnet.ts @@ -1,34 +1,58 @@ import { expect } from "chai"; import { Contract } from "ethers"; import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; import { expectEvents } from "src/utils"; import { forking, testVip } from "src/vip-framework"; import vip536, { + BSC_CONVERSION_INCENTIVE, + ConversionAccessibility, NEW_SINGLE_TOKEN_CONVERTER_IMP_BSC, SINGLE_TOKEN_CONVERTER_BEACON_BSC, + TREASURY_CONVERTER, + TREASURY_CONVERTER_BSC, } from "../../vips/vip-536/bscmainnet"; +import ACCESS_CONTROLL_MANAGER_ABI from "./abi/AccessControlManager.json"; import BEACON_ABI from "./abi/Beacon.json"; +import CONVERTER_ABI from "./abi/singletokenconverter.json"; + +const { bscmainnet } = NETWORK_ADDRESSES; const OLD_SINGLE_TOKEN_CONVERTER_IMP_BSC = "0x40ed28180Df01FdeB957224E4A5415704B9D5990"; -forking(53537328, async () => { +forking(55597156, async () => { const provider = ethers.provider; let beacon: Contract; + let treasuryConverter: Contract; + let acm: Contract; before(async () => { beacon = new ethers.Contract(SINGLE_TOKEN_CONVERTER_BEACON_BSC, BEACON_ABI, provider); + treasuryConverter = new ethers.Contract(TREASURY_CONVERTER_BSC, CONVERTER_ABI, provider); + acm = new ethers.Contract(bscmainnet.ACCESS_CONTROL_MANAGER, ACCESS_CONTROLL_MANAGER_ABI, provider); }); describe("Pre-VIP behavior", () => { it("SingleTokenConverter should have old implementation", async () => { expect(await beacon.implementation()).to.equal(OLD_SINGLE_TOKEN_CONVERTER_IMP_BSC); }); + + describe("TreasuryConverter", () => { + it("should have a correct pending owner", async () => { + expect(await treasuryConverter.pendingOwner()).to.equal(bscmainnet.NORMAL_TIMELOCK); + }); + }); }); testVip("VIP-536", await vip536(), { callbackAfterExecution: async (txResponse: any) => { - await expectEvents(txResponse, [BEACON_ABI], ["Upgraded"], [1]); + await expectEvents( + txResponse, + [BEACON_ABI, CONVERTER_ABI], + ["Upgraded", "ConverterNetworkAddressUpdated", "OwnershipTransferred", "ConversionConfigUpdated"], + [1, 1, 2, 4], + ); }, }); @@ -36,5 +60,154 @@ forking(53537328, async () => { it("SingleTokenConverter should have new implementation", async () => { expect(await beacon.implementation()).to.equal(NEW_SINGLE_TOKEN_CONVERTER_IMP_BSC); }); + + describe("TreasuryConverter", () => { + it("should not be paused", async () => { + expect(await treasuryConverter.conversionPaused()).to.be.false; + }); + + it("should have Treasury as destination for conversion", async () => { + expect(await treasuryConverter.destinationAddress()).to.equal(bscmainnet.VTREASURY); + }); + + it("should have correct owner", async () => { + expect(await treasuryConverter.owner()).to.equal(bscmainnet.NORMAL_TIMELOCK); + }); + + it("should have correct converters network address", async () => { + expect(await treasuryConverter.converterNetwork()).to.equal(TREASURY_CONVERTER.bscmainnet.converterNetwork); + }); + + it("should have correct conversion configuration", async () => { + const { tokenIn, tokenOuts } = TREASURY_CONVERTER.bscmainnet; + + for (const tokenOut of tokenOuts) { + const config = await treasuryConverter.conversionConfigurations(tokenIn, tokenOut); + + expect(config.incentive).to.equal(BSC_CONVERSION_INCENTIVE); + expect(config.conversionAccess).to.equal(ConversionAccessibility.ALL); + } + }); + + it("guardian should have all permissions to call TreasuryConverter", async () => { + const pauseConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSC, "pauseConversion()"], + ); + const pauseConversionRoleHash = ethers.utils.keccak256(pauseConversionRole); + expect(await acm.hasRole(pauseConversionRoleHash, bscmainnet.GUARDIAN)).to.be.true; + + const resumeConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSC, "resumeConversion()"], + ); + const resumeConversionRoleHash = ethers.utils.keccak256(resumeConversionRole); + expect(await acm.hasRole(resumeConversionRoleHash, bscmainnet.GUARDIAN)).to.be.true; + + const setMinAmountToConvertRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSC, "setMinAmountToConvert(uint256)"], + ); + const setMinAmountToConvertRoleHash = ethers.utils.keccak256(setMinAmountToConvertRole); + expect(await acm.hasRole(setMinAmountToConvertRoleHash, bscmainnet.GUARDIAN)).to.be.true; + + const setConversionConfigRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSC, "setConversionConfig(address,address,ConversionConfig)"], + ); + const setConversionConfigRoleHash = ethers.utils.keccak256(setConversionConfigRole); + expect(await acm.hasRole(setConversionConfigRoleHash, bscmainnet.GUARDIAN)).to.be.true; + }); + + it("Regular timelock should have true permissions to call TreasuryConverter", async () => { + const pauseConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSC, "pauseConversion()"], + ); + const pauseConversionRoleHash = ethers.utils.keccak256(pauseConversionRole); + expect(await acm.hasRole(pauseConversionRoleHash, bscmainnet.NORMAL_TIMELOCK)).to.be.true; + + const resumeConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSC, "resumeConversion()"], + ); + const resumeConversionRoleHash = ethers.utils.keccak256(resumeConversionRole); + expect(await acm.hasRole(resumeConversionRoleHash, bscmainnet.NORMAL_TIMELOCK)).to.be.true; + + const setMinAmountToConvertRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSC, "setMinAmountToConvert(uint256)"], + ); + const setMinAmountToConvertRoleHash = ethers.utils.keccak256(setMinAmountToConvertRole); + expect(await acm.hasRole(setMinAmountToConvertRoleHash, bscmainnet.NORMAL_TIMELOCK)).to.be.true; + + const setConversionConfigRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSC, "setConversionConfig(address,address,ConversionConfig)"], + ); + const setConversionConfigRoleHash = ethers.utils.keccak256(setConversionConfigRole); + expect(await acm.hasRole(setConversionConfigRoleHash, bscmainnet.NORMAL_TIMELOCK)).to.be.true; + }); + + it("Fast Track timelock should have true permissions to call TreasuryConverter", async () => { + const pauseConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSC, "pauseConversion()"], + ); + const pauseConversionRoleHash = ethers.utils.keccak256(pauseConversionRole); + expect(await acm.hasRole(pauseConversionRoleHash, bscmainnet.FAST_TRACK_TIMELOCK)).to.be.true; + + const resumeConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSC, "resumeConversion()"], + ); + const resumeConversionRoleHash = ethers.utils.keccak256(resumeConversionRole); + expect(await acm.hasRole(resumeConversionRoleHash, bscmainnet.FAST_TRACK_TIMELOCK)).to.be.true; + + const setMinAmountToConvertRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSC, "setMinAmountToConvert(uint256)"], + ); + const setMinAmountToConvertRoleHash = ethers.utils.keccak256(setMinAmountToConvertRole); + expect(await acm.hasRole(setMinAmountToConvertRoleHash, bscmainnet.FAST_TRACK_TIMELOCK)).to.be.true; + + const setConversionConfigRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSC, "setConversionConfig(address,address,ConversionConfig)"], + ); + const setConversionConfigRoleHash = ethers.utils.keccak256(setConversionConfigRole); + expect(await acm.hasRole(setConversionConfigRoleHash, bscmainnet.FAST_TRACK_TIMELOCK)).to.be.true; + }); + + it("Critical timelock should have true permissions to call TreasuryConverter", async () => { + const pauseConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSC, "pauseConversion()"], + ); + const pauseConversionRoleHash = ethers.utils.keccak256(pauseConversionRole); + expect(await acm.hasRole(pauseConversionRoleHash, bscmainnet.CRITICAL_TIMELOCK)).to.be.true; + + const resumeConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSC, "resumeConversion()"], + ); + const resumeConversionRoleHash = ethers.utils.keccak256(resumeConversionRole); + expect(await acm.hasRole(resumeConversionRoleHash, bscmainnet.CRITICAL_TIMELOCK)).to.be.true; + + const setMinAmountToConvertRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSC, "setMinAmountToConvert(uint256)"], + ); + const setMinAmountToConvertRoleHash = ethers.utils.keccak256(setMinAmountToConvertRole); + expect(await acm.hasRole(setMinAmountToConvertRoleHash, bscmainnet.CRITICAL_TIMELOCK)).to.be.true; + + const setConversionConfigRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSC, "setConversionConfig(address,address,ConversionConfig)"], + ); + const setConversionConfigRoleHash = ethers.utils.keccak256(setConversionConfigRole); + expect(await acm.hasRole(setConversionConfigRoleHash, bscmainnet.CRITICAL_TIMELOCK)).to.be.true; + }); + }); }); }); diff --git a/simulations/vip-536/ethereum.ts b/simulations/vip-536/ethereum.ts index 1dbfb9ec6..809d1ee89 100644 --- a/simulations/vip-536/ethereum.ts +++ b/simulations/vip-536/ethereum.ts @@ -1,34 +1,58 @@ import { expect } from "chai"; import { Contract } from "ethers"; import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; import { expectEvents } from "src/utils"; import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; import vip536, { + ConversionAccessibility, + ETHEREUM_CONVERSION_INCENTIVE, NEW_SINGLE_TOKEN_CONVERTER_IMP_ETHEREUM, SINGLE_TOKEN_CONVERTER_BEACON_ETHEREUM, + TREASURY_CONVERTER, + TREASURY_CONVERTER_ETHEREUM, } from "../../vips/vip-536/bscmainnet"; +import ACCESS_CONTROLL_MANAGER_ABI from "./abi/AccessControlManager.json"; import BEACON_ABI from "./abi/Beacon.json"; +import CONVERTER_ABI from "./abi/singletokenconverter.json"; + +const { ethereum } = NETWORK_ADDRESSES; const OLD_SINGLE_TOKEN_CONVERTER_IMP_ETHEREUM = "0x95de59aD391589603DF33F81B53C4d894D8e5545"; -forking(22895432, async () => { +forking(23017363, async () => { const provider = ethers.provider; let beacon: Contract; + let treasuryConverter: Contract; + let acm: Contract; before(async () => { beacon = new ethers.Contract(SINGLE_TOKEN_CONVERTER_BEACON_ETHEREUM, BEACON_ABI, provider); + treasuryConverter = new ethers.Contract(TREASURY_CONVERTER_ETHEREUM, CONVERTER_ABI, provider); + acm = new ethers.Contract(ethereum.ACCESS_CONTROL_MANAGER, ACCESS_CONTROLL_MANAGER_ABI, provider); }); describe("Pre-VIP behavior", () => { it("SingleTokenConverter should have old implementation", async () => { expect(await beacon.implementation()).to.equal(OLD_SINGLE_TOKEN_CONVERTER_IMP_ETHEREUM); }); + + describe("TreasuryConverter", () => { + it("should have a correct pending owner", async () => { + expect(await treasuryConverter.pendingOwner()).to.equal(ethereum.NORMAL_TIMELOCK); + }); + }); }); testForkedNetworkVipCommands("VIP-536", await vip536(), { callbackAfterExecution: async (txResponse: any) => { - await expectEvents(txResponse, [BEACON_ABI], ["Upgraded"], [1]); + await expectEvents( + txResponse, + [BEACON_ABI, CONVERTER_ABI], + ["Upgraded", "ConverterNetworkAddressUpdated", "OwnershipTransferred", "ConversionConfigUpdated"], + [1, 1, 2, 3], + ); }, }); @@ -36,5 +60,153 @@ forking(22895432, async () => { it("RiskFundConverter and SingleTokenConverter should have new implementation", async () => { expect(await beacon.implementation()).to.equal(NEW_SINGLE_TOKEN_CONVERTER_IMP_ETHEREUM); }); + describe("TreasuryConverter", () => { + it("should not be paused", async () => { + expect(await treasuryConverter.conversionPaused()).to.be.false; + }); + + it("should have Treasury as destination for conversion", async () => { + expect(await treasuryConverter.destinationAddress()).to.equal(ethereum.VTREASURY); + }); + + it("should have correct owner", async () => { + expect(await treasuryConverter.owner()).to.equal(ethereum.NORMAL_TIMELOCK); + }); + + it("should have correct converters network address", async () => { + expect(await treasuryConverter.converterNetwork()).to.equal(TREASURY_CONVERTER.ethereum.converterNetwork); + }); + + it("should have correct conversion configuration", async () => { + const { tokenIn, tokenOuts } = TREASURY_CONVERTER.ethereum; + + for (const tokenOut of tokenOuts) { + const config = await treasuryConverter.conversionConfigurations(tokenIn, tokenOut); + + expect(config.incentive).to.equal(ETHEREUM_CONVERSION_INCENTIVE); + expect(config.conversionAccess).to.equal(ConversionAccessibility.ALL); + } + }); + + it("guardian should have all permissions to call TreasuryConverter", async () => { + const pauseConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ETHEREUM, "pauseConversion()"], + ); + const pauseConversionRoleHash = ethers.utils.keccak256(pauseConversionRole); + expect(await acm.hasRole(pauseConversionRoleHash, ethereum.GUARDIAN)).to.be.true; + + const resumeConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ETHEREUM, "resumeConversion()"], + ); + const resumeConversionRoleHash = ethers.utils.keccak256(resumeConversionRole); + expect(await acm.hasRole(resumeConversionRoleHash, ethereum.GUARDIAN)).to.be.true; + + const setMinAmountToConvertRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ETHEREUM, "setMinAmountToConvert(uint256)"], + ); + const setMinAmountToConvertRoleHash = ethers.utils.keccak256(setMinAmountToConvertRole); + expect(await acm.hasRole(setMinAmountToConvertRoleHash, ethereum.GUARDIAN)).to.be.true; + + const setConversionConfigRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ETHEREUM, "setConversionConfig(address,address,ConversionConfig)"], + ); + const setConversionConfigRoleHash = ethers.utils.keccak256(setConversionConfigRole); + expect(await acm.hasRole(setConversionConfigRoleHash, ethereum.GUARDIAN)).to.be.true; + }); + + it("Regular timelock should have true permissions to call TreasuryConverter", async () => { + const pauseConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ETHEREUM, "pauseConversion()"], + ); + const pauseConversionRoleHash = ethers.utils.keccak256(pauseConversionRole); + expect(await acm.hasRole(pauseConversionRoleHash, ethereum.NORMAL_TIMELOCK)).to.be.true; + + const resumeConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ETHEREUM, "resumeConversion()"], + ); + const resumeConversionRoleHash = ethers.utils.keccak256(resumeConversionRole); + expect(await acm.hasRole(resumeConversionRoleHash, ethereum.NORMAL_TIMELOCK)).to.be.true; + + const setMinAmountToConvertRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ETHEREUM, "setMinAmountToConvert(uint256)"], + ); + const setMinAmountToConvertRoleHash = ethers.utils.keccak256(setMinAmountToConvertRole); + expect(await acm.hasRole(setMinAmountToConvertRoleHash, ethereum.NORMAL_TIMELOCK)).to.be.true; + + const setConversionConfigRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ETHEREUM, "setConversionConfig(address,address,ConversionConfig)"], + ); + const setConversionConfigRoleHash = ethers.utils.keccak256(setConversionConfigRole); + expect(await acm.hasRole(setConversionConfigRoleHash, ethereum.NORMAL_TIMELOCK)).to.be.true; + }); + + it("Fast Track timelock should have true permissions to call TreasuryConverter", async () => { + const pauseConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ETHEREUM, "pauseConversion()"], + ); + const pauseConversionRoleHash = ethers.utils.keccak256(pauseConversionRole); + expect(await acm.hasRole(pauseConversionRoleHash, ethereum.FAST_TRACK_TIMELOCK)).to.be.true; + + const resumeConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ETHEREUM, "resumeConversion()"], + ); + const resumeConversionRoleHash = ethers.utils.keccak256(resumeConversionRole); + expect(await acm.hasRole(resumeConversionRoleHash, ethereum.FAST_TRACK_TIMELOCK)).to.be.true; + + const setMinAmountToConvertRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ETHEREUM, "setMinAmountToConvert(uint256)"], + ); + const setMinAmountToConvertRoleHash = ethers.utils.keccak256(setMinAmountToConvertRole); + expect(await acm.hasRole(setMinAmountToConvertRoleHash, ethereum.FAST_TRACK_TIMELOCK)).to.be.true; + + const setConversionConfigRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ETHEREUM, "setConversionConfig(address,address,ConversionConfig)"], + ); + const setConversionConfigRoleHash = ethers.utils.keccak256(setConversionConfigRole); + expect(await acm.hasRole(setConversionConfigRoleHash, ethereum.FAST_TRACK_TIMELOCK)).to.be.true; + }); + + it("Critical timelock should have true permissions to call TreasuryConverter", async () => { + const pauseConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ETHEREUM, "pauseConversion()"], + ); + const pauseConversionRoleHash = ethers.utils.keccak256(pauseConversionRole); + expect(await acm.hasRole(pauseConversionRoleHash, ethereum.CRITICAL_TIMELOCK)).to.be.true; + + const resumeConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ETHEREUM, "resumeConversion()"], + ); + const resumeConversionRoleHash = ethers.utils.keccak256(resumeConversionRole); + expect(await acm.hasRole(resumeConversionRoleHash, ethereum.CRITICAL_TIMELOCK)).to.be.true; + + const setMinAmountToConvertRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ETHEREUM, "setMinAmountToConvert(uint256)"], + ); + const setMinAmountToConvertRoleHash = ethers.utils.keccak256(setMinAmountToConvertRole); + expect(await acm.hasRole(setMinAmountToConvertRoleHash, ethereum.CRITICAL_TIMELOCK)).to.be.true; + + const setConversionConfigRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_ETHEREUM, "setConversionConfig(address,address,ConversionConfig)"], + ); + const setConversionConfigRoleHash = ethers.utils.keccak256(setConversionConfigRole); + expect(await acm.hasRole(setConversionConfigRoleHash, ethereum.CRITICAL_TIMELOCK)).to.be.true; + }); + }); }); }); diff --git a/src/networkAddresses.ts b/src/networkAddresses.ts index 4d5736a64..4df839cf1 100644 --- a/src/networkAddresses.ts +++ b/src/networkAddresses.ts @@ -75,6 +75,7 @@ export const NETWORK_ADDRESSES = { REDSTONE_ORACLE: oracleBsctestnetContracts.addresses.RedStoneOracle, }, ethereum: { + ACCESS_CONTROL_MANAGER: "0x230058da2D23eb8836EC5DB7037ef7250c56E25E", NORMAL_TIMELOCK: "0xd969E79406c35E80750aAae061D402Aab9325714", FAST_TRACK_TIMELOCK: "0x8764F50616B62a99A997876C2DEAaa04554C5B2E", CRITICAL_TIMELOCK: "0xeB9b85342c34F65af734C7bd4a149c86c472bC00", @@ -161,6 +162,7 @@ export const NETWORK_ADDRESSES = { OMNICHAIN_GOVERNANCE_EXECUTOR: "0xcf3e6972a8e9c53D33b642a2592938944956f138", }, arbitrumone: { + ACCESS_CONTROL_MANAGER: "0xD9dD18EB0cf10CbA837677f28A8F9Bda4bc2b157", NORMAL_TIMELOCK: "0x4b94589Cc23F618687790036726f744D602c4017", FAST_TRACK_TIMELOCK: "0x2286a9B2a5246218f2fC1F380383f45BDfCE3E04", CRITICAL_TIMELOCK: "0x181E4f8F21D087bF02Ea2F64D5e550849FBca674", diff --git a/vips/vip-536/bscmainnet.ts b/vips/vip-536/bscmainnet.ts index 577090f51..f5f79a504 100644 --- a/vips/vip-536/bscmainnet.ts +++ b/vips/vip-536/bscmainnet.ts @@ -1,3 +1,4 @@ +import { NETWORK_ADDRESSES } from "src/networkAddresses"; import { LzChainId, ProposalType } from "src/types"; import { makeProposal } from "src/utils"; @@ -8,6 +9,171 @@ export const NEW_SINGLE_TOKEN_CONVERTER_IMP_ETHEREUM = "0x560E50dc157E7140C0E5bd export const SINGLE_TOKEN_CONVERTER_BEACON_ARBITRUM = "0x993900Ab4ef4092e5B76d4781D09A2732086F0F0"; export const NEW_SINGLE_TOKEN_CONVERTER_IMP_ARBITRUM = "0x2EE413F4e060451CB25AeD5Cdd348F430aa79105"; +export const TREASURY_CONVERTER_BSC = "0x3d459f128cf6b938d6B7E626115F149F1567546f"; +export const TREASURY_CONVERTER_ETHEREUM = "0x47faB3596F221078f6e3A90B74504d5b9f9FaEC3"; +export const TREASURY_CONVERTER_ARBITRUM = "0x557684a9B7743B8D24Dbb1C0B88D659D56035f38"; + +export const BSC_CONVERSION_INCENTIVE = 1e14; +export const ARBITRUM_CONVERSION_INCENTIVE = 1e14; +export const ETHEREUM_CONVERSION_INCENTIVE = 1e13; + +const { bscmainnet, ethereum, arbitrumone } = NETWORK_ADDRESSES; + +export enum ConversionAccessibility { + NONE = 0, + ALL = 1, + ONLY_FOR_CONVERTERS = 2, + ONLY_FOR_USERS = 3, +} + +export const TREASURY_CONVERTER = { + bscmainnet: { + converter: TREASURY_CONVERTER_BSC, + tokenIn: "0x55d398326f99059fF775485246999027B3197955", // USDT + tokenOuts: [ + "0x2170Ed0880ac9A755fd29B2688956BD959F933F8", // ETH + "0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c", // BTCB + "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", // BNB + "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d", // USDC + ], + conversionIncentive: new Array(4).fill([BSC_CONVERSION_INCENTIVE, ConversionAccessibility.ALL]), + converterNetwork: "0xF7Caad5CeB0209165f2dFE71c92aDe14d0F15995", + }, + ethereum: { + converter: TREASURY_CONVERTER_ETHEREUM, + tokenIn: "0xdAC17F958D2ee523a2206206994597C13D831ec7", // USDT + tokenOuts: [ + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH + "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", // WBTC + "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC + ], + conversionIncentive: new Array(3).fill([ETHEREUM_CONVERSION_INCENTIVE, ConversionAccessibility.ALL]), + converterNetwork: "0x232CC47AECCC55C2CAcE4372f5B268b27ef7cac8", + }, + arbitrumone: { + converter: TREASURY_CONVERTER_ARBITRUM, + tokenIn: "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9", // USDT + tokenOuts: [ + "0x82af49447d8a07e3bd95bd0d56f35241523fbab1", // WETH + "0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f", // WBTC + "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", // USDC + ], + conversionIncentive: new Array(3).fill([ARBITRUM_CONVERSION_INCENTIVE, ConversionAccessibility.ALL]), + converterNetwork: "0x2F6672C9A0988748b0172D97961BecfD9DC6D6d5", + }, +}; + +function grantPremissions( + converter: string, + network: { + ACCESS_CONTROL_MANAGER: string; + NORMAL_TIMELOCK: string; + FAST_TRACK_TIMELOCK: string; + CRITICAL_TIMELOCK: string; + GUARDIAN: string; + }, + dstChainId?: LzChainId, +) { + return [ + { + target: network.ACCESS_CONTROL_MANAGER, + signature: "giveCallPermission(address,string,address)", + params: [converter, "pauseConversion()", network.NORMAL_TIMELOCK], + dstChainId, + }, + { + target: network.ACCESS_CONTROL_MANAGER, + signature: "giveCallPermission(address,string,address)", + params: [converter, "pauseConversion()", network.FAST_TRACK_TIMELOCK], + dstChainId, + }, + { + target: network.ACCESS_CONTROL_MANAGER, + signature: "giveCallPermission(address,string,address)", + params: [converter, "pauseConversion()", network.CRITICAL_TIMELOCK], + dstChainId, + }, + { + target: network.ACCESS_CONTROL_MANAGER, + signature: "giveCallPermission(address,string,address)", + params: [converter, "pauseConversion()", network.GUARDIAN], + dstChainId, + }, + { + target: network.ACCESS_CONTROL_MANAGER, + signature: "giveCallPermission(address,string,address)", + params: [converter, "resumeConversion()", network.NORMAL_TIMELOCK], + dstChainId, + }, + { + target: network.ACCESS_CONTROL_MANAGER, + signature: "giveCallPermission(address,string,address)", + params: [converter, "resumeConversion()", network.FAST_TRACK_TIMELOCK], + dstChainId, + }, + { + target: network.ACCESS_CONTROL_MANAGER, + signature: "giveCallPermission(address,string,address)", + params: [converter, "resumeConversion()", network.CRITICAL_TIMELOCK], + dstChainId, + }, + { + target: network.ACCESS_CONTROL_MANAGER, + signature: "giveCallPermission(address,string,address)", + params: [converter, "resumeConversion()", network.GUARDIAN], + dstChainId, + }, + { + target: network.ACCESS_CONTROL_MANAGER, + signature: "giveCallPermission(address,string,address)", + params: [converter, "setMinAmountToConvert(uint256)", network.NORMAL_TIMELOCK], + dstChainId, + }, + { + target: network.ACCESS_CONTROL_MANAGER, + signature: "giveCallPermission(address,string,address)", + params: [converter, "setMinAmountToConvert(uint256)", network.FAST_TRACK_TIMELOCK], + dstChainId, + }, + { + target: network.ACCESS_CONTROL_MANAGER, + signature: "giveCallPermission(address,string,address)", + params: [converter, "setMinAmountToConvert(uint256)", network.CRITICAL_TIMELOCK], + dstChainId, + }, + { + target: network.ACCESS_CONTROL_MANAGER, + signature: "giveCallPermission(address,string,address)", + params: [converter, "setMinAmountToConvert(uint256)", network.GUARDIAN], + dstChainId, + }, + { + target: network.ACCESS_CONTROL_MANAGER, + signature: "giveCallPermission(address,string,address)", + params: [converter, "setConversionConfig(address,address,ConversionConfig)", network.NORMAL_TIMELOCK], + dstChainId, + }, + { + target: network.ACCESS_CONTROL_MANAGER, + signature: "giveCallPermission(address,string,address)", + params: [converter, "setConversionConfig(address,address,ConversionConfig)", network.FAST_TRACK_TIMELOCK], + dstChainId, + }, + { + target: network.ACCESS_CONTROL_MANAGER, + signature: "giveCallPermission(address,string,address)", + params: [converter, "setConversionConfig(address,address,ConversionConfig)", network.CRITICAL_TIMELOCK], + dstChainId, + }, + { + target: network.ACCESS_CONTROL_MANAGER, + signature: "giveCallPermission(address,string,address)", + params: [converter, "setConversionConfig(address,address,ConversionConfig)", network.GUARDIAN], + dstChainId, + }, + ]; +} + export const vip536 = () => { const meta = { version: "v2", @@ -21,6 +187,7 @@ export const vip536 = () => { return makeProposal( [ + // Upgrade SingleTokenConverter implementation { target: SINGLE_TOKEN_CONVERTER_BEACON_BSC, signature: "upgradeTo(address)", @@ -38,6 +205,75 @@ export const vip536 = () => { params: [NEW_SINGLE_TOKEN_CONVERTER_IMP_ARBITRUM], dstChainId: LzChainId.arbitrumone, }, + // Treasury Converter configurations BSCMainnet + { + target: TREASURY_CONVERTER.bscmainnet.converter, + signature: "acceptOwnership()", + params: [], + }, + ...grantPremissions(TREASURY_CONVERTER.bscmainnet.converter, bscmainnet), + { + target: TREASURY_CONVERTER.bscmainnet.converter, + signature: "setConverterNetwork(address)", + params: [TREASURY_CONVERTER.bscmainnet.converterNetwork], + }, + { + target: TREASURY_CONVERTER.bscmainnet.converter, + signature: "setConversionConfigs(address,address[],(uint256,uint8)[])", + params: [ + TREASURY_CONVERTER.bscmainnet.tokenIn, + TREASURY_CONVERTER.bscmainnet.tokenOuts, + TREASURY_CONVERTER.bscmainnet.conversionIncentive, + ], + }, + // Treasury Converter configurations Ethereum + { + target: TREASURY_CONVERTER.ethereum.converter, + signature: "acceptOwnership()", + params: [], + dstChainId: LzChainId.ethereum, + }, + ...grantPremissions(TREASURY_CONVERTER.ethereum.converter, ethereum, LzChainId.ethereum), + { + target: TREASURY_CONVERTER.ethereum.converter, + signature: "setConverterNetwork(address)", + params: [TREASURY_CONVERTER.ethereum.converterNetwork], + dstChainId: LzChainId.ethereum, + }, + { + target: TREASURY_CONVERTER.ethereum.converter, + signature: "setConversionConfigs(address,address[],(uint256,uint8)[])", + params: [ + TREASURY_CONVERTER.ethereum.tokenIn, + TREASURY_CONVERTER.ethereum.tokenOuts, + TREASURY_CONVERTER.ethereum.conversionIncentive, + ], + dstChainId: LzChainId.ethereum, + }, + // Treasury Converter configurations Arbitrum + { + target: TREASURY_CONVERTER.arbitrumone.converter, + signature: "acceptOwnership()", + params: [], + dstChainId: LzChainId.arbitrumone, + }, + ...grantPremissions(TREASURY_CONVERTER.arbitrumone.converter, arbitrumone, LzChainId.arbitrumone), + { + target: TREASURY_CONVERTER.arbitrumone.converter, + signature: "setConverterNetwork(address)", + params: [TREASURY_CONVERTER.arbitrumone.converterNetwork], + dstChainId: LzChainId.arbitrumone, + }, + { + target: TREASURY_CONVERTER.arbitrumone.converter, + signature: "setConversionConfigs(address,address[],(uint256,uint8)[])", + params: [ + TREASURY_CONVERTER.arbitrumone.tokenIn, + TREASURY_CONVERTER.arbitrumone.tokenOuts, + TREASURY_CONVERTER.arbitrumone.conversionIncentive, + ], + dstChainId: LzChainId.arbitrumone, + }, ], meta, ProposalType.REGULAR, From 8125a7378ce290402424e2444db1999262f594b9 Mon Sep 17 00:00:00 2001 From: Filip Malachowicz Date: Mon, 28 Jul 2025 14:21:26 +0200 Subject: [PATCH 2/3] fixup! feat: TreasuryConverter configured --- simulations/vip-515/abi/ConverterNetwork.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simulations/vip-515/abi/ConverterNetwork.json b/simulations/vip-515/abi/ConverterNetwork.json index 3bf045b3b..0fa27deec 100644 --- a/simulations/vip-515/abi/ConverterNetwork.json +++ b/simulations/vip-515/abi/ConverterNetwork.json @@ -445,4 +445,4 @@ "stateMutability": "nonpayable", "type": "function" } -] \ No newline at end of file +] From a559408a1c61d41a55f600b13132888a04a68d03 Mon Sep 17 00:00:00 2001 From: Filip Malachowicz Date: Wed, 13 Aug 2025 15:41:19 +0200 Subject: [PATCH 3/3] feat: WIP use ACM_COMMANDS --- package.json | 2 +- .../vip-536/abi/ProtocolShareReserve.json | 357 ++++++++++++++++++ .../vip-536/abi/singletokenconverter.json | 67 ++++ simulations/vip-536/arbitrumone.ts | 23 +- simulations/vip-536/bscmainnet.ts | 26 +- simulations/vip-536/bsctestnet.ts | 186 ++++++++- simulations/vip-536/ethereum.ts | 24 +- src/networkAddresses.ts | 6 + src/permissions.ts | 272 +++++++++++++ vips/vip-536/bscmainnet.ts | 236 ++++-------- vips/vip-536/bsctestnet.ts | 61 ++- vips/vip-536/configuration.ts | 329 ++++++++++++++++ vips/vip-536/permissions.ts | 94 +++++ yarn.lock | 20 +- 14 files changed, 1508 insertions(+), 195 deletions(-) create mode 100644 simulations/vip-536/abi/ProtocolShareReserve.json create mode 100644 src/permissions.ts create mode 100644 vips/vip-536/configuration.ts create mode 100644 vips/vip-536/permissions.ts diff --git a/package.json b/package.json index 079b11517..453fe2970 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "@morpho-labs/gnosis-tx-builder": "^1.3.1", "@openzeppelin/contracts": "^4.8.2", "@openzeppelin/contracts-upgradeable": "^4.8.2", - "@venusprotocol/governance-contracts": "^1.4.0", + "@venusprotocol/governance-contracts": "^2.12.0", "@venusprotocol/isolated-pools": "^2.5.0", "@venusprotocol/oracle": "^1.10.0", "@venusprotocol/token-bridge": "^1.1.0", diff --git a/simulations/vip-536/abi/ProtocolShareReserve.json b/simulations/vip-536/abi/ProtocolShareReserve.json new file mode 100644 index 000000000..194bc7e90 --- /dev/null +++ b/simulations/vip-536/abi/ProtocolShareReserve.json @@ -0,0 +1,357 @@ +[ + { + "inputs": [ + { "internalType": "address", "name": "_corePoolComptroller", "type": "address" }, + { "internalType": "address", "name": "_wbnb", "type": "address" }, + { "internalType": "address", "name": "_vbnb", "type": "address" } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { "inputs": [], "name": "InvalidAddress", "type": "error" }, + { "inputs": [], "name": "InvalidTotalPercentage", "type": "error" }, + { + "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" + }, + { "inputs": [], "name": "ZeroAddressNotAllowed", "type": "error" }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "destination", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "asset", "type": "address" }, + { "indexed": false, "internalType": "enum ProtocolShareReserve.Schema", "name": "schema", "type": "uint8" }, + { "indexed": false, "internalType": "uint256", "name": "percent", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "AssetReleased", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "comptroller", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "asset", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" }, + { + "indexed": false, + "internalType": "enum IProtocolShareReserve.IncomeType", + "name": "incomeType", + "type": "uint8" + }, + { "indexed": false, "internalType": "enum ProtocolShareReserve.Schema", "name": "schema", "type": "uint8" } + ], + "name": "AssetsReservesUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "destination", "type": "address" }, + { "indexed": false, "internalType": "uint16", "name": "percentage", "type": "uint16" }, + { "indexed": false, "internalType": "enum ProtocolShareReserve.Schema", "name": "schema", "type": "uint8" } + ], + "name": "DistributionConfigAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "destination", "type": "address" }, + { "indexed": false, "internalType": "uint16", "name": "percentage", "type": "uint16" }, + { "indexed": false, "internalType": "enum ProtocolShareReserve.Schema", "name": "schema", "type": "uint8" } + ], + "name": "DistributionConfigRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "destination", "type": "address" }, + { "indexed": false, "internalType": "uint16", "name": "oldPercentage", "type": "uint16" }, + { "indexed": false, "internalType": "uint16", "name": "newPercentage", "type": "uint16" }, + { "indexed": false, "internalType": "enum ProtocolShareReserve.Schema", "name": "schema", "type": "uint8" } + ], + "name": "DistributionConfigUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "uint8", "name": "version", "type": "uint8" }], + "name": "Initialized", + "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": "oldPoolRegistry", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "newPoolRegistry", "type": "address" } + ], + "name": "PoolRegistryUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "comptroller", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "asset", "type": "address" }, + { "indexed": false, "internalType": "enum ProtocolShareReserve.Schema", "name": "schema", "type": "uint8" }, + { "indexed": false, "internalType": "uint256", "name": "oldBalance", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newBalance", "type": "uint256" } + ], + "name": "ReservesUpdated", + "type": "event" + }, + { + "inputs": [], + "name": "CORE_POOL_COMPTROLLER", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAX_PERCENT", + "outputs": [{ "internalType": "uint16", "name": "", "type": "uint16" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "WBNB", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "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": [ + { + "components": [ + { "internalType": "enum ProtocolShareReserve.Schema", "name": "schema", "type": "uint8" }, + { "internalType": "uint16", "name": "percentage", "type": "uint16" }, + { "internalType": "address", "name": "destination", "type": "address" } + ], + "internalType": "struct ProtocolShareReserve.DistributionConfig[]", + "name": "configs", + "type": "tuple[]" + } + ], + "name": "addOrUpdateDistributionConfigs", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "enum ProtocolShareReserve.Schema", "name": "", "type": "uint8" } + ], + "name": "assetsReserves", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "distributionTargets", + "outputs": [ + { "internalType": "enum ProtocolShareReserve.Schema", "name": "schema", "type": "uint8" }, + { "internalType": "uint16", "name": "percentage", "type": "uint16" }, + { "internalType": "address", "name": "destination", "type": "address" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "destination", "type": "address" }, + { "internalType": "enum ProtocolShareReserve.Schema", "name": "schema", "type": "uint8" } + ], + "name": "getPercentageDistribution", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "comptroller", "type": "address" }, + { "internalType": "enum ProtocolShareReserve.Schema", "name": "schema", "type": "uint8" }, + { "internalType": "address", "name": "destination", "type": "address" }, + { "internalType": "address", "name": "asset", "type": "address" } + ], + "name": "getUnreleasedFunds", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_accessControlManager", "type": "address" }, + { "internalType": "uint256", "name": "_loopsLimit", "type": "uint256" } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "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": "poolRegistry", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "comptroller", "type": "address" }, + { "internalType": "address[]", "name": "assets", "type": "address[]" } + ], + "name": "releaseFunds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "enum ProtocolShareReserve.Schema", "name": "schema", "type": "uint8" }, + { "internalType": "address", "name": "destination", "type": "address" } + ], + "name": "removeDistributionConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { "inputs": [], "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [{ "internalType": "address", "name": "accessControlManager_", "type": "address" }], + "name": "setAccessControlManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "_poolRegistry", "type": "address" }], + "name": "setPoolRegistry", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "totalAssetReserve", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalDistributions", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "comptroller", "type": "address" }, + { "internalType": "address", "name": "asset", "type": "address" }, + { "internalType": "enum IProtocolShareReserve.IncomeType", "name": "incomeType", "type": "uint8" } + ], + "name": "updateAssetsState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "vBNB", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + } +] diff --git a/simulations/vip-536/abi/singletokenconverter.json b/simulations/vip-536/abi/singletokenconverter.json index c8d0f7077..a5fc91286 100644 --- a/simulations/vip-536/abi/singletokenconverter.json +++ b/simulations/vip-536/abi/singletokenconverter.json @@ -132,6 +132,11 @@ "name": "NonZeroIncentiveForPrivateConversion", "type": "error" }, + { + "inputs": [], + "name": "SameBaseAssetNotAllowed", + "type": "error" + }, { "inputs": [ { @@ -194,6 +199,31 @@ "name": "AssetTransferredToDestination", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "asset", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "value", + "type": "bool" + } + ], + "name": "AssetsDirectTransferUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -658,6 +688,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "assetsDirectTransfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1189,6 +1238,24 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "assets", + "type": "address[]" + }, + { + "internalType": "bool[]", + "name": "values", + "type": "bool[]" + } + ], + "name": "setAssetsDirectTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/simulations/vip-536/arbitrumone.ts b/simulations/vip-536/arbitrumone.ts index 4bd1ce301..2cb7342ab 100644 --- a/simulations/vip-536/arbitrumone.ts +++ b/simulations/vip-536/arbitrumone.ts @@ -6,15 +6,18 @@ import { expectEvents } from "src/utils"; import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; import vip536, { - ARBITRUM_CONVERSION_INCENTIVE, - ConversionAccessibility, NEW_SINGLE_TOKEN_CONVERTER_IMP_ARBITRUM, SINGLE_TOKEN_CONVERTER_BEACON_ARBITRUM, +} from "../../vips/vip-536/bscmainnet"; +import { + ARBITRUM_CONVERSION_INCENTIVE, + ConversionAccessibility, TREASURY_CONVERTER, TREASURY_CONVERTER_ARBITRUM, -} from "../../vips/vip-536/bscmainnet"; +} from "../../vips/vip-536/configuration"; import ACCESS_CONTROLL_MANAGER_ABI from "./abi/AccessControlManager.json"; import BEACON_ABI from "./abi/Beacon.json"; +import PSR_ABI from "./abi/ProtocolShareReserve.json"; import CONVERTER_ABI from "./abi/singletokenconverter.json"; const { arbitrumone } = NETWORK_ADDRESSES; @@ -49,9 +52,15 @@ forking(362442798, async () => { callbackAfterExecution: async (txResponse: any) => { await expectEvents( txResponse, - [BEACON_ABI, CONVERTER_ABI], - ["Upgraded", "ConverterNetworkAddressUpdated", "OwnershipTransferred", "ConversionConfigUpdated"], - [1, 1, 2, 3], + [BEACON_ABI, CONVERTER_ABI, PSR_ABI], + [ + "Upgraded", + "ConverterNetworkAddressUpdated", + "ConversionConfigUpdated", + "DistributionConfigAdded", + "DistributionConfigRemoved", + ], + [1, 1, TREASURY_CONVERTER.arbitrumone.tokensOut.length, 4, 2], ); }, }); @@ -78,7 +87,7 @@ forking(362442798, async () => { }); it("should have correct conversion configuration", async () => { - const { tokenIn, tokenOuts } = TREASURY_CONVERTER.arbitrumone; + const { tokenIn, whitelistedTokens: tokenOuts } = TREASURY_CONVERTER.arbitrumone; for (const tokenOut of tokenOuts) { const config = await treasuryConverter.conversionConfigurations(tokenIn, tokenOut); diff --git a/simulations/vip-536/bscmainnet.ts b/simulations/vip-536/bscmainnet.ts index 6e0551218..62c5d5055 100644 --- a/simulations/vip-536/bscmainnet.ts +++ b/simulations/vip-536/bscmainnet.ts @@ -6,22 +6,25 @@ import { expectEvents } from "src/utils"; import { forking, testVip } from "src/vip-framework"; import vip536, { - BSC_CONVERSION_INCENTIVE, - ConversionAccessibility, NEW_SINGLE_TOKEN_CONVERTER_IMP_BSC, SINGLE_TOKEN_CONVERTER_BEACON_BSC, +} from "../../vips/vip-536/bscmainnet"; +import { + BSC_CONVERSION_INCENTIVE, + ConversionAccessibility, TREASURY_CONVERTER, TREASURY_CONVERTER_BSC, -} from "../../vips/vip-536/bscmainnet"; +} from "../../vips/vip-536/configuration"; import ACCESS_CONTROLL_MANAGER_ABI from "./abi/AccessControlManager.json"; import BEACON_ABI from "./abi/Beacon.json"; +import PSR_ABI from "./abi/ProtocolShareReserve.json"; import CONVERTER_ABI from "./abi/singletokenconverter.json"; const { bscmainnet } = NETWORK_ADDRESSES; const OLD_SINGLE_TOKEN_CONVERTER_IMP_BSC = "0x40ed28180Df01FdeB957224E4A5415704B9D5990"; -forking(55597156, async () => { +forking(56542578, async () => { const provider = ethers.provider; let beacon: Contract; let treasuryConverter: Contract; @@ -49,9 +52,16 @@ forking(55597156, async () => { callbackAfterExecution: async (txResponse: any) => { await expectEvents( txResponse, - [BEACON_ABI, CONVERTER_ABI], - ["Upgraded", "ConverterNetworkAddressUpdated", "OwnershipTransferred", "ConversionConfigUpdated"], - [1, 1, 2, 4], + [BEACON_ABI, CONVERTER_ABI, PSR_ABI], + [ + "Upgraded", + "ConverterNetworkAddressUpdated", + "ConversionConfigUpdated", + "DistributionConfigAdded", + "DistributionConfigUpdated", + "DistributionConfigRemoved", + ], + [1, 1, TREASURY_CONVERTER.bscmainnet.whitelistedTokens.length, 2, 2, 2], ); }, }); @@ -79,7 +89,7 @@ forking(55597156, async () => { }); it("should have correct conversion configuration", async () => { - const { tokenIn, tokenOuts } = TREASURY_CONVERTER.bscmainnet; + const { tokenIn, whitelistedTokens: tokenOuts } = TREASURY_CONVERTER.bscmainnet; for (const tokenOut of tokenOuts) { const config = await treasuryConverter.conversionConfigurations(tokenIn, tokenOut); diff --git a/simulations/vip-536/bsctestnet.ts b/simulations/vip-536/bsctestnet.ts index 162e08de8..67225842a 100644 --- a/simulations/vip-536/bsctestnet.ts +++ b/simulations/vip-536/bsctestnet.ts @@ -1,6 +1,7 @@ import { expect } from "chai"; import { Contract } from "ethers"; import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; import { expectEvents } from "src/utils"; import { forking, testVip } from "src/vip-framework"; @@ -8,27 +9,59 @@ import vip536, { NEW_SINGLE_TOKEN_CONVERTER_IMP_BSC, SINGLE_TOKEN_CONVERTER_BEACON_BSC, } from "../../vips/vip-536/bsctestnet"; +import { + BSCTESTNET_CONVERSION_INCENTIVE, + ConversionAccessibility, + TREASURY_CONVERTER, + TREASURY_CONVERTER_BSCTESTNET, +} from "../../vips/vip-536/configuration"; +import ACCESS_CONTROLL_MANAGER_ABI from "./abi/AccessControlManager.json"; import BEACON_ABI from "./abi/Beacon.json"; +import PSR_ABI from "./abi/ProtocolShareReserve.json"; +import CONVERTER_ABI from "./abi/singletokenconverter.json"; + +const { bsctestnet } = NETWORK_ADDRESSES; const OLD_SINGLE_TOKEN_CONVERTER_IMP_BSC = "0x42Ec3Eb6F23460dFDfa3aE5688f3415CDfE0C6AD"; -forking(57758332, async () => { +forking(60736885, async () => { const provider = ethers.provider; let beacon: Contract; + let treasuryConverter: Contract; + let acm: Contract; before(async () => { beacon = new ethers.Contract(SINGLE_TOKEN_CONVERTER_BEACON_BSC, BEACON_ABI, provider); + treasuryConverter = new ethers.Contract(TREASURY_CONVERTER_BSCTESTNET, CONVERTER_ABI, provider); + acm = new ethers.Contract(bsctestnet.ACCESS_CONTROL_MANAGER, ACCESS_CONTROLL_MANAGER_ABI, provider); }); describe("Pre-VIP behavior", () => { it("SingleTokenConverter should have old implementation", async () => { expect(await beacon.implementation()).to.equal(OLD_SINGLE_TOKEN_CONVERTER_IMP_BSC); }); + + describe("TreasuryConverter", () => { + it("should have a correct pending owner", async () => { + expect(await treasuryConverter.pendingOwner()).to.equal(bsctestnet.NORMAL_TIMELOCK); + }); + }); }); testVip("VIP-536", await vip536(), { callbackAfterExecution: async (txResponse: any) => { - await expectEvents(txResponse, [BEACON_ABI], ["Upgraded"], [1]); + await expectEvents( + txResponse, + [BEACON_ABI, CONVERTER_ABI, PSR_ABI], + [ + "Upgraded", + "ConverterNetworkAddressUpdated", + "ConversionConfigUpdated", + "DistributionConfigAdded", + "DistributionConfigRemoved", + ], + [1, 1, TREASURY_CONVERTER.bsctestnet.tokensOut.length, 2, 2], + ); }, }); @@ -36,5 +69,154 @@ forking(57758332, async () => { it("SingleTokenConverter should have new implementation", async () => { expect(await beacon.implementation()).to.equal(NEW_SINGLE_TOKEN_CONVERTER_IMP_BSC); }); + describe("TreasuryConverter", () => { + it("should not be paused", async () => { + expect(await treasuryConverter.conversionPaused()).to.be.false; + }); + + it("should have Treasury as destination for conversion", async () => { + const destinationAddress = await treasuryConverter.destinationAddress(); + expect(destinationAddress.toLowerCase()).to.equal(bsctestnet.VTREASURY.toLowerCase()); + }); + + it("should have correct owner", async () => { + expect(await treasuryConverter.owner()).to.equal(bsctestnet.NORMAL_TIMELOCK); + }); + + it("should have correct converters network address", async () => { + expect(await treasuryConverter.converterNetwork()).to.equal(TREASURY_CONVERTER.bsctestnet.converterNetwork); + }); + + it("should have correct conversion configuration", async () => { + const { tokenIn, tokensOut } = TREASURY_CONVERTER.bsctestnet; + + for (const tokenOut of tokensOut) { + const config = await treasuryConverter.conversionConfigurations(tokenIn, tokenOut); + + expect(config.incentive).to.equal(BSCTESTNET_CONVERSION_INCENTIVE); + expect(config.conversionAccess).to.equal(ConversionAccessibility.ALL); + } + }); + + it("guardian should have all permissions to call TreasuryConverter", async () => { + const pauseConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSCTESTNET, "pauseConversion()"], + ); + const pauseConversionRoleHash = ethers.utils.keccak256(pauseConversionRole); + expect(await acm.hasRole(pauseConversionRoleHash, bsctestnet.GUARDIAN)).to.be.true; + + const resumeConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSCTESTNET, "resumeConversion()"], + ); + const resumeConversionRoleHash = ethers.utils.keccak256(resumeConversionRole); + expect(await acm.hasRole(resumeConversionRoleHash, bsctestnet.GUARDIAN)).to.be.true; + + const setMinAmountToConvertRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSCTESTNET, "setMinAmountToConvert(uint256)"], + ); + const setMinAmountToConvertRoleHash = ethers.utils.keccak256(setMinAmountToConvertRole); + expect(await acm.hasRole(setMinAmountToConvertRoleHash, bsctestnet.GUARDIAN)).to.be.true; + + const setConversionConfigRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSCTESTNET, "setConversionConfig(address,address,ConversionConfig)"], + ); + const setConversionConfigRoleHash = ethers.utils.keccak256(setConversionConfigRole); + expect(await acm.hasRole(setConversionConfigRoleHash, bsctestnet.GUARDIAN)).to.be.true; + }); + + it("Regular timelock should have true permissions to call TreasuryConverter", async () => { + const pauseConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSCTESTNET, "pauseConversion()"], + ); + const pauseConversionRoleHash = ethers.utils.keccak256(pauseConversionRole); + expect(await acm.hasRole(pauseConversionRoleHash, bsctestnet.NORMAL_TIMELOCK)).to.be.true; + + const resumeConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSCTESTNET, "resumeConversion()"], + ); + const resumeConversionRoleHash = ethers.utils.keccak256(resumeConversionRole); + expect(await acm.hasRole(resumeConversionRoleHash, bsctestnet.NORMAL_TIMELOCK)).to.be.true; + + const setMinAmountToConvertRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSCTESTNET, "setMinAmountToConvert(uint256)"], + ); + const setMinAmountToConvertRoleHash = ethers.utils.keccak256(setMinAmountToConvertRole); + expect(await acm.hasRole(setMinAmountToConvertRoleHash, bsctestnet.NORMAL_TIMELOCK)).to.be.true; + + const setConversionConfigRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSCTESTNET, "setConversionConfig(address,address,ConversionConfig)"], + ); + const setConversionConfigRoleHash = ethers.utils.keccak256(setConversionConfigRole); + expect(await acm.hasRole(setConversionConfigRoleHash, bsctestnet.NORMAL_TIMELOCK)).to.be.true; + }); + + it("Fast Track timelock should have true permissions to call TreasuryConverter", async () => { + const pauseConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSCTESTNET, "pauseConversion()"], + ); + const pauseConversionRoleHash = ethers.utils.keccak256(pauseConversionRole); + expect(await acm.hasRole(pauseConversionRoleHash, bsctestnet.FAST_TRACK_TIMELOCK)).to.be.true; + + const resumeConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSCTESTNET, "resumeConversion()"], + ); + const resumeConversionRoleHash = ethers.utils.keccak256(resumeConversionRole); + expect(await acm.hasRole(resumeConversionRoleHash, bsctestnet.FAST_TRACK_TIMELOCK)).to.be.true; + + const setMinAmountToConvertRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSCTESTNET, "setMinAmountToConvert(uint256)"], + ); + const setMinAmountToConvertRoleHash = ethers.utils.keccak256(setMinAmountToConvertRole); + expect(await acm.hasRole(setMinAmountToConvertRoleHash, bsctestnet.FAST_TRACK_TIMELOCK)).to.be.true; + + const setConversionConfigRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSCTESTNET, "setConversionConfig(address,address,ConversionConfig)"], + ); + const setConversionConfigRoleHash = ethers.utils.keccak256(setConversionConfigRole); + expect(await acm.hasRole(setConversionConfigRoleHash, bsctestnet.FAST_TRACK_TIMELOCK)).to.be.true; + }); + + it("Critical timelock should have true permissions to call TreasuryConverter", async () => { + const pauseConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSCTESTNET, "pauseConversion()"], + ); + const pauseConversionRoleHash = ethers.utils.keccak256(pauseConversionRole); + expect(await acm.hasRole(pauseConversionRoleHash, bsctestnet.CRITICAL_TIMELOCK)).to.be.true; + + const resumeConversionRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSCTESTNET, "resumeConversion()"], + ); + const resumeConversionRoleHash = ethers.utils.keccak256(resumeConversionRole); + expect(await acm.hasRole(resumeConversionRoleHash, bsctestnet.CRITICAL_TIMELOCK)).to.be.true; + + const setMinAmountToConvertRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSCTESTNET, "setMinAmountToConvert(uint256)"], + ); + const setMinAmountToConvertRoleHash = ethers.utils.keccak256(setMinAmountToConvertRole); + expect(await acm.hasRole(setMinAmountToConvertRoleHash, bsctestnet.CRITICAL_TIMELOCK)).to.be.true; + + const setConversionConfigRole = ethers.utils.solidityPack( + ["address", "string"], + [TREASURY_CONVERTER_BSCTESTNET, "setConversionConfig(address,address,ConversionConfig)"], + ); + const setConversionConfigRoleHash = ethers.utils.keccak256(setConversionConfigRole); + expect(await acm.hasRole(setConversionConfigRoleHash, bsctestnet.CRITICAL_TIMELOCK)).to.be.true; + }); + }); }); }); diff --git a/simulations/vip-536/ethereum.ts b/simulations/vip-536/ethereum.ts index 809d1ee89..857e0e7d4 100644 --- a/simulations/vip-536/ethereum.ts +++ b/simulations/vip-536/ethereum.ts @@ -6,15 +6,18 @@ import { expectEvents } from "src/utils"; import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; import vip536, { - ConversionAccessibility, - ETHEREUM_CONVERSION_INCENTIVE, NEW_SINGLE_TOKEN_CONVERTER_IMP_ETHEREUM, SINGLE_TOKEN_CONVERTER_BEACON_ETHEREUM, +} from "../../vips/vip-536/bscmainnet"; +import { + ConversionAccessibility, + ETHEREUM_CONVERSION_INCENTIVE, TREASURY_CONVERTER, TREASURY_CONVERTER_ETHEREUM, -} from "../../vips/vip-536/bscmainnet"; +} from "../../vips/vip-536/configuration"; import ACCESS_CONTROLL_MANAGER_ABI from "./abi/AccessControlManager.json"; import BEACON_ABI from "./abi/Beacon.json"; +import PSR_ABI from "./abi/ProtocolShareReserve.json"; import CONVERTER_ABI from "./abi/singletokenconverter.json"; const { ethereum } = NETWORK_ADDRESSES; @@ -49,9 +52,16 @@ forking(23017363, async () => { callbackAfterExecution: async (txResponse: any) => { await expectEvents( txResponse, - [BEACON_ABI, CONVERTER_ABI], - ["Upgraded", "ConverterNetworkAddressUpdated", "OwnershipTransferred", "ConversionConfigUpdated"], - [1, 1, 2, 3], + [BEACON_ABI, CONVERTER_ABI, PSR_ABI], + [ + "Upgraded", + "ConverterNetworkAddressUpdated", + "ConversionConfigUpdated", + "DistributionConfigAdded", + "DistributionConfigUpdated", + "DistributionConfigRemoved", + ], + [1, 1, TREASURY_CONVERTER.ethereum.tokensOut.length, 2, 2, 2], ); }, }); @@ -78,7 +88,7 @@ forking(23017363, async () => { }); it("should have correct conversion configuration", async () => { - const { tokenIn, tokenOuts } = TREASURY_CONVERTER.ethereum; + const { tokenIn, whitelistedTokens: tokenOuts } = TREASURY_CONVERTER.ethereum; for (const tokenOut of tokenOuts) { const config = await treasuryConverter.conversionConfigurations(tokenIn, tokenOut); diff --git a/src/networkAddresses.ts b/src/networkAddresses.ts index 4df839cf1..52bcd133e 100644 --- a/src/networkAddresses.ts +++ b/src/networkAddresses.ts @@ -1,5 +1,7 @@ +import govArbitrumContracts from "@venusprotocol/governance-contracts/deployments/arbitrumone_addresses.json"; import govBscmainnetContracts from "@venusprotocol/governance-contracts/deployments/bscmainnet_addresses.json"; import govBsctestnetContracts from "@venusprotocol/governance-contracts/deployments/bsctestnet_addresses.json"; +import govEthereumContracts from "@venusprotocol/governance-contracts/deployments/ethereum_addresses.json"; import ilBscmainnetDeployedContracts from "@venusprotocol/isolated-pools/deployments/bscmainnet_addresses.json"; import ilBsctestnetDeployedContracts from "@venusprotocol/isolated-pools/deployments/bsctestnet_addresses.json"; import ilEthereumDeployedContracts from "@venusprotocol/isolated-pools/deployments/ethereum_addresses.json"; @@ -27,6 +29,7 @@ export const NETWORK_ADDRESSES = { bscmainnet: { DEFAULT_PROPOSER_ADDRESS: "0x97a32D4506F6A35De68e0680859cDF41D077a9a9", ACCESS_CONTROL_MANAGER: "0x4788629ABc6cFCA10F9f969efdEAa1cF70c23555", + ACM_AGGREGATOR: govBscmainnetContracts.addresses.ACMCommandsAggregator, GOVERNOR_PROXY: govBscmainnetContracts.addresses.GovernorBravoDelegator, NORMAL_TIMELOCK: govBscmainnetContracts.addresses.NormalTimelock, FAST_TRACK_TIMELOCK: govBscmainnetContracts.addresses.FastTrackTimelock, @@ -53,6 +56,7 @@ export const NETWORK_ADDRESSES = { DEFAULT_PROPOSER_ADDRESS: "0x2Ce1d0ffD7E869D9DF33e28552b12DdDed326706", GUARDIAN: "0x2Ce1d0ffD7E869D9DF33e28552b12DdDed326706", ACCESS_CONTROL_MANAGER: govBsctestnetContracts.addresses.AccessControlManager, + ACM_AGGREGATOR: govBsctestnetContracts.addresses.ACMCommandsAggregator, GOVERNOR_PROXY: govBsctestnetContracts.addresses.GovernorBravoDelegator, NORMAL_TIMELOCK: govBsctestnetContracts.addresses.NormalTimelock, FAST_TRACK_TIMELOCK: govBsctestnetContracts.addresses.FastTrackTimelock, @@ -76,6 +80,7 @@ export const NETWORK_ADDRESSES = { }, ethereum: { ACCESS_CONTROL_MANAGER: "0x230058da2D23eb8836EC5DB7037ef7250c56E25E", + ACM_AGGREGATOR: govEthereumContracts.addresses.ACMCommandsAggregator, NORMAL_TIMELOCK: "0xd969E79406c35E80750aAae061D402Aab9325714", FAST_TRACK_TIMELOCK: "0x8764F50616B62a99A997876C2DEAaa04554C5B2E", CRITICAL_TIMELOCK: "0xeB9b85342c34F65af734C7bd4a149c86c472bC00", @@ -163,6 +168,7 @@ export const NETWORK_ADDRESSES = { }, arbitrumone: { ACCESS_CONTROL_MANAGER: "0xD9dD18EB0cf10CbA837677f28A8F9Bda4bc2b157", + ACM_AGGREGATOR: govArbitrumContracts.addresses.ACMCommandsAggregator, NORMAL_TIMELOCK: "0x4b94589Cc23F618687790036726f744D602c4017", FAST_TRACK_TIMELOCK: "0x2286a9B2a5246218f2fC1F380383f45BDfCE3E04", CRITICAL_TIMELOCK: "0x181E4f8F21D087bF02Ea2F64D5e550849FBca674", diff --git a/src/permissions.ts b/src/permissions.ts new file mode 100644 index 000000000..d67a7b561 --- /dev/null +++ b/src/permissions.ts @@ -0,0 +1,272 @@ +import { ACMCommandsAggregator } from "@venusprotocol/governance-contracts/typechain/contracts/Utils/ACMCommandsAggregator"; +import { ethers } from "hardhat"; + +export enum AccountType { + NORMAL_TIMELOCK = "NormalTimelock", + FAST_TRACK_TIMELOCK = "FastTrackTimelock", + CRITICAL_TIMELOCK = "CriticalTimelock", + GUARDIAN = "Guardian", + POOL_REGISTRY = "PoolRegistry", + XVS_BRIDGE_DEST = "XVSBridgeDest", +} + +const timelocks = [AccountType.NORMAL_TIMELOCK] + .concat(AccountType.CRITICAL_TIMELOCK) + .concat(AccountType.FAST_TRACK_TIMELOCK); + +const accounts = timelocks.concat(AccountType.GUARDIAN); + +export const getResilientOraclePermissions = (resilientOracle: string): string[][] => { + return [ + ...accounts.map(account => [resilientOracle, "pause()", account]), + ...accounts.map(account => [resilientOracle, "unpause()", account]), + ...accounts.map(account => [resilientOracle, "setTokenConfig(TokenConfig)", account]), + [resilientOracle, "setOracle(address,address,uint8)", AccountType.NORMAL_TIMELOCK], + [resilientOracle, "enableOracle(address,uint8,bool)", AccountType.NORMAL_TIMELOCK], + ]; +}; + +export const getChainlinkOraclePermissions = (chainlinkOracle: string): string[][] => { + return [ + ...accounts.map(account => [chainlinkOracle, "setTokenConfig(TokenConfig)", account]), + ...accounts.map(account => [chainlinkOracle, "setDirectPrice(address,uint256)", account]), + ]; +}; + +export const getRedstoneOraclePermissions = (redstoneOracle: string): string[][] => { + return [ + ...accounts.map(account => [redstoneOracle, "setTokenConfig(TokenConfig)", account]), + ...accounts.map(account => [redstoneOracle, "setDirectPrice(address,uint256)", account]), + ]; +}; + +export const getBoundValidatorPermissions = (boundValidator: string): string[][] => { + return [[boundValidator, "setValidateConfig(ValidateConfig)", AccountType.NORMAL_TIMELOCK]]; +}; + +export const getSFrxETHOraclePermissions = (sFrxETHOracle: string): string[][] => { + return [...timelocks.map(account => [sFrxETHOracle, "setMaxAllowedPriceDifference(uint256)", account])]; +}; + +export const getBinanceOraclePermissions = (binanceOracle: string): string[][] => { + return [ + ...accounts.map(account => [binanceOracle, "setMaxStalePeriod(string,uint256)", account]), + ...accounts.map(account => [binanceOracle, "setSymbolOverride(string,string)", account]), + ]; +}; + +export const getXVSPermissions = (xvs: string): string[][] => { + return [ + ...accounts.map(account => [xvs, "migrateMinterTokens(address,address)", account]), + ...accounts.map(account => [xvs, "setMintCap(address,uint256)", account]), + ...accounts.map(account => [xvs, "updateBlacklist(address,bool)", account]), + ...accounts.map(account => [xvs, "pause()", account]), + ...accounts.map(account => [xvs, "unpause()", account]), + [xvs, "mint(address,uint256)", AccountType.XVS_BRIDGE_DEST], + [xvs, "burn(address,uint256)", AccountType.XVS_BRIDGE_DEST], + ]; +}; + +export const getXVSBridgeAdminPermissions = (xvsBridgeAdmin: string): string[][] => { + return [ + ...timelocks.map(account => [xvsBridgeAdmin, "setSendVersion(uint16)", account]), + ...timelocks.map(account => [xvsBridgeAdmin, "setReceiveVersion(uint16)", account]), + ...timelocks.map(account => [xvsBridgeAdmin, "forceResumeReceive(uint16,bytes)", account]), + ...accounts.map(account => [xvsBridgeAdmin, "setMaxSingleTransactionLimit(uint16,uint256)", account]), + [xvsBridgeAdmin, "setOracle(address)", AccountType.NORMAL_TIMELOCK], + ...accounts.map(account => [xvsBridgeAdmin, "setMaxDailyLimit(uint16,uint256)", account]), + ...accounts.map(account => [xvsBridgeAdmin, "setMaxSingleReceiveTransactionLimit(uint16,uint256)", account]), + ...accounts.map(account => [xvsBridgeAdmin, "setMaxDailyReceiveLimit(uint16,uint256)", account]), + ...accounts.map(account => [xvsBridgeAdmin, "pause()", account]), + ...accounts.map(account => [xvsBridgeAdmin, "unpause()", account]), + ...timelocks.map(account => [xvsBridgeAdmin, "removeTrustedRemote(uint16)", account]), + ...timelocks.map(account => [xvsBridgeAdmin, "dropFailedMessage(uint16,bytes,uint64)", account]), + [xvsBridgeAdmin, "setPrecrime(address)", AccountType.NORMAL_TIMELOCK], + ...timelocks.map(account => [xvsBridgeAdmin, "setMinDstGas(uint16,uint16,uint256)", account]), + ...timelocks.map(account => [xvsBridgeAdmin, "setPayloadSizeLimit(uint16,uint256)", account]), + ...timelocks.map(account => [xvsBridgeAdmin, "setWhitelist(address,bool)", account]), + ...timelocks.map(account => [xvsBridgeAdmin, "setConfig(uint16,uint16,uint256,bytes)", account]), + [xvsBridgeAdmin, "sweepToken(address,address,uint256)", AccountType.NORMAL_TIMELOCK], + ...timelocks.map(account => [xvsBridgeAdmin, "updateSendAndCallEnabled(bool)", account]), + [xvsBridgeAdmin, "setTrustedRemoteAddress(uint16,bytes)", AccountType.NORMAL_TIMELOCK], + [xvsBridgeAdmin, "transferBridgeOwnership(address)", AccountType.NORMAL_TIMELOCK], + ]; +}; + +export const getXVSVaultPermissions = (xvsVault: string): string[][] => { + return [ + [xvsVault, "pause()", AccountType.CRITICAL_TIMELOCK], + [xvsVault, "resume()", AccountType.CRITICAL_TIMELOCK], + [xvsVault, "setRewardAmountPerBlockOrSecond(address,uint256)", AccountType.CRITICAL_TIMELOCK], + [xvsVault, "pause()", AccountType.FAST_TRACK_TIMELOCK], + [xvsVault, "resume()", AccountType.FAST_TRACK_TIMELOCK], + [xvsVault, "setRewardAmountPerBlockOrSecond(address,uint256)", AccountType.FAST_TRACK_TIMELOCK], + [xvsVault, "pause()", AccountType.NORMAL_TIMELOCK], + [xvsVault, "resume()", AccountType.NORMAL_TIMELOCK], + [xvsVault, "add(address,uint256,address,uint256,uint256)", AccountType.NORMAL_TIMELOCK], + [xvsVault, "set(address,uint256,uint256)", AccountType.NORMAL_TIMELOCK], + [xvsVault, "setRewardAmountPerBlockOrSecond(address,uint256)", AccountType.NORMAL_TIMELOCK], + [xvsVault, "setWithdrawalLockingPeriod(address,uint256,uint256)", AccountType.NORMAL_TIMELOCK], + [xvsVault, "pause()", AccountType.GUARDIAN], + [xvsVault, "resume()", AccountType.GUARDIAN], + ]; +}; + +export const getPoolRegistryPermissions = (poolRegistry: string): string[][] => { + return [ + [poolRegistry, "addPool(string,address,uint256,uint256,uint256)", AccountType.NORMAL_TIMELOCK], + [poolRegistry, "addMarket(AddMarketInput)", AccountType.NORMAL_TIMELOCK], + [poolRegistry, "setPoolName(address,string)", AccountType.NORMAL_TIMELOCK], + [poolRegistry, "updatePoolMetadata(address,VenusPoolMetaData)", AccountType.NORMAL_TIMELOCK], + ]; +}; + +export const getPrimePermissions = (prime: string): string[][] => { + return [ + ...timelocks.map(account => [prime, "updateAlpha(uint128,uint128)", account]), + ...timelocks.map(account => [prime, "updateMultipliers(address,uint256,uint256)", account]), + ...timelocks.map(account => [prime, "setStakedAt(address[],uint256[])", account]), + ...timelocks.map(account => [prime, "addMarket(address,address,uint256,uint256)", account]), + ...timelocks.map(account => [prime, "setLimit(uint256,uint256)", account]), + ...timelocks.map(account => [prime, "setMaxLoopsLimit(uint256)", account]), + ...timelocks.map(account => [prime, "issue(bool,address[])", account]), + ...timelocks.map(account => [prime, "burn(address)", account]), + ...accounts.map(account => [prime, "togglePause()", account]), + ]; +}; + +export const getPrimeLiquidityProviderPermissions = (primeLiquidityProvider: string): string[][] => { + return [ + ...timelocks.map(account => [primeLiquidityProvider, "setTokensDistributionSpeed(address[],uint256[])", account]), + ...timelocks.map(account => [ + primeLiquidityProvider, + "setMaxTokensDistributionSpeed(address[],uint256[])", + account, + ]), + ...timelocks.map(account => [primeLiquidityProvider, "setMaxLoopsLimit(uint256)", account]), + ...accounts.map(account => [primeLiquidityProvider, "pauseFundsTransfer()", account]), + ...accounts.map(account => [primeLiquidityProvider, "resumeFundsTransfer()", account]), + ]; +}; + +export const getProtocolShareReservePermissions = (protocolShareReserve: string): string[][] => { + return [ + ...accounts.map(account => [protocolShareReserve, "addOrUpdateDistributionConfigs(DistributionConfig[])", account]), + ...accounts.map(account => [protocolShareReserve, "removeDistributionConfig(Schema,address)", account]), + ]; +}; + +export const getConverterNetworkPermissions = (converterNetwork: string): string[][] => { + return [ + ...timelocks.map(account => [converterNetwork, "addTokenConverter(address)", account]), + ...timelocks.map(account => [converterNetwork, "removeTokenConverter(address)", account]), + ]; +}; + +export const getComptrollerPermissions = (): string[][] => { + return [ + ...accounts + .concat(AccountType.POOL_REGISTRY) + .map(account => [ethers.constants.AddressZero, "setCollateralFactor(address,uint256,uint256)", account]), + ...accounts + .concat(AccountType.POOL_REGISTRY) + .map(account => [ethers.constants.AddressZero, "setMarketBorrowCaps(address[],uint256[])", account]), + ...accounts + .concat(AccountType.POOL_REGISTRY) + .map(account => [ethers.constants.AddressZero, "setMarketSupplyCaps(address[],uint256[])", account]), + ...accounts.map(account => [ethers.constants.AddressZero, "setActionsPaused(address[],uint256[],bool)", account]), + ...timelocks.map(account => [ethers.constants.AddressZero, "setForcedLiquidation(address,bool)", account]), + ...accounts.map(account => [ethers.constants.AddressZero, "unlistMarket(address)", account]), + [ethers.constants.AddressZero, "setCloseFactor(uint256)", AccountType.NORMAL_TIMELOCK], + [ethers.constants.AddressZero, "setLiquidationIncentive(uint256)", AccountType.NORMAL_TIMELOCK], + [ethers.constants.AddressZero, "setMinLiquidatableCollateral(uint256)", AccountType.NORMAL_TIMELOCK], + [ethers.constants.AddressZero, "setCloseFactor(uint256)", AccountType.POOL_REGISTRY], + [ethers.constants.AddressZero, "setLiquidationIncentive(uint256)", AccountType.POOL_REGISTRY], + [ethers.constants.AddressZero, "setMinLiquidatableCollateral(uint256)", AccountType.POOL_REGISTRY], + [ethers.constants.AddressZero, "supportMarket(address)", AccountType.POOL_REGISTRY], + ]; +}; + +export const getVTokenPermissions = (): string[][] => { + return [ + ...timelocks.map(account => [ethers.constants.AddressZero, "setReserveFactor(uint256)", account]), + ...timelocks.map(account => [ethers.constants.AddressZero, "setInterestRateModel(address)", account]), + ...timelocks.map(account => [ethers.constants.AddressZero, "setReduceReservesBlockDelta(uint256)", account]), + [ethers.constants.AddressZero, "setProtocolSeizeShare(uint256)", AccountType.NORMAL_TIMELOCK], + ]; +}; + +export const getRewardDistributorPermissionsTimebased = (): string[][] => { + return [ + [ethers.constants.AddressZero, "setRewardTokenSpeeds(address[],uint256[],uint256[])", AccountType.NORMAL_TIMELOCK], + [ + ethers.constants.AddressZero, + "setLastRewardingBlockTimestamps(address[],uint256[],uint256[])", + AccountType.NORMAL_TIMELOCK, + ], + ]; +}; + +export const getRewardDistributorPermissionsBlockbased = (): string[][] => { + return [ + [ethers.constants.AddressZero, "setRewardTokenSpeeds(address[],uint256[],uint256[])", AccountType.NORMAL_TIMELOCK], + [ethers.constants.AddressZero, "setLastRewardingBlocks(address[],uint32[],uint32[])", AccountType.NORMAL_TIMELOCK], + ]; +}; + +export const getIRMPermissions = (): string[][] => { + return [ + [ethers.constants.AddressZero, "updateJumpRateModel(uint256,uint256,uint256,uint256)", AccountType.NORMAL_TIMELOCK], + ]; +}; + +export const getConverterPermissions = (converter: string): string[][] => { + return [ + ...accounts.map(account => [converter, "pauseConversion()", account]), + ...accounts.map(account => [converter, "resumeConversion()", account]), + ...timelocks.map(account => [converter, "setMinAmountToConvert(uint256)", account]), + ...timelocks.map(account => [converter, "setConversionConfig(address,address,ConversionConfig)", account]), + ...timelocks.map(account => [converter, "setAssetsDirectTransfer(address[],bool[])", account]), + ]; +}; + +export const getXVSVaultTreasuryPermissions = (xvsVaultTreasury: string): string[][] => { + return [...timelocks.map(account => [xvsVaultTreasury, "fundXVSVault(uint256)", account])]; +}; + +export const getOmniChainExecutorOwnerPermissions = (omniChainExecutor: string): string[][] => { + return [ + [omniChainExecutor, "setSendVersion(uint16)", AccountType.NORMAL_TIMELOCK], + ...accounts.map(account => [omniChainExecutor, "setReceiveVersion(uint16)", account]), + [omniChainExecutor, "forceResumeReceive(uint16,bytes)", AccountType.GUARDIAN], + ...accounts.map(account => [omniChainExecutor, "setMaxDailyReceiveLimit(uint256)", account]), + ...accounts.map(account => [omniChainExecutor, "pause()", account]), + [omniChainExecutor, "unpause()", AccountType.GUARDIAN], + ...accounts.map(account => [omniChainExecutor, "addTimelocks(address[])", account]), + ...accounts.map(account => [omniChainExecutor, "setConfig(uint16,uint16,uint256,bytes)", account]), + [omniChainExecutor, "setTrustedRemoteAddress(uint16,bytes)", AccountType.GUARDIAN], + [omniChainExecutor, "setTrustedRemoteAddress(uint16,bytes)", AccountType.NORMAL_TIMELOCK], + [omniChainExecutor, "setTimelockPendingAdmin(address,uint8)", AccountType.GUARDIAN], + [omniChainExecutor, "setTimelockPendingAdmin(address,uint8)", AccountType.NORMAL_TIMELOCK], + ...accounts.map(account => [omniChainExecutor, "retryMessage(uint16,bytes,uint64,bytes)", account]), + [omniChainExecutor, "setGuardian(address)", AccountType.NORMAL_TIMELOCK], + [omniChainExecutor, "setSrcChainId(uint16)", AccountType.GUARDIAN], + [omniChainExecutor, "setSrcChainId(uint16)", AccountType.NORMAL_TIMELOCK], + [omniChainExecutor, "transferBridgeOwnership(address)", AccountType.GUARDIAN], + [omniChainExecutor, "transferBridgeOwnership(address)", AccountType.NORMAL_TIMELOCK], + ]; +}; + +export function splitPermissions( + array: ACMCommandsAggregator.PermissionStruct[], + chunkSize: number = 200, +): ACMCommandsAggregator.PermissionStruct[][] { + const result: ACMCommandsAggregator.PermissionStruct[][] = []; + + for (let i = 0; i < array.length; i += chunkSize) { + const chunk = array.slice(i, i + chunkSize); + result.push(chunk); + } + + return result; +} diff --git a/vips/vip-536/bscmainnet.ts b/vips/vip-536/bscmainnet.ts index f5f79a504..e5dbe5e03 100644 --- a/vips/vip-536/bscmainnet.ts +++ b/vips/vip-536/bscmainnet.ts @@ -2,173 +2,37 @@ import { NETWORK_ADDRESSES } from "src/networkAddresses"; import { LzChainId, ProposalType } from "src/types"; import { makeProposal } from "src/utils"; +import { TREASURY_CONVERTER } from "./configuration"; + export const SINGLE_TOKEN_CONVERTER_BEACON_BSC = "0x4c9D57b05B245c40235D720A5f3A592f3DfF11ca"; -export const NEW_SINGLE_TOKEN_CONVERTER_IMP_BSC = "0xF96363e03D175eEcc6A965f117e1497EAe878d29"; +export const NEW_SINGLE_TOKEN_CONVERTER_IMP_BSC = "0x7D90b5Bc23e6E6E59744F7DEbD12b1844A22bAEb"; // TODO: Change after deployment export const SINGLE_TOKEN_CONVERTER_BEACON_ETHEREUM = "0x5C0b5D09388F2BA6441E74D40666C4d96e4527D1"; -export const NEW_SINGLE_TOKEN_CONVERTER_IMP_ETHEREUM = "0x560E50dc157E7140C0E5bdF46e586c658C8A066c"; +export const NEW_SINGLE_TOKEN_CONVERTER_IMP_ETHEREUM = "0x560E50dc157E7140C0E5bdF46e586c658C8A066c"; // TODO: Change after deployment export const SINGLE_TOKEN_CONVERTER_BEACON_ARBITRUM = "0x993900Ab4ef4092e5B76d4781D09A2732086F0F0"; -export const NEW_SINGLE_TOKEN_CONVERTER_IMP_ARBITRUM = "0x2EE413F4e060451CB25AeD5Cdd348F430aa79105"; +export const NEW_SINGLE_TOKEN_CONVERTER_IMP_ARBITRUM = "0x2EE413F4e060451CB25AeD5Cdd348F430aa79105"; // TODO: Change after deployment -export const TREASURY_CONVERTER_BSC = "0x3d459f128cf6b938d6B7E626115F149F1567546f"; -export const TREASURY_CONVERTER_ETHEREUM = "0x47faB3596F221078f6e3A90B74504d5b9f9FaEC3"; -export const TREASURY_CONVERTER_ARBITRUM = "0x557684a9B7743B8D24Dbb1C0B88D659D56035f38"; +export const PSR_BSC = "0xCa01D5A9A248a830E9D93231e791B1afFed7c446"; +export const PSR_ETHEREUM = "0x8c8c8530464f7D95552A11eC31Adbd4dC4AC4d3E"; +export const PSR_ARBITRUM = "0xF9263eaF7eB50815194f26aCcAB6765820B13D41"; -export const BSC_CONVERSION_INCENTIVE = 1e14; -export const ARBITRUM_CONVERSION_INCENTIVE = 1e14; -export const ETHEREUM_CONVERSION_INCENTIVE = 1e13; +export const ACM_COMMANDS_GRANT_PERMISSION_ID_BSC = 1; // TODO: Change after tx to grant permissions +export const ACM_COMMANDS_GRANT_PERMISSION_ID_ETHEREUM = 2; // TODO: Change after tx to grant permissions +export const ACM_COMMANDS_GRANT_PERMISSION_ID_ARBITRUM = 3; // TODO: Change after tx to grant permissions const { bscmainnet, ethereum, arbitrumone } = NETWORK_ADDRESSES; -export enum ConversionAccessibility { - NONE = 0, - ALL = 1, - ONLY_FOR_CONVERTERS = 2, - ONLY_FOR_USERS = 3, -} - -export const TREASURY_CONVERTER = { - bscmainnet: { - converter: TREASURY_CONVERTER_BSC, - tokenIn: "0x55d398326f99059fF775485246999027B3197955", // USDT - tokenOuts: [ - "0x2170Ed0880ac9A755fd29B2688956BD959F933F8", // ETH - "0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c", // BTCB - "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", // BNB - "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d", // USDC - ], - conversionIncentive: new Array(4).fill([BSC_CONVERSION_INCENTIVE, ConversionAccessibility.ALL]), - converterNetwork: "0xF7Caad5CeB0209165f2dFE71c92aDe14d0F15995", - }, - ethereum: { - converter: TREASURY_CONVERTER_ETHEREUM, - tokenIn: "0xdAC17F958D2ee523a2206206994597C13D831ec7", // USDT - tokenOuts: [ - "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH - "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", // WBTC - "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC - ], - conversionIncentive: new Array(3).fill([ETHEREUM_CONVERSION_INCENTIVE, ConversionAccessibility.ALL]), - converterNetwork: "0x232CC47AECCC55C2CAcE4372f5B268b27ef7cac8", - }, - arbitrumone: { - converter: TREASURY_CONVERTER_ARBITRUM, - tokenIn: "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9", // USDT - tokenOuts: [ - "0x82af49447d8a07e3bd95bd0d56f35241523fbab1", // WETH - "0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f", // WBTC - "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", // USDC - ], - conversionIncentive: new Array(3).fill([ARBITRUM_CONVERSION_INCENTIVE, ConversionAccessibility.ALL]), - converterNetwork: "0x2F6672C9A0988748b0172D97961BecfD9DC6D6d5", - }, -}; - -function grantPremissions( - converter: string, +export function grantPremissions( + grantPermissionId: number, network: { - ACCESS_CONTROL_MANAGER: string; - NORMAL_TIMELOCK: string; - FAST_TRACK_TIMELOCK: string; - CRITICAL_TIMELOCK: string; - GUARDIAN: string; + ACM_AGGREGATOR: string; }, dstChainId?: LzChainId, ) { return [ { - target: network.ACCESS_CONTROL_MANAGER, - signature: "giveCallPermission(address,string,address)", - params: [converter, "pauseConversion()", network.NORMAL_TIMELOCK], - dstChainId, - }, - { - target: network.ACCESS_CONTROL_MANAGER, - signature: "giveCallPermission(address,string,address)", - params: [converter, "pauseConversion()", network.FAST_TRACK_TIMELOCK], - dstChainId, - }, - { - target: network.ACCESS_CONTROL_MANAGER, - signature: "giveCallPermission(address,string,address)", - params: [converter, "pauseConversion()", network.CRITICAL_TIMELOCK], - dstChainId, - }, - { - target: network.ACCESS_CONTROL_MANAGER, - signature: "giveCallPermission(address,string,address)", - params: [converter, "pauseConversion()", network.GUARDIAN], - dstChainId, - }, - { - target: network.ACCESS_CONTROL_MANAGER, - signature: "giveCallPermission(address,string,address)", - params: [converter, "resumeConversion()", network.NORMAL_TIMELOCK], - dstChainId, - }, - { - target: network.ACCESS_CONTROL_MANAGER, - signature: "giveCallPermission(address,string,address)", - params: [converter, "resumeConversion()", network.FAST_TRACK_TIMELOCK], - dstChainId, - }, - { - target: network.ACCESS_CONTROL_MANAGER, - signature: "giveCallPermission(address,string,address)", - params: [converter, "resumeConversion()", network.CRITICAL_TIMELOCK], - dstChainId, - }, - { - target: network.ACCESS_CONTROL_MANAGER, - signature: "giveCallPermission(address,string,address)", - params: [converter, "resumeConversion()", network.GUARDIAN], - dstChainId, - }, - { - target: network.ACCESS_CONTROL_MANAGER, - signature: "giveCallPermission(address,string,address)", - params: [converter, "setMinAmountToConvert(uint256)", network.NORMAL_TIMELOCK], - dstChainId, - }, - { - target: network.ACCESS_CONTROL_MANAGER, - signature: "giveCallPermission(address,string,address)", - params: [converter, "setMinAmountToConvert(uint256)", network.FAST_TRACK_TIMELOCK], - dstChainId, - }, - { - target: network.ACCESS_CONTROL_MANAGER, - signature: "giveCallPermission(address,string,address)", - params: [converter, "setMinAmountToConvert(uint256)", network.CRITICAL_TIMELOCK], - dstChainId, - }, - { - target: network.ACCESS_CONTROL_MANAGER, - signature: "giveCallPermission(address,string,address)", - params: [converter, "setMinAmountToConvert(uint256)", network.GUARDIAN], - dstChainId, - }, - { - target: network.ACCESS_CONTROL_MANAGER, - signature: "giveCallPermission(address,string,address)", - params: [converter, "setConversionConfig(address,address,ConversionConfig)", network.NORMAL_TIMELOCK], - dstChainId, - }, - { - target: network.ACCESS_CONTROL_MANAGER, - signature: "giveCallPermission(address,string,address)", - params: [converter, "setConversionConfig(address,address,ConversionConfig)", network.FAST_TRACK_TIMELOCK], - dstChainId, - }, - { - target: network.ACCESS_CONTROL_MANAGER, - signature: "giveCallPermission(address,string,address)", - params: [converter, "setConversionConfig(address,address,ConversionConfig)", network.CRITICAL_TIMELOCK], - dstChainId, - }, - { - target: network.ACCESS_CONTROL_MANAGER, - signature: "giveCallPermission(address,string,address)", - params: [converter, "setConversionConfig(address,address,ConversionConfig)", network.GUARDIAN], + target: network.ACM_AGGREGATOR, + signature: "executeGrantPermissions(uint256)", + params: [grantPermissionId], dstChainId, }, ]; @@ -211,7 +75,7 @@ export const vip536 = () => { signature: "acceptOwnership()", params: [], }, - ...grantPremissions(TREASURY_CONVERTER.bscmainnet.converter, bscmainnet), + ...grantPremissions(ACM_COMMANDS_GRANT_PERMISSION_ID_BSC, bscmainnet), { target: TREASURY_CONVERTER.bscmainnet.converter, signature: "setConverterNetwork(address)", @@ -222,7 +86,7 @@ export const vip536 = () => { signature: "setConversionConfigs(address,address[],(uint256,uint8)[])", params: [ TREASURY_CONVERTER.bscmainnet.tokenIn, - TREASURY_CONVERTER.bscmainnet.tokenOuts, + TREASURY_CONVERTER.bscmainnet.whitelistedTokens, TREASURY_CONVERTER.bscmainnet.conversionIncentive, ], }, @@ -233,7 +97,7 @@ export const vip536 = () => { params: [], dstChainId: LzChainId.ethereum, }, - ...grantPremissions(TREASURY_CONVERTER.ethereum.converter, ethereum, LzChainId.ethereum), + ...grantPremissions(ACM_COMMANDS_GRANT_PERMISSION_ID_ETHEREUM, ethereum, LzChainId.ethereum), { target: TREASURY_CONVERTER.ethereum.converter, signature: "setConverterNetwork(address)", @@ -245,7 +109,7 @@ export const vip536 = () => { signature: "setConversionConfigs(address,address[],(uint256,uint8)[])", params: [ TREASURY_CONVERTER.ethereum.tokenIn, - TREASURY_CONVERTER.ethereum.tokenOuts, + TREASURY_CONVERTER.ethereum.whitelistedTokens, TREASURY_CONVERTER.ethereum.conversionIncentive, ], dstChainId: LzChainId.ethereum, @@ -257,7 +121,7 @@ export const vip536 = () => { params: [], dstChainId: LzChainId.arbitrumone, }, - ...grantPremissions(TREASURY_CONVERTER.arbitrumone.converter, arbitrumone, LzChainId.arbitrumone), + ...grantPremissions(ACM_COMMANDS_GRANT_PERMISSION_ID_ARBITRUM, arbitrumone, LzChainId.arbitrumone), { target: TREASURY_CONVERTER.arbitrumone.converter, signature: "setConverterNetwork(address)", @@ -269,11 +133,65 @@ export const vip536 = () => { signature: "setConversionConfigs(address,address[],(uint256,uint8)[])", params: [ TREASURY_CONVERTER.arbitrumone.tokenIn, - TREASURY_CONVERTER.arbitrumone.tokenOuts, + TREASURY_CONVERTER.arbitrumone.whitelistedTokens, TREASURY_CONVERTER.arbitrumone.conversionIncentive, ], dstChainId: LzChainId.arbitrumone, }, + // Update PSR distribution configs BSCMainnet + { + target: TREASURY_CONVERTER.bscmainnet.psr, + signature: "addOrUpdateDistributionConfigs((uint8,uint16,address)[])", + params: [TREASURY_CONVERTER.bscmainnet.psrAddOrUpdateDistributionConfigsParams], + }, + { + target: TREASURY_CONVERTER.bscmainnet.psr, + signature: "removeDistributionConfig(uint8,address)", + params: [0, bscmainnet.VTREASURY], + }, + { + target: TREASURY_CONVERTER.bscmainnet.psr, + signature: "removeDistributionConfig(uint8,address)", + params: [1, bscmainnet.VTREASURY], + }, + // Update PSR distribution configs Ethereum + { + target: TREASURY_CONVERTER.ethereum.psr, + signature: "addOrUpdateDistributionConfigs((uint8,uint16,address)[])", + params: [TREASURY_CONVERTER.ethereum.psrAddOrUpdateDistributionConfigsParams], + dstChainId: LzChainId.ethereum, + }, + { + target: TREASURY_CONVERTER.ethereum.psr, + signature: "removeDistributionConfig(uint8,address)", + params: [0, ethereum.VTREASURY], + dstChainId: LzChainId.ethereum, + }, + { + target: TREASURY_CONVERTER.ethereum.psr, + signature: "removeDistributionConfig(uint8,address)", + params: [1, ethereum.VTREASURY], + dstChainId: LzChainId.ethereum, + }, + // // Update PSR distribution configs Arbitrum + { + target: TREASURY_CONVERTER.arbitrumone.psr, + signature: "addOrUpdateDistributionConfigs((uint8,uint16,address)[])", + params: [TREASURY_CONVERTER.arbitrumone.psrAddOrUpdateDistributionConfigsParams], + dstChainId: LzChainId.arbitrumone, + }, + { + target: TREASURY_CONVERTER.arbitrumone.psr, + signature: "removeDistributionConfig(uint8,address)", + params: [0, ethereum.VTREASURY], + dstChainId: LzChainId.arbitrumone, + }, + { + target: TREASURY_CONVERTER.arbitrumone.psr, + signature: "removeDistributionConfig(uint8,address)", + params: [1, ethereum.VTREASURY], + dstChainId: LzChainId.arbitrumone, + }, ], meta, ProposalType.REGULAR, diff --git a/vips/vip-536/bsctestnet.ts b/vips/vip-536/bsctestnet.ts index b6f544920..bd74e5c1c 100644 --- a/vips/vip-536/bsctestnet.ts +++ b/vips/vip-536/bsctestnet.ts @@ -1,13 +1,21 @@ -import { LzChainId, ProposalType } from "src/types"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { ProposalType } from "src/types"; import { makeProposal } from "src/utils"; +import { grantPremissions } from "./bscmainnet"; +import { TREASURY_CONVERTER } from "./configuration"; + export const SINGLE_TOKEN_CONVERTER_BEACON_BSC = "0xD2410D8B581D37c5B474CD9Ee0C15F02138AC028"; -export const NEW_SINGLE_TOKEN_CONVERTER_IMP_BSC = "0x892A70c9D9f946c0CB2b148f40B95Ba0024e8968"; +export const NEW_SINGLE_TOKEN_CONVERTER_IMP_BSC = "0x8279D424e85eeb431d72dDA5B971F40871ec8965"; export const SINGLE_TOKEN_CONVERTER_BEACON_ETHEREUM = "0xb86e532a5333d413A1c35d86cCdF1484B40219eF"; export const NEW_SINGLE_TOKEN_CONVERTER_IMP_ETHEREUM = "0x04444eAc8811140A3B22814a2203F6908d0708ad"; export const SINGLE_TOKEN_CONVERTER_BEACON_ARBITRUM = "0xC77D0F75f1e4e3720DA1D2F5D809F439125a2Fd4"; export const NEW_SINGLE_TOKEN_CONVERTER_IMP_ARBITRUM = "0xcf78eB1806660F0D001F786C66f294DADb9F95b0"; +const { bsctestnet } = NETWORK_ADDRESSES; + +export const ACM_COMMANDS_GRANT_PERMISSION_ID_BSCTESTNET = 1; + export const vip536 = () => { const meta = { version: "v2", @@ -21,22 +29,55 @@ export const vip536 = () => { return makeProposal( [ + // Upgrade SingleTokenConverter implementation { target: SINGLE_TOKEN_CONVERTER_BEACON_BSC, signature: "upgradeTo(address)", params: [NEW_SINGLE_TOKEN_CONVERTER_IMP_BSC], }, + // Treasury Converter configurations BSC Testnet { - target: SINGLE_TOKEN_CONVERTER_BEACON_ETHEREUM, - signature: "upgradeTo(address)", - params: [NEW_SINGLE_TOKEN_CONVERTER_IMP_ETHEREUM], - dstChainId: LzChainId.sepolia, + target: TREASURY_CONVERTER.bsctestnet.converter, + signature: "acceptOwnership()", + params: [], }, + ...grantPremissions(ACM_COMMANDS_GRANT_PERMISSION_ID_BSCTESTNET, bsctestnet), { - target: SINGLE_TOKEN_CONVERTER_BEACON_ARBITRUM, - signature: "upgradeTo(address)", - params: [NEW_SINGLE_TOKEN_CONVERTER_IMP_ARBITRUM], - dstChainId: LzChainId.arbitrumsepolia, + target: TREASURY_CONVERTER.bsctestnet.converter, + signature: "setConverterNetwork(address)", + params: [TREASURY_CONVERTER.bsctestnet.converterNetwork], + }, + { + target: TREASURY_CONVERTER.bsctestnet.converter, + signature: "setConversionConfigs(address,address[],(uint256,uint8)[])", + params: [ + TREASURY_CONVERTER.bsctestnet.tokenIn, + TREASURY_CONVERTER.bsctestnet.tokensOut, + TREASURY_CONVERTER.bsctestnet.conversionIncentive, + ], + }, + { + target: TREASURY_CONVERTER.bsctestnet.converter, + signature: "setAssetsDirectTransfer(address[],bool[])", + params: [ + TREASURY_CONVERTER.bsctestnet.whitelistedTokens, + new Array(TREASURY_CONVERTER.bsctestnet.whitelistedTokens.length).fill(true), + ], + }, + { + target: TREASURY_CONVERTER.bsctestnet.psr, + signature: "addOrUpdateDistributionConfigs((uint8,uint16,address)[])", + params: [TREASURY_CONVERTER.bsctestnet.psrAddOrUpdateDistributionConfigsParams], + }, + { + target: TREASURY_CONVERTER.bsctestnet.psr, + signature: "removeDistributionConfig(uint8,address)", + params: [0, bsctestnet.VTREASURY], + }, + { + target: TREASURY_CONVERTER.bsctestnet.psr, + signature: "removeDistributionConfig(uint8,address)", + params: [1, bsctestnet.VTREASURY], }, ], meta, diff --git a/vips/vip-536/configuration.ts b/vips/vip-536/configuration.ts new file mode 100644 index 000000000..ecbe1d0d4 --- /dev/null +++ b/vips/vip-536/configuration.ts @@ -0,0 +1,329 @@ +// Function to filter assets based on a base asset +const filterAssets = (assets: string[], baseAsset: string, whitelistedAssets: string[]) => + assets.filter( + asset => + asset.toLowerCase() !== baseAsset.toLowerCase() && + !whitelistedAssets.map(asset => asset.toLowerCase()).includes(asset.toLowerCase()), + ); + +export const ethereumAssets = [ + "0xba100000625a3754423978a60c9317c58a424e3D", // BAL + "0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E", // CRV_USD + "0xD533a949740bb3306d119CC777fa900bA034cd52", // CRV + "0x6B175474E89094C44Da98b954EedeAC495271d0F", // DAI + "0x853d955aCEf822Db058eb8505911ED77F175b99e", // FRAX + "0xA663B02CF0a4b149d2aD41910CB81e23e1c41c32", // SFRAX + "0x6ee2b5E19ECBa773a352E5B21415Dc419A700d1d", // PT-weETH-26DEC2024 + "0x0000000000085d4780B73119b644AE5ecd22b376", // TUSD + "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC + "0xdAC17F958D2ee523a2206206994597C13D831ec7", // USDT + "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", // WBTC + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH + "0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee", // W_E_ETH + "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", // WST_ETH + "0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7", // rsETH + "0xac3E018457B222d93114458476f3E3416Abbe38F", // sfrxETH + "0xbf5495Efe5DB9ce00f80364C8B423567e58d2110", // ezETH + "0x917ceE801a67f933F2e6b33fC0cD1ED2d5909D88", // weETHs + "0x657e8C867D8B37dCC18fA4Caead9C45EB088C642", // eBTC + "0xec53bF9167f50cDEB3Ae105f56099aaaB9061F83", // EIGEN + "0x8236a87084f8B84306f72007F36F2618A5634494", // LBTC + "0xD9A442856C234a39a81a089C06451EBAa4306a72", // pufETH + "0xE00bd3Df25fb187d6ABBB620b3dfd19839947b81", // PT-sUSDE + "0x8A47b431A7D947c6a3ED6E42d501803615a97EAa", // PT-USDe + "0x9D39A5DE30e57443BfF2A8307A4256c8797A3497", // sUSDe + "0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD", // SUSDS + "0x18084fbA666a33d37592fA2633fD49a74DD93a88", // tBTC + "0x4c9EDD5852cd905f086C759E8383e09bff1E68B3", // USDe + "0xdC035D45d973E3EC169d2276DDab16f1e407384F", // USDS + "0xBe53A109B494E5c9f97b9Cd39Fe969BE68BF6204", // yvUSDC-1 + "0x310B7Ea7475A0B449Cfd73bE81522F1B88eFAFaa", // yvUSDT-1 + "0x182863131F9a4630fF9E27830d945B1413e347E8", // yvUSDS-1 + "0xc56413869c6CDf96496f2b1eF801fEDBdFA7dDB0", // yvWETH-1 +]; + +export const arbitrumAssets = [ + "0x912ce59144191c1204e64559fe8253a0e49e6548", // ARB + "0x47c031236e19d024b42f8AE6780E44A573170703", // GM (gmBTC-USDC) + "0x70d95587d40A2caf56bd97485aB3Eec10Bee6336", // GM (gmWETH-USDC) + "0xaf88d065e77c8cc2239327c5edb3a432268e5831", // USDC + "0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9", // USDT + "0x2f2a2543b76a4166549f7aab2e75bef0aefc5b0f", // WBTC + "0x82af49447d8a07e3bd95bd0d56f35241523fbab1", // WETH + "0x35751007a407ca6FEFfE80b3cB397736D2cf4dbe", // weETH + "0x5979D7b546E38E414F7E9822514be443A4800529", // wstETH +]; + +export const bscmainnetAssets = Object.values({ + AAVE: "0xfb6115445Bff7b52FeB98650C87f44907E58f802", + ADA: "0x3EE2200Efb3400fAbB9AacF31297cBdD1d435D47", + BCH: "0x8fF795a6F4D97E7887C79beA79aba5cc76444aDf", + BETH: "0x250632378E573c6Be1AC2f97Fcdf00515d0Aa91B", + BTCB: "0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c", + BUSD: "0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56", + CAKE: "0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82", + DAI: "0x1AF3F329e8BE154074D8769D1FFa4eE058B1DBc3", + DOGE: "0xbA2aE424d960c26247Dd6c32edC70B295c744C43", + DOT: "0x7083609fCE4d1d8Dc0C979AAb8c869Ea2C873402", + ETH: "0x2170Ed0880ac9A755fd29B2688956BD959F933F8", + FIL: "0x0D8Ce2A99Bb6e3B7Db580eD848240e4a0F9aE153", + LINK: "0xF8A0BF9cF54Bb92F17374d9e9A321E6a111a51bD", + lisUSD: "0x0782b6d8c4551B9760e74c0545a9bCD90bdc41E5", + LTC: "0x4338665CBB7B2485A8855A139b75D5e34AB0DB94", + LUNA: "0x156ab3346823B651294766e23e6Cf87254d68962", + MATIC: "0xCC42724C6683B7E57334c4E856f4c9965ED682bD", + PT_sUSDE_26JUN2025: "0xDD809435ba6c9d6903730f923038801781cA66ce", + SOL: "0x570A5D26f7765Ecb712C0924E4De545B89fD43dF", + SolvBTC: "0x4aae823a6a0b376De6A78e74eCC5b079d38cBCf7", + sUSDe: "0x211Cc4DD073734dA055fbF44a2b4667d5E5fE5d2", + SXP: "0x47BEAd2563dCBf3bF2c9407fEa4dC236fAbA485A", + THE: "0xF4C8E32EaDEC4BFe97E0F595AdD0f4450a863a11", + TRX: "0xCE7de646e7208a4Ef112cb6ed5038FA6cC6b12e3", + TRXOLD: "0x85EAC5Ac2F758618dFa09bDbe0cf174e7d574D5B", + TUSD: "0x40af3827F39D0EAcBF4A168f8D4ee67c121D11c9", + TUSDOLD: "0x14016E85a25aeb13065688cAFB43044C2ef86784", + TWT: "0x4B0F1812e5Df2A09796481Ff14017e6005508003", + UNI: "0xBf5140A22578168FD562DCcF235E5D43A02ce9B1", + USDC: "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d", + USDe: "0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34", + USDT: "0x55d398326f99059fF775485246999027B3197955", + USD1: "0x8d0D000Ee44948FC98c9B98A4FA4921476f08B0d", + UST: "0x3d4350cD54aeF9f9b2C29435e0fa809957B3F30a", + VAI: "0x4BD17003473389A42DAF6a0a729f6Fdb328BbBd7", + WBETH: "0xa2e3356610840701bdf5611a53974510ae27e2e1", + XRP: "0x1D2F0da169ceB9fC7B3144628dB156f3F6c60dBE", + xSolvBTC: "0x1346b618dC92810EC74163e4c27004c921D446a5", + XVS: "0xcF6BB5389c92Bdda8a3747Ddb454cB7a64626C63", + PT_SolvBTC_27MAR2025_BBN: "0x541b5eeac7d4434c8f87e2d32019d67611179606", + ALPACA: "0x8F0528cE5eF7B51152A59745bEfDD91D97091d2F", + ANKR: "0xf307910A4c7bbc79691fD374889b36d8531B08e3", + ankrBNB: "0x52F24a5e03aee338Da5fd9Df68D2b6FAe1178827", + BSW: "0x965F527D9159dCe6288a2219DB51fc6Eef120dD1", + PLANET: "0xCa6d678e74f553f0E59cccC03ae644a3c2c5EE7d", + USDD: "0xd17479997f34dd9156deef8f95a52d81d265be9c", + FLOKI: "0xfb5B838b6cfEEdC2873aB27866079AC55363D37E", + RACA: "0x12BB890508c125661E03b09EC06E404bc9289040", + asBNB: "0x77734e70b6E88b4d82fE632a168EDf6e700912b6", + BNBx: "0x1bdd3Cf7F79cfB8EdbB955f20ad99211551BA275", + PT_clisBNB_25APR2025: "0xe8f1c9804770e11ab73395be54686ad656601e9e", + slisBNB: "0xB0b84D294e0C75A6abe60171b70edEb2EFd14A1B", + stkBNB: "0xc2E9d07F66A89c44062459A47a0D2Dc038E4fb16", + weETH: "0x04C0599Ae5A44757c0af6F9eC3b93da8976c150A", + wstETH: "0x26c5e01524d2E6280A48F2c50fF6De7e52E9611C", + BabyDoge: "0xc748673057861a797275CD8A068AbB95A902e8de", + EURA: "0x12f31B73D812C6Bb0d735a218c086d44D5fe5f89", + BTT: "0x352Cb5E19b12FC216548a2677bD0fce83BaE434B", + WIN: "0xaeF0d72a118ce24feE3cD1d43d383897D05B4e99", + FDUSD: "0xc5f0f7b66764F6ec8C8Dff7BA683102295E16409", +}); + +export const bsctestnetAssets = [ + "0x4B7268FC7C727B88c5Fc127D41b491BfAe63e144", // AAVE + "0xcD34BC54106bd45A04Ed99EBcC2A6a3e70d7210F", // ADA + "0xc625f060ad25f4A6c2d9eBF30C133dB61B7AF072", // asBNB + "0xA808e341e8e723DC6BA0Bb5204Bafc2330d7B8e4", // BTCB + "0x8301F2213c0eeD49a7E28Ae4c3e91722919B8B47", // BUSD + "0xe8bd7cCC165FAEb9b81569B05424771B9A20cbEF", // CAKE + "0x67D262CE2b8b846d9B94060BC04DC40a83F0e25B", // DOGE + "0x98f7A83361F7Ac8765CcEBAB1425da6b341958a7", // ETH + "0xcF27439fA231af9931ee40c4f27Bb77B83826F3C", // FDUSD + "0xe73774DfCD551BF75650772dC2cC56a2B6323453", // lisUSD + "0x969F147B6b8D81f86175de33206A4FD43dF17913", // LTC + "0xf36160EC62E3B191EA375dadfe465E8Fa1F8CabB", // LUNA + "0xcfeb0103d4BEfa041EA4c2dACce7B3E83E1aE7E3", // MATIC + "0x95e58161BA2423c3034658d957F3f5b94DeAbf81", // PT-sUSDE-26JUN2025 + "0xC337Dd0390FdFD0Ee5D2b682E425986EDD7b59da", // SOL + "0x6855E14A6df91b8E4D55163d068E9ef2530fd4CE", // SolvBTC + "0xcFec590e417Abb378cfEfE6296829E35fa25cEbd", // sUSDe + "0x75107940Cf1121232C0559c747A986DEfbc69DA9", // SXP + "0x952653d23cB9bef19E442D2BF8fBc8843A968052", // THE + "0x7D21841DC10BA1C5797951EFc62fADBBDD06704B", // TRX + "0x19E7215abF8B2716EE807c9f4b83Af0e7f92653F", // TRXOLD + "0xB32171ecD878607FFc4F8FC0bCcE6852BB3149E0", // TUSD + "0xFeC3A63401Eb9C1476200d7C32c4009Be0154169", // TUSDOLD + "0xb99c6b26fdf3678c6e2aff8466e3625a0e7182f8", // TWT + "0x8D2f061C75780d8D91c10A7230B907411aCBC8fC", // UNI + "0x16227D60f7a0e586C66B005219dfc887D13C9531", // USDC + "0x986C30591f5aAb401ea3aa63aFA595608721B1B9", // USDe + "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", // USDT + "0x7792af341a10ccc4B1CDd7B317F0460a37346a0A", // USD1 + "0x5A79efD958432E72211ee73D5DDFa9bc8f248b5F", // UST + "0x5fFbE5302BadED40941A403228E6AD03f93752d9", // VAI + "0xf9F98365566F4D55234f24b99caA1AfBE6428D44", // WBETH + "0x3022A32fdAdB4f02281E8Fab33e0A6811237aab0", // XRP + "0x3ea87323806586A0282b50377e0FEa76070F532B", // xSolvBTC + "0xB9e0E753630434d7863528cc73CB7AC638a7c8ff", // XVS +]; + +export const TREASURY_CONVERTER_BSC = "0x3d459f128cf6b938d6B7E626115F149F1567546f"; +export const RISK_FUND_CONVERTER_BSC = "0xA5622D276CcbB8d9BBE3D1ffd1BB11a0032E53F0"; +export const VTREASURY_BSC = "0xf322942f644a996a617bd29c16bd7d231d9f35e9"; +export const XVS_VAULT_CONVERTER_BSC = "0xd5b9AE835F4C59272032B3B954417179573331E0"; +export const USDC_PRIME_CONVERTER_BSC = "0xa758c9C215B6c4198F0a0e3FA46395Fa15Db691b"; +export const USDT_PRIME_CONVERTER_BSC = "0xD9f101AA67F3D72662609a2703387242452078C3"; +export const BTCB_PRIME_CONVERTER_BSC = "0xE8CeAa79f082768f99266dFd208d665d2Dd18f53"; +export const ETH_PRIME_CONVERTER_BSC = "0xca430B8A97Ea918fF634162acb0b731445B8195E"; +export const BURNING_CONVERTER_BSC = "0x9eF79830e626C8ccA7e46DCEd1F90e51E7cFCeBE"; + +export const TREASURY_CONVERTER_ETHEREUM = "0x47faB3596F221078f6e3A90B74504d5b9f9FaEC3"; +export const VTREASURY_ETHEREUM = "0xFD9B071168bC27DBE16406eC3Aba050Ce8Eb22FA"; +export const USDT_PRIME_CONVERTER_ETHEREUM = "0x4f55cb0a24D5542a3478B0E284259A6B850B06BD"; +export const USDC_PRIME_CONVERTER_ETHEREUM = "0xcEB9503f10B781E30213c0b320bCf3b3cE54216E"; +export const WBTC_PRIME_CONVERTER_ETHEREUM = "0xDcCDE673Cd8988745dA384A7083B0bd22085dEA0"; +export const WETH_PRIME_CONVERTER_ETHEREUM = "0xb8fD67f215117FADeF06447Af31590309750529D"; +export const XVS_VAULT_CONVERTER_ETHEREUM = "0x1FD30e761C3296fE36D9067b1e398FD97B4C0407"; + +export const TREASURY_CONVERTER_ARBITRUM = "0x557684a9B7743B8D24Dbb1C0B88D659D56035f38"; +export const VTREASURY_ARBITRUM = "0x8a662ceAC418daeF956Bc0e6B2dd417c80CDA631"; +export const USDT_PRIME_CONVERTER_ARBITRUM = "0x435Fac1B002d5D31f374E07c0177A1D709d5DC2D"; +export const USDC_PRIME_CONVERTER_ARBITRUM = "0x6553C9f9E131191d4fECb6F0E73bE13E229065C6"; +export const WBTC_PRIME_CONVERTER_ARBITRUM = "0xF91369009c37f029aa28AF89709a352375E5A162"; +export const WETH_PRIME_CONVERTER_ARBITRUM = "0x4aCB90ddD6df24dC6b0D50df84C94e72012026d0"; +export const XVS_VAULT_CONVERTER_ARBITRUM = "0x9c5A7aB705EA40876c1B292630a3ff2e0c213DB1"; + +export const TREASURY_CONVERTER_BSCTESTNET = "0x23f8d0823F058B72daF0c0Dad2128593043d514A"; +export const RISK_FUND_CONVERTER_BSCTESTNET = "0x32Fbf7bBbd79355B86741E3181ef8c1D9bD309Bb"; +export const VTREASURY_BSCTESTNET = "0x8b293600c50d6fbdc6ed4251cc75ece29880276f"; +export const XVS_VAULT_CONVERTER_BSCTESTNET = "0x258f49254C758a0E37DAb148ADDAEA851F4b02a2"; +export const USDC_PRIME_CONVERTER_BSCTESTNET = "0x2ecEdE6989d8646c992344fF6C97c72a3f811A13"; +export const USDT_PRIME_CONVERTER_BSCTESTNET = "0xf1FA230D25fC5D6CAfe87C5A6F9e1B17Bc6F194E"; +export const BTCB_PRIME_CONVERTER_BSCTESTNET = "0x989A1993C023a45DA141928921C0dE8fD123b7d1"; +export const ETH_PRIME_CONVERTER_BSCTESTNET = "0xf358650A007aa12ecC8dac08CF8929Be7f72A4D9"; +export const BURNING_CONVERTER_BSCTESTNET = "0x42DBA48e7cCeB030eC73AaAe29d4A3F0cD4facba"; + +export enum ConversionAccessibility { + NONE = 0, + ALL = 1, + ONLY_FOR_CONVERTERS = 2, + ONLY_FOR_USERS = 3, +} + +export const BSC_CONVERSION_INCENTIVE = 1e14; +export const ARBITRUM_CONVERSION_INCENTIVE = 1e14; +export const ETHEREUM_CONVERSION_INCENTIVE = 1e13; +export const BSCTESTNET_CONVERSION_INCENTIVE = 1e14; + +const WHITELISTED_TOKENS_BSCMAINNET = [ + "0x2170Ed0880ac9A755fd29B2688956BD959F933F8", // ETH + "0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c", // BTCB + "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", // BNB + "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d", +]; + +const WHITELISTED_TOKENS_ETHEREUM = [ + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH + "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", // WBTC + "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", +]; + +const WHITELISTED_TOKENS_ARBITRUM = [ + "0x82af49447d8a07e3bd95bd0d56f35241523fbab1", // WETH + "0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f", // WBTC + "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", // USDC +]; + +const WHITELISTED_TOKENS_BSCTESTNET = [ + "0x98f7A83361F7Ac8765CcEBAB1425da6b341958a7", // ETH + "0xA808e341e8e723DC6BA0Bb5204Bafc2330d7B8e4", // BTCB + "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", // BNB + "0x16227D60f7a0e586C66B005219dfc887D13C9531", // USDC +]; + +export const TOKENS_OUT_BSCMAINNET = filterAssets( + bscmainnetAssets, + "0x55d398326f99059fF775485246999027B3197955", + WHITELISTED_TOKENS_BSCMAINNET, +); + +export const TOKENS_OUT_BSCTESTNET = filterAssets( + bsctestnetAssets, + "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", + WHITELISTED_TOKENS_BSCTESTNET, +); + +export const TOKENS_OUT_ETHEREUM = filterAssets( + ethereumAssets, + "0xdAC17F958D2ee523a2206206994597C13D831ec7", + WHITELISTED_TOKENS_ETHEREUM, +); + +export const TOKENS_OUT_ARBITRUM = filterAssets( + arbitrumAssets, + "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9", + WHITELISTED_TOKENS_ARBITRUM, +); + +export const TREASURY_CONVERTER = { + bscmainnet: { + converter: TREASURY_CONVERTER_BSC, + tokenIn: "0x55d398326f99059fF775485246999027B3197955", // USDT + tokensOut: TOKENS_OUT_BSCMAINNET, + whitelistedTokens: WHITELISTED_TOKENS_BSCMAINNET, + conversionIncentive: new Array(WHITELISTED_TOKENS_BSCMAINNET.length).fill([ + BSC_CONVERSION_INCENTIVE, + ConversionAccessibility.ALL, + ]), + converterNetwork: "0xF7Caad5CeB0209165f2dFE71c92aDe14d0F15995", + psr: "0xCa01D5A9A248a830E9D93231e791B1afFed7c446", + psrAddOrUpdateDistributionConfigsParams: [ + [0, 1500, TREASURY_CONVERTER_BSC], + [0, 0, VTREASURY_BSC], + [1, 3500, TREASURY_CONVERTER_BSC], + [1, 0, VTREASURY_BSC], + ], + }, + ethereum: { + converter: TREASURY_CONVERTER_ETHEREUM, + tokenIn: "0xdAC17F958D2ee523a2206206994597C13D831ec7", // USDT + tokensOut: TOKENS_OUT_ETHEREUM, + whitelistedTokens: WHITELISTED_TOKENS_ETHEREUM, + conversionIncentive: new Array(TOKENS_OUT_ETHEREUM.length).fill([ + ETHEREUM_CONVERSION_INCENTIVE, + ConversionAccessibility.ALL, + ]), + converterNetwork: "0x232CC47AECCC55C2CAcE4372f5B268b27ef7cac8", + psr: "0x8c8c8530464f7D95552A11eC31Adbd4dC4AC4d3E", + psrAddOrUpdateDistributionConfigsParams: [ + [0, 6000, TREASURY_CONVERTER_ETHEREUM], + [0, 0, VTREASURY_ETHEREUM], + [1, 8000, TREASURY_CONVERTER_ETHEREUM], + [1, 0, VTREASURY_ETHEREUM], + ], + }, + arbitrumone: { + converter: TREASURY_CONVERTER_ARBITRUM, + tokenIn: "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9", // USDT + tokensOut: TOKENS_OUT_ARBITRUM, + whitelistedTokens: WHITELISTED_TOKENS_ARBITRUM, + conversionIncentive: new Array(TOKENS_OUT_ARBITRUM.length).fill([ + ARBITRUM_CONVERSION_INCENTIVE, + ConversionAccessibility.ALL, + ]), + converterNetwork: "0x2F6672C9A0988748b0172D97961BecfD9DC6D6d5", + psr: "0xF9263eaF7eB50815194f26aCcAB6765820B13D41", + psrAddOrUpdateDistributionConfigsParams: [ + [0, 6000, TREASURY_CONVERTER_ARBITRUM], + [0, 0, VTREASURY_ARBITRUM], + [1, 8000, TREASURY_CONVERTER_ARBITRUM], + [1, 0, VTREASURY_ARBITRUM], + ], + }, + bsctestnet: { + converter: TREASURY_CONVERTER_BSCTESTNET, + tokenIn: "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c", // USDT + tokensOut: TOKENS_OUT_BSCTESTNET, + whitelistedTokens: WHITELISTED_TOKENS_BSCTESTNET, + conversionIncentive: new Array(TOKENS_OUT_BSCTESTNET.length).fill([ + BSCTESTNET_CONVERSION_INCENTIVE, + ConversionAccessibility.ALL, + ]), + converterNetwork: "0xF7Caad5CeB0209165f2dFE71c92aDe14d0F15995", + psr: "0x25c7c7D6Bf710949fD7f03364E9BA19a1b3c10E3", + psrAddOrUpdateDistributionConfigsParams: [ + [0, 1500, TREASURY_CONVERTER_BSCTESTNET], + [0, 0, VTREASURY_BSCTESTNET], + [1, 3500, TREASURY_CONVERTER_BSCTESTNET], + [1, 0, VTREASURY_BSCTESTNET], + ], + }, +}; diff --git a/vips/vip-536/permissions.ts b/vips/vip-536/permissions.ts new file mode 100644 index 000000000..fb3c9beee --- /dev/null +++ b/vips/vip-536/permissions.ts @@ -0,0 +1,94 @@ +import ACM_COMMANDS_AGGREATOR_ABI from "@venusprotocol/governance-contracts/artifacts/contracts/Utils/ACMCommandsAggregator.sol/ACMCommandsAggregator.json"; +import { ACMCommandsAggregator } from "@venusprotocol/governance-contracts/typechain/contracts/Utils/ACMCommandsAggregator"; +import { ethers } from "hardhat"; +import hre from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { AccountType, getConverterPermissions, splitPermissions } from "src/permissions"; + +import { TREASURY_CONVERTER } from "./configuration"; + +const { bscmainnet, ethereum, arbitrumone, bsctestnet } = NETWORK_ADDRESSES; + +interface Permissions { + [key: string]: string[][]; +} + +const grantPermissions: Permissions = { + bscmainnet: [...getConverterPermissions(TREASURY_CONVERTER.bscmainnet.converter)], + bsctestnet: [...getConverterPermissions(TREASURY_CONVERTER.bsctestnet.converter)], + ethereum: [...getConverterPermissions(TREASURY_CONVERTER.ethereum.converter)], + arbitrumone: [...getConverterPermissions(TREASURY_CONVERTER.arbitrumone.converter)], +}; + +const acmCommandsAggregatorAddresses: any = { + bscmainnet: bscmainnet.ACM_AGGREGATOR, + bsctestnet: bsctestnet.ACM_AGGREGATOR, + ethereum: ethereum.ACM_AGGREGATOR, + arbitrumone: arbitrumone.ACM_AGGREGATOR, +}; + +const accounts: any = { + bscmainnet: { + [AccountType.NORMAL_TIMELOCK]: bscmainnet.NORMAL_TIMELOCK, + [AccountType.FAST_TRACK_TIMELOCK]: bscmainnet.FAST_TRACK_TIMELOCK, + [AccountType.CRITICAL_TIMELOCK]: bscmainnet.CRITICAL_TIMELOCK, + [AccountType.GUARDIAN]: bscmainnet.GUARDIAN, + }, + bsctestnet: { + [AccountType.NORMAL_TIMELOCK]: bsctestnet.NORMAL_TIMELOCK, + [AccountType.FAST_TRACK_TIMELOCK]: bsctestnet.FAST_TRACK_TIMELOCK, + [AccountType.CRITICAL_TIMELOCK]: bsctestnet.CRITICAL_TIMELOCK, + [AccountType.GUARDIAN]: bsctestnet.GUARDIAN, + }, + ethereum: { + [AccountType.NORMAL_TIMELOCK]: ethereum.NORMAL_TIMELOCK, + [AccountType.FAST_TRACK_TIMELOCK]: ethereum.FAST_TRACK_TIMELOCK, + [AccountType.CRITICAL_TIMELOCK]: ethereum.CRITICAL_TIMELOCK, + [AccountType.GUARDIAN]: ethereum.GUARDIAN, + }, + arbitrumone: { + [AccountType.NORMAL_TIMELOCK]: arbitrumone.NORMAL_TIMELOCK, + [AccountType.FAST_TRACK_TIMELOCK]: arbitrumone.FAST_TRACK_TIMELOCK, + [AccountType.CRITICAL_TIMELOCK]: arbitrumone.CRITICAL_TIMELOCK, + [AccountType.GUARDIAN]: arbitrumone.GUARDIAN, + }, +}; + +async function main() { + const acmCommandsAggregator = await ethers.getContractAt( + ACM_COMMANDS_AGGREATOR_ABI.abi, + acmCommandsAggregatorAddresses[hre.network.name], + ); + const networkGrantPermissions = grantPermissions[hre.network.name]; + + for (const permission of networkGrantPermissions) { + if (Object.values(AccountType).includes(permission[2] as AccountType)) { + permission[2] = accounts[hre.network.name][permission[2]]; + } + } + + const _grantPermissions: ACMCommandsAggregator.PermissionStruct[] = networkGrantPermissions.map(permission => ({ + contractAddress: permission[0], + functionSig: permission[1], + account: permission[2], + })); + + const grantChunks = splitPermissions(_grantPermissions); + const grantIndexes: string[] = []; + + for (const chunk of grantChunks) { + const tx = await acmCommandsAggregator.addGrantPermissions(chunk); + const receipt = await tx.wait(); + const events = receipt.events?.filter((event: any) => event.event === "GrantPermissionsAdded"); + grantIndexes.push(events?.[0].args?.index.toString()); + } + + console.log("Grant Permissions added with indexes: ", grantIndexes.toString()); +} + +main() + .then(() => process.exit(0)) + .catch(error => { + console.error(error); + process.exit(1); + }); diff --git a/yarn.lock b/yarn.lock index 5145aee6a..0dee06eda 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2718,6 +2718,17 @@ __metadata: languageName: node linkType: hard +"@venusprotocol/governance-contracts@npm:^2.12.0": + version: 2.12.0 + resolution: "@venusprotocol/governance-contracts@npm:2.12.0" + dependencies: + "@venusprotocol/solidity-utilities": 2.0.0 + hardhat-deploy-ethers: ^0.3.0-beta.13 + module-alias: ^2.2.2 + checksum: 7ba150d1e61db3a8e7d0653fa7b7b5b0f1f7e709f9d55ff4a03f4fcf2892dd30fd6cb569fc927ba736c9c1444104bd3b1e07c917c76cb8f4dee938bcb0dca762 + languageName: node + linkType: hard + "@venusprotocol/isolated-pools@npm:^2.5.0": version: 2.8.0 resolution: "@venusprotocol/isolated-pools@npm:2.8.0" @@ -2779,6 +2790,13 @@ __metadata: languageName: node linkType: hard +"@venusprotocol/solidity-utilities@npm:2.0.0": + version: 2.0.0 + resolution: "@venusprotocol/solidity-utilities@npm:2.0.0" + checksum: 87a2ce2fd1d702bc04c4e98d675b904176c7f2489476e8da586d1782b48faae92aa4f2ba894737773d189ba72a6b274f1464cf2e0308e62758303d0adde749e6 + languageName: node + linkType: hard + "@venusprotocol/token-bridge@npm:^1.1.0": version: 1.1.0 resolution: "@venusprotocol/token-bridge@npm:1.1.0" @@ -2864,7 +2882,7 @@ __metadata: "@types/sinon": ^17.0.3 "@typescript-eslint/eslint-plugin": ^5.44.0 "@typescript-eslint/parser": ^5.44.0 - "@venusprotocol/governance-contracts": ^1.4.0 + "@venusprotocol/governance-contracts": ^2.12.0 "@venusprotocol/isolated-pools": ^2.5.0 "@venusprotocol/oracle": ^1.10.0 "@venusprotocol/token-bridge": ^1.1.0