diff --git a/script/upgrades/MU03/MU03.sol b/script/upgrades/MU03/MU03.sol index b38c3df2..cbd65832 100644 --- a/script/upgrades/MU03/MU03.sol +++ b/script/upgrades/MU03/MU03.sol @@ -50,7 +50,7 @@ contract MU03 is IMentoUpgrade, GovernanceScript { address private breakerBox; address private medianDeltaBreaker; address private valueDeltaBreaker; - address private biPoolManagerProxyAddress; + address payable private biPoolManagerProxyAddress; address private brokerProxyAddress; address private sortedOraclesProxy; @@ -88,7 +88,7 @@ contract MU03 is IMentoUpgrade, GovernanceScript { breakerBox = contracts.deployed("BreakerBox"); medianDeltaBreaker = contracts.deployed("MedianDeltaBreaker"); valueDeltaBreaker = contracts.deployed("ValueDeltaBreaker"); - biPoolManagerProxyAddress = contracts.deployed("BiPoolManagerProxy"); + biPoolManagerProxyAddress = address(uint160(contracts.deployed("BiPoolManagerProxy"))); brokerProxyAddress = contracts.deployed("BrokerProxy"); sortedOraclesProxy = contracts.celoRegistry("SortedOracles"); } @@ -151,30 +151,42 @@ contract MU03 is IMentoUpgrade, GovernanceScript { ); } + function proposal_updateBiPoolManagerImplementation() public { + transactions.push( + ICeloGovernance.Transaction( + 0, + biPoolManagerProxyAddress, + abi.encodeWithSelector(Proxy(0)._setImplementation.selector, contracts.deployed("BiPoolManager")) + ) + ); + } + + function proposal_updateBrokerImplementation() public { + transactions.push( + ICeloGovernance.Transaction( + 0, + brokerProxyAddress, + abi.encodeWithSelector(Proxy(0)._setImplementation.selector, contracts.deployed("Broker")) + ) + ); + } + + function proposal_updateSortedOraclesImplementation() public { + transactions.push( + ICeloGovernance.Transaction( + 0, + sortedOraclesProxy, + abi.encodeWithSelector(Proxy(0)._setImplementation.selector, contracts.deployed("SortedOracles")) + ) + ); + } + /** * @notice This function generates the transactions required to create the * BiPoolManager exchanges (cUSD/CELO, cEUR/CELO, cBRL/CELO, cUSD/bridgedUSDC, * cEUR/bridgedUSDC, cBRL/bridgedUSDC) */ function proposal_createExchanges(MU03Config.MU03 memory config) private { - address payable biPoolManagerProxy = contracts.deployed("BiPoolManagerProxy"); - bool biPoolManagerInitialized = BiPoolManagerProxy(biPoolManagerProxy)._getImplementation() != address(0); - if (biPoolManagerInitialized) { - bytes32[] memory existingExchangeIds = IBiPoolManager(contracts.deployed("BiPoolManagerProxy")).getExchangeIds(); - if (existingExchangeIds.length > 0) { - console.log("Destroying existing exchanges: ", existingExchangeIds.length); - for (uint256 i = existingExchangeIds.length; i > 0; i--) { - transactions.push( - ICeloGovernance.Transaction( - 0, - contracts.deployed("BiPoolManagerProxy"), - abi.encodeWithSelector(IBiPoolManager(0).destroyExchange.selector, existingExchangeIds[i - 1], i - 1) - ) - ); - } - } - } - // Get the address of the pricing modules IPricingModule constantProduct = IPricingModule(contracts.deployed("ConstantProductPricingModule")); IPricingModule constantSum = IPricingModule(contracts.deployed("ConstantSumPricingModule")); @@ -194,31 +206,55 @@ contract MU03 is IMentoUpgrade, GovernanceScript { ) ); - for (uint256 i = 0; i < config.pools.length; i++) { - Config.Pool memory poolConfig = config.pools[i]; - IBiPoolManager.PoolExchange memory pool = IBiPoolManager.PoolExchange({ - asset0: poolConfig.asset0, - asset1: poolConfig.asset1, - pricingModule: poolConfig.isConstantSum ? constantSum : constantProduct, - bucket0: 0, - bucket1: 0, - lastBucketUpdate: 0, - config: IBiPoolManager.PoolConfig({ - spread: FixidityLib.wrap(poolConfig.spread.unwrap()), - referenceRateFeedID: poolConfig.referenceRateFeedID, - referenceRateResetFrequency: poolConfig.referenceRateResetFrequency, - minimumReports: poolConfig.minimumReports, - stablePoolResetSize: poolConfig.stablePoolResetSize - }) - }); + Config.Pool[] memory poolsToCreate = new Config.Pool[](4); + poolsToCreate[0] = config.cUSDUSDC; + poolsToCreate[1] = config.cEURUSDC; + poolsToCreate[2] = config.cBRLUSDC; + poolsToCreate[3] = config.cEUREUROC; + bool biPoolManagerInitialized = BiPoolManagerProxy(biPoolManagerProxyAddress)._getImplementation() != address(0); + if (biPoolManagerInitialized) { + // Destroy cUSD/brdgedUSDC exchange -> since ConstantSum logic has changed + bytes32 cUSDUSDCExchangeId = getExchangeId( + config.cUSDUSDC.asset0, + config.cUSDUSDC.asset1, + config.cUSDUSDC.isConstantSum + ); transactions.push( ICeloGovernance.Transaction( 0, contracts.deployed("BiPoolManagerProxy"), - abi.encodeWithSelector(IBiPoolManager(0).createExchange.selector, pool) + //it's ok to hardcode the index here since the transaction would fail if index and identifier don't match + abi.encodeWithSelector(IBiPoolManager(0).destroyExchange.selector, cUSDUSDCExchangeId, 3) ) ); + + for (uint256 i = 0; i < poolsToCreate.length; i++) { + Config.Pool memory poolConfig = poolsToCreate[i]; + IBiPoolManager.PoolExchange memory pool = IBiPoolManager.PoolExchange({ + asset0: poolConfig.asset0, + asset1: poolConfig.asset1, + pricingModule: poolConfig.isConstantSum ? constantSum : constantProduct, + bucket0: 0, + bucket1: 0, + lastBucketUpdate: 0, + config: IBiPoolManager.PoolConfig({ + spread: FixidityLib.wrap(poolConfig.spread.unwrap()), + referenceRateFeedID: poolConfig.referenceRateFeedID, + referenceRateResetFrequency: poolConfig.referenceRateResetFrequency, + minimumReports: poolConfig.minimumReports, + stablePoolResetSize: poolConfig.stablePoolResetSize + }) + }); + + transactions.push( + ICeloGovernance.Transaction( + 0, + biPoolManagerProxyAddress, + abi.encodeWithSelector(IBiPoolManager(0).createExchange.selector, pool) + ) + ); + } } } @@ -278,36 +314,6 @@ contract MU03 is IMentoUpgrade, GovernanceScript { } } - function proposal_updateBiPoolManagerImplementation() public { - transactions.push( - ICeloGovernance.Transaction( - 0, - biPoolManagerProxyAddress, - abi.encodeWithSelector(Proxy(0)._setImplementation.selector, contracts.deployed("BiPoolManager")) - ) - ); - } - - function proposal_updateBrokerImplementation() public { - transactions.push( - ICeloGovernance.Transaction( - 0, - brokerProxyAddress, - abi.encodeWithSelector(Proxy(0)._setImplementation.selector, contracts.deployed("Broker")) - ) - ); - } - - function proposal_updateSortedOraclesImplementation() public { - transactions.push( - ICeloGovernance.Transaction( - 0, - sortedOraclesProxy, - abi.encodeWithSelector(Proxy(0)._setImplementation.selector, contracts.deployed("SortedOracles")) - ) - ); - } - function proposal_configureBreakerBox(MU03Config.MU03 memory config) public { // Add the rate feeds to breaker box transactions.push( diff --git a/script/upgrades/MU03/MU03Checks.sol b/script/upgrades/MU03/MU03Checks.sol index b30100f6..84796b4f 100644 --- a/script/upgrades/MU03/MU03Checks.sol +++ b/script/upgrades/MU03/MU03Checks.sol @@ -530,12 +530,12 @@ contract MU03Checks is Script, Test { console2.log("\n== Doing some test swaps... =="); - swapCeloTocUSD(); - swapcUSDtoCelo(); - swapCeloTocEUR(); - swapcEURtoCELO(); - swapCeloTocBRL(); - swapcBrlToCELO(); + swapCeloTocUSD(config); + swapcUSDtoCelo(config); + swapCeloTocEUR(config); + swapcEURtoCELO(config); + swapCeloTocBRL(config); + swapcBrlToCELO(config); swapBridgedUSDCTocUSD(config); swapcUSDtoBridgedUSDC(config); swapBridgedUSDCTocEUR(config); @@ -546,7 +546,7 @@ contract MU03Checks is Script, Test { swapcEURtoBridgedEUROC(config); } - function swapCeloTocUSD() internal { + function swapCeloTocUSD(MU03Config.MU03 memory config) internal { bytes32 exchangeID = BiPoolManager(biPoolManagerProxy).exchangeIds(0); address trader = vm.addr(5); @@ -557,12 +557,19 @@ contract MU03Checks is Script, Test { // Give trader some celo vm.deal(trader, amountIn); - testAndPerformConstantProductSwap(exchangeID, trader, tokenIn, tokenOut, amountIn); + testAndPerformConstantProductSwap( + exchangeID, + trader, + tokenIn, + tokenOut, + amountIn, + config.cUSDCelo.referenceRateFeedID + ); console2.log("\tCELO -> cUSD swap successful 🚀"); } - function swapcUSDtoCelo() internal { + function swapcUSDtoCelo(MU03Config.MU03 memory config) internal { bytes32 exchangeID = BiPoolManager(biPoolManagerProxy).exchangeIds(0); address trader = vm.addr(5); @@ -570,12 +577,19 @@ contract MU03Checks is Script, Test { address tokenOut = celoToken; uint256 amountIn = 1e18; - testAndPerformConstantProductSwap(exchangeID, trader, tokenIn, tokenOut, amountIn); + testAndPerformConstantProductSwap( + exchangeID, + trader, + tokenIn, + tokenOut, + amountIn, + config.cUSDCelo.referenceRateFeedID + ); console2.log("\tcUSD -> CELO swap successful 🚀"); } - function swapCeloTocEUR() internal { + function swapCeloTocEUR(MU03Config.MU03 memory config) internal { bytes32 exchangeID = BiPoolManager(biPoolManagerProxy).exchangeIds(1); address trader = vm.addr(5); @@ -586,12 +600,19 @@ contract MU03Checks is Script, Test { // Give trader some celo vm.deal(trader, amountIn); - testAndPerformConstantProductSwap(exchangeID, trader, tokenIn, tokenOut, amountIn); + testAndPerformConstantProductSwap( + exchangeID, + trader, + tokenIn, + tokenOut, + amountIn, + config.cEURCelo.referenceRateFeedID + ); console2.log("\tCELO -> cEUR swap successful 🚀"); } - function swapcEURtoCELO() internal { + function swapcEURtoCELO(MU03Config.MU03 memory config) internal { bytes32 exchangeID = BiPoolManager(biPoolManagerProxy).exchangeIds(1); address trader = vm.addr(5); @@ -599,12 +620,19 @@ contract MU03Checks is Script, Test { address tokenOut = celoToken; uint256 amountIn = 1e18; - testAndPerformConstantProductSwap(exchangeID, trader, tokenIn, tokenOut, amountIn); + testAndPerformConstantProductSwap( + exchangeID, + trader, + tokenIn, + tokenOut, + amountIn, + config.cEURCelo.referenceRateFeedID + ); console2.log("\tcEUR -> CELO swap successful 🚀"); } - function swapCeloTocBRL() internal { + function swapCeloTocBRL(MU03Config.MU03 memory config) internal { bytes32 exchangeID = BiPoolManager(biPoolManagerProxy).exchangeIds(2); address trader = vm.addr(5); @@ -615,12 +643,19 @@ contract MU03Checks is Script, Test { // Give trader some celo vm.deal(trader, amountIn); - testAndPerformConstantProductSwap(exchangeID, trader, tokenIn, tokenOut, amountIn); + testAndPerformConstantProductSwap( + exchangeID, + trader, + tokenIn, + tokenOut, + amountIn, + config.cBRLCelo.referenceRateFeedID + ); console2.log("\tCELO -> cBRL swap successful 🚀"); } - function swapcBrlToCELO() internal { + function swapcBrlToCELO(MU03Config.MU03 memory config) internal { bytes32 exchangeID = BiPoolManager(biPoolManagerProxy).exchangeIds(2); address trader = vm.addr(5); @@ -628,7 +663,14 @@ contract MU03Checks is Script, Test { address tokenOut = celoToken; uint256 amountIn = 1e18; - testAndPerformConstantProductSwap(exchangeID, trader, tokenIn, tokenOut, amountIn); + testAndPerformConstantProductSwap( + exchangeID, + trader, + tokenIn, + tokenOut, + amountIn, + config.cBRLCelo.referenceRateFeedID + ); console2.log("\tcBRL -> CELO swap successful 🚀"); } @@ -644,15 +686,7 @@ contract MU03Checks is Script, Test { // Mint some USDC to trader deal(bridgedUSDC, trader, amountIn, true); - testAndPerformConstantSumSwap( - exchangeID, - trader, - tokenIn, - tokenOut, - amountIn, - config.cUSDUSDC.referenceRateFeedID, - true - ); + testAndPerformConstantSumSwap(exchangeID, trader, tokenIn, tokenOut, amountIn, config.cUSDUSDC.referenceRateFeedID); console2.log("\tbridgedUSDC -> cUSD swap successful 🚀"); } @@ -668,15 +702,7 @@ contract MU03Checks is Script, Test { // Mint some USDC to the reserve deal(bridgedUSDC, reserve, 1000e18, true); - testAndPerformConstantSumSwap( - exchangeID, - trader, - tokenIn, - tokenOut, - amountIn, - config.cUSDUSDC.referenceRateFeedID, - false - ); + testAndPerformConstantSumSwap(exchangeID, trader, tokenIn, tokenOut, amountIn, config.cUSDUSDC.referenceRateFeedID); console2.log("\tcUSD -> bridgedUSDC swap successful 🚀"); } @@ -692,15 +718,7 @@ contract MU03Checks is Script, Test { // Mint some USDC to trader deal(bridgedUSDC, trader, amountIn, true); - testAndPerformConstantSumSwap( - exchangeID, - trader, - tokenIn, - tokenOut, - amountIn, - config.cEURUSDC.referenceRateFeedID, - true - ); + testAndPerformConstantSumSwap(exchangeID, trader, tokenIn, tokenOut, amountIn, config.cEURUSDC.referenceRateFeedID); console2.log("\tbridgedUSDC -> cEUR swap successful 🚀"); } @@ -713,15 +731,7 @@ contract MU03Checks is Script, Test { address tokenOut = bridgedUSDC; uint256 amountIn = 10e18; - testAndPerformConstantSumSwap( - exchangeID, - trader, - tokenIn, - tokenOut, - amountIn, - config.cEURUSDC.referenceRateFeedID, - false - ); + testAndPerformConstantSumSwap(exchangeID, trader, tokenIn, tokenOut, amountIn, config.cEURUSDC.referenceRateFeedID); console2.log("\tcEUR -> bridgedUSDC swap successful 🚀"); } @@ -737,15 +747,7 @@ contract MU03Checks is Script, Test { // Mint some USDC to trader deal(bridgedUSDC, trader, amountIn, true); - testAndPerformConstantSumSwap( - exchangeID, - trader, - tokenIn, - tokenOut, - amountIn, - config.cBRLUSDC.referenceRateFeedID, - true - ); + testAndPerformConstantSumSwap(exchangeID, trader, tokenIn, tokenOut, amountIn, config.cBRLUSDC.referenceRateFeedID); console2.log("\tbridgedUSDC -> cBRL swap successful 🚀"); } @@ -758,15 +760,7 @@ contract MU03Checks is Script, Test { address tokenOut = bridgedUSDC; uint256 amountIn = 10e18; - testAndPerformConstantSumSwap( - exchangeID, - trader, - tokenIn, - tokenOut, - amountIn, - config.cBRLUSDC.referenceRateFeedID, - false - ); + testAndPerformConstantSumSwap(exchangeID, trader, tokenIn, tokenOut, amountIn, config.cBRLUSDC.referenceRateFeedID); console2.log("\tcBRL -> bridgedUSDC swap successful 🚀"); } @@ -788,8 +782,7 @@ contract MU03Checks is Script, Test { tokenIn, tokenOut, amountIn, - config.cEUREUROC.referenceRateFeedID, - true + config.cEUREUROC.referenceRateFeedID ); console2.log("\tbridgedEUROC -> cEUR swap successful 🚀"); @@ -812,8 +805,7 @@ contract MU03Checks is Script, Test { tokenIn, tokenOut, amountIn, - config.cEUREUROC.referenceRateFeedID, - false + config.cEUREUROC.referenceRateFeedID ); console2.log("\tcEUR -> bridgedEUROC swap successful 🚀"); @@ -860,28 +852,29 @@ contract MU03Checks is Script, Test { address trader, address tokenIn, address tokenOut, - uint256 amountIn + uint256 amountIn, + address rateFeedID ) internal { uint256 amountOut = Broker(brokerProxy).getAmountOut(biPoolManagerProxy, exchangeID, tokenIn, tokenOut, amountIn); IBiPoolManager.PoolExchange memory pool = BiPoolManager(biPoolManagerProxy).getPoolExchange(exchangeID); + (uint256 numerator, uint256 denominator) = SortedOracles(sortedOraclesProxy).medianRate(rateFeedID); + FixidityLib.Fraction memory rate = FixidityLib.newFixedFraction(numerator, denominator); - FixidityLib.Fraction memory numerator; - FixidityLib.Fraction memory denominator; + FixidityLib.Fraction memory netAmountIn = FixidityLib.newFixed(amountIn).multiply( + FixidityLib.newFixedFraction(9975, 10000) + ); + uint256 estimatedAmountOut; if (tokenIn == pool.asset0) { - numerator = FixidityLib.newFixed(amountIn).multiply(FixidityLib.newFixed(pool.bucket1)); - denominator = FixidityLib.newFixed(pool.bucket0).add(FixidityLib.newFixed(amountIn)); + estimatedAmountOut = netAmountIn.divide(rate).fromFixed(); } else { - numerator = FixidityLib.newFixed(amountIn).multiply(FixidityLib.newFixed(pool.bucket0)); - denominator = FixidityLib.newFixed(pool.bucket1).add(FixidityLib.newFixed(amountIn)); + estimatedAmountOut = netAmountIn.multiply(rate).fromFixed(); } - uint256 estimatedAmountOut = numerator.unwrap().div(denominator.unwrap()); - FixidityLib.Fraction memory maxTolerance = FixidityLib.newFixedFraction(25, 10000); uint256 threshold = FixidityLib.newFixed(estimatedAmountOut).multiply(maxTolerance).fromFixed(); - assertApproxEqAbs(amountOut, estimatedAmountOut, threshold); + assertApproxEqAbs(amountOut, estimatedAmountOut, threshold); doSwapIn(exchangeID, trader, tokenIn, tokenOut, amountIn, amountOut); } @@ -891,30 +884,25 @@ contract MU03Checks is Script, Test { address tokenIn, address tokenOut, uint256 amountIn, - address rateFeedID, - bool isBridgedUsdcToStable + address rateFeedID ) internal { uint256 amountOut = Broker(brokerProxy).getAmountOut(biPoolManagerProxy, exchangeID, tokenIn, tokenOut, amountIn); + IBiPoolManager.PoolExchange memory pool = BiPoolManager(biPoolManagerProxy).getPoolExchange(exchangeID); (uint256 numerator, uint256 denominator) = SortedOracles(sortedOraclesProxy).medianRate(rateFeedID); - uint256 estimatedAmountOut; + FixidityLib.Fraction memory rate = FixidityLib.newFixedFraction(numerator, denominator); - if (isBridgedUsdcToStable) { - estimatedAmountOut = FixidityLib - .newFixed(amountIn.mul(1e12)) - .multiply(FixidityLib.wrap(numerator).divide(FixidityLib.wrap(denominator))) - .fromFixed(); - } else { - estimatedAmountOut = FixidityLib - .newFixed(amountIn) - .multiply(FixidityLib.wrap(denominator).divide(FixidityLib.wrap(numerator))) - .fromFixed(); + uint256 estimatedAmountOut; + if (tokenIn == pool.asset0) { + estimatedAmountOut = FixidityLib.newFixed(amountIn).divide(rate).fromFixed(); estimatedAmountOut = estimatedAmountOut.div(1e12); + } else { + estimatedAmountOut = FixidityLib.newFixed(amountIn.mul(1e12)).multiply(rate).fromFixed(); } FixidityLib.Fraction memory maxTolerance = FixidityLib.newFixedFraction(25, 1000); uint256 threshold = FixidityLib.newFixed(estimatedAmountOut).multiply(maxTolerance).fromFixed(); - assertApproxEqAbs(amountOut, estimatedAmountOut, threshold); + assertApproxEqAbs(amountOut, estimatedAmountOut, threshold); doSwapIn(exchangeID, trader, tokenIn, tokenOut, amountIn, amountOut); }