From e840fa38d6fe1a08d7d2d6fd87a3e919d2cb73ac Mon Sep 17 00:00:00 2001 From: philbow61 <80156619+philbow61@users.noreply.github.com> Date: Tue, 26 Nov 2024 12:15:37 +0100 Subject: [PATCH] fix: ensure scaling for different reserveAsset token decimals (#551) ### Description This PR adds scaling to the reserve balance read in mintUBIFromReserveBalance in Case the token has less than 18 decimals. ### Other changes ### Tested - added test verifying expected behavior for token with 6 decimals ### Related issues ### Backwards compatibility ### Documentation --- .../GoodDollarExpansionController.sol | 5 ++- .../GoodDollarExpansionController.t.sol | 32 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/contracts/goodDollar/GoodDollarExpansionController.sol b/contracts/goodDollar/GoodDollarExpansionController.sol index 44d1297..402e334 100644 --- a/contracts/goodDollar/GoodDollarExpansionController.sol +++ b/contracts/goodDollar/GoodDollarExpansionController.sol @@ -5,6 +5,7 @@ import { IGoodDollarExpansionController } from "contracts/interfaces/IGoodDollar import { IGoodDollarExchangeProvider } from "contracts/interfaces/IGoodDollarExchangeProvider.sol"; import { IBancorExchangeProvider } from "contracts/interfaces/IBancorExchangeProvider.sol"; import { IERC20 } from "openzeppelin-contracts-next/contracts/token/ERC20/IERC20.sol"; +import { IERC20Metadata } from "openzeppelin-contracts-next/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import { IGoodDollar } from "contracts/goodDollar/interfaces/IGoodProtocol.sol"; import { IDistributionHelper } from "contracts/goodDollar/interfaces/IGoodProtocol.sol"; @@ -152,7 +153,9 @@ contract GoodDollarExpansionController is IGoodDollarExpansionController, Ownabl IBancorExchangeProvider.PoolExchange memory exchange = IBancorExchangeProvider(address(goodDollarExchangeProvider)) .getPoolExchange(exchangeId); - uint256 contractReserveBalance = IERC20(exchange.reserveAsset).balanceOf(reserve); + uint256 contractReserveBalance = IERC20(exchange.reserveAsset).balanceOf(reserve) * + (10 ** (18 - IERC20Metadata(exchange.reserveAsset).decimals())); + uint256 additionalReserveBalance = contractReserveBalance - exchange.reserveBalance; if (additionalReserveBalance > 0) { amountMinted = goodDollarExchangeProvider.mintFromInterest(exchangeId, additionalReserveBalance); diff --git a/test/unit/goodDollar/GoodDollarExpansionController.t.sol b/test/unit/goodDollar/GoodDollarExpansionController.t.sol index 4e46e62..974843a 100644 --- a/test/unit/goodDollar/GoodDollarExpansionController.t.sol +++ b/test/unit/goodDollar/GoodDollarExpansionController.t.sol @@ -5,6 +5,7 @@ pragma solidity 0.8.18; import { Test } from "forge-std/Test.sol"; import { ERC20Mock } from "openzeppelin-contracts-next/contracts/mocks/ERC20Mock.sol"; +import { ERC20DecimalsMock } from "openzeppelin-contracts-next/contracts/mocks/ERC20DecimalsMock.sol"; import { GoodDollarExpansionController } from "contracts/goodDollar/GoodDollarExpansionController.sol"; import { IGoodDollarExpansionController } from "contracts/interfaces/IGoodDollarExpansionController.sol"; @@ -326,6 +327,37 @@ contract GoodDollarExpansionControllerTest_mintUBIFromReserveBalance is GoodDoll assertEq(amountMinted, 0); } + function test_mintUBIFromReserveBalance_whenReserveAssetDecimalsIsLessThan18_shouldScaleCorrectly() public { + ERC20DecimalsMock reserveToken6DecimalsMock = new ERC20DecimalsMock("Reserve Token", "RES", 6); + IBancorExchangeProvider.PoolExchange memory pool2 = IBancorExchangeProvider.PoolExchange({ + reserveAsset: address(reserveToken6DecimalsMock), + tokenAddress: address(token), + tokenSupply: 7 * 1e9 * 1e18, + reserveBalance: 200_000 * 1e18, // internally scaled to 18 decimals + reserveRatio: 0.2 * 1e8, // 20% + exitContribution: 0.1 * 1e8 // 10% + }); + + uint256 reserveInterest = 1000e6; + deal(address(reserveToken6DecimalsMock), reserveAddress, 200_000 * 1e6 + reserveInterest); + + vm.mockCall( + address(exchangeProvider), + abi.encodeWithSelector(IBancorExchangeProvider(exchangeProvider).getPoolExchange.selector, exchangeId), + abi.encode(pool2) + ); + + vm.expectCall( + address(exchangeProvider), + abi.encodeWithSelector( + IGoodDollarExchangeProvider(exchangeProvider).mintFromInterest.selector, + exchangeId, + reserveInterest * 1e12 + ) + ); + expansionController.mintUBIFromReserveBalance(exchangeId); + } + function test_mintUBIFromReserveBalance_whenAdditionalReserveBalanceIsLargerThan0_shouldMintAndEmit() public { uint256 amountToMint = 1000e18; uint256 additionalReserveBalance = 1000e18;