mirror of
https://github.com/Instadapp/fluid-contracts-public.git
synced 2024-07-29 21:57:37 +00:00
d7a58e88ff
ARB: deploy protocols
134 lines
5.0 KiB
Solidity
134 lines
5.0 KiB
Solidity
// SPDX-License-Identifier: BUSL-1.1
|
|
pragma solidity 0.8.21;
|
|
|
|
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
|
|
import { FluidLiquidityUserModule } from "../liquidity/userModule/main.sol";
|
|
import { IFluidLiquidity } from "../liquidity/interfaces/iLiquidity.sol";
|
|
|
|
/// @title Mock Protocol
|
|
/// @notice Mock protocol for testing, implements:
|
|
/// function liquidityCallback(address token_, uint256 amount_, bytes calldata data_) external;
|
|
/// This callback method MUST transferFrom data_ decoded from address to the liquidity contract
|
|
contract MockProtocol {
|
|
using SafeERC20 for IERC20;
|
|
|
|
/// @dev address that is mapped to the chain native token
|
|
address internal constant NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
|
|
|
address public immutable liquidityContract;
|
|
|
|
/// @notice thrown when liquidity callback is called for a native token operation
|
|
error MockProtocol__UnexpectedLiquidityCallback();
|
|
|
|
bool transferInsufficientMode = false;
|
|
bool transferExcessMode = false;
|
|
bool reentrancyFromCallback = false;
|
|
address transferFromAddress;
|
|
|
|
/// @notice Construct a new MockProtocol
|
|
/// @param liquidityContract_ The address of the liquidity contract
|
|
constructor(address liquidityContract_) {
|
|
liquidityContract = liquidityContract_;
|
|
}
|
|
|
|
receive() external payable {}
|
|
|
|
function setTransferInsufficientMode(bool transferInsufficientMode_) public {
|
|
transferInsufficientMode = transferInsufficientMode_;
|
|
}
|
|
|
|
function setTransferExcessMode(bool transferExcessMode_) public {
|
|
transferExcessMode = transferExcessMode_;
|
|
}
|
|
|
|
function setReentrancyFromCallback(bool reentrancyFromCallback_) public {
|
|
reentrancyFromCallback = reentrancyFromCallback_;
|
|
}
|
|
|
|
function setTransferFromAddress(address transferFromAddress_) public {
|
|
transferFromAddress = transferFromAddress_;
|
|
}
|
|
|
|
/// @notice Mock liquidity callback
|
|
/// @param token_ The token being transferred
|
|
/// @param amount_ The amount being transferred
|
|
function liquidityCallback(address token_, uint256 amount_, bytes memory data_) external {
|
|
if (reentrancyFromCallback) {
|
|
// call operate with some random values (should not matter as it reverts anyway)
|
|
IFluidLiquidity(liquidityContract).operate(token_, 10, 0, address(0), address(0), abi.encode(address(this)));
|
|
}
|
|
|
|
if (token_ == NATIVE_TOKEN_ADDRESS) {
|
|
revert MockProtocol__UnexpectedLiquidityCallback();
|
|
}
|
|
|
|
address from_;
|
|
if (transferFromAddress == address(0)) {
|
|
// take the last 20 bytes of data_ and decode them to address. Gives more flexibility in type of
|
|
// data that can be passed in to Liquidity at mock calls while ensuring mock Protocol can do what it
|
|
// is supposed to do: transfer amount of token to liquidity.
|
|
assembly {
|
|
from_ := mload(
|
|
add(
|
|
// add padding for length as present for dynamic arrays in memory
|
|
add(data_, 32),
|
|
// assembly expects address with leading zeros / left padded so need to use 32 as length here
|
|
sub(mload(data_), 32)
|
|
)
|
|
)
|
|
}
|
|
} else {
|
|
from_ = transferFromAddress;
|
|
}
|
|
|
|
if (amount_ > 0) {
|
|
if (transferExcessMode) {
|
|
amount_ += 1e6;
|
|
} else if (transferInsufficientMode) {
|
|
amount_ -= 1;
|
|
}
|
|
}
|
|
|
|
if (from_ == address(this)) {
|
|
// use approve and transferFrom for more consistent testing of methods called
|
|
// (always transferFrom instead of transfer)
|
|
IERC20(token_).safeApprove(address(this), amount_);
|
|
IERC20(token_).safeTransferFrom(address(this), liquidityContract, amount_);
|
|
} else {
|
|
IERC20(token_).safeTransferFrom(from_, liquidityContract, amount_);
|
|
}
|
|
}
|
|
|
|
/// @notice Proxy method for executing `operate` on the liquidity contract
|
|
function operate(
|
|
address token_,
|
|
int256 supplyAmount_,
|
|
int256 borrowAmount_,
|
|
address withdrawTo_,
|
|
address borrowTo_,
|
|
bytes calldata callbackData_
|
|
) external payable returns (uint256 supplyExchangePrice_, uint256 borrowExchangePrice_) {
|
|
uint256 valueAmount = msg.value;
|
|
|
|
if (valueAmount > 0) {
|
|
if (transferExcessMode) {
|
|
valueAmount += 1e9 + 1;
|
|
} else if (transferInsufficientMode) {
|
|
valueAmount -= 1;
|
|
}
|
|
}
|
|
|
|
return
|
|
FluidLiquidityUserModule(liquidityContract).operate{ value: valueAmount }(
|
|
token_,
|
|
supplyAmount_,
|
|
borrowAmount_,
|
|
withdrawTo_,
|
|
borrowTo_,
|
|
callbackData_
|
|
);
|
|
}
|
|
}
|