Contract 0xD94cB7131e6cB9255d73E1d51777bc67831625fe

Contract Overview

Balance:
0 Ether

Token:
Txn Hash
Method
Block
From
To
Value
0x161d86661be632883c95dc21e12c87b71467514c7d1e0aac015c1f80296b707aSponsor Deposit289817622021-12-27 21:07:44189 days 2 hrs ago0x65f6bfcfe22b925c34d05efae9101926b970570c IN  0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether0.00021262.5
0xe68daabd8efeac4698456458cbe6bf4681afce797a57b8a022cee72e27da475dDeposit289815882021-12-27 20:52:32189 days 2 hrs ago0x65f6bfcfe22b925c34d05efae9101926b970570c IN  0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether0.000245282.5
0x2363dcfde17aec83f5cfb93069e69a7917dd61bf878b27541271623652f92629Deposit287686062021-12-14 19:03:00202 days 4 hrs ago0xcbb6c1415aa8d5c89c27a3314d562e71f127790b IN  0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether0.00024534 2.5
0x4513114ac3bf9314233ee9fbdcbf0459f910e898e20572569a36a6520a8959beSponsor Withdraw285694312021-11-27 17:27:48219 days 5 hrs ago0x74acf5cf26883b6c2907b26b16445f6df1a44bb8 IN  0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether0.00066241 2.5
0x9e091f01b447e409cacb7646efafb0c4bc99bddb15fc06ab8c818998f0d3c297Sponsor Deposit285693072021-11-27 17:15:24219 days 6 hrs ago0x74acf5cf26883b6c2907b26b16445f6df1a44bb8 IN  0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether0.00009111 2.5
0x5da6a8bf9f2fbda2dbe363db052889ab914c33ad4870782d3389e6c201bd5d6eSponsor Deposit285693032021-11-27 17:15:00219 days 6 hrs ago0x74acf5cf26883b6c2907b26b16445f6df1a44bb8 IN  0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether0.00062698 2.5
0x3d09f4341e63be94657db2da40c5113278f1c92af273652562e08c0c0cea05efDeposit285171612021-11-24 2:18:36222 days 21 hrs ago0xcc0f23d338ad43af60db54d83046fb5040ce014e IN  0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether0.00025065 2
0x0c25e4221f1dbd6445db3367df638cb856547892fc8d8f600a2720eb589cf25dSponsor Deposit284592002021-11-20 1:39:24226 days 21 hrs ago0x0fb680e7de03f32bfe31e774ec10adf5bd5a5f6b IN  0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether0.00175945 7.46496001
0x0b7b338ffb6bbfb6694574093508292a7a511e9450f058b3bde22dcbe432b1adSponsor Deposit284591722021-11-20 1:36:36226 days 21 hrs ago0x0fb680e7de03f32bfe31e774ec10adf5bd5a5f6b IN  0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether0.001908 7.46496001
0xc57cf6015b9ff09164afe55332de5a5e534c7674c51219209eb36b2e981f11c6Deposit284094372021-11-16 14:42:24230 days 8 hrs ago0x2f0c6d4c3cf5520a93da201bc914f97f3c2aa041 IN  0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether0.00024107 2
0x8e01e9ea2917cc92b8d78c0bc8f0842c505416c541153a4c18b5c08c5c94608fSponsor Withdraw282606952021-11-09 7:06:16237 days 16 hrs ago0x31434666c2cc48a871ae51bfbc3d65a0aae58555 IN  0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether0.0001188 2
0x9c6693bdc47fa21097763702477d5dcbf798e2e85746aafe087f20bac59756e7Sponsor Withdraw282606492021-11-09 7:03:12237 days 16 hrs ago0xe6f40288ecf3e36d2edbbc132194108ae3bd03d8 IN  0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether0.0001188 2
0xe27f97a78bcbf6ebea9426d911d32e00f732d58daf1a29350060506518af8222Sponsor Withdraw282606092021-11-09 7:00:32237 days 16 hrs ago0x7a492814b572da95c29451c25ce9bcde0626b74d IN  0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether0.0001188 2
0xefcedace00b6937e2e6f72d1aecab93ea78a75ad789b78eb144a83ec09b9a208Sponsor Withdraw282605472021-11-09 6:56:24237 days 16 hrs ago0x087aeb40bb08b02da858742b0c6eac931778a1fd IN  0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether0.0001188 2
0xd88585646ef4672b36085968ad6852cc3119e2bc085d203bdc0a776e5c5a40c6Sponsor Withdraw282604782021-11-09 6:51:48237 days 16 hrs ago0x4930a87f553553167908685617f3e32c3b25200d IN  0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether0.0001188 2
0xc25ec14e08c6e8deccef3641159e6008358728ecd4d086e3baf015eb9c3491d3Sponsor Deposit282603972021-11-09 6:46:24237 days 16 hrs ago0x31434666c2cc48a871ae51bfbc3d65a0aae58555 IN  0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether0.00017966 2
0xd677903ee6d68ff754d9dd953b36dfbf3453269a060e192a41bb8a329dd0ffa8Deposit282603822021-11-09 6:45:24237 days 16 hrs ago0x31434666c2cc48a871ae51bfbc3d65a0aae58555 IN  0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether0.00019622 2
0xece62cae819633bbd4e48da52df12948524d7fbb74e60253ff349c839c7b5e36Sponsor Deposit282603222021-11-09 6:41:24237 days 16 hrs ago0xe6f40288ecf3e36d2edbbc132194108ae3bd03d8 IN  0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether0.00017966 2
0x061c33334494eb6e274bc8a1046ed8f25e1315972129a4740da5769b18c6773bDeposit282603042021-11-09 6:40:12237 days 16 hrs ago0xe6f40288ecf3e36d2edbbc132194108ae3bd03d8 IN  0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether0.00019622 2
0x9c58ad872ef52c8e83485f813d83dd49c056a9f309f74be7cfbff1561631fcbaSponsor Deposit282602282021-11-09 6:35:08237 days 16 hrs ago0x7a492814b572da95c29451c25ce9bcde0626b74d IN  0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether0.00017966 2
0x97d648b67671bb61d24aca1c463457b0750bd1ee03b487f4cca7446c36427b1dDeposit282602092021-11-09 6:33:52237 days 16 hrs ago0x7a492814b572da95c29451c25ce9bcde0626b74d IN  0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether0.00019622 2
0x131503d66e19f0d7f64a5677642a1fa3e9747fc7b7515fe110021ca69d8e9d2fSponsor Deposit282600972021-11-09 6:26:24237 days 17 hrs ago0x087aeb40bb08b02da858742b0c6eac931778a1fd IN  0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether0.00017966 2
0x1b5ef58b9972270ab360c3a88e49fc8279911a64a23eface2882d14689e08660Deposit282600732021-11-09 6:24:48237 days 17 hrs ago0x087aeb40bb08b02da858742b0c6eac931778a1fd IN  0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether0.00019622 2
0x1b49f1c4a2acd7fb2025bfb3a42aeaeb8d5e96b980ad6943a1f7c7501fdf8708Sponsor Deposit282599982021-11-09 6:19:48237 days 17 hrs ago0x4930a87f553553167908685617f3e32c3b25200d IN  0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether0.00014546 2
0x0b849e0daff29efec0d5656be851deac7100200a5130cabcf480baac0e2498e5Sponsor Deposit282599972021-11-09 6:19:44237 days 17 hrs ago0x4930a87f553553167908685617f3e32c3b25200d IN  0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether0.00017966 2
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x49ce3184d5d9295a68b6ac0342469a915ab8928708981e627b92df5d2b5c93fc325464372022-07-04 19:13:444 hrs 13 mins ago 0xd94cb7131e6cb9255d73e1d51777bc67831625fe 0x13512979ade267ab5100878e2e0f485b568328a40 Ether
0x49ce3184d5d9295a68b6ac0342469a915ab8928708981e627b92df5d2b5c93fc325464372022-07-04 19:13:444 hrs 13 mins ago 0xd94cb7131e6cb9255d73e1d51777bc67831625fe 0xcd43ae6fc7531049352bc802926c703b7352a21b0 Ether
0x49ce3184d5d9295a68b6ac0342469a915ab8928708981e627b92df5d2b5c93fc325464372022-07-04 19:13:444 hrs 13 mins ago 0xd94cb7131e6cb9255d73e1d51777bc67831625fe 0x68ddb4c5eb8ab55dfffb06a50b4a89c4f37f4ae70 Ether
0x49ce3184d5d9295a68b6ac0342469a915ab8928708981e627b92df5d2b5c93fc325464372022-07-04 19:13:444 hrs 13 mins ago 0xd94cb7131e6cb9255d73e1d51777bc67831625fe 0xcd43ae6fc7531049352bc802926c703b7352a21b0 Ether
0x49ce3184d5d9295a68b6ac0342469a915ab8928708981e627b92df5d2b5c93fc325464372022-07-04 19:13:444 hrs 13 mins ago 0x1befe499df6a39608937c9318003b3caabe07679 0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether
0x49ce3184d5d9295a68b6ac0342469a915ab8928708981e627b92df5d2b5c93fc325464372022-07-04 19:13:444 hrs 13 mins ago 0x1befe499df6a39608937c9318003b3caabe07679 0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether
0x49ce3184d5d9295a68b6ac0342469a915ab8928708981e627b92df5d2b5c93fc325464372022-07-04 19:13:444 hrs 13 mins ago 0xd94cb7131e6cb9255d73e1d51777bc67831625fe 0xcd43ae6fc7531049352bc802926c703b7352a21b0 Ether
0x49ce3184d5d9295a68b6ac0342469a915ab8928708981e627b92df5d2b5c93fc325464372022-07-04 19:13:444 hrs 13 mins ago 0xd94cb7131e6cb9255d73e1d51777bc67831625fe 0x13512979ade267ab5100878e2e0f485b568328a40 Ether
0x49ce3184d5d9295a68b6ac0342469a915ab8928708981e627b92df5d2b5c93fc325464372022-07-04 19:13:444 hrs 13 mins ago 0xd94cb7131e6cb9255d73e1d51777bc67831625fe 0x3d400312bb3456f4dc06d528b55707f08dffd6640 Ether
0x49ce3184d5d9295a68b6ac0342469a915ab8928708981e627b92df5d2b5c93fc325464372022-07-04 19:13:444 hrs 13 mins ago 0x1befe499df6a39608937c9318003b3caabe07679 0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether
0x49ce3184d5d9295a68b6ac0342469a915ab8928708981e627b92df5d2b5c93fc325464372022-07-04 19:13:444 hrs 13 mins ago 0x1befe499df6a39608937c9318003b3caabe07679 0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether
0x49ce3184d5d9295a68b6ac0342469a915ab8928708981e627b92df5d2b5c93fc325464372022-07-04 19:13:444 hrs 13 mins ago 0x1befe499df6a39608937c9318003b3caabe07679 0xd94cb7131e6cb9255d73e1d51777bc67831625fe0 Ether
0xc8bf85d2ee823ca61b2466937dd72c50d41ec0ec9a5c2ff09164593cc405345e325464362022-07-04 19:13:404 hrs 14 mins ago 0xd94cb7131e6cb9255d73e1d51777bc67831625fe 0xcd43ae6fc7531049352bc802926c703b7352a21b0 Ether
0xc8bf85d2ee823ca61b2466937dd72c50d41ec0ec9a5c2ff09164593cc405345e325464362022-07-04 19:13:404 hrs 14 mins ago 0xd94cb7131e6cb9255d73e1d51777bc67831625fe 0x03d2dd5b568a60bb7e0eb12daf13f372e8d7b8060 Ether
0xc8bf85d2ee823ca61b2466937dd72c50d41ec0ec9a5c2ff09164593cc405345e325464362022-07-04 19:13:404 hrs 14 mins ago 0xd94cb7131e6cb9255d73e1d51777bc67831625fe 0x03d2dd5b568a60bb7e0eb12daf13f372e8d7b8060 Ether
0xc8bf85d2ee823ca61b2466937dd72c50d41ec0ec9a5c2ff09164593cc405345e325464362022-07-04 19:13:404 hrs 14 mins ago 0xd94cb7131e6cb9255d73e1d51777bc67831625fe 0x13512979ade267ab5100878e2e0f485b568328a40 Ether
0xc8bf85d2ee823ca61b2466937dd72c50d41ec0ec9a5c2ff09164593cc405345e325464362022-07-04 19:13:404 hrs 14 mins ago 0xd94cb7131e6cb9255d73e1d51777bc67831625fe 0xec7ed93d77368a0101cef1a3cb8af79ede1dfec00 Ether
0xc8bf85d2ee823ca61b2466937dd72c50d41ec0ec9a5c2ff09164593cc405345e325464362022-07-04 19:13:404 hrs 14 mins ago 0xd94cb7131e6cb9255d73e1d51777bc67831625fe 0x68ddb4c5eb8ab55dfffb06a50b4a89c4f37f4ae70 Ether
0xc8bf85d2ee823ca61b2466937dd72c50d41ec0ec9a5c2ff09164593cc405345e325464362022-07-04 19:13:404 hrs 14 mins ago 0xd94cb7131e6cb9255d73e1d51777bc67831625fe 0xcd43ae6fc7531049352bc802926c703b7352a21b0 Ether
0xc8bf85d2ee823ca61b2466937dd72c50d41ec0ec9a5c2ff09164593cc405345e325464362022-07-04 19:13:404 hrs 14 mins ago 0xd94cb7131e6cb9255d73e1d51777bc67831625fe 0x3d400312bb3456f4dc06d528b55707f08dffd6640 Ether
0xc8bf85d2ee823ca61b2466937dd72c50d41ec0ec9a5c2ff09164593cc405345e325464362022-07-04 19:13:404 hrs 14 mins ago 0xd94cb7131e6cb9255d73e1d51777bc67831625fe 0xe0fba4fc209b4948668006b2be61711b7f465bae0 Ether
0xc8bf85d2ee823ca61b2466937dd72c50d41ec0ec9a5c2ff09164593cc405345e325464362022-07-04 19:13:404 hrs 14 mins ago 0xd94cb7131e6cb9255d73e1d51777bc67831625fe 0xff3c8bc103682fa918c954e84f5056ab4dd5189d0 Ether
0xc8bf85d2ee823ca61b2466937dd72c50d41ec0ec9a5c2ff09164593cc405345e325464362022-07-04 19:13:404 hrs 14 mins ago 0xd94cb7131e6cb9255d73e1d51777bc67831625fe 0x3c73a5e5785cac854d468f727c606c07488a29d60 Ether
0xc8bf85d2ee823ca61b2466937dd72c50d41ec0ec9a5c2ff09164593cc405345e325464362022-07-04 19:13:404 hrs 14 mins ago 0xd94cb7131e6cb9255d73e1d51777bc67831625fe 0x88757f2f99175387ab4c6a4b3067c77a695b03490 Ether
0xc8bf85d2ee823ca61b2466937dd72c50d41ec0ec9a5c2ff09164593cc405345e325464362022-07-04 19:13:404 hrs 14 mins ago 0xd94cb7131e6cb9255d73e1d51777bc67831625fe 0x88757f2f99175387ab4c6a4b3067c77a695b03490 Ether
[ Download CSV Export 
Loading

Similar Match Source Code
Note: This contract matches the deployed ByteCode of the Source Code for Contract 0x2c16E95E5F564523472B535017152793404bA92F

Contract Name:
LosslessV2Pool

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 15 : LosslessV2Pool.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.6.12;

import "../interfaces/ILosslessV2Pool.sol";
import "../interfaces/ILosslessV2Factory.sol";
import "../interfaces/ILosslessV2Token.sol";

import "../interfaces/IPriceOracleGetter.sol";
import "../interfaces/ILendingPoolAddressesProvider.sol";
import "../interfaces/ILendingPool.sol";
import "../interfaces/IProtocolDataProvider.sol";

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";

import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol";
import "@chainlink/contracts/src/v0.6/interfaces/KeeperCompatibleInterface.sol";

contract LosslessV2Pool is ILosslessV2Pool, KeeperCompatibleInterface{
	using SafeMath for uint256;

	// basic info for initializing a pool
	address public override factory;
	address public override bidToken;
	address public override principalToken;
	address public override aToken;
	address public override addressProvider;

	AggregatorV3Interface private priceFeed;

	// used for calculating share price, define the precision is 0.0001
	uint256 public constant PRECISION = 10**4;

	///@dev the actual share value is valuePerShortToken /  PRECISION (constant = 10000)
	uint256 public valuePerShortToken = PRECISION; // the value of a single share - short
	uint256 public valuePerLongToken = PRECISION; // the value of a single share - long
	uint256 public constant valuePerSponsorToken = PRECISION; // the value of sponsor share should be fixed to PRECISION

	uint256 private totalInterest;

	GameStatus public status;
	PoolTokensInfo public poolTokensInfo;
	// mapping(address => uint256) public override inPoolTimestamp;

	ILosslessV2Token private _shortToken;
	ILosslessV2Token private _longToken;
	ILosslessV2Token private _sponsorToken;

	// lock modifier
	bool private accepting = true;
	modifier lock() {
		require(accepting == true, "LosslessV2Pool: LOCKED");
		accepting = false;
		_;
		accepting = true;
	}

	modifier onlyFactory() {
		require(msg.sender == factory, "LosslessV2Factory: FACTORY ONLY");
		_;
	}

	modifier onlyAfter(uint256 _time) {
		require(block.timestamp > _time, "LosslessV2Pool: INVALID TIMESTAMP AFTER");
		_;
	}

	constructor(
		address _bidToken,
		address _principalToken,
		address _addressProvider,
		address _aggregator,
		uint256 _biddingDuration,
		uint256 _gamingDuration
	) public {
		factory = msg.sender;
		bidToken = _bidToken;
		principalToken = _principalToken;
		
		addressProvider = _addressProvider;
		aToken = _getATokenAddress(principalToken);

		priceFeed = AggregatorV3Interface(_aggregator);

		// modify status variable
		status.gameRound = 1;
		status.durationOfBidding = _biddingDuration;
		status.durationOfGame = _gamingDuration;
		status.lastUpdateTimestamp = block.timestamp;
		// status.initialPrice - unchange for now
		// status.endPrice - unchange for now
		// status.isShortLastRoundWinner - default to false
		status.isFirstRound = true;
		status.isFirstUser = true;
		status.currState = PoolStatus.FirstGame;
	}

	/**
	 * @dev initialize pool
	 **/
	function initialize(
		address shortToken_,
		address longToken_,
		address sponsorToken_
	) external override onlyFactory {
		poolTokensInfo.shortToken = shortToken_;
		poolTokensInfo.longToken = longToken_;
		poolTokensInfo.sponsorToken = sponsorToken_;

		_shortToken = ILosslessV2Token(shortToken_);
		_longToken = ILosslessV2Token(longToken_);
		_sponsorToken = ILosslessV2Token(sponsorToken_);
	}

	/**
	 * @dev only be called once, after initalize
	 **/
	function startFirstRound() external override {
		require(status.isFirstRound == true, "LosslessV2Pool: NOT FIRST ROUND!");
		require(status.currState == PoolStatus.FirstGame, "LosslessV2Pool: WRONG STATUS");
		// modify status variable
		// status.gameRound = 1;
		status.lastUpdateTimestamp = block.timestamp;
		// status.initialPrice - unchange for now
		// status.endPrice - unchange for now
		// status.isShortLastRoundWinner - unchange for now
		status.isFirstRound = false;
		// status.isFirstUser = true;
		status.currState = PoolStatus.Accepting;
	}

	/**
	 * @dev start the gaming, lock pool and transfer asset to defi lending
	 **/
	function startGame() public override lock onlyAfter(status.lastUpdateTimestamp.add(status.durationOfBidding)) {
		require(status.currState == PoolStatus.Accepting, "LosslessV2Pool: WRONG STATUS");
		require(_shortToken.totalSupply() != 0 && _longToken.totalSupply() != 0, "LosslessV2Pool: NO FUND IN POOL");
		// modify status variable
		// status.gameRound = 1;
		status.lastUpdateTimestamp = block.timestamp;
		// fisrt user can set the inital price
		if (status.isFirstUser == true) {
			status.initialPrice = _getPrice();
			status.isFirstUser = false;
		}
		// status.endPrice - unchange for now
		// status.isShortLastRoundWinner - unchange for now
		// status.isFirstRound = false;
		// status.isFirstUser = true;
		status.currState = PoolStatus.Locked;

		// transfer to aave
		_supplyToAAVE(principalToken, IERC20(principalToken).balanceOf(address(this)));
	}

	/**
	 * @dev end the gaming, redeem assets from aave and get end price
	 **/
	function endGame() public override lock onlyAfter(status.lastUpdateTimestamp.add(status.durationOfGame)) {
		require(status.currState == PoolStatus.Locked, "LosslessV2Pool: WRONG STATUS");

		// modify status variable
		status.gameRound = status.gameRound.add(1);
		status.lastUpdateTimestamp = block.timestamp;
		// status.initialPrice - unchange for now
		// status.endPrice - unchange for now
		// status.isShortLastRoundWinner - unchange for now
		// status.isFirstRound = false;
		status.isFirstUser = true;
		status.currState = PoolStatus.Accepting;

		// redeem from AAVE
		_redeemFromAAVE(principalToken, 0); // redeem all
		// get end price
		status.endPrice = _getPrice();

		// if end price higher than inital price -> long users win !
		if (status.endPrice >= status.initialPrice) {
			status.isShortLastRoundWinner = false;
		} else {
			status.isShortLastRoundWinner = true;
		}

		// update interest and principal amount
		uint256 totalShortPrincipal = _shortToken.totalSupply().mul(valuePerShortToken).div(PRECISION);
		uint256 totalLongPrincipal = _longToken.totalSupply().mul(valuePerLongToken).div(PRECISION);
		uint256 totalSponsorPrincipal = _sponsorToken.totalSupply().mul(valuePerSponsorToken).div(PRECISION);
		uint256 totalPrincipal = totalShortPrincipal.add(totalLongPrincipal.add(totalSponsorPrincipal));
		if (IERC20(principalToken).balanceOf(address(this)) < totalPrincipal) {
			totalInterest = 0;	// in case kovan testnet give us aToken slightly less than deposit amount
		} else {
			totalInterest = IERC20(principalToken).balanceOf(address(this)).sub(totalPrincipal);
		}
		

		// update share value
		_updateTokenValue(totalShortPrincipal, totalLongPrincipal);

		emit AnnounceWinner(status.isShortLastRoundWinner, status.initialPrice, status.endPrice);
	}

	/**
	 * @dev chainlink keeper checkUpkeep function to constantly check whether we need function call
	 **/
	function checkUpkeep(bytes calldata checkData) external override returns (bool upkeepNeeded, bytes memory performData) {
		PoolStatus currState = status.currState;
		uint256 lastUpdateTimestamp = status.lastUpdateTimestamp;
		uint256 durationOfGame = status.durationOfGame;
		uint256 durationOfBidding = status.durationOfBidding;

		if (currState == PoolStatus.Accepting && block.timestamp > lastUpdateTimestamp.add(durationOfBidding)) {
			upkeepNeeded = true;
		}
		else if (currState == PoolStatus.Locked && block.timestamp > lastUpdateTimestamp.add(durationOfGame)) {
			upkeepNeeded = true;
		}
		else {
			upkeepNeeded = false;
		}
		performData = checkData;
	}

	/**
	 * @dev once checkUpKeep been trigered, keeper will call performUpKeep
	 **/
	function performUpkeep(bytes calldata performData) external override {
		PoolStatus currState = status.currState;
		uint256 lastUpdateTimestamp = status.lastUpdateTimestamp;
		uint256 durationOfGame = status.durationOfGame;
		uint256 durationOfBidding = status.durationOfBidding;

		if (currState == PoolStatus.Accepting && block.timestamp > lastUpdateTimestamp.add(durationOfBidding)) {
			startGame();
		}
		if (currState == PoolStatus.Locked && block.timestamp > lastUpdateTimestamp.add(durationOfGame)) {
			endGame();
		}
		performData;
	}

	/**
	 * @dev termination function, use this to terminate the game
	 **/
	function poolTermination() external override onlyFactory {
		// only when pool status is at Accepting
		require(status.currState == PoolStatus.Accepting, "LosslessV2Pool: WRONG STATUS");

		// modify status variable
		// status.gameRound = status.gameRound.add(1);
		// status.durationOfGame = 6 days;
		// status.durationOfBidding = 1 days;
		// status.lastUpdateTimestamp = block.timestamp;
		// status.initialPrice - unchange for now
		// status.endPrice - unchange for now
		// status.isShortLastRoundWinner - unchange for now
		// status.isFirstRound = false;
		// status.isFirstUser = true;
		status.currState = PoolStatus.Terminated;
	}

	/**
	 * @dev users can add principal as long as the status is accpeting
	 * @param shortPrincipalAmount how many principal in short pool does user want to deposit
	 * @param longPrincipalAmount how many principal in long pool does user want to deposit
	 **/
	function deposit(uint256 shortPrincipalAmount, uint256 longPrincipalAmount) external override lock {
		require(status.currState == PoolStatus.Accepting, "LosslessV2Pool: WRONG STATUS");
		require(shortPrincipalAmount > 0 || longPrincipalAmount > 0, "LosslessV2Pool: INVALID AMOUNT");

		// fisrt user can set the inital price
		if (status.isFirstUser == true) {
			status.initialPrice = _getPrice();
			status.isFirstUser = false;
		}
		// // if user's balance is zero record user's join timestamp for reward
		// if (_shortToken.balanceOf(msg.sender) == 0 && _longToken.balanceOf(msg.sender) == 0) {
		// 	inPoolTimestamp[msg.sender] = block.timestamp;
		// }
		// transfer principal to pool contract
		SafeERC20.safeTransferFrom(IERC20(principalToken), msg.sender, address(this), shortPrincipalAmount.add(longPrincipalAmount));
		_mintTokens(true, msg.sender, shortPrincipalAmount, longPrincipalAmount);

		emit Deposit(shortPrincipalAmount, longPrincipalAmount);
	}

	/**
	 * @dev user can call it to redeem pool tokens to principal tokens
	 * @param shortTokenAmount 	how many short token in short pool does user want to redeem
	 * @param longTokenAmount 	how many long token in long pool does user want to redeem
	 **/
	function withdraw(
		bool isAToken,
		uint256 shortTokenAmount,
		uint256 longTokenAmount
	) external override lock {
		// withdraw should have no limitation in pool status
		require(shortTokenAmount > 0 || longTokenAmount > 0, "LosslessV2Pool: INVALID AMOUNT");

		// check user token balance
		uint256 userShortTokenBalance = _shortToken.balanceOf(msg.sender);
		uint256 userLongTokenBalance = _longToken.balanceOf(msg.sender);
		require(userShortTokenBalance >= shortTokenAmount && userLongTokenBalance >= longTokenAmount, "LosslessV2Pool: INSUFFICIENT BALANCE");

		// calculate withdraw principal amount
		uint256 shortPrincipalAmount = shortTokenAmount.mul(valuePerShortToken).div(PRECISION);
		uint256 longPrincipalAmount = longTokenAmount.mul(valuePerLongToken).div(PRECISION);

		// user withdraw will cause timestamp update -> reduce their goverance reward
		// inPoolTimestamp[msg.sender] = block.timestamp;

		// burn user withdraw token
		_burnTokens(false, msg.sender, shortTokenAmount, longTokenAmount);

		/*  pool status | isAToken | Operation
				lock	     T       transfer aToken
				lock 		 F		 redeem then transfer principal Token
			  unlock  		 T 		 supply to aave then transfer aToken
			  unlock         F       transfer principal token
		 */
		if (isAToken == false) {
			if (status.currState == PoolStatus.Locked) {
				_redeemFromAAVE(principalToken, shortPrincipalAmount.add(longPrincipalAmount));
			}
			SafeERC20.safeTransfer(IERC20(principalToken), msg.sender, shortPrincipalAmount.add(longPrincipalAmount));
		} else {
			if (status.currState == PoolStatus.Accepting) {
				_supplyToAAVE(principalToken, shortPrincipalAmount.add(longPrincipalAmount));
			}
			SafeERC20.safeTransfer(IERC20(aToken), msg.sender, shortPrincipalAmount.add(longPrincipalAmount));
		}

		emit Withdraw(isAToken, shortTokenAmount, longTokenAmount);
	}

	/**
	 * @dev user can call this to shift share from long -> short, short -> long without withdrawing assets
	 * @param fromLongToShort is user choosing to shift from long to short
	 * @param swapTokenAmount the amount of token that user wishes to swap
	 **/
	function swap(bool fromLongToShort, uint256 swapTokenAmount) external override lock {
		require(status.currState == PoolStatus.Accepting, "LosslessV2Pool: WRONG STATUS");
		uint256 shortTokenBalance = _shortToken.balanceOf(msg.sender);
		uint256 longTokenBalance = _longToken.balanceOf(msg.sender);
		uint256 tokenBalanceOfTargetPosition = fromLongToShort ? longTokenBalance : shortTokenBalance;
		// check user balance
		require(swapTokenAmount > 0 && swapTokenAmount <= tokenBalanceOfTargetPosition, "LosslessV2Pool: INSUFFICIENT BALANCE");

		// reallocate user's share balance
		if (fromLongToShort == true) {
			// user wants to shift from long to short, so burn long share and increase short share
			_burnTokens(false, msg.sender, 0, swapTokenAmount);
			_mintTokens(false, msg.sender, swapTokenAmount.mul(valuePerLongToken).div(valuePerShortToken), 0);
		} else {
			// user wants to shift from short to long, so burn short share and increase long share
			_burnTokens(false, msg.sender, swapTokenAmount, 0);
			_mintTokens(false, msg.sender, 0, swapTokenAmount.mul(valuePerShortToken).div(valuePerLongToken));
		}
	}

	/**
	 * @dev sponsr can deposit and withdraw principals to the game
	 * @param principalAmount amount of principal token
	 **/
	function sponsorDeposit(uint256 principalAmount) external override lock {
		require(status.currState != PoolStatus.Terminated, "LosslessV2Pool: POOL TERMINATED");
		require(principalAmount > 0, "LosslessV2Pool: INVALID AMOUNT");
		require(IERC20(principalToken).balanceOf(msg.sender) >= principalAmount, "LosslessV2Pool: INSUFFICIENT BALANCE");

		// transfer asset first
		SafeERC20.safeTransferFrom(IERC20(principalToken), msg.sender, address(this), principalAmount);

		// check current game state
		if (status.currState == PoolStatus.Locked) {
			// if during the lock time
			// interact with AAVE to get the principal back
			_supplyToAAVE(principalToken, principalAmount);
		}

		// mint sponsor token
		_sponsorToken.mint(msg.sender, principalAmount);

		emit SponsorDeposit(principalAmount);
	}

	/**
	 * @dev sponsr can deposit and withdraw principals to the game
	 * @param sponsorTokenAmount amount of zero token
	 **/
	function sponsorWithdraw(uint256 sponsorTokenAmount) external override lock {
		require(sponsorTokenAmount > 0, "LosslessV2Pool: INVALID AMOUNT");
		// burn user sponsor token
		_sponsorToken.burn(msg.sender, sponsorTokenAmount);

		// check current game state
		if (status.currState == PoolStatus.Locked) {
			// if during the lock time
			// interact with AAVE to get the principal back
			_redeemFromAAVE(principalToken, sponsorTokenAmount);
		}

		// transfer principal token
		SafeERC20.safeTransfer(IERC20(principalToken), msg.sender, sponsorTokenAmount);

		emit SponsorWithdraw(sponsorTokenAmount);
	}

	/**
	 * @dev calculate each token's value
	 * @param _totalShortPrincipal 	the total amount of short principal
	 * @param _totalLongPrincipal	the total amount of long principal
	 **/
	function _updateTokenValue(uint256 _totalShortPrincipal, uint256 _totalLongPrincipal) private {
		address feeTo = ILosslessV2Factory(factory).feeTo();
		uint256 feePercent = ILosslessV2Factory(factory).feePercent();
		uint256 fee = totalInterest.mul(feePercent).div(PRECISION);

		// if fee is on and feeTo been set
		if (feePercent != 0 && feeTo != address(0)) {
			totalInterest = totalInterest.sub(fee);
			SafeERC20.safeTransfer(IERC20(principalToken), feeTo, fee);
		}

		// update short/long token value
		if (status.isShortLastRoundWinner == true) {
			// short win
			_totalShortPrincipal = _totalShortPrincipal.add(totalInterest);
			valuePerShortToken = _totalShortPrincipal.mul(PRECISION).div(_shortToken.totalSupply());
		} else if (status.isShortLastRoundWinner == false) {
			// long win
			_totalLongPrincipal = _totalLongPrincipal.add(totalInterest);
			valuePerLongToken = _totalLongPrincipal.mul(PRECISION).div(_longToken.totalSupply());
		}

		emit UpdateTokenValue(valuePerShortToken, valuePerLongToken);
	}

	/**
	 * @dev supply to aave protocol
	 * @param _asset 	the address of the principal token
	 * @param _amount	the amount of the principal token wish to supply to AAVE
	 **/
	function _supplyToAAVE(address _asset, uint256 _amount) private {
		address lendingPoolAddress = ILendingPoolAddressesProvider(addressProvider).getLendingPool();
		ILendingPool lendingPool = ILendingPool(lendingPoolAddress);
		SafeERC20.safeApprove(IERC20(_asset), address(lendingPool), _amount);
		lendingPool.deposit(_asset, _amount, address(this), 0);
	}

	/**
	 * @dev redeem from aave protocol
	 * @param _asset 	the address of the principal token
	 * @param _amount	the amount of the principal token wish to withdraw from AAVE
	 **/
	function _redeemFromAAVE(address _asset, uint256 _amount) private {
		// lendingPool
		address lendingPoolAddress = ILendingPoolAddressesProvider(addressProvider).getLendingPool();
		ILendingPool lendingPool = ILendingPool(lendingPoolAddress);
		// protocol data provider
		aToken = _getATokenAddress(_asset);
		if (_amount == 0) {
			_amount = IERC20(aToken).balanceOf(address(this));
		}
		lendingPool.withdraw(_asset, _amount, address(this));
	}

	/**
	 * @dev get atoken address
	 * @param _asset 	the address of the principal token
	 **/
	function _getATokenAddress(address _asset) private view returns (address _aToken) {
		// protocol data provider
		uint8 number = 1;
		bytes32 id = bytes32(bytes1(number));
		address dataProviderAddress = ILendingPoolAddressesProvider(addressProvider).getAddress(id);
		IProtocolDataProvider protocolDataProvider = IProtocolDataProvider(dataProviderAddress);
		(_aToken, , ) = protocolDataProvider.getReserveTokensAddresses(_asset);
	}

	/**
	 * @dev mint token function to mint long and short token
	 * @param _isPrincipal 	true: principal, false:long/short token amount
	 * @param _to			the destination account token got burned
	 * @param _shortAmount 	the amount of the token to short
	 * @param _longAmount 	the amount of the token to long
	 **/
	function _mintTokens(
		bool _isPrincipal,
		address _to,
		uint256 _shortAmount,
		uint256 _longAmount
	) private {
		if (_isPrincipal == true) {
			// convert principal token amount to long/short token amount
			_shortAmount = _shortAmount.mul(PRECISION).div(valuePerShortToken);
			_longAmount = _longAmount.mul(PRECISION).div(valuePerLongToken);
		}
		if (_shortAmount != 0) {
			_shortToken.mint(_to, _shortAmount);
		}
		if (_longAmount != 0) {
			_longToken.mint(_to, _longAmount);
		}
	}

	/**
	 * @dev burn token function to burn long and short token
	 * @param _isPrincipal 	true: principal, false:long/short token amount
	 * @param _from			the destination account token got burned
	 * @param _shortAmount 	the amount of the token to short
	 * @param _longAmount 	the amount of the token to long
	 **/
	function _burnTokens(
		bool _isPrincipal,
		address _from,
		uint256 _shortAmount,
		uint256 _longAmount
	) private {
		if (_isPrincipal == true) {
			// convert principal token amount to long/short token amount
			_shortAmount = _shortAmount.mul(PRECISION).div(valuePerShortToken);
			_longAmount = _longAmount.mul(PRECISION).div(valuePerLongToken);
		}
		if (_shortAmount != 0) {
			_shortToken.burn(_from, _shortAmount);
		}
		if (_longAmount != 0) {
			_longToken.burn(_from, _longAmount);
		}
	}

	/**
	 * @dev communicate with oracle to get current trusted price
	 * @return price ratio of bidToken * PRECISION / principalToken -> the result comes with precision
	 **/
	function _getPrice() private view returns (int256) {
		(uint80 roundID, int256 price, uint256 startedAt, uint256 timeStamp, uint80 answeredInRound) = priceFeed.latestRoundData();
		return price;
	}

	/**
	 * @dev return user's long token equivalent principal token amount
	 **/
	function userLongPrincipalBalance(address userAddress) external view override returns (uint256 userLongAmount) {
		userLongAmount = _longToken.balanceOf(userAddress).mul(valuePerLongToken).div(PRECISION);
	}

	/**
	 * @dev return user's short token equivalent principal token amount
	 **/
	function userShortPrincipalBalance(address userAddress) external view override returns (uint256 userShortAmount) {
		userShortAmount = _shortToken.balanceOf(userAddress).mul(valuePerShortToken).div(PRECISION);
	}
}

File 2 of 15 : ILosslessV2Pool.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.6.12;

interface ILosslessV2Pool {
	// defined and controls all game logic related variables
	struct GameStatus {
		bool isShortLastRoundWinner; // record whether last round winner
		bool isFirstUser; // check if the user is the first one to enter the game or not
		bool isFirstRound; // is this game the first round of the entire pool?
		uint256 gameRound; // count for showing current game round
		uint256 durationOfGame; // which should be 6 days in default
		uint256 durationOfBidding; // which should be 1 days in default
		uint256 lastUpdateTimestamp; // the timestamp when last game logic function been called
		int256 initialPrice; // game initial price
		int256 endPrice; // game end price
		PoolStatus currState; // current pool status
	}

	// token info for current pool
	struct PoolTokensInfo {
		address longToken;
		address shortToken;
		address sponsorToken;
	}

	// # ENUM FOR POOL STATUS
	/*  
      PoolStatus Explaination
      *****
        Locked ------ game period. interacting with compound
        Accepting --- users can adding or reducing the bet
        FirstGame --- only been used for the first round
		Terminated -- only when special cases admin decided to close the pool

      Notation
      ******
        /name/ - status name
        [name] - function call name

      Workflow
      *******  

                                    
                     /Accepting/            /Locked/         /Accepting/				/Terminated/
                          |                     |                | 							 |
    [startFirstRound] ---------> [startGame] -------> [endGame] ---> [poolTermination] --------------->
                                      ^                    | |
                                      |                    | record time
                                       --------------------
                                                 |
                                            /Accepting/
    */
	enum PoolStatus { FirstGame, Locked, Accepting, Terminated }

	// ## DEFINE USER OPERATION EVENTS
	event Deposit			(uint256 shortPrincipalAmount, uint256 longPrincipalAmount);
	event Withdraw			(bool isAToken, uint256 shortTokenAmount, uint256 longTokenAmount);
	event SponsorDeposit	(uint256 principalAmount);
	event SponsorWithdraw	(uint256 sponsorTokenAmount);
	// ## DEFINE GAME OPERATION EVENTS
	event UpdateTokenValue	(uint256 valuePerShortToken, uint256 valuePerLongToken);
	event AnnounceWinner	(bool isShortLastRoundWinner, int256 initialPrice, int256 endPrice);

	// ## PUBLIC VARIABLES
	function factory() external view returns (address);
	function bidToken() external view returns (address);
	function principalToken() external view returns (address);
	function aToken() external view returns (address);
	function addressProvider() external view returns (address);

	// ### GAME SETTING VARIABLES
	// function inPoolTimestamp(address userAddress) external view returns (uint256);

	// ## STATE-CHANGING FUNCTION
	/* 
		initialize: 		initialize the game
		startFirstRound: 	start the frist round logic
		startGame: 			start game -> pool lock supply principal to AAVE, get start game price
		endGame: 			end game -> pool unlock redeem fund to AAVE, get end game price
		poolTermination:	terminate the pool, no more game, but user can still withdraw fund
    */
	function initialize(
		address shortToken_,
		address longToken_,
		address sponsorToken_
	) external;

	function startFirstRound() external; // only be called to start the first Round
	function startGame() external; // called after bidding duration
	function endGame() external; // called after game duraion

	///@dev admin only
	function poolTermination() external; // called after selectWinner only by admin

	// user actions in below, join game, add, reduce or withDraw all fund
	/* 
		deposit: 			adding funds can be either just long or short or both
		withdraw: 			reduce funds can be either just long or short or both
		swap: 				change amount of tokens from long -> short / short -> long
		sponsorDeposit:		deposit principal to the pool as interest sponsor
		sponsorWithdraw:	withdraw sponsor donation from the pool
    */
	function deposit(uint256 shortPrincipalAmount, uint256 longPrincipalAmount) external;
	function withdraw(bool isAToken, uint256 shortTokenAmount, uint256 longTokenAmount) external;
	function swap(bool fromLongToShort, uint256 swapTokenAmount) external;
	
	function sponsorDeposit(uint256 principalAmount) external;
	function sponsorWithdraw(uint256 sponsorTokenAmount) external;

	// view functions to return user balance
	function userLongPrincipalBalance(address userAddress) external view returns (uint256);
	function userShortPrincipalBalance(address userAddress) external view returns (uint256);
}

File 3 of 15 : ILosslessV2Factory.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.6.12;

interface ILosslessV2Factory {
	// event related
	event PoolCreated(address indexed bidToken, address indexed principalToken, address pool, uint256 allPoolLength);
	event PoolTerminated(address pool);
	event FeeToChanged(address feeTo);
	event FeePercentChanged(uint256 feePercent);
	event FeeToSetterChanged(address feeToSetter);

	function allPools(uint256) external view returns (address pool);
	function allPoolsLength() external view returns (uint256);
	function getPool(address bidToken, address principalToken) external view returns (address pool);
	function isPoolActive(address) external view returns (bool);

	function getPoolShortToken(address) external view returns (address);
	function getPoolLongToken(address) external view returns (address);
	function getPoolSponsorToken(address) external view returns (address);

	function createPool(
		address bidToken,
		address principalToken,
		address addressProvider,
		address aggregator,
		uint256 biddingDuration,
		uint256 gamingDuration,
		string memory tokenName,
		string memory tokenSymbol
	) external;

	// all fee related getter functions
	function feeTo() external view returns (address);
	function feeToSetter() external view returns (address);
	function feePercent() external view returns (uint256);

	// only admin functions
	// The default FeeToSetter is admin but admin can assign this role to others by calling `setFeeToSetter`
	function setFeeTo(address) external;
	function setFeePercent(uint256 _feePercent) external;
	function setFeeToSetter(address _feeToSetter) external;
}

File 4 of 15 : ILosslessV2Token.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.6.12;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface ILosslessV2Token is IERC20{
    function mint (address to, uint256 amount) external returns (bool);
    function burn (address from, uint256 amount) external returns (bool);
}

File 5 of 15 : IPriceOracleGetter.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.6.12;

interface IPriceOracleGetter {
	function getAssetPrice(address _asset) external view returns (uint256);

	function getAssetsPrices(address[] calldata _assets) external view returns (uint256[] memory);

	function getSourceOfAsset(address _asset) external view returns (address);

	function getFallbackOracle() external view returns (address);
}

File 6 of 15 : ILendingPoolAddressesProvider.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.6.12;

/**
 * @title LendingPoolAddressesProvider contract
 * @dev Main registry of addresses part of or connected to the protocol, including permissioned roles
 * - Acting also as factory of proxies and admin of those, so with right to change its implementations
 * - Owned by the Aave Governance
 * @author Aave
 **/
interface ILendingPoolAddressesProvider {
  event MarketIdSet(string newMarketId);
  event LendingPoolUpdated(address indexed newAddress);
  event ConfigurationAdminUpdated(address indexed newAddress);
  event EmergencyAdminUpdated(address indexed newAddress);
  event LendingPoolConfiguratorUpdated(address indexed newAddress);
  event LendingPoolCollateralManagerUpdated(address indexed newAddress);
  event PriceOracleUpdated(address indexed newAddress);
  event LendingRateOracleUpdated(address indexed newAddress);
  event ProxyCreated(bytes32 id, address indexed newAddress);
  event AddressSet(bytes32 id, address indexed newAddress, bool hasProxy);

  function getMarketId() external view returns (string memory);

  function setMarketId(string calldata marketId) external;

  function setAddress(bytes32 id, address newAddress) external;

  function setAddressAsProxy(bytes32 id, address impl) external;

  function getAddress(bytes32 id) external view returns (address);

  function getLendingPool() external view returns (address);

  function setLendingPoolImpl(address pool) external;

  function getLendingPoolConfigurator() external view returns (address);

  function setLendingPoolConfiguratorImpl(address configurator) external;

  function getLendingPoolCollateralManager() external view returns (address);

  function setLendingPoolCollateralManager(address manager) external;

  function getPoolAdmin() external view returns (address);

  function setPoolAdmin(address admin) external;

  function getEmergencyAdmin() external view returns (address);

  function setEmergencyAdmin(address admin) external;

  function getPriceOracle() external view returns (address);

  function setPriceOracle(address priceOracle) external;

  function getLendingRateOracle() external view returns (address);

  function setLendingRateOracle(address lendingRateOracle) external;
}

File 7 of 15 : ILendingPool.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;

import {ILendingPoolAddressesProvider} from './ILendingPoolAddressesProvider.sol';
import {DataTypes} from '../core/libraries/DataTypes.sol';

interface ILendingPool {
  /**
   * @dev Emitted on deposit()
   * @param reserve The address of the underlying asset of the reserve
   * @param user The address initiating the deposit
   * @param onBehalfOf The beneficiary of the deposit, receiving the aTokens
   * @param amount The amount deposited
   * @param referral The referral code used
   **/
  event Deposit(
    address indexed reserve,
    address user,
    address indexed onBehalfOf,
    uint256 amount,
    uint16 indexed referral
  );

  /**
   * @dev Emitted on withdraw()
   * @param reserve The address of the underlyng asset being withdrawn
   * @param user The address initiating the withdrawal, owner of aTokens
   * @param to Address that will receive the underlying
   * @param amount The amount to be withdrawn
   **/
  event Withdraw(address indexed reserve, address indexed user, address indexed to, uint256 amount);

  /**
   * @dev Emitted on borrow() and flashLoan() when debt needs to be opened
   * @param reserve The address of the underlying asset being borrowed
   * @param user The address of the user initiating the borrow(), receiving the funds on borrow() or just
   * initiator of the transaction on flashLoan()
   * @param onBehalfOf The address that will be getting the debt
   * @param amount The amount borrowed out
   * @param borrowRateMode The rate mode: 1 for Stable, 2 for Variable
   * @param borrowRate The numeric rate at which the user has borrowed
   * @param referral The referral code used
   **/
  event Borrow(
    address indexed reserve,
    address user,
    address indexed onBehalfOf,
    uint256 amount,
    uint256 borrowRateMode,
    uint256 borrowRate,
    uint16 indexed referral
  );

  /**
   * @dev Emitted on repay()
   * @param reserve The address of the underlying asset of the reserve
   * @param user The beneficiary of the repayment, getting his debt reduced
   * @param repayer The address of the user initiating the repay(), providing the funds
   * @param amount The amount repaid
   **/
  event Repay(
    address indexed reserve,
    address indexed user,
    address indexed repayer,
    uint256 amount
  );

  /**
   * @dev Emitted on swapBorrowRateMode()
   * @param reserve The address of the underlying asset of the reserve
   * @param user The address of the user swapping his rate mode
   * @param rateMode The rate mode that the user wants to swap to
   **/
  event Swap(address indexed reserve, address indexed user, uint256 rateMode);

  /**
   * @dev Emitted on setUserUseReserveAsCollateral()
   * @param reserve The address of the underlying asset of the reserve
   * @param user The address of the user enabling the usage as collateral
   **/
  event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user);

  /**
   * @dev Emitted on setUserUseReserveAsCollateral()
   * @param reserve The address of the underlying asset of the reserve
   * @param user The address of the user enabling the usage as collateral
   **/
  event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user);

  /**
   * @dev Emitted on rebalanceStableBorrowRate()
   * @param reserve The address of the underlying asset of the reserve
   * @param user The address of the user for which the rebalance has been executed
   **/
  event RebalanceStableBorrowRate(address indexed reserve, address indexed user);

  /**
   * @dev Emitted on flashLoan()
   * @param target The address of the flash loan receiver contract
   * @param initiator The address initiating the flash loan
   * @param asset The address of the asset being flash borrowed
   * @param amount The amount flash borrowed
   * @param premium The fee flash borrowed
   * @param referralCode The referral code used
   **/
  event FlashLoan(
    address indexed target,
    address indexed initiator,
    address indexed asset,
    uint256 amount,
    uint256 premium,
    uint16 referralCode
  );

  /**
   * @dev Emitted when the pause is triggered.
   */
  event Paused();

  /**
   * @dev Emitted when the pause is lifted.
   */
  event Unpaused();

  /**
   * @dev Emitted when a borrower is liquidated. This event is emitted by the LendingPool via
   * LendingPoolCollateral manager using a DELEGATECALL
   * This allows to have the events in the generated ABI for LendingPool.
   * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation
   * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation
   * @param user The address of the borrower getting liquidated
   * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover
   * @param liquidatedCollateralAmount The amount of collateral received by the liiquidator
   * @param liquidator The address of the liquidator
   * @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants
   * to receive the underlying collateral asset directly
   **/
  event LiquidationCall(
    address indexed collateralAsset,
    address indexed debtAsset,
    address indexed user,
    uint256 debtToCover,
    uint256 liquidatedCollateralAmount,
    address liquidator,
    bool receiveAToken
  );

  /**
   * @dev Emitted when the state of a reserve is updated. NOTE: This event is actually declared
   * in the ReserveLogic library and emitted in the updateInterestRates() function. Since the function is internal,
   * the event will actually be fired by the LendingPool contract. The event is therefore replicated here so it
   * gets added to the LendingPool ABI
   * @param reserve The address of the underlying asset of the reserve
   * @param liquidityRate The new liquidity rate
   * @param stableBorrowRate The new stable borrow rate
   * @param variableBorrowRate The new variable borrow rate
   * @param liquidityIndex The new liquidity index
   * @param variableBorrowIndex The new variable borrow index
   **/
  event ReserveDataUpdated(
    address indexed reserve,
    uint256 liquidityRate,
    uint256 stableBorrowRate,
    uint256 variableBorrowRate,
    uint256 liquidityIndex,
    uint256 variableBorrowIndex
  );

  /**
   * @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.
   * - E.g. User deposits 100 USDC and gets in return 100 aUSDC
   * @param asset The address of the underlying asset to deposit
   * @param amount The amount to be deposited
   * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user
   *   wants to receive them on his own wallet, or a different address if the beneficiary of aTokens
   *   is a different wallet
   * @param referralCode Code used to register the integrator originating the operation, for potential rewards.
   *   0 if the action is executed directly by the user, without any middle-man
   **/
  function deposit(
    address asset,
    uint256 amount,
    address onBehalfOf,
    uint16 referralCode
  ) external;

  /**
   * @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned
   * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC
   * @param asset The address of the underlying asset to withdraw
   * @param amount The underlying amount to be withdrawn
   *   - Send the value type(uint256).max in order to withdraw the whole aToken balance
   * @param to Address that will receive the underlying, same as msg.sender if the user
   *   wants to receive it on his own wallet, or a different address if the beneficiary is a
   *   different wallet
   * @return The final amount withdrawn
   **/
  function withdraw(
    address asset,
    uint256 amount,
    address to
  ) external returns (uint256);

  /**
   * @dev Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower
   * already deposited enough collateral, or he was given enough allowance by a credit delegator on the
   * corresponding debt token (StableDebtToken or VariableDebtToken)
   * - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet
   *   and 100 stable/variable debt tokens, depending on the `interestRateMode`
   * @param asset The address of the underlying asset to borrow
   * @param amount The amount to be borrowed
   * @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for Stable, 2 for Variable
   * @param referralCode Code used to register the integrator originating the operation, for potential rewards.
   *   0 if the action is executed directly by the user, without any middle-man
   * @param onBehalfOf Address of the user who will receive the debt. Should be the address of the borrower itself
   * calling the function if he wants to borrow against his own collateral, or the address of the credit delegator
   * if he has been given credit delegation allowance
   **/
  function borrow(
    address asset,
    uint256 amount,
    uint256 interestRateMode,
    uint16 referralCode,
    address onBehalfOf
  ) external;

  /**
   * @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned
   * - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` address
   * @param asset The address of the borrowed underlying asset previously borrowed
   * @param amount The amount to repay
   * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`
   * @param rateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable
   * @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the address of the
   * user calling the function if he wants to reduce/remove his own debt, or the address of any other
   * other borrower whose debt should be removed
   * @return The final amount repaid
   **/
  function repay(
    address asset,
    uint256 amount,
    uint256 rateMode,
    address onBehalfOf
  ) external returns (uint256);

  /**
   * @dev Allows a borrower to swap his debt between stable and variable mode, or viceversa
   * @param asset The address of the underlying asset borrowed
   * @param rateMode The rate mode that the user wants to swap to
   **/
  function swapBorrowRateMode(address asset, uint256 rateMode) external;

  /**
   * @dev Rebalances the stable interest rate of a user to the current stable rate defined on the reserve.
   * - Users can be rebalanced if the following conditions are satisfied:
   *     1. Usage ratio is above 95%
   *     2. the current deposit APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which means that too much has been
   *        borrowed at a stable rate and depositors are not earning enough
   * @param asset The address of the underlying asset borrowed
   * @param user The address of the user to be rebalanced
   **/
  function rebalanceStableBorrowRate(address asset, address user) external;

  /**
   * @dev Allows depositors to enable/disable a specific deposited asset as collateral
   * @param asset The address of the underlying asset deposited
   * @param useAsCollateral `true` if the user wants to use the deposit as collateral, `false` otherwise
   **/
  function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external;

  /**
   * @dev Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1
   * - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives
   *   a proportionally amount of the `collateralAsset` plus a bonus to cover market risk
   * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation
   * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation
   * @param user The address of the borrower getting liquidated
   * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover
   * @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants
   * to receive the underlying collateral asset directly
   **/
  function liquidationCall(
    address collateralAsset,
    address debtAsset,
    address user,
    uint256 debtToCover,
    bool receiveAToken
  ) external;

  /**
   * @dev Allows smartcontracts to access the liquidity of the pool within one transaction,
   * as long as the amount taken plus a fee is returned.
   * IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept into consideration.
   * For further details please visit https://developers.aave.com
   * @param receiverAddress The address of the contract receiving the funds, implementing the IFlashLoanReceiver interface
   * @param assets The addresses of the assets being flash-borrowed
   * @param amounts The amounts amounts being flash-borrowed
   * @param modes Types of the debt to open if the flash loan is not returned:
   *   0 -> Don't open any debt, just revert if funds can't be transferred from the receiver
   *   1 -> Open debt at stable rate for the value of the amount flash-borrowed to the `onBehalfOf` address
   *   2 -> Open debt at variable rate for the value of the amount flash-borrowed to the `onBehalfOf` address
   * @param onBehalfOf The address  that will receive the debt in the case of using on `modes` 1 or 2
   * @param params Variadic packed params to pass to the receiver as extra information
   * @param referralCode Code used to register the integrator originating the operation, for potential rewards.
   *   0 if the action is executed directly by the user, without any middle-man
   **/
  function flashLoan(
    address receiverAddress,
    address[] calldata assets,
    uint256[] calldata amounts,
    uint256[] calldata modes,
    address onBehalfOf,
    bytes calldata params,
    uint16 referralCode
  ) external;

  /**
   * @dev Returns the user account data across all the reserves
   * @param user The address of the user
   * @return totalCollateralETH the total collateral in ETH of the user
   * @return totalDebtETH the total debt in ETH of the user
   * @return availableBorrowsETH the borrowing power left of the user
   * @return currentLiquidationThreshold the liquidation threshold of the user
   * @return ltv the loan to value of the user
   * @return healthFactor the current health factor of the user
   **/
  function getUserAccountData(address user)
    external
    view
    returns (
      uint256 totalCollateralETH,
      uint256 totalDebtETH,
      uint256 availableBorrowsETH,
      uint256 currentLiquidationThreshold,
      uint256 ltv,
      uint256 healthFactor
    );

  function initReserve(
    address reserve,
    address aTokenAddress,
    address stableDebtAddress,
    address variableDebtAddress,
    address interestRateStrategyAddress
  ) external;

  function setReserveInterestRateStrategyAddress(address reserve, address rateStrategyAddress)
    external;

  function setConfiguration(address reserve, uint256 configuration) external;

  /**
   * @dev Returns the configuration of the reserve
   * @param asset The address of the underlying asset of the reserve
   * @return The configuration of the reserve
   **/
  function getConfiguration(address asset)
    external
    view
    returns (DataTypes.ReserveConfigurationMap memory);

  /**
   * @dev Returns the configuration of the user across all the reserves
   * @param user The user address
   * @return The configuration of the user
   **/
  function getUserConfiguration(address user)
    external
    view
    returns (DataTypes.UserConfigurationMap memory);

  /**
   * @dev Returns the normalized income normalized income of the reserve
   * @param asset The address of the underlying asset of the reserve
   * @return The reserve's normalized income
   */
  function getReserveNormalizedIncome(address asset) external view returns (uint256);

  /**
   * @dev Returns the normalized variable debt per unit of asset
   * @param asset The address of the underlying asset of the reserve
   * @return The reserve normalized variable debt
   */
  function getReserveNormalizedVariableDebt(address asset) external view returns (uint256);

  /**
   * @dev Returns the state and configuration of the reserve
   * @param asset The address of the underlying asset of the reserve
   * @return The state of the reserve
   **/
  function getReserveData(address asset) external view returns (DataTypes.ReserveData memory);

  function finalizeTransfer(
    address asset,
    address from,
    address to,
    uint256 amount,
    uint256 balanceFromAfter,
    uint256 balanceToBefore
  ) external;

  function getReservesList() external view returns (address[] memory);

  function getAddressesProvider() external view returns (ILendingPoolAddressesProvider);

  function setPause(bool val) external;

  function paused() external view returns (bool);
}

