Branch data Line data Source code
1 : : // SPDX-License-Identifier: BUSL-1.1
2 : : pragma solidity ^0.8.10;
3 : :
4 : : import {DataTypes} from '../../protocol/libraries/types/DataTypes.sol';
5 : : import {FlashLoanSimpleReceiverBase} from '../../misc/flashloan/base/FlashLoanSimpleReceiverBase.sol';
6 : : import {GPv2SafeERC20} from '../../dependencies/gnosis/contracts/GPv2SafeERC20.sol';
7 : : import {IERC20} from '../../dependencies/openzeppelin/contracts/IERC20.sol';
8 : : import {IERC20Detailed} from '../../dependencies/openzeppelin/contracts/IERC20Detailed.sol';
9 : : import {IERC20WithPermit} from '../../interfaces/IERC20WithPermit.sol';
10 : : import {IPoolAddressesProvider} from '../../interfaces/IPoolAddressesProvider.sol';
11 : : import {IPriceOracleGetter} from '../../interfaces/IPriceOracleGetter.sol';
12 : : import {SafeMath} from '../../dependencies/openzeppelin/contracts/SafeMath.sol';
13 : : import {Ownable} from '../../dependencies/openzeppelin/contracts/Ownable.sol';
14 : :
15 : : /**
16 : : * @title BaseParaSwapAdapter
17 : : * @notice Utility functions for adapters using ParaSwap
18 : : * @author Jason Raymond Bell
19 : : */
20 : : abstract contract BaseParaSwapAdapter is FlashLoanSimpleReceiverBase, Ownable {
21 : : using SafeMath for uint256;
22 : : using GPv2SafeERC20 for IERC20;
23 : : using GPv2SafeERC20 for IERC20Detailed;
24 : : using GPv2SafeERC20 for IERC20WithPermit;
25 : :
26 : : struct PermitSignature {
27 : : uint256 amount;
28 : : uint256 deadline;
29 : : uint8 v;
30 : : bytes32 r;
31 : : bytes32 s;
32 : : }
33 : :
34 : : // Max slippage percent allowed
35 : : uint256 public constant MAX_SLIPPAGE_PERCENT = 3000; // 30%
36 : :
37 : : IPriceOracleGetter public immutable ORACLE;
38 : :
39 : : event Swapped(
40 : : address indexed fromAsset,
41 : : address indexed toAsset,
42 : : uint256 fromAmount,
43 : : uint256 receivedAmount
44 : : );
45 : : event Bought(
46 : : address indexed fromAsset,
47 : : address indexed toAsset,
48 : : uint256 amountSold,
49 : : uint256 receivedAmount
50 : : );
51 : :
52 : : constructor(
53 : : IPoolAddressesProvider addressesProvider
54 : : ) FlashLoanSimpleReceiverBase(addressesProvider) {
55 : 0 : ORACLE = IPriceOracleGetter(addressesProvider.getPriceOracle());
56 : : }
57 : :
58 : : /**
59 : : * @dev Get the price of the asset from the oracle denominated in eth
60 : : * @param asset address
61 : : * @return eth price for the asset
62 : : */
63 : : function _getPrice(address asset) internal view returns (uint256) {
64 : 30 : return ORACLE.getAssetPrice(asset);
65 : : }
66 : :
67 : : /**
68 : : * @dev Get the decimals of an asset
69 : : * @return number of decimals of the asset
70 : : */
71 : : function _getDecimals(IERC20Detailed asset) internal view returns (uint8) {
72 : 30 : uint8 decimals = asset.decimals();
73 : : // Ensure 10**decimals won't overflow a uint256
74 : 30 : require(decimals <= 77, 'TOO_MANY_DECIMALS_ON_TOKEN');
75 : 30 : return decimals;
76 : : }
77 : :
78 : : /**
79 : : * @dev Get the aToken associated to the asset
80 : : * @return address of the aToken
81 : : */
82 : : function _getReserveData(
83 : : address asset
84 : : ) internal view returns (DataTypes.ReserveDataLegacy memory) {
85 : 21 : return POOL.getReserveData(asset);
86 : : }
87 : :
88 : : function _pullATokenAndWithdraw(
89 : : address reserve,
90 : : address user,
91 : : uint256 amount,
92 : : PermitSignature memory permitSignature
93 : : ) internal {
94 : 6 : IERC20WithPermit reserveAToken = IERC20WithPermit(
95 : : _getReserveData(address(reserve)).aTokenAddress
96 : : );
97 : 6 : _pullATokenAndWithdraw(reserve, reserveAToken, user, amount, permitSignature);
98 : : }
99 : :
100 : : /**
101 : : * @dev Pull the ATokens from the user
102 : : * @param reserve address of the asset
103 : : * @param reserveAToken address of the aToken of the reserve
104 : : * @param user address
105 : : * @param amount of tokens to be transferred to the contract
106 : : * @param permitSignature struct containing the permit signature
107 : : */
108 : : function _pullATokenAndWithdraw(
109 : : address reserve,
110 : : IERC20WithPermit reserveAToken,
111 : : address user,
112 : : uint256 amount,
113 : : PermitSignature memory permitSignature
114 : : ) internal {
115 : : // If deadline is set to zero, assume there is no signature for permit
116 : 14 : if (permitSignature.deadline != 0) {
117 : 5 : reserveAToken.permit(
118 : : user,
119 : : address(this),
120 : : permitSignature.amount,
121 : : permitSignature.deadline,
122 : : permitSignature.v,
123 : : permitSignature.r,
124 : : permitSignature.s
125 : : );
126 : : }
127 : :
128 : : // transfer from user to adapter
129 : 14 : reserveAToken.safeTransferFrom(user, address(this), amount);
130 : :
131 : : // withdraw reserve
132 : 14 : require(POOL.withdraw(reserve, amount, address(this)) == amount, 'UNEXPECTED_AMOUNT_WITHDRAWN');
133 : : }
134 : :
135 : : /**
136 : : * @dev Emergency rescue for token stucked on this contract, as failsafe mechanism
137 : : * - Funds should never remain in this contract more time than during transactions
138 : : * - Only callable by the owner
139 : : */
140 : : function rescueTokens(IERC20 token) external onlyOwner {
141 : 1 : token.safeTransfer(owner(), token.balanceOf(address(this)));
142 : : }
143 : : }
|