Skip to content

Commit

Permalink
execution contract
Browse files Browse the repository at this point in the history
  • Loading branch information
pruales committed Sep 24, 2022
1 parent 16c94ff commit 0772cc5
Show file tree
Hide file tree
Showing 10 changed files with 324 additions and 14 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
[submodule "packages/contracts/lib/openzeppelin-contracts"]
path = packages/contracts/lib/openzeppelin-contracts
url = https://github.com/OpenZeppelin/openzeppelin-contracts
[submodule "packages/contracts/lib/v3-core"]
path = packages/contracts/lib/v3-core
url = https://github.com/uniswap/v3-core
1 change: 1 addition & 0 deletions packages/contracts/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ verbosity = 1
remappings = [
"forge-std/=./lib/forge-std/src/",
"@openzeppelin/=./lib/openzeppelin-contracts/",
"@uniswap/=./lib/v3-core/contracts/"
]
1 change: 1 addition & 0 deletions packages/contracts/lib/v3-core
Submodule v3-core added at 412d9b
156 changes: 156 additions & 0 deletions packages/contracts/src/Execution.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

import './handlers/aavev3/IPool.sol';
import './handlers/aavev3/IPoolAddressesProvider.sol';
import './interfaces/IERC20Usdt.sol';
import './handlers/univ3/ISwapRouter.sol';

import '@openzeppelin/contracts/access/Ownable.sol';
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';

contract Execution is Ownable {
using SafeERC20 for IERC20;

//Goerli
address public constant PROVIDER = 0xc4dCB5126a3AfEd129BC3668Ea19285A9f56D15D;
ISwapRouter public constant ROUTER = ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564);
address public constant NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

function getContractName() public pure returns (string memory) {
return 'Execution';
}

function transferToken(
address token,
address to,
uint256 amount,
address originationAddress
) external onlyOwner {
IERC20(token).safeTransferFrom(originationAddress, to, amount);
}

function exactInputSingle(
address originationAddress,
address tokenIn,
address tokenOut,
uint24 fee,
address destinationAddress,
uint256 amountIn
) external payable onlyOwner returns (uint256 amountOut) {
// Build params for router call
ISwapRouter.ExactInputSingleParams memory params;
params.tokenIn = tokenIn;
params.tokenOut = tokenOut;
params.fee = fee;
params.amountIn = _getBalance(tokenIn, amountIn);
params.amountOutMinimum = 0;
params.sqrtPriceLimitX96 = 0;
params.recipient = destinationAddress;

IERC20(tokenIn).safeTransferFrom(originationAddress, address(this), amountIn);
_tokenApprove(tokenIn, address(ROUTER), params.amountIn);
amountOut = _exactInputSingle(0, params);
}

function depositAaveV3(
address token,
uint256 amount,
address destinationAddress,
address originationAddress
) external payable onlyOwner {
amount = _getBalance(token, amount);
IERC20(token).safeTransferFrom(originationAddress, address(this), amount);
_depositAaveV3(token, amount, destinationAddress);
}

function _depositAaveV3(
address asset,
uint256 amount,
address destinationAddress
) internal {
(address pool, ) = _getPoolAndAToken(asset);
_tokenApprove(asset, pool, amount);
try IPool(pool).supply(asset, amount, destinationAddress, 0) {} catch Error(
string memory reason
) {
_revertMsg('supply', reason);
} catch {
_revertMsg('supply');
}
}

/* ========== INTERNAL FUNCTIONS ========== */

function _getPoolAndAToken(address underlying)
internal
view
returns (address pool, address aToken)
{
pool = IPoolAddressesProvider(PROVIDER).getPool();
try IPool(pool).getReserveData(underlying) returns (DataTypes.ReserveData memory data) {
aToken = data.aTokenAddress;
_requireMsg(aToken != address(0), 'General', 'aToken should not be zero address');
} catch Error(string memory reason) {
_revertMsg('General', reason);
} catch {
_revertMsg('General');
}
}

function _exactInputSingle(uint256 value, ISwapRouter.ExactInputSingleParams memory params)
internal
returns (uint256)
{
params.deadline = block.timestamp;

try ROUTER.exactInputSingle{value: value}(params) returns (uint256 amountOut) {
return amountOut;
} catch Error(string memory reason) {
_revertMsg('exactInputSingle', reason);
} catch {
_revertMsg('exactInputSingle');
}
}

function _tokenApprove(
address token,
address spender,
uint256 amount
) internal {
try IERC20Usdt(token).approve(spender, amount) {} catch {
IERC20(token).safeApprove(spender, 0);
IERC20(token).safeApprove(spender, amount);
}
}

function _getBalance(address token, uint256 amount) internal view returns (uint256) {
if (amount != type(uint256).max) {
return amount;
}

// ETH case
if (token == address(0) || token == NATIVE_TOKEN_ADDRESS) {
return address(this).balance;
}
// ERC20 token case
return IERC20(token).balanceOf(address(this));
}

function _requireMsg(
bool condition,
string memory functionName,
string memory reason
) internal pure {
if (!condition) _revertMsg(functionName, reason);
}

function _revertMsg(string memory functionName, string memory reason) internal pure {
revert(string(abi.encodePacked(getContractName(), '_', functionName, ': ', reason)));
}

function _revertMsg(string memory functionName) internal pure {
_revertMsg(functionName, 'Unspecified');
}
}
5 changes: 3 additions & 2 deletions packages/contracts/src/handlers/aavev3/HAaveProtocolV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ import './IFlashLoanReceiver.sol';