File 8 of 15 : IProtocolDataProvider.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;

import { ILendingPoolAddressesProvider } from "./ILendingPoolAddressesProvider.sol";

interface IProtocolDataProvider {
	struct TokenData {
		string symbol;
		address tokenAddress;
	}

	function ADDRESSES_PROVIDER() external view returns (ILendingPoolAddressesProvider);

	function getAllReservesTokens() external view returns (TokenData[] memory);

	function getAllATokens() external view returns (TokenData[] memory);

	function getReserveConfigurationData(address asset)
		external
		view
		returns (
			uint256 decimals,
			uint256 ltv,
			uint256 liquidationThreshold,
			uint256 liquidationBonus,
			uint256 reserveFactor,
			bool usageAsCollateralEnabled,
			bool borrowingEnabled,
			bool stableBorrowRateEnabled,
			bool isActive,
			bool isFrozen
		);

	function getReserveData(address asset)
		external
		view
		returns (
			uint256 availableLiquidity,
			uint256 totalStableDebt,
			uint256 totalVariableDebt,
			uint256 liquidityRate,
			uint256 variableBorrowRate,
			uint256 stableBorrowRate,
			uint256 averageStableBorrowRate,
			uint256 liquidityIndex,
			uint256 variableBorrowIndex,
			uint40 lastUpdateTimestamp
		);

