From 77f3b6f33d88cf66b9af9e6d4a3b28d097bbd6c5 Mon Sep 17 00:00:00 2001
From: Richa-iitr <richa@cs.iitr.ac.in>
Date: Tue, 30 Aug 2022 18:06:00 +0530
Subject: [PATCH] basic functions added

---
 .../connectors/compound-iii/events.sol        |  54 +++++
 .../connectors/compound-iii/helpers.sol       |  58 +++++
 .../connectors/compound-iii/interface.sol     |  96 ++++++++
 .../mainnet/connectors/compound-iii/main.sol  | 205 ++++++++++++++++++
 4 files changed, 413 insertions(+)
 create mode 100644 contracts/mainnet/connectors/compound-iii/events.sol
 create mode 100644 contracts/mainnet/connectors/compound-iii/helpers.sol
 create mode 100644 contracts/mainnet/connectors/compound-iii/interface.sol
 create mode 100644 contracts/mainnet/connectors/compound-iii/main.sol

diff --git a/contracts/mainnet/connectors/compound-iii/events.sol b/contracts/mainnet/connectors/compound-iii/events.sol
new file mode 100644
index 00000000..a83641f4
--- /dev/null
+++ b/contracts/mainnet/connectors/compound-iii/events.sol
@@ -0,0 +1,54 @@
+//SPDX-License-Identifier: MIT
+pragma solidity ^0.7.0;
+
+contract Events {
+    event LogDeposit(
+        address indexed token,
+        address cToken,
+        uint256 tokenAmt,
+        uint256 getId,
+        uint256 setId
+    );
+
+    event LogWithdraw(
+        address indexed token,
+        address cToken,
+        uint256 tokenAmt,
+        uint256 getId,
+        uint256 setId
+    );
+
+    event LogBorrow(
+        address indexed token,
+        address cToken,
+        uint256 tokenAmt,
+        uint256 getId,
+        uint256 setId
+    );
+
+    event LogPayback(
+        address indexed token,
+        address cToken,
+        uint256 tokenAmt,
+        uint256 getId,
+        uint256 setId
+    );
+
+    event LogRewardsClaimed(
+        address indexed token,
+        address cToken,
+        uint256 tokenAmt,
+        uint256 cTokenAmt,
+        uint256 getId, 
+        uint256 setId
+    );
+    
+    event LogLiquidate(
+        address indexed borrower,
+        address indexed tokenToPay,
+        address indexed tokenInReturn,
+        uint256 tokenAmt,
+        uint256 getId,
+        uint256 setId
+    );
+}
diff --git a/contracts/mainnet/connectors/compound-iii/helpers.sol b/contracts/mainnet/connectors/compound-iii/helpers.sol
new file mode 100644
index 00000000..d25925be
--- /dev/null
+++ b/contracts/mainnet/connectors/compound-iii/helpers.sol
@@ -0,0 +1,58 @@
+//SPDX-License-Identifier: MIT
+pragma solidity ^0.7.0;
+
+import { DSMath } from "../../common/math.sol";
+import { Basic } from "../../common/basic.sol";
+import { CometInterface } from "./interface.sol";
+
+abstract contract Helpers is DSMath, Basic {
+	function getBaseToken(address market)
+		internal
+		view
+		returns (address baseToken)
+	{
+		baseToken = CometInterface(market).baseToken();
+	}
+
+	function _supply(
+		address market,
+		address token,
+		uint256 amt
+	) internal payable returns (bool success) {
+		bytes memory data = abi.encodeWithSignature(
+			"supply(address, uint256)",
+			token,
+			amt
+		);
+		(success, ) = market.delegateCall(data);
+	}
+
+	function _withdraw(
+		address market,
+		address token,
+		uint256 amt
+	) internal payable returns (bool success) {
+		bytes memory data = abi.encodeWithSignature(
+			"withdraw(address, uint256)",
+			token,
+			amt
+		);
+		(success, ) = market.delegateCall(data);
+	}
+
+	function getAccountSupplyBalanceOfAsset(
+		address account,
+		address market,
+		address asset
+	) internal view returns (uint256 balance) {
+		if (asset == getBaseToken(market)) {
+			//balance in base
+			balance = CometInterface(market).balanceOf(account);
+		} else {
+			//balance in asset denomination
+			balance = uint256(
+				CometInterface(market).userCollateral(account, asset).balance
+			);
+		}
+	}
+}
diff --git a/contracts/mainnet/connectors/compound-iii/interface.sol b/contracts/mainnet/connectors/compound-iii/interface.sol
new file mode 100644
index 00000000..a72d2bb6
--- /dev/null
+++ b/contracts/mainnet/connectors/compound-iii/interface.sol
@@ -0,0 +1,96 @@
+//SPDX-License-Identifier: MIT
+pragma solidity ^0.7.0;
+
+struct UserCollateral {
+	uint128 balance;
+	uint128 _reserved;
+}
+
+interface CometInterface {
+	function supply(address asset, uint256 amount) external virtual;
+
+	function supplyTo(
+		address dst,
+		address asset,
+		uint256 amount
+	) external virtual;
+
+	function supplyFrom(
+		address from,
+		address dst,
+		address asset,
+		uint256 amount
+	) external virtual;
+
+	function transfer(address dst, uint256 amount)
+		external
+		virtual
+		returns (bool);
+
+	function transferFrom(
+		address src,
+		address dst,
+		uint256 amount
+	) external virtual returns (bool);
+
+	function transferAsset(
+		address dst,
+		address asset,
+		uint256 amount
+	) external virtual;
+
+	function transferAssetFrom(
+		address src,
+		address dst,
+		address asset,
+		uint256 amount
+	) external virtual;
+
+	function withdraw(address asset, uint256 amount) external virtual;
+
+	function withdrawTo(
+		address to,
+		address asset,
+		uint256 amount
+	) external virtual;
+
+	function withdrawFrom(
+		address src,
+		address to,
+		address asset,
+		uint256 amount
+	) external virtual;
+
+	function approveThis(
+		address manager,
+		address asset,
+		uint256 amount
+	) external virtual;
+
+	function withdrawReserves(address to, uint256 amount) external virtual;
+
+	function absorb(address absorber, address[] calldata accounts)
+		external
+		virtual;
+
+	function buyCollateral(
+		address asset,
+		uint256 minAmount,
+		uint256 baseAmount,
+		address recipient
+	) external virtual;
+
+	function quoteCollateral(address asset, uint256 baseAmount)
+		public
+		view
+		virtual
+		returns (uint256);
+
+	function userCollateral(address, address)
+		external
+		returns (UserCollateral memory);
+
+	function baseToken() external view returns (address);
+
+	function balanceOf(address account) external view returns (uint256);
+}
diff --git a/contracts/mainnet/connectors/compound-iii/main.sol b/contracts/mainnet/connectors/compound-iii/main.sol
new file mode 100644
index 00000000..5bd56a14
--- /dev/null
+++ b/contracts/mainnet/connectors/compound-iii/main.sol
@@ -0,0 +1,205 @@
+//SPDX-License-Identifier: MIT
+pragma solidity ^0.7.0;
+pragma experimental ABIEncoderV2;
+
+/**
+ * @title Compound.
+ * @dev Lending & Borrowing.
+ */
+
+import { TokenInterface } from "../../common/interfaces.sol";
+import { Stores } from "../../common/stores.sol";
+import { Helpers } from "./helpers.sol";
+import { Events } from "./events.sol";
+import { CometInterface } from "./interface.sol";
+
+abstract contract CompoundIIIResolver is Events, Helpers {
+	/**
+	 * @dev Deposit base asset or collateral asset supported by the .
+	 * @notice Deposit a token to Compound for lending / collaterization.
+	 * @param market The address of the market from where to supply.
+	 * @param token The address of the token to be supplied. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
+	 * @param amt The amount of the token to deposit. (For max: `uint256(-1)`)
+	 * @param getId ID to retrieve amt.
+	 * @param setId ID stores the amount of tokens deposited.
+	 */
+	function deposit(
+		address market,
+		address token,
+		uint256 amt,
+		uint256 getId,
+		uint256 setId
+	)
+		public
+		payable
+		returns (string memory _eventName, bytes memory _eventParam)
+	{
+		uint256 _amt = getUint(getId, amt);
+
+		require(
+			market != address(0) && token != address(0),
+			"invalid market/token address"
+		);
+
+		bool isEth = token == ethAddr;
+		address _token = isEth ? wethAddr : token;
+		TokenInterface tokenContract = TokenInterface(_token);
+
+		if (isEth) {
+			convertEthToWeth(isEth, tokenContract, _amt);
+		}
+
+		approve(tokenContract, market, _amt);
+
+		bool success = _supply(market, _token, _amt);
+		require(success, "supply-failed");
+
+		setUint(setId, _amt);
+
+		_eventName = "LogDeposit(address,address,uint256,uint256,uint256)";
+		_eventParam = abi.encode(market, token, _amt, getId, setId);
+	}
+
+	/**
+	 * @dev Withdraw base/collateral asset or borrow base asset.
+	 * @notice Withdraw base token or deposited token from Compound.
+	 * @param market The address of the market from where to withdraw.
+	 * @param token The address of the token to be withdrawn. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
+	 * @param amt The amount of the token to withdraw. (For max: `uint256(-1)`)
+	 * @param getId ID to retrieve amt.
+	 * @param setId ID stores the amount of tokens withdrawn.
+	 */
+	function withdraw(
+		address market,
+		address token,
+		uint256 amt,
+		uint256 getId,
+		uint256 setId
+	)
+		public
+		payable
+		returns (string memory _eventName, bytes memory _eventParam)
+	{
+		uint256 _amt = getUint(getId, amt);
+
+		require(
+			market != address(0) && token != address(0),
+			"invalid market/token address"
+		);
+
+		bool isEth = token == ethAddr;
+		address _token = isEth ? wethAddr : token;
+
+		TokenInterface tokenContract = TokenInterface(_token);
+
+		uint256 initialBal = getAccountSupplyBalanceOfAsset(
+			address(this),
+			market,
+			token
+		);
+		bool success = _withdraw(market, token, _amt);
+		require(success, "withdraw-failed");
+
+		uint256 finalBal = getAccountSupplyBalanceOfAsset(
+			address(this),
+			market,
+			token
+		);
+
+		_amt = sub(finalBal, initialBal);
+
+		convertWethToEth(isEth, tokenContract, _amt);
+
+		setUint(setId, _amt);
+
+		_eventName = "LogWithdraw(address,address,uint256,uint256,uint256)";
+		_eventParam = abi.encode(market, token, _amt, getId, setId);
+	}
+
+	/**
+	 * @dev Withdraw base/collateral asset or borrow base asset.
+	 * @notice Withdraw base token or deposited token from Compound.
+	 * @param market The address of the market from where to withdraw.
+	 * @param amt The amount of the token to withdraw. (For max: `uint256(-1)`)
+	 * @param getId ID to retrieve amt.
+	 * @param setId ID stores the amount of tokens withdrawn.
+	 */
+	function borrow(
+		address market,
+		uint256 amt,
+		uint256 getId,
+		uint256 setId
+	)
+		external
+		payable
+		returns (string memory _eventName, bytes memory _eventParam)
+	{
+		uint256 _amt = getUint(getId, amt);
+
+		require(market != address(0), "invalid market address");
+
+		bool token = getBaseToken(market);
+		bool isEth = token == ethAddr;
+		address _token = isEth ? wethAddr : token;
+
+		TokenInterface tokenContract = TokenInterface(_token);
+
+		uint256 initialBal = getAccountSupplyBalanceOfAsset(
+			address(this),
+			market,
+			token
+		);
+		bool success = _withdraw(market, token, _amt);
+		require(success, "borrow-failed");
+
+		uint256 finalBal = getAccountSupplyBalanceOfAsset(
+			address(this),
+			market,
+			token
+		);
+
+		_amt = sub(finalBal, initialBal);
+
+		convertWethToEth(isEth, tokenContract, _amt);
+
+		setUint(setId, _amt);
+
+		_eventName = "LogBorrow(address,uint256,uint256,uint256)";
+		_eventParam = abi.encode(market, _amt, getId, setId);
+	}
+
+	function payBack(
+		address market,
+		uint256 getId,
+		uint256 setId
+	)
+		external
+		payable
+		returns (string memory _eventName, bytes memory _eventParam)
+	{
+		require(market != address(0), "invalid market address");
+
+		address token = getBaseToken(market);
+		bool isEth = token == ethAddr;
+		address _token = isEth ? wethAddr : token;
+		TokenInterface tokenContract = TokenInterface(_token);
+
+		if (isEth) {
+			convertEthToWeth(isEth, tokenContract, _amt);
+		}
+
+		approve(tokenContract, market, _amt);
+
+		bool success = _supply(market, _token, _amt);
+		require(success, "supply-failed");
+
+		setUint(setId, _amt);
+
+		_eventName = "LogDeposit(address,address,uint256,uint256,uint256)";
+		_eventParam = abi.encode(market, token, _amt, getId, setId);
+	}
+}
+
+contract ConnectV3Compound is CompoundResolver {
+	string public name = "Compound-v1.0";
+}