contract HAaveProtocolV3 is HandlerBase, IFlashLoanReceiver {
// prettier-ignore
address public constant PROVIDER = 0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb;
//mumbai testnet
address public constant PROVIDER = 0x5343b5bA672Ae99d627A1C87866b8E53F47Db2E6;
// prettier-ignore
address public constant WMATIC = 0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270;
address public constant WMATIC = 0xb685400156cF3CBE8725958DeAA61436727A30c3;
uint16 public constant REFERRAL_CODE = 56;

function getContractName() public pure override returns (string memory) {
Expand Down
42 changes: 42 additions & 0 deletions packages/contracts/src/handlers/funds/HFunds.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import '../HandlerBase.sol';

contract HFunds is HandlerBase {
using SafeERC20 for IERC20;

function getContractName() public pure override returns (string memory) {
return 'HFunds';
}

function inject(address[] calldata tokens, uint256[] calldata amounts)
external
payable
returns (uint256[] memory)
{
return _inject(tokens, amounts);
}

function _inject(address[] calldata tokens, uint256[] calldata amounts)
internal
returns (uint256[] memory)
{
_requireMsg(tokens.length == amounts.length, 'inject', 'token and amount does not match');
address sender = _getSender();
uint256[] memory amountsInProxy = new uint256[](amounts.length);

for (uint256 i = 0; i < tokens.length; i++) {
_notMaticToken(tokens[i]);
IERC20(tokens[i]).safeTransferFrom(sender, address(this), amounts[i]);

amountsInProxy[i] = amounts[i];

// Update involved token
_updateToken(tokens[i]);
}
return amountsInProxy;
}
}
105 changes: 105 additions & 0 deletions packages/contracts/src/handlers/univ3/ISwapRouter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;

import '@uniswap/interfaces/callback/IUniswapV3SwapCallback.sol';

/// @title Periphery Payments
/// @notice Functions to ease deposits and withdrawals of ETH
interface IPeripheryPayments {
/// @notice Unwraps the contract's WETH9 balance and sends it to recipient as ETH.
/// @dev The amountMinimum parameter prevents malicious contracts from stealing WETH9 from users.
/// @param amountMinimum The minimum amount of WETH9 to unwrap
/// @param recipient The address receiving ETH
function unwrapWETH9(uint256 amountMinimum, address recipient) external payable;

/// @notice Refunds any ETH balance held by this contract to the `msg.sender`
/// @dev Useful for bundling with mint or increase liquidity that uses ether, or exact output swaps
/// that use ether for the input amount
function refundETH() external payable;

/// @notice Transfers the full amount of a token held by this contract to recipient
/// @dev The amountMinimum parameter prevents malicious contracts from stealing the token from users
/// @param token The contract address of the token which will be transferred to `recipient`
/// @param amountMinimum The minimum amount of token required for a transfer
/// @param recipient The destination address of the token
function sweepToken(
address token,
uint256 amountMinimum,
address recipient
) external payable;
}

/// @title Router token swapping functionality
/// @notice Functions for swapping tokens via Uniswap V3
interface ISwapRouter is IUniswapV3SwapCallback, IPeripheryPayments {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}

/// @notice Swaps `amountIn` of one token for as much as possible of another token
/// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
/// @return amountOut The amount of the received token
function exactInputSingle(ExactInputSingleParams calldata params)
external
payable
returns (uint256 amountOut);

struct ExactInputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
}

/// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path
/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata
/// @return amountOut The amount of the received token
function exactInput(ExactInputParams calldata params)
external
payable
returns (uint256 amountOut);

struct ExactOutputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
uint160 sqrtPriceLimitX96;
}

/// @notice Swaps as little as possible of one token for `amountOut` of another token
/// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata
/// @return amountIn The amount of the input token
function exactOutputSingle(ExactOutputSingleParams calldata params)
external
payable
returns (uint256 amountIn);

struct ExactOutputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
}

/// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)
/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata
/// @return amountIn The amount of the input token
function exactOutput(ExactOutputParams calldata params)
external
payable
returns (uint256 amountIn);
}
2 changes: 1 addition & 1 deletion packages/contracts/src/handlers/wmatic/HWmatic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import './IWMATIC.sol';

contract HWmatic is HandlerBase {
// prettier-ignore
address public constant WMATIC = 0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270;
address public constant WMATIC = 0xb685400156cF3CBE8725958DeAA61436727A30c3;

function getContractName() public pure override returns (string memory) {
return 'HWmatic';
Expand Down
22 changes: 11 additions & 11 deletions packages/contracts/test/Counter.t.sol
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import {Counter} from "../src/Counter.sol";
import "forge-std/Test.sol";
import {Counter} from '../src/Counter.sol';
import 'forge-std/Test.sol';

contract CounterTest is Test {
Counter c;
Counter c;

function setUp() public {
c = new Counter();
}
function setUp() public {
c = new Counter();
}

function testIncrementCounter() public {
require(c.getCount() == 0, "Counter should be 0");
c.increment();
require(c.getCount() == 1, "Counter should be 1");
}
function testIncrementCounter() public {
require(c.getCount() == 0, 'Counter should be 0');
c.increment();
require(c.getCount() == 1, 'Counter should be 1');
}
}
1 change: 1 addition & 0 deletions remappings.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@openzeppelin/=./packages/contracts/lib/openzeppelin-contracts/
ds-test/=packages/contracts/lib/forge-std/lib/ds-test/src/
forge-std/=./packages/contracts/lib/forge-std/src/
@uniswap/=./packages/contracts/lib/v3-core/contracts/

0 comments on commit 0772cc5

Please sign in to comment.