	function getUserReserveData(address asset, address user)
		external
		view
		returns (
			uint256 currentATokenBalance,
			uint256 currentStableDebt,
			uint256 currentVariableDebt,
			uint256 principalStableDebt,
			uint256 scaledVariableDebt,
			uint256 stableBorrowRate,
			uint256 liquidityRate,
			uint40 stableRateLastUpdated,
			bool usageAsCollateralEnabled
		);

	function getReserveTokensAddresses(address asset)
		external
		view
		returns (
			address aTokenAddress,
			address stableDebtTokenAddress,
			address variableDebtTokenAddress
		);
}

File 9 of 15 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

File 10 of 15 : SafeERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using SafeMath for uint256;
    using Address for address;

    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        // solhint-disable-next-line max-line-length
        require((value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).add(value);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 11 of 15 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        uint256 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b > a) return (false, 0);
        return (true, a - b);
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) return (true, 0);
        uint256 c = a * b;
        if (c / a != b) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a / b);
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a % b);
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) return 0;
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: modulo by zero");
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        return a - b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a % b;
    }
}

File 12 of 15 : AggregatorV3Interface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

interface AggregatorV3Interface {

  function decimals()
    external
    view
    returns (
      uint8
    );

  function description()
    external
    view
    returns (
      string memory
    );

