Branch data Line data Source code
1 : : // SPDX-License-Identifier: BUSL-1.1
2 : : pragma solidity ^0.8.10;
3 : :
4 : : import {IERC20} from '../../../dependencies/openzeppelin/contracts/IERC20.sol';
5 : : import {GPv2SafeERC20} from '../../../dependencies/gnosis/contracts/GPv2SafeERC20.sol';
6 : : import {SafeCast} from '../../../dependencies/openzeppelin/contracts/SafeCast.sol';
7 : : import {IAToken} from '../../../interfaces/IAToken.sol';
8 : : import {DataTypes} from '../types/DataTypes.sol';
9 : : import {UserConfiguration} from '../configuration/UserConfiguration.sol';
10 : : import {ReserveConfiguration} from '../configuration/ReserveConfiguration.sol';
11 : : import {WadRayMath} from '../math/WadRayMath.sol';
12 : : import {PercentageMath} from '../math/PercentageMath.sol';
13 : : import {Errors} from '../helpers/Errors.sol';
14 : : import {ValidationLogic} from './ValidationLogic.sol';
15 : : import {ReserveLogic} from './ReserveLogic.sol';
16 : :
17 : : library BridgeLogic {
18 : : using ReserveLogic for DataTypes.ReserveCache;
19 : : using ReserveLogic for DataTypes.ReserveData;
20 : : using UserConfiguration for DataTypes.UserConfigurationMap;
21 : : using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
22 : : using WadRayMath for uint256;
23 : : using PercentageMath for uint256;
24 : : using SafeCast for uint256;
25 : : using GPv2SafeERC20 for IERC20;
26 : :
27 : : // See `IPool` for descriptions
28 : : event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user);
29 : : event MintUnbacked(
30 : : address indexed reserve,
31 : : address user,
32 : : address indexed onBehalfOf,
33 : : uint256 amount,
34 : : uint16 indexed referralCode
35 : : );
36 : : event BackUnbacked(address indexed reserve, address indexed backer, uint256 amount, uint256 fee);
37 : :
38 : : /**
39 : : * @notice Mint unbacked aTokens to a user and updates the unbacked for the reserve.
40 : : * @dev Essentially a supply without transferring the underlying.
41 : : * @dev Emits the `MintUnbacked` event
42 : : * @dev Emits the `ReserveUsedAsCollateralEnabled` if asset is set as collateral
43 : : * @param reservesData The state of all the reserves
44 : : * @param reservesList The addresses of all the active reserves
45 : : * @param userConfig The user configuration mapping that tracks the supplied/borrowed assets
46 : : * @param asset The address of the underlying asset to mint aTokens of
47 : : * @param amount The amount to mint
48 : : * @param onBehalfOf The address that will receive the aTokens
49 : : * @param referralCode Code used to register the integrator originating the operation, for potential rewards.
50 : : * 0 if the action is executed directly by the user, without any middle-man
51 : : */
52 : : function executeMintUnbacked(
53 : : mapping(address => DataTypes.ReserveData) storage reservesData,
54 : : mapping(uint256 => address) storage reservesList,
55 : : DataTypes.UserConfigurationMap storage userConfig,
56 : : address asset,
57 : : uint256 amount,
58 : : address onBehalfOf,
59 : : uint16 referralCode
60 : : ) external {
61 : 16 : DataTypes.ReserveData storage reserve = reservesData[asset];
62 : 16 : DataTypes.ReserveCache memory reserveCache = reserve.cache();
63 : :
64 : 16 : reserve.updateState(reserveCache);
65 : :
66 : 16 : ValidationLogic.validateSupply(reserveCache, reserve, amount, onBehalfOf);
67 : :
68 : 16 : uint256 unbackedMintCap = reserveCache.reserveConfiguration.getUnbackedMintCap();
69 : 16 : uint256 reserveDecimals = reserveCache.reserveConfiguration.getDecimals();
70 : :
71 : 16 : uint256 unbacked = reserve.unbacked += amount.toUint128();
72 : :
73 : 16 : require(
74 : : unbacked <= unbackedMintCap * (10 ** reserveDecimals),
75 : : Errors.UNBACKED_MINT_CAP_EXCEEDED
76 : : );
77 : :
78 : 14 : reserve.updateInterestRatesAndVirtualBalance(reserveCache, asset, 0, 0);
79 : :
80 : 14 : bool isFirstSupply = IAToken(reserveCache.aTokenAddress).mint(
81 : : msg.sender,
82 : : onBehalfOf,
83 : : amount,
84 : : reserveCache.nextLiquidityIndex
85 : : );
86 : :
87 : 14 : if (isFirstSupply) {
88 : : if (
89 : 7 : ValidationLogic.validateAutomaticUseAsCollateral(
90 : : reservesData,
91 : : reservesList,
92 : : userConfig,
93 : : reserveCache.reserveConfiguration,
94 : : reserveCache.aTokenAddress
95 : : )
96 : : ) {
97 : 7 : userConfig.setUsingAsCollateral(reserve.id, true);
98 : 7 : emit ReserveUsedAsCollateralEnabled(asset, onBehalfOf);
99 : : }
100 : : }
101 : :
102 : 14 : emit MintUnbacked(asset, msg.sender, onBehalfOf, amount, referralCode);
103 : : }
104 : :
105 : : /**
106 : : * @notice Back the current unbacked with `amount` and pay `fee`.
107 : : * @dev It is not possible to back more than the existing unbacked amount of the reserve
108 : : * @dev Emits the `BackUnbacked` event
109 : : * @param reserve The reserve to back unbacked for
110 : : * @param asset The address of the underlying asset to repay
111 : : * @param amount The amount to back
112 : : * @param fee The amount paid in fees
113 : : * @param protocolFeeBps The fraction of fees in basis points paid to the protocol
114 : : * @return The backed amount
115 : : */
116 : : function executeBackUnbacked(
117 : : DataTypes.ReserveData storage reserve,
118 : : address asset,
119 : : uint256 amount,
120 : : uint256 fee,
121 : : uint256 protocolFeeBps
122 : : ) external returns (uint256) {
123 : 9 : DataTypes.ReserveCache memory reserveCache = reserve.cache();
124 : :
125 : 9 : reserve.updateState(reserveCache);
126 : :
127 : 9 : uint256 backingAmount = (amount < reserve.unbacked) ? amount : reserve.unbacked;
128 : :
129 : 9 : uint256 feeToProtocol = fee.percentMul(protocolFeeBps);
130 : 9 : uint256 feeToLP = fee - feeToProtocol;
131 : 9 : uint256 added = backingAmount + fee;
132 : :
133 : 9 : reserveCache.nextLiquidityIndex = reserve.cumulateToLiquidityIndex(
134 : : IERC20(reserveCache.aTokenAddress).totalSupply() +
135 : : uint256(reserve.accruedToTreasury).rayMul(reserveCache.nextLiquidityIndex),
136 : : feeToLP
137 : : );
138 : :
139 : 9 : reserve.accruedToTreasury += feeToProtocol.rayDiv(reserveCache.nextLiquidityIndex).toUint128();
140 : :
141 : 9 : reserve.unbacked -= backingAmount.toUint128();
142 : 9 : reserve.updateInterestRatesAndVirtualBalance(reserveCache, asset, added, 0);
143 : :
144 : 9 : IERC20(asset).safeTransferFrom(msg.sender, reserveCache.aTokenAddress, added);
145 : :
146 : 9 : emit BackUnbacked(asset, msg.sender, backingAmount, fee);
147 : :
148 : 9 : return backingAmount;
149 : : }
150 : : }
|