diff --git a/src/contracts/facilitators/gsm/converter/USTBGsmConverter.sol b/src/contracts/facilitators/gsm/converter/USTBGsmConverter.sol index 4836103a..bac174a7 100644 --- a/src/contracts/facilitators/gsm/converter/USTBGsmConverter.sol +++ b/src/contracts/facilitators/gsm/converter/USTBGsmConverter.sol @@ -9,8 +9,8 @@ import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; import {IGhoToken} from '../../../gho/interfaces/IGhoToken.sol'; import {IGsm} from '../interfaces/IGsm.sol'; import {IGsmConverter} from './interfaces/IGsmConverter.sol'; -import {IRedemption} from '../dependencies/circle/IRedemption.sol'; -// TODO: replace with proper issuance implementation later +// TODO: replace with proper issuance implementation/interface later from USTB +import {ISubscriptionRedemption} from '../dependencies/USTB/ISubscriptionRedemption.sol'; import {MockBUIDLSubscription} from '../../../../test/mocks/MockBUIDLSubscription.sol'; import 'forge-std/console2.sol'; @@ -169,7 +169,7 @@ contract USTBGsmConverter is Ownable, EIP712, IGsmConverter { /** * @notice Buys the GSM underlying asset in exchange for selling GHO, after asset redemption - * @param minAmount The minimum amount of the underlying asset to buy (ie USTB) + * @param minAmount The minimum amount of the underlying asset to buy via conversion (USDC) * @param receiver Recipient address of the underlying asset being purchased * @return The amount of underlying asset bought, after asset redemption * @return The amount of GHO sold by the user @@ -183,26 +183,20 @@ contract USTBGsmConverter is Ownable, EIP712, IGsmConverter { uint256 initialIssuedAssetBalance = IERC20(ISSUED_ASSET).balanceOf(address(this)); uint256 initialRedeemedAssetBalance = IERC20(REDEEMED_ASSET).balanceOf(address(this)); - (, uint256 ghoAmount, , ) = IGsm(GSM).getGhoAmountForBuyAsset(minAmount); + uint256 minUSTBAmount = ISubscriptionRedemption(REDEMPTION_CONTRACT).calculateUstbIn(minAmount); + + (, uint256 ghoAmount, , ) = IGsm(GSM).getGhoAmountForBuyAsset(minUSTBAmount); IGhoToken(GHO_TOKEN).transferFrom(originator, address(this), ghoAmount); IGhoToken(GHO_TOKEN).approve(address(GSM), ghoAmount); - (uint256 boughtAssetAmount, uint256 ghoSold) = IGsm(GSM).buyAsset(minAmount, address(this)); + (uint256 boughtAssetAmount, uint256 ghoSold) = IGsm(GSM).buyAsset(minUSTBAmount, address(this)); require(ghoAmount == ghoSold, 'INVALID_GHO_SOLD'); IGhoToken(GHO_TOKEN).approve(address(GSM), 0); IERC20(ISSUED_ASSET).approve(address(REDEMPTION_CONTRACT), boughtAssetAmount); IRedemption(REDEMPTION_CONTRACT).redeem(boughtAssetAmount); - // TODO: adjust require depending on how much USDC is redeemed - // because USTB increases in price, redemption will NOT be in 1:1 ratio - uint256 redeemedAmount = boughtAssetAmount; - // require( - // IERC20(REDEEMED_ASSET).balanceOf(address(this)) == - // initialRedeemedAssetBalance + , - // 'INVALID_REDEMPTION' - // ); IERC20(ISSUED_ASSET).approve(address(REDEMPTION_CONTRACT), 0); - IERC20(REDEEMED_ASSET).safeTransfer(receiver, redeemedAmount); + IERC20(REDEEMED_ASSET).safeTransfer(receiver, minAmount); require( IGhoToken(GHO_TOKEN).balanceOf(address(this)) == initialGhoBalance, diff --git a/src/contracts/facilitators/gsm/dependencies/USTB/ISubscriptionRedemption.sol b/src/contracts/facilitators/gsm/dependencies/USTB/ISubscriptionRedemption.sol new file mode 100644 index 00000000..760f4032 --- /dev/null +++ b/src/contracts/facilitators/gsm/dependencies/USTB/ISubscriptionRedemption.sol @@ -0,0 +1,39 @@ +// Simple interface for subscriptions/redemptions of USTB/USDC +pragma solidity ^0.8.10; + +/** + * @title ISubscriptionRedemption + */ +interface ISubscriptionRedemption { + /** + * @notice Subscribes an amount of USTB in exchange for USDC + * @param amount The amount of USDC to subscribe + */ + function subscribe(uint256 amount) external; + + /** + * @notice Redeems an amount of USDC in exchange for USTB + * @param amount The amount of the USTB to redeem + */ + function redeem(uint256 amount) external; + + /** + * @notice Calculates the amount of USTB required to redeem to get a given amount of USDC + * @param usdcOutAmount The amount of USDC to receive + * @return ustbInAmount The amount of USTB required to redeem to get usdcOutAmount + * @return usdPerUstbChainlinkRaw The price of USTB in USD, in Chainlink raw format + */ + function calculateUstbIn( + uint256 usdcOutAmount + ) external view returns (uint256 ustbInAmount, uint256 usdPerUstbChainlinkRaw); + + /** + * @notice Calculates the amount of USDC that will be received when redeeming a given amount of USTB + * @param superstateTokenInAmount The amount of USTB to redeem + * @return usdcOutAmount The amount of USDC to receive + * @return usdPerUstbChainlinkRaw The price of USTB in USD, in Chainlink raw format + */ + function calculateUsdcOut( + uint256 superstateTokenInAmount + ) external view returns (uint256 usdcOutAmount, uint256 usdPerUstbChainlinkRaw); +}