  function version()
    external
    view
    returns (
      uint256
    );

  // getRoundData and latestRoundData should both raise "No data present"
  // if they do not have data to report, instead of returning unset values
  // which could be misinterpreted as actual reported values.
  function getRoundData(
    uint80 _roundId
  )
    external
    view
    returns (
      uint80 roundId,
      int256 answer,
      uint256 startedAt,
      uint256 updatedAt,
      uint80 answeredInRound
    );

  function latestRoundData()
    external
    view
    returns (
      uint80 roundId,
      int256 answer,
      uint256 startedAt,
      uint256 updatedAt,
      uint80 answeredInRound
    );

}

File 13 of 15 : KeeperCompatibleInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

interface KeeperCompatibleInterface {

  /**
   * @notice checks if the contract requires work to be done.
   * @param checkData data passed to the contract when checking for upkeep.
   * @return upkeepNeeded boolean to indicate whether the keeper should call
   * performUpkeep or not.
   * @return performData bytes that the keeper should call performUpkeep with,
   * if upkeep is needed.
   */
  function checkUpkeep(
    bytes calldata checkData
  )
    external
    returns (
      bool upkeepNeeded,
      bytes memory performData
    );

  /**
   * @notice Performs work on the contract. Executed by the keepers, via the registry.
   * @param performData is the data which was passed back from the checkData
   * simulation.
   */
  function performUpkeep(
    bytes calldata performData
  ) external;
}

File 14 of 15 : DataTypes.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.6.12;

library DataTypes {
  // refer to the whitepaper, section 1.1 basic concepts for a formal description of these properties.
  struct ReserveData {
    //stores the reserve configuration
    ReserveConfigurationMap configuration;
    //the liquidity index. Expressed in ray
    uint128 liquidityIndex;
    //variable borrow index. Expressed in ray
    uint128 variableBorrowIndex;
    //the current supply rate. Expressed in ray
    uint128 currentLiquidityRate;
    //the current variable borrow rate. Expressed in ray
    uint128 currentVariableBorrowRate;
    //the current stable borrow rate. Expressed in ray
    uint128 currentStableBorrowRate;
    uint40 lastUpdateTimestamp;
    //tokens addresses
    address aTokenAddress;
    address stableDebtTokenAddress;
    address variableDebtTokenAddress;
    //address of the interest rate strategy
    address interestRateStrategyAddress;
    //the id of the reserve. Represents the position in the list of the active reserves
    uint8 id;
  }

  struct ReserveConfigurationMap {
    //bit 0-15: LTV
    //bit 16-31: Liq. threshold
    //bit 32-47: Liq. bonus
    //bit 48-55: Decimals
    //bit 56: Reserve is active
    //bit 57: reserve is frozen
    //bit 58: borrowing is enabled
    //bit 59: stable rate borrowing enabled
    //bit 60-63: reserved
    //bit 64-79: reserve factor
    uint256 data;
  }

  struct UserConfigurationMap {
    uint256 data;
  }

  enum InterestRateMode {NONE, STABLE, VARIABLE}
}

File 15 of 15 : Address.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain`call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
      return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "evmVersion": "istanbul",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract ABI

[{"inputs":[{"internalType":"address","name":"_bidToken","type":"address"},{"internalType":"address","name":"_principalToken","type":"address"},{"internalType":"address","name":"_addressProvider","type":"address"},{"internalType":"address","name":"_aggregator","type":"address"},{"internalType":"uint256","name":"_biddingDuration","type":"uint256"},{"internalType":"uint256","name":"_gamingDuration","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isShortLastRoundWinner","type":"bool"},{"indexed":false,"internalType":"int256","name":"initialPrice","type":"int256"},{"indexed":false,"internalType":"int256","name":"endPrice","type":"int256"}],"name":"AnnounceWinner","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"shortPrincipalAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"longPrincipalAmount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"principalAmount","type":"uint256"}],"name":"SponsorDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"sponsorTokenAmount","type":"uint256"}],"name":"SponsorWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"valuePerShortToken","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"valuePerLongToken","type":"uint256"}],"name":"UpdateTokenValue","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isAToken","type":"bool"},{"indexed":false,"internalType":"uint256","name":"shortTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"longTokenAmount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"addressProvider","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bidToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"checkData","type":"bytes"}],"name":"checkUpkeep","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shortPrincipalAmount","type":"uint256"},{"internalType":"uint256","name":"longPrincipalAmount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"endGame","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"shortToken_","type":"address"},{"internalType":"address","name":"longToken_","type":"address"},{"internalType":"address","name":"sponsorToken_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"performData","type":"bytes"}],"name":"performUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"poolTermination","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"poolTokensInfo","outputs":[{"internalType":"address","name":"longToken","type":"address"},{"internalType":"address","name":"shortToken","type":"address"},{"internalType":"address","name":"sponsorToken","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"principalToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"principalAmount","type":"uint256"}],"name":"sponsorDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"sponsorTokenAmount","type":"uint256"}],"name":"sponsorWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startFirstRound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startGame","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"status","outputs":[{"internalType":"bool","name":"isShortLastRoundWinner","type":"bool"},{"internalType":"bool","name":"isFirstUser","type":"bool"},{"internalType":"bool","name":"isFirstRound","type":"bool"},{"internalType":"uint256","name":"gameRound","type":"uint256"},{"internalType":"uint256","name":"durationOfGame","type":"uint256"},{"internalType":"uint256","name":"durationOfBidding","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"},{"internalType":"int256","name":"initialPrice","type":"int256"},{"internalType":"int256","name":"endPrice","type":"int256"},{"internalType":"enum ILosslessV2Pool.PoolStatus","name":"currState","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"fromLongToShort","type":"bool"},{"internalType":"uint256","name":"swapTokenAmount","type":"uint256"}],"name":"swap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"userLongPrincipalBalance","outputs":[{"internalType":"uint256","name":"userLongAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"userShortPrincipalBalance","outputs":[{"internalType":"uint256","name":"userShortAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"valuePerLongToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"valuePerShortToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"valuePerSponsorToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"isAToken","type":"bool"},{"internalType":"uint256","name":"shortTokenAmount","type":"uint256"},{"internalType":"uint256","name":"longTokenAmount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405261271060068190556007556016805460ff60a01b1916600160a01b1790553480156200002f57600080fd5b506040516200315d3803806200315d833981810160405260c08110156200005557600080fd5b508051602082015160408301516060840151608085015160a09095015160008054336001600160a01b0319918216179091556001805482166001600160a01b0380891691909117909155600280548316828816179081905560048054909316828716179092559596949593949293620000cf91166200013d565b600380546001600160a01b039283166001600160a01b03199182161790915560058054959092169416939093179092556001600a55600c55600b55505042600d55506009805461ff001962ff0000199091166201000017166101001790556010805460ff191690556200024f565b60048054604080516321f8a72160e01b8152600160f81b9381018490529051600093600193909285926001600160a01b03909216916321f8a72191602480820192602092909190829003018186803b1580156200019957600080fd5b505afa158015620001ae573d6000803e3d6000fd5b505050506040513d6020811015620001c557600080fd5b5051604080516334924edb60e21b81526001600160a01b038881166004830152915192935083929183169163d2493b6c91602480820192606092909190829003018186803b1580156200021757600080fd5b505afa1580156200022c573d6000803e3d6000fd5b505050506040513d60608110156200024357600080fd5b50519695505050505050565b612efe806200025f6000396000f3fe608060405234801561001057600080fd5b50600436106101735760003560e01c8063a0c1f15e116100de578063c45a015511610097578063dfafd4fd11610071578063dfafd4fd146104b7578063e2bbb158146104bf578063fb5dfe78146104e2578063fdd89a341461050857610173565b8063c45a01551461049f578063d65ab5f2146104a7578063dbc162de146104af57610173565b8063a0c1f15e1461042a578063aa18ca9214610432578063aaf5eb681461043a578063bb6e17961461043a578063c037646a14610442578063c0c53b8b1461046757610173565b80634585e33b116101305780634585e33b146102765780635785c18c146102e65780636cbc2ded146103035780636e04ff0d1461030b578063889c0bbd146103fc5780638fe688551461042257610173565b8063200d2ed21461017857806324294b1f146101e65780632954018c146101f0578063344846dd1461021457806334e08db5146102315780633b3bbc9c1461025c575b600080fd5b61018061053b565b604051808b151581526020018a1515815260200189151581526020018881526020018781526020018681526020018581526020018481526020018381526020018260038111156101cc57fe5b81526020019a505050505050505050505060405180910390f35b6101ee61057b565b005b6101f8610657565b604080516001600160a01b039092168252519081900360200190f35b6101ee6004803603602081101561022a57600080fd5b5035610666565b6101ee6004803603606081101561024757600080fd5b50803515159060208101359060400135610814565b610264610b64565b60408051918252519081900360200190f35b6101ee6004803603602081101561028c57600080fd5b8101906020810181356401000000008111156102a757600080fd5b8201836020820111156102b957600080fd5b803590602001918460018302840111640100000000831117156102db57600080fd5b509092509050610b6a565b6101ee600480360360208110156102fc57600080fd5b5035610be4565b6101ee610eae565b61037b6004803603602081101561032157600080fd5b81019060208101813564010000000081111561033c57600080fd5b82018360208201111561034e57600080fd5b8035906020019184600183028401116401000000008311171561037057600080fd5b50909250905061130e565b60405180831515815260200180602001828103825283818151815260200191508051906020019080838360005b838110156103c05781810151838201526020016103a8565b50505050905090810190601f1680156103ed5780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b6102646004803603602081101561041257600080fd5b50356001600160a01b03166113d4565b6101ee611439565b6101f86114ff565b61026461150e565b610264611514565b6101ee6004803603604081101561045857600080fd5b5080351515906020013561151a565b6101ee6004803603606081101561047d57600080fd5b506001600160a01b0381358116916020810135821691604090910135166117b3565b6101f8611873565b6101ee611882565b6101f8611ba5565b6101f8611bb4565b6101ee600480360360408110156104d557600080fd5b5080359060200135611bc3565b610264600480360360208110156104f857600080fd5b50356001600160a01b0316611d6f565b610510611dce565b604080516001600160a01b039485168152928416602084015292168183015290519081900360600190f35b600954600a54600b54600c54600d54600e54600f5460105460ff80891698610100810482169862010000909104821697909690959094909390929091168a565b60095462010000900460ff1615156001146105dd576040805162461bcd60e51b815260206004820181905260248201527f4c6f73736c6573735632506f6f6c3a204e4f5420464952535420524f554e4421604482015290519081900360640190fd5b600060105460ff1660038111156105f057fe5b14610630576040805162461bcd60e51b815260206004820152601c6024820152600080516020612e4f833981519152604482015290519081900360640190fd5b42600d556009805462ff000019169055601080546002919060ff19166001835b0217905550565b6004546001600160a01b031681565b601654600160a01b900460ff1615156001146106b7576040805162461bcd60e51b81526020600482015260166024820152600080516020612e2f833981519152604482015290519081900360640190fd5b6016805460ff60a01b1916905580610704576040805162461bcd60e51b815260206004820152601e6024820152600080516020612de5833981519152604482015290519081900360640190fd5b60165460408051632770a7eb60e21b81523360048201526024810184905290516001600160a01b0390921691639dc29fac916044808201926020929091908290030181600087803b15801561075857600080fd5b505af115801561076c573d6000803e3d6000fd5b505050506040513d602081101561078257600080fd5b506001905060105460ff16600381111561079857fe5b14156107b4576002546107b4906001600160a01b031682611deb565b6002546107cb906001600160a01b03163383611f95565b6040805182815290517f53f39bc00c1c01fadfe8bb9bd4d3398572c1cd9b0061bebcdd8c1abd4e4e21d19181900360200190a1506016805460ff60a01b1916600160a01b179055565b601654600160a01b900460ff161515600114610865576040805162461bcd60e51b81526020600482015260166024820152600080516020612e2f833981519152604482015290519081900360640190fd5b6016805460ff60a01b19169055811515806108805750600081115b6108bf576040805162461bcd60e51b815260206004820152601e6024820152600080516020612de5833981519152604482015290519081900360640190fd5b601454604080516370a0823160e01b815233600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b15801561090a57600080fd5b505afa15801561091e573d6000803e3d6000fd5b505050506040513d602081101561093457600080fd5b5051601554604080516370a0823160e01b815233600482015290519293506000926001600160a01b03909216916370a0823191602480820192602092909190829003018186803b15801561098757600080fd5b505afa15801561099b573d6000803e3d6000fd5b505050506040513d60208110156109b157600080fd5b505190508382108015906109c55750828110155b610a005760405162461bcd60e51b8152600401808060200182810382526024815260200180612ea56024913960400191505060405180910390fd5b6000610a23612710610a1d60065488611fec90919063ffffffff16565b9061204c565b90506000610a42612710610a1d60075488611fec90919063ffffffff16565b9050610a5160003388886120b3565b86610ab357600160105460ff166003811115610a6957fe5b1415610a8e57600254610a8e906001600160a01b0316610a8984846121d5565b611deb565b600254610aae906001600160a01b031633610aa985856121d5565b611f95565b610b06565b600260105460ff166003811115610ac657fe5b1415610aeb57600254610aeb906001600160a01b0316610ae684846121d5565b61222f565b600354610b06906001600160a01b031633610aa985856121d5565b6040805188151581526020810188905280820187905290517ffedb0622d5d5fa46cc706a5c2c169f2bf2eb31a59ff2f70cef3096376f58c2c09181900360600190a150506016805460ff60a01b1916600160a01b1790555050505050565b60065481565b601054600d54600b54600c5460ff909316926002846003811115610b8a57fe5b148015610b9f5750610b9c83826121d5565b42115b15610bac57610bac611882565b6001846003811115610bba57fe5b148015610bcf5750610bcc83836121d5565b42115b15610bdc57610bdc610eae565b505050505050565b601654600160a01b900460ff161515600114610c35576040805162461bcd60e51b81526020600482015260166024820152600080516020612e2f833981519152604482015290519081900360640190fd5b6016805460ff60a01b19169055600360105460ff166003811115610c5557fe5b1415610ca8576040805162461bcd60e51b815260206004820152601f60248201527f4c6f73736c6573735632506f6f6c3a20504f4f4c205445524d494e4154454400604482015290519081900360640190fd5b60008111610ceb576040805162461bcd60e51b815260206004820152601e6024820152600080516020612de5833981519152604482015290519081900360640190fd5b600254604080516370a0823160e01b8152336004820152905183926001600160a01b0316916370a08231916024808301926020929190829003018186803b158015610d3557600080fd5b505afa158015610d49573d6000803e3d6000fd5b505050506040513d6020811015610d5f57600080fd5b50511015610d9e5760405162461bcd60e51b8152600401808060200182810382526024815260200180612ea56024913960400191505060405180910390fd5b600254610db6906001600160a01b0316333084612333565b600160105460ff166003811115610dc957fe5b1415610de557600254610de5906001600160a01b03168261222f565b601654604080516340c10f1960e01b81523360048201526024810184905290516001600160a01b03909216916340c10f19916044808201926020929091908290030181600087803b158015610e3957600080fd5b505af1158015610e4d573d6000803e3d6000fd5b505050506040513d6020811015610e6357600080fd5b50506040805182815290517f40b61effeb22345307b6b4acfbb4580925caf61a4b62d8672e9f3d1214d3479d9181900360200190a1506016805460ff60a01b1916600160a01b179055565b601654600160a01b900460ff161515600114610eff576040805162461bcd60e51b81526020600482015260166024820152600080516020612e2f833981519152604482015290519081900360640190fd5b6016805460ff60a01b19169055600b54600d54610f1b916121d5565b804211610f595760405162461bcd60e51b8152600401808060200182810382526027815260200180612d9d6027913960400191505060405180910390fd5b600160105460ff166003811115610f6c57fe5b14610fac576040805162461bcd60e51b815260206004820152601c6024820152600080516020612e4f833981519152604482015290519081900360640190fd5b600a54610fba9060016121d5565b600a5542600d556009805461ff00191661010017905560108054600260ff19909116811790915554610ff6906001600160a01b03166000611deb565b610ffe61238d565b600f819055600e541361101a576009805460ff19169055611028565b6009805460ff191660011790555b60006110b6612710610a1d600654601460009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561108457600080fd5b505afa158015611098573d6000803e3d6000fd5b505050506040513d60208110156110ae57600080fd5b505190611fec565b90506000611114612710610a1d600754601560009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561108457600080fd5b90506000611172612710610a1d612710601660009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561108457600080fd5b9050600061118a61118384846121d5565b85906121d5565b600254604080516370a0823160e01b8152306004820152905192935083926001600160a01b03909216916370a0823191602480820192602092909190829003018186803b1580156111da57600080fd5b505afa1580156111ee573d6000803e3d6000fd5b505050506040513d602081101561120457600080fd5b5051101561121657600060085561129d565b600254604080516370a0823160e01b815230600482015290516112999284926001600160a01b03909116916370a0823191602480820192602092909190829003018186803b15801561126757600080fd5b505afa15801561127b573d6000803e3d6000fd5b505050506040513d602081101561129157600080fd5b50519061241d565b6008555b6112a7848461247a565b600954600e54600f546040805160ff90941615158452602084019290925282820152517f363f3c6d2f590883f657a36adeb0d1b0440383e505ebfc904e41834f2c6eba889181900360600190a150506016805460ff60a01b1916600160a01b179055505050565b601054600d54600b54600c5460009360609360ff909116929091600284600381111561133657fe5b14801561134b575061134883826121d5565b42115b15611359576001955061138f565b600184600381111561136757fe5b14801561137c575061137983836121d5565b42115b1561138a576001955061138f565b600095505b87878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250989b929a509198505050505050505050565b600754601554604080516370a0823160e01b81526001600160a01b03858116600483015291516000946114339461271094610a1d9492939116916370a08231916024808301926020929190829003018186803b15801561108457600080fd5b92915050565b6000546001600160a01b03163314611498576040805162461bcd60e51b815260206004820152601f60248201527f4c6f73736c6573735632466163746f72793a20464143544f5259204f4e4c5900604482015290519081900360640190fd5b600260105460ff1660038111156114ab57fe5b146114eb576040805162461bcd60e51b815260206004820152601c6024820152600080516020612e4f833981519152604482015290519081900360640190fd5b601080546003919060ff1916600183610650565b6003546001600160a01b031681565b60075481565b61271081565b601654600160a01b900460ff16151560011461156b576040805162461bcd60e51b81526020600482015260166024820152600080516020612e2f833981519152604482015290519081900360640190fd5b6016805460ff60a01b19169055600260105460ff16600381111561158b57fe5b146115cb576040805162461bcd60e51b815260206004820152601c6024820152600080516020612e4f833981519152604482015290519081900360640190fd5b601454604080516370a0823160e01b815233600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b15801561161657600080fd5b505afa15801561162a573d6000803e3d6000fd5b505050506040513d602081101561164057600080fd5b5051601554604080516370a0823160e01b815233600482015290519293506000926001600160a01b03909216916370a0823191602480820192602092909190829003018186803b15801561169357600080fd5b505afa1580156116a7573d6000803e3d6000fd5b505050506040513d60208110156116bd57600080fd5b505190506000846116ce57826116d0565b815b90506000841180156116e25750808411155b61171d5760405162461bcd60e51b8152600401808060200182810382526024815260200180612ea56024913960400191505060405180910390fd5b60018515151415611763576117366000336000876120b3565b61175e600033611757600654610a1d6007548a611fec90919063ffffffff16565b600061276d565b611799565b6117716000338660006120b3565b6117996000336000611794600754610a1d6006548b611fec90919063ffffffff16565b61276d565b50506016805460ff60a01b1916600160a01b179055505050565b6000546001600160a01b03163314611812576040805162461bcd60e51b815260206004820152601f60248201527f4c6f73736c6573735632466163746f72793a20464143544f5259204f4e4c5900604482015290519081900360640190fd5b601280546001600160a01b039485166001600160a01b03199182168117909255601180549486169482168517905560138054939095169281168317909455601480548516909117905560158054841690921790915560168054909216179055565b6000546001600160a01b031681565b601654600160a01b900460ff1615156001146118d3576040805162461bcd60e51b81526020600482015260166024820152600080516020612e2f833981519152604482015290519081900360640190fd5b6016805460ff60a01b19169055600c54600d546118ef916121d5565b80421161192d5760405162461bcd60e51b8152600401808060200182810382526027815260200180612d9d6027913960400191505060405180910390fd5b600260105460ff16600381111561194057fe5b14611980576040805162461bcd60e51b815260206004820152601c6024820152600080516020612e4f833981519152604482015290519081900360640190fd5b601460009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156119ce57600080fd5b505afa1580156119e2573d6000803e3d6000fd5b505050506040513d60208110156119f857600080fd5b505115801590611a805750601560009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611a5157600080fd5b505afa158015611a65573d6000803e3d6000fd5b505050506040513d6020811015611a7b57600080fd5b505115155b611ad1576040805162461bcd60e51b815260206004820152601f60248201527f4c6f73736c6573735632506f6f6c3a204e4f2046554e4420494e20504f4f4c00604482015290519081900360640190fd5b42600d5560095460ff61010090910416151560011415611b0257611af361238d565b600e556009805461ff00191690555b6010805460ff19166001179055600254604080516370a0823160e01b81523060048201529051611b8f926001600160a01b03169182916370a0823191602480820192602092909190829003018186803b158015611b5e57600080fd5b505afa158015611b72573d6000803e3d6000fd5b505050506040513d6020811015611b8857600080fd5b505161222f565b506016805460ff60a01b1916600160a01b179055565b6002546001600160a01b031681565b6001546001600160a01b031681565b601654600160a01b900460ff161515600114611c14576040805162461bcd60e51b81526020600482015260166024820152600080516020612e2f833981519152604482015290519081900360640190fd5b6016805460ff60a01b19169055600260105460ff166003811115611c3457fe5b14611c74576040805162461bcd60e51b815260206004820152601c6024820152600080516020612e4f833981519152604482015290519081900360640190fd5b6000821180611c835750600081115b611cc2576040805162461bcd60e51b815260206004820152601e6024820152600080516020612de5833981519152604482015290519081900360640190fd5b60095460ff61010090910416151560011415611cef57611ce061238d565b600e556009805461ff00191690555b600254611d10906001600160a01b03163330611d0b86866121d5565b612333565b611d1d600133848461276d565b604080518381526020810183905281517fa3af609bf46297028ce551832669030f9effef2b02606d02cbbcc40fe6b47c55929181900390910190a150506016805460ff60a01b1916600160a01b179055565b600654601454604080516370a0823160e01b81526001600160a01b03858116600483015291516000946114339461271094610a1d9492939116916370a08231916024808301926020929190829003018186803b15801561108457600080fd5b6011546012546013546001600160a01b0392831692918216911683565b6000600460009054906101000a90046001600160a01b03166001600160a01b0316630261bf8b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e3b57600080fd5b505afa158015611e4f573d6000803e3d6000fd5b505050506040513d6020811015611e6557600080fd5b5051905080611e7384612889565b600380546001600160a01b0319166001600160a01b039290921691909117905582611f1257600354604080516370a0823160e01b815230600482015290516001600160a01b03909216916370a0823191602480820192602092909190829003018186803b158015611ee357600080fd5b505afa158015611ef7573d6000803e3d6000fd5b505050506040513d6020811015611f0d57600080fd5b505192505b60408051631a4ca37b60e21b81526001600160a01b038681166004830152602482018690523060448301529151918316916369328dec916064808201926020929091908290030181600087803b158015611f6b57600080fd5b505af1158015611f7f573d6000803e3d6000fd5b505050506040513d6020811015610bdc57600080fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611fe7908490612995565b505050565b600082611ffb57506000611433565b8282028284828161200857fe5b04146120455760405162461bcd60e51b8152600401808060200182810382526021815260200180612dc46021913960400191505060405180910390fd5b9392505050565b60008082116120a2576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b8183816120ab57fe5b049392505050565b600184151514156120ea576006546120d190610a1d84612710611fec565b6007549092506120e790610a1d83612710611fec565b90505b81156121735760145460408051632770a7eb60e21b81526001600160a01b0386811660048301526024820186905291519190921691639dc29fac9160448083019260209291908290030181600087803b15801561214657600080fd5b505af115801561215a573d6000803e3d6000fd5b505050506040513d602081101561217057600080fd5b50505b80156121cf5760155460408051632770a7eb60e21b81526001600160a01b0386811660048301526024820185905291519190921691639dc29fac9160448083019260209291908290030181600087803b158015611f6b57600080fd5b50505050565b600082820183811015612045576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000600460009054906101000a90046001600160a01b03166001600160a01b0316630261bf8b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561227f57600080fd5b505afa158015612293573d6000803e3d6000fd5b505050506040513d60208110156122a957600080fd5b50519050806122b9848285612a46565b6040805163e8eda9df60e01b81526001600160a01b0386811660048301526024820186905230604483015260006064830181905292519084169263e8eda9df926084808201939182900301818387803b15801561231557600080fd5b505af1158015612329573d6000803e3d6000fd5b5050505050505050565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b1790526121cf908590612995565b600080600080600080600560009054906101000a90046001600160a01b03166001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b1580156123e457600080fd5b505afa1580156123f8573d6000803e3d6000fd5b505050506040513d60a081101561240e57600080fd5b50602001519550505050505090565b600082821115612474576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b60008060009054906101000a90046001600160a01b03166001600160a01b031663017e7e586040518163ffffffff1660e01b815260040160206040518083038186803b1580156124c957600080fd5b505afa1580156124dd573d6000803e3d6000fd5b505050506040513d60208110156124f357600080fd5b50516000805460408051631ff5bc5760e21b8152905193945091926001600160a01b0390911691637fd6f15c916004808301926020929190829003018186803b15801561253f57600080fd5b505afa158015612553573d6000803e3d6000fd5b505050506040513d602081101561256957600080fd5b50516008549091506000906125869061271090610a1d9085611fec565b9050811580159061259f57506001600160a01b03831615155b156125cb576008546125b1908261241d565b6008556002546125cb906001600160a01b03168483611f95565b60095460ff1615156001141561267c576008546125e99086906121d5565b9450612674601460009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561263c57600080fd5b505afa158015612650573d6000803e3d6000fd5b505050506040513d602081101561266657600080fd5b5051610a1d87612710611fec565b600655612723565b60095460ff16612723576008546126949085906121d5565b935061271f601560009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156126e757600080fd5b505afa1580156126fb573d6000803e3d6000fd5b505050506040513d602081101561271157600080fd5b5051610a1d86612710611fec565b6007555b7f3b18646b3983733450bdfbad0272e569b970aa8e53a92ab463689709f0bc4c0e600654600754604051808381526020018281526020019250505060405180910390a15050505050565b600184151514156127a45760065461278b90610a1d84612710611fec565b6007549092506127a190610a1d83612710611fec565b90505b811561282d57601454604080516340c10f1960e01b81526001600160a01b03868116600483015260248201869052915191909216916340c10f199160448083019260209291908290030181600087803b15801561280057600080fd5b505af1158015612814573d6000803e3d6000fd5b505050506040513d602081101561282a57600080fd5b50505b80156121cf57601554604080516340c10f1960e01b81526001600160a01b03868116600483015260248201859052915191909216916340c10f199160448083019260209291908290030181600087803b158015611f6b57600080fd5b60048054604080516321f8a72160e01b8152600160f81b9381018490529051600093600193909285926001600160a01b03909216916321f8a72191602480820192602092909190829003018186803b1580156128e457600080fd5b505afa1580156128f8573d6000803e3d6000fd5b505050506040513d602081101561290e57600080fd5b5051604080516334924edb60e21b81526001600160a01b038881166004830152915192935083929183169163d2493b6c91602480820192606092909190829003018186803b15801561295f57600080fd5b505afa158015612973573d6000803e3d6000fd5b505050506040513d606081101561298957600080fd5b50519695505050505050565b60606129ea826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612b599092919063ffffffff16565b805190915015611fe757808060200190516020811015612a0957600080fd5b5051611fe75760405162461bcd60e51b815260040180806020018281038252602a815260200180612e05602a913960400191505060405180910390fd5b801580612acc575060408051636eb1769f60e11b81523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b158015612a9e57600080fd5b505afa158015612ab2573d6000803e3d6000fd5b505050506040513d6020811015612ac857600080fd5b5051155b612b075760405162461bcd60e51b8152600401808060200182810382526036815260200180612e6f6036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052611fe7908490612995565b6060612b688484600085612b70565b949350505050565b606082471015612bb15760405162461bcd60e51b8152600401808060200182810382526026815260200180612d776026913960400191505060405180910390fd5b612bba85612ccc565b612c0b576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b60208310612c4a5780518252601f199092019160209182019101612c2b565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114612cac576040519150601f19603f3d011682016040523d82523d6000602084013e612cb1565b606091505b5091509150612cc1828286612cd2565b979650505050505050565b3b151590565b60608315612ce1575081612045565b825115612cf15782518084602001fd5b8160405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612d3b578181015183820152602001612d23565b50505050905090810190601f168015612d685780820380516001836020036101000a031916815260200191505b509250505060405180910390fdfe416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c4c6f73736c6573735632506f6f6c3a20494e56414c49442054494d455354414d50204146544552536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774c6f73736c6573735632506f6f6c3a20494e56414c494420414d4f554e5400005361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565644c6f73736c6573735632506f6f6c3a204c4f434b4544000000000000000000004c6f73736c6573735632506f6f6c3a2057524f4e4720535441545553000000005361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e63654c6f73736c6573735632506f6f6c3a20494e53554646494349454e542042414c414e4345a2646970667358221220141e183b3a0e1d30227aaa9bae15b570d141a267a21fb0debc49e6e26d9ebafc64736f6c634300060c0033000000000000000000000000d1b98b6607330172f1d991521145a22bce79327700000000000000000000000013512979ade267ab5100878e2e0f485b568328a400000000000000000000000088757f2f99175387ab4c6a4b3067c77a695b03490000000000000000000000006135b13325bfc4b00278b4abc5e20bbce2d6580e000000000000000000000000000000000000000000000000000000000002a3000000000000000000000000000000000000000000000000000000000000069780

Block Transaction Difficulty Gas Used Reward
Block Uncle Number Difficulty Gas Used Reward
Loading

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.