Contract Address Details

0x3Bd4D48D022ACA4C3FC1Fe673CF4741D5888bcc7

Contract Name
StakingPoolPatronKYC
Creator
0x162f82–d3ec40 at 0x11a762–369772
Balance
61,300.475792292130976119 EWT ( )
Tokens
Fetching tokens...
Transactions
14,298 Transactions
Transfers
6 Transfers
Gas Used
1,408,563,534
Last Balance Update
33394491
Contract name:
StakingPoolPatronKYC




Optimization enabled
false
Compiler version
v0.8.6+commit.11564f7e




EVM Version
default




Verified at
2021-12-17T11:20:01.849130Z

Constructor Arguments

000000000000000000000000935b00bdf181c207d954e97dbb1197e83366fd4900000000000000000000000023b026631a6f265d17cfee8aa6ced1b244f3920c

Arg [0] (address) : 0x935b00bdf181c207d954e97dbb1197e83366fd49
Arg [1] (address) : 0x23b026631a6f265d17cfee8aa6ced1b244f3920c

              

Contract source code

// SPDX Licence-Identifier: MIT AND  BSD-4-Clause

pragma solidity 0.8.6;

interface IClaimManager {
	function hasRole(
		address subject,
		bytes32 role,
		uint256 version
	) external view returns (bool);
}

library RolesLibrary {
	function hasRole(
		address _userAddress,
		address _claimManagerAddress,
		bytes32[] memory _roles
	) internal view returns (bool) {
		if (_roles.length == 0) {
			return true;
		}
		IClaimManager claimManager = IClaimManager(_claimManagerAddress); // Contract deployed and maintained by EnergyWeb Fondation
		for (uint256 i = 0; i < _roles.length; i++) {
			if (claimManager.hasRole(_userAddress, _roles[i], 1)) {
				return true;
			}
		}
		return false;
	}

	function isOwner(
		address _user,
		address _claimManagerAddress,
		bytes32 _ownerRole
	) internal view returns (bool) {
		IClaimManager claimManager = IClaimManager(_claimManagerAddress); // Contract deployed and maintained by EnergyWeb Fondation

		return (claimManager.hasRole(_user, _ownerRole, 1));
	}
}

/*
 * ABDK Math 64.64 Smart Contract Library.  Copyright © 2019 by ABDK Consulting.
 * Author: Mikhail Vladimirov <[email protected]>
 */

/**
 * Smart contract library of mathematical functions operating with signed
 * 64.64-bit fixed point numbers.  Signed 64.64-bit fixed point number is
 * basically a simple fraction whose numerator is signed 128-bit integer and
 * denominator is 2^64.  As long as denominator is always the same, there is no
 * need to store it, thus in Solidity signed 64.64-bit fixed point numbers are
 * represented by int128 type holding only the numerator.
 */
library ABDKMath64x64 {
	/*
	 * Minimum value signed 64.64-bit fixed point number may have.
	 */
	int128 private constant MIN_64x64 = -0x80000000000000000000000000000000;

	/*
	 * Maximum value signed 64.64-bit fixed point number may have.
	 */
	int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

	/**
	 * Convert signed 256-bit integer number into signed 64.64-bit fixed point
	 * number.  Revert on overflow.
	 *
	 * @param x signed 256-bit integer number
	 * @return signed 64.64-bit fixed point number
	 */
	function fromInt(int256 x) internal pure returns (int128) {
		unchecked {
			require(x >= -0x8000000000000000 && x <= 0x7FFFFFFFFFFFFFFF);
			return int128(x << 64);
		}
	}

	/**
	 * Convert signed 64.64 fixed point number into signed 64-bit integer number
	 * rounding down.
	 *
	 * @param x signed 64.64-bit fixed point number
	 * @return signed 64-bit integer number
	 */
	function toInt(int128 x) internal pure returns (int64) {
		unchecked {
			return int64(x >> 64);
		}
	}

	/**
	 * Convert unsigned 256-bit integer number into signed 64.64-bit fixed point
	 * number.  Revert on overflow.
	 *
	 * @param x unsigned 256-bit integer number
	 * @return signed 64.64-bit fixed point number
	 */
	function fromUInt(uint256 x) internal pure returns (int128) {
		unchecked {
			require(x <= 0x7FFFFFFFFFFFFFFF);
			return int128(int256(x << 64));
		}
	}

	/**
	 * Convert signed 64.64 fixed point number into unsigned 64-bit integer
	 * number rounding down.  Revert on underflow.
	 *
	 * @param x signed 64.64-bit fixed point number
	 * @return unsigned 64-bit integer number
	 */
	function toUInt(int128 x) internal pure returns (uint64) {
		unchecked {
			require(x >= 0);
			return uint64(uint128(x >> 64));
		}
	}

	/**
	 * Convert signed 128.128 fixed point number into signed 64.64-bit fixed point
	 * number rounding down.  Revert on overflow.
	 *
	 * @param x signed 128.128-bin fixed point number
	 * @return signed 64.64-bit fixed point number
	 */
	function from128x128(int256 x) internal pure returns (int128) {
		unchecked {
			int256 result = x >> 64;
			require(result >= MIN_64x64 && result <= MAX_64x64);
			return int128(result);
		}
	}

	/**
	 * Convert signed 64.64 fixed point number into signed 128.128 fixed point
	 * number.
	 *
	 * @param x signed 64.64-bit fixed point number
	 * @return signed 128.128 fixed point number
	 */
	function to128x128(int128 x) internal pure returns (int256) {
		unchecked {
			return int256(x) << 64;
		}
	}

	/**
	 * Calculate x + y.  Revert on overflow.
	 *
	 * @param x signed 64.64-bit fixed point number
	 * @param y signed 64.64-bit fixed point number
	 * @return signed 64.64-bit fixed point number
	 */
	function add(int128 x, int128 y) internal pure returns (int128) {
		unchecked {
			int256 result = int256(x) + y;
			require(result >= MIN_64x64 && result <= MAX_64x64);
			return int128(result);
		}
	}

	/**
	 * Calculate x - y.  Revert on overflow.
	 *
	 * @param x signed 64.64-bit fixed point number
	 * @param y signed 64.64-bit fixed point number
	 * @return signed 64.64-bit fixed point number
	 */
	function sub(int128 x, int128 y) internal pure returns (int128) {
		unchecked {
			int256 result = int256(x) - y;
			require(result >= MIN_64x64 && result <= MAX_64x64);
			return int128(result);
		}
	}

	/**
	 * Calculate x * y rounding down.  Revert on overflow.
	 *
	 * @param x signed 64.64-bit fixed point number
	 * @param y signed 64.64-bit fixed point number
	 * @return signed 64.64-bit fixed point number
	 */
	function mul(int128 x, int128 y) internal pure returns (int128) {
		unchecked {
			int256 result = (int256(x) * y) >> 64;
			require(result >= MIN_64x64 && result <= MAX_64x64);
			return int128(result);
		}
	}

	/**
	 * Calculate x * y rounding towards zero, where x is signed 64.64 fixed point
	 * number and y is signed 256-bit integer number.  Revert on overflow.
	 *
	 * @param x signed 64.64 fixed point number
	 * @param y signed 256-bit integer number
	 * @return signed 256-bit integer number
	 */
	function muli(int128 x, int256 y) internal pure returns (int256) {
		unchecked {
			if (x == MIN_64x64) {
				require(
					y >= -0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF &&
						y <= 0x1000000000000000000000000000000000000000000000000
				);
				return -y << 63;
			} else {
				bool negativeResult = false;
				if (x < 0) {
					x = -x;
					negativeResult = true;
				}
				if (y < 0) {
					y = -y; // We rely on overflow behavior here
					negativeResult = !negativeResult;
				}
				uint256 absoluteResult = mulu(x, uint256(y));
				if (negativeResult) {
					require(
						absoluteResult <=
							0x8000000000000000000000000000000000000000000000000000000000000000
					);
					return -int256(absoluteResult); // We rely on overflow behavior here
				} else {
					require(
						absoluteResult <=
							0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
					);
					return int256(absoluteResult);
				}
			}
		}
	}

	/**
	 * Calculate x * y rounding down, where x is signed 64.64 fixed point number
	 * and y is unsigned 256-bit integer number.  Revert on overflow.
	 *
	 * @param x signed 64.64 fixed point number
	 * @param y unsigned 256-bit integer number
	 * @return unsigned 256-bit integer number
	 */
	function mulu(int128 x, uint256 y) internal pure returns (uint256) {
		unchecked {
			if (y == 0) return 0;

			require(x >= 0);

			uint256 lo = (uint256(int256(x)) *
				(y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) >> 64;
			uint256 hi = uint256(int256(x)) * (y >> 128);

			require(hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
			hi <<= 64;

			require(
				hi <=
					0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -
						lo
			);
			return hi + lo;
		}
	}

	/**
	 * Calculate x / y rounding towards zero.  Revert on overflow or when y is
	 * zero.
	 *
	 * @param x signed 64.64-bit fixed point number
	 * @param y signed 64.64-bit fixed point number
	 * @return signed 64.64-bit fixed point number
	 */
	function div(int128 x, int128 y) internal pure returns (int128) {
		unchecked {
			require(y != 0);
			int256 result = (int256(x) << 64) / y;
			require(result >= MIN_64x64 && result <= MAX_64x64);
			return int128(result);
		}
	}

	/**
	 * Calculate x / y rounding towards zero, where x and y are signed 256-bit
	 * integer numbers.  Revert on overflow or when y is zero.
	 *
	 * @param x signed 256-bit integer number
	 * @param y signed 256-bit integer number
	 * @return signed 64.64-bit fixed point number
	 */
	function divi(int256 x, int256 y) internal pure returns (int128) {
		unchecked {
			require(y != 0);

			bool negativeResult = false;
			if (x < 0) {
				x = -x; // We rely on overflow behavior here
				negativeResult = true;
			}
			if (y < 0) {
				y = -y; // We rely on overflow behavior here
				negativeResult = !negativeResult;
			}
			uint128 absoluteResult = divuu(uint256(x), uint256(y));
			if (negativeResult) {
				require(absoluteResult <= 0x80000000000000000000000000000000);
				return -int128(absoluteResult); // We rely on overflow behavior here
			} else {
				require(absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
				return int128(absoluteResult); // We rely on overflow behavior here
			}
		}
	}

	/**
	 * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit
	 * integer numbers.  Revert on overflow or when y is zero.
	 *
	 * @param x unsigned 256-bit integer number
	 * @param y unsigned 256-bit integer number
	 * @return signed 64.64-bit fixed point number
	 */
	function divu(uint256 x, uint256 y) internal pure returns (int128) {
		unchecked {
			require(y != 0);
			uint128 result = divuu(x, y);
			require(result <= uint128(MAX_64x64));
			return int128(result);
		}
	}

	/**
	 * Calculate -x.  Revert on overflow.
	 *
	 * @param x signed 64.64-bit fixed point number
	 * @return signed 64.64-bit fixed point number
	 */
	function neg(int128 x) internal pure returns (int128) {
		unchecked {
			require(x != MIN_64x64);
			return -x;
		}
	}

	/**
	 * Calculate |x|.  Revert on overflow.
	 *
	 * @param x signed 64.64-bit fixed point number
	 * @return signed 64.64-bit fixed point number
	 */
	function abs(int128 x) internal pure returns (int128) {
		unchecked {
			require(x != MIN_64x64);
			return x < 0 ? -x : x;
		}
	}

	/**
	 * Calculate 1 / x rounding towards zero.  Revert on overflow or when x is
	 * zero.
	 *
	 * @param x signed 64.64-bit fixed point number
	 * @return signed 64.64-bit fixed point number
	 */
	function inv(int128 x) internal pure returns (int128) {
		unchecked {
			require(x != 0);
			int256 result = int256(0x100000000000000000000000000000000) / x;
			require(result >= MIN_64x64 && result <= MAX_64x64);
			return int128(result);
		}
	}

	/**
	 * Calculate arithmetics average of x and y, i.e. (x + y) / 2 rounding down.
	 *
	 * @param x signed 64.64-bit fixed point number
	 * @param y signed 64.64-bit fixed point number
	 * @return signed 64.64-bit fixed point number
	 */
	function avg(int128 x, int128 y) internal pure returns (int128) {
		unchecked {
			return int128((int256(x) + int256(y)) >> 1);
		}
	}

	/**
	 * Calculate geometric average of x and y, i.e. sqrt (x * y) rounding down.
	 * Revert on overflow or in case x * y is negative.
	 *
	 * @param x signed 64.64-bit fixed point number
	 * @param y signed 64.64-bit fixed point number
	 * @return signed 64.64-bit fixed point number
	 */
	function gavg(int128 x, int128 y) internal pure returns (int128) {
		unchecked {
			int256 m = int256(x) * int256(y);
			require(m >= 0);
			require(
				m <
					0x4000000000000000000000000000000000000000000000000000000000000000
			);
			return int128(sqrtu(uint256(m)));
		}
	}

	/**
	 * Calculate x^y assuming 0^0 is 1, where x is signed 64.64 fixed point number
	 * and y is unsigned 256-bit integer number.  Revert on overflow.
	 *
	 * @param x signed 64.64-bit fixed point number
	 * @param y uint256 value
	 * @return signed 64.64-bit fixed point number
	 */
	function pow(int128 x, uint256 y) internal pure returns (int128) {
		unchecked {
			bool negative = x < 0 && y & 1 == 1;

			uint256 absX = uint128(x < 0 ? -x : x);
			uint256 absResult;
			absResult = 0x100000000000000000000000000000000;

			if (absX <= 0x10000000000000000) {
				absX <<= 63;
				while (y != 0) {
					if (y & 0x1 != 0) {
						absResult = (absResult * absX) >> 127;
					}
					absX = (absX * absX) >> 127;

					if (y & 0x2 != 0) {
						absResult = (absResult * absX) >> 127;
					}
					absX = (absX * absX) >> 127;

					if (y & 0x4 != 0) {
						absResult = (absResult * absX) >> 127;
					}
					absX = (absX * absX) >> 127;

					if (y & 0x8 != 0) {
						absResult = (absResult * absX) >> 127;
					}
					absX = (absX * absX) >> 127;

					y >>= 4;
				}

				absResult >>= 64;
			} else {
				uint256 absXShift = 63;
				if (absX < 0x1000000000000000000000000) {
					absX <<= 32;
					absXShift -= 32;
				}
				if (absX < 0x10000000000000000000000000000) {
					absX <<= 16;
					absXShift -= 16;
				}
				if (absX < 0x1000000000000000000000000000000) {
					absX <<= 8;
					absXShift -= 8;
				}
				if (absX < 0x10000000000000000000000000000000) {
					absX <<= 4;
					absXShift -= 4;
				}
				if (absX < 0x40000000000000000000000000000000) {
					absX <<= 2;
					absXShift -= 2;
				}
				if (absX < 0x80000000000000000000000000000000) {
					absX <<= 1;
					absXShift -= 1;
				}

				uint256 resultShift = 0;
				while (y != 0) {
					require(absXShift < 64);

					if (y & 0x1 != 0) {
						absResult = (absResult * absX) >> 127;
						resultShift += absXShift;
						if (absResult > 0x100000000000000000000000000000000) {
							absResult >>= 1;
							resultShift += 1;
						}
					}
					absX = (absX * absX) >> 127;
					absXShift <<= 1;
					if (absX >= 0x100000000000000000000000000000000) {
						absX >>= 1;
						absXShift += 1;
					}

					y >>= 1;
				}

				require(resultShift < 64);
				absResult >>= 64 - resultShift;
			}
			int256 result = negative ? -int256(absResult) : int256(absResult);
			require(result >= MIN_64x64 && result <= MAX_64x64);
			return int128(result);
		}
	}

	/**
	 * Calculate sqrt (x) rounding down.  Revert if x < 0.
	 *
	 * @param x signed 64.64-bit fixed point number
	 * @return signed 64.64-bit fixed point number
	 */
	function sqrt(int128 x) internal pure returns (int128) {
		unchecked {
			require(x >= 0);
			return int128(sqrtu(uint256(int256(x)) << 64));
		}
	}

	/**
	 * Calculate binary logarithm of x.  Revert if x <= 0.
	 *
	 * @param x signed 64.64-bit fixed point number
	 * @return signed 64.64-bit fixed point number
	 */
	function log_2(int128 x) internal pure returns (int128) {
		unchecked {
			require(x > 0);

			int256 msb = 0;
			int256 xc = x;
			if (xc >= 0x10000000000000000) {
				xc >>= 64;
				msb += 64;
			}
			if (xc >= 0x100000000) {
				xc >>= 32;
				msb += 32;
			}
			if (xc >= 0x10000) {
				xc >>= 16;
				msb += 16;
			}
			if (xc >= 0x100) {
				xc >>= 8;
				msb += 8;
			}
			if (xc >= 0x10) {
				xc >>= 4;
				msb += 4;
			}
			if (xc >= 0x4) {
				xc >>= 2;
				msb += 2;
			}
			if (xc >= 0x2) msb += 1; // No need to shift xc anymore

			int256 result = (msb - 64) << 64;
			uint256 ux = uint256(int256(x)) << uint256(127 - msb);
			for (int256 bit = 0x8000000000000000; bit > 0; bit >>= 1) {
				ux *= ux;
				uint256 b = ux >> 255;
				ux >>= 127 + b;
				result += bit * int256(b);
			}

			return int128(result);
		}
	}

	/**
	 * Calculate natural logarithm of x.  Revert if x <= 0.
	 *
	 * @param x signed 64.64-bit fixed point number
	 * @return signed 64.64-bit fixed point number
	 */
	function ln(int128 x) internal pure returns (int128) {
		unchecked {
			require(x > 0);

			return
				int128(
					int256(
						(uint256(int256(log_2(x))) *
							0xB17217F7D1CF79ABC9E3B39803F2F6AF) >> 128
					)
				);
		}
	}

	/**
	 * Calculate binary exponent of x.  Revert on overflow.
	 *
	 * @param x signed 64.64-bit fixed point number
	 * @return signed 64.64-bit fixed point number
	 */
	function exp_2(int128 x) internal pure returns (int128) {
		unchecked {
			require(x < 0x400000000000000000); // Overflow

			if (x < -0x400000000000000000) return 0; // Underflow

			uint256 result = 0x80000000000000000000000000000000;

			if (x & 0x8000000000000000 > 0)
				result = (result * 0x16A09E667F3BCC908B2FB1366EA957D3E) >> 128;
			if (x & 0x4000000000000000 > 0)
				result = (result * 0x1306FE0A31B7152DE8D5A46305C85EDEC) >> 128;
			if (x & 0x2000000000000000 > 0)
				result = (result * 0x1172B83C7D517ADCDF7C8C50EB14A791F) >> 128;
			if (x & 0x1000000000000000 > 0)
				result = (result * 0x10B5586CF9890F6298B92B71842A98363) >> 128;
			if (x & 0x800000000000000 > 0)
				result = (result * 0x1059B0D31585743AE7C548EB68CA417FD) >> 128;
			if (x & 0x400000000000000 > 0)
				result = (result * 0x102C9A3E778060EE6F7CACA4F7A29BDE8) >> 128;
			if (x & 0x200000000000000 > 0)
				result = (result * 0x10163DA9FB33356D84A66AE336DCDFA3F) >> 128;
			if (x & 0x100000000000000 > 0)
				result = (result * 0x100B1AFA5ABCBED6129AB13EC11DC9543) >> 128;
			if (x & 0x80000000000000 > 0)
				result = (result * 0x10058C86DA1C09EA1FF19D294CF2F679B) >> 128;
			if (x & 0x40000000000000 > 0)
				result = (result * 0x1002C605E2E8CEC506D21BFC89A23A00F) >> 128;
			if (x & 0x20000000000000 > 0)
				result = (result * 0x100162F3904051FA128BCA9C55C31E5DF) >> 128;
			if (x & 0x10000000000000 > 0)
				result = (result * 0x1000B175EFFDC76BA38E31671CA939725) >> 128;
			if (x & 0x8000000000000 > 0)
				result = (result * 0x100058BA01FB9F96D6CACD4B180917C3D) >> 128;
			if (x & 0x4000000000000 > 0)
				result = (result * 0x10002C5CC37DA9491D0985C348C68E7B3) >> 128;
			if (x & 0x2000000000000 > 0)
				result = (result * 0x1000162E525EE054754457D5995292026) >> 128;
			if (x & 0x1000000000000 > 0)
				result = (result * 0x10000B17255775C040618BF4A4ADE83FC) >> 128;
			if (x & 0x800000000000 > 0)
				result = (result * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB) >> 128;
			if (x & 0x400000000000 > 0)
				result = (result * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9) >> 128;
			if (x & 0x200000000000 > 0)
				result = (result * 0x10000162E43F4F831060E02D839A9D16D) >> 128;
			if (x & 0x100000000000 > 0)
				result = (result * 0x100000B1721BCFC99D9F890EA06911763) >> 128;
			if (x & 0x80000000000 > 0)
				result = (result * 0x10000058B90CF1E6D97F9CA14DBCC1628) >> 128;
			if (x & 0x40000000000 > 0)
				result = (result * 0x1000002C5C863B73F016468F6BAC5CA2B) >> 128;
			if (x & 0x20000000000 > 0)
				result = (result * 0x100000162E430E5A18F6119E3C02282A5) >> 128;
			if (x & 0x10000000000 > 0)
				result = (result * 0x1000000B1721835514B86E6D96EFD1BFE) >> 128;
			if (x & 0x8000000000 > 0)
				result = (result * 0x100000058B90C0B48C6BE5DF846C5B2EF) >> 128;
			if (x & 0x4000000000 > 0)
				result = (result * 0x10000002C5C8601CC6B9E94213C72737A) >> 128;
			if (x & 0x2000000000 > 0)
				result = (result * 0x1000000162E42FFF037DF38AA2B219F06) >> 128;
			if (x & 0x1000000000 > 0)
				result = (result * 0x10000000B17217FBA9C739AA5819F44F9) >> 128;
			if (x & 0x800000000 > 0)
				result = (result * 0x1000000058B90BFCDEE5ACD3C1CEDC823) >> 128;
			if (x & 0x400000000 > 0)
				result = (result * 0x100000002C5C85FE31F35A6A30DA1BE50) >> 128;
			if (x & 0x200000000 > 0)
				result = (result * 0x10000000162E42FF0999CE3541B9FFFCF) >> 128;
			if (x & 0x100000000 > 0)
				result = (result * 0x100000000B17217F80F4EF5AADDA45554) >> 128;
			if (x & 0x80000000 > 0)
				result = (result * 0x10000000058B90BFBF8479BD5A81B51AD) >> 128;
			if (x & 0x40000000 > 0)
				result = (result * 0x1000000002C5C85FDF84BD62AE30A74CC) >> 128;
			if (x & 0x20000000 > 0)
				result = (result * 0x100000000162E42FEFB2FED257559BDAA) >> 128;
			if (x & 0x10000000 > 0)
				result = (result * 0x1000000000B17217F7D5A7716BBA4A9AE) >> 128;
			if (x & 0x8000000 > 0)
				result = (result * 0x100000000058B90BFBE9DDBAC5E109CCE) >> 128;
			if (x & 0x4000000 > 0)
				result = (result * 0x10000000002C5C85FDF4B15DE6F17EB0D) >> 128;
			if (x & 0x2000000 > 0)
				result = (result * 0x1000000000162E42FEFA494F1478FDE05) >> 128;
			if (x & 0x1000000 > 0)
				result = (result * 0x10000000000B17217F7D20CF927C8E94C) >> 128;
			if (x & 0x800000 > 0)
				result = (result * 0x1000000000058B90BFBE8F71CB4E4B33D) >> 128;
			if (x & 0x400000 > 0)
				result = (result * 0x100000000002C5C85FDF477B662B26945) >> 128;
			if (x & 0x200000 > 0)
				result = (result * 0x10000000000162E42FEFA3AE53369388C) >> 128;
			if (x & 0x100000 > 0)
				result = (result * 0x100000000000B17217F7D1D351A389D40) >> 128;
			if (x & 0x80000 > 0)
				result = (result * 0x10000000000058B90BFBE8E8B2D3D4EDE) >> 128;
			if (x & 0x40000 > 0)
				result = (result * 0x1000000000002C5C85FDF4741BEA6E77E) >> 128;
			if (x & 0x20000 > 0)
				result = (result * 0x100000000000162E42FEFA39FE95583C2) >> 128;
			if (x & 0x10000 > 0)
				result = (result * 0x1000000000000B17217F7D1CFB72B45E1) >> 128;
			if (x & 0x8000 > 0)
				result = (result * 0x100000000000058B90BFBE8E7CC35C3F0) >> 128;
			if (x & 0x4000 > 0)
				result = (result * 0x10000000000002C5C85FDF473E242EA38) >> 128;
			if (x & 0x2000 > 0)
				result = (result * 0x1000000000000162E42FEFA39F02B772C) >> 128;
			if (x & 0x1000 > 0)
				result = (result * 0x10000000000000B17217F7D1CF7D83C1A) >> 128;
			if (x & 0x800 > 0)
				result = (result * 0x1000000000000058B90BFBE8E7BDCBE2E) >> 128;
			if (x & 0x400 > 0)
				result = (result * 0x100000000000002C5C85FDF473DEA871F) >> 128;
			if (x & 0x200 > 0)
				result = (result * 0x10000000000000162E42FEFA39EF44D91) >> 128;
			if (x & 0x100 > 0)
				result = (result * 0x100000000000000B17217F7D1CF79E949) >> 128;
			if (x & 0x80 > 0)
				result = (result * 0x10000000000000058B90BFBE8E7BCE544) >> 128;
			if (x & 0x40 > 0)
				result = (result * 0x1000000000000002C5C85FDF473DE6ECA) >> 128;
			if (x & 0x20 > 0)
				result = (result * 0x100000000000000162E42FEFA39EF366F) >> 128;
			if (x & 0x10 > 0)
				result = (result * 0x1000000000000000B17217F7D1CF79AFA) >> 128;
			if (x & 0x8 > 0)
				result = (result * 0x100000000000000058B90BFBE8E7BCD6D) >> 128;
			if (x & 0x4 > 0)
				result = (result * 0x10000000000000002C5C85FDF473DE6B2) >> 128;
			if (x & 0x2 > 0)
				result = (result * 0x1000000000000000162E42FEFA39EF358) >> 128;
			if (x & 0x1 > 0)
				result = (result * 0x10000000000000000B17217F7D1CF79AB) >> 128;

			result >>= uint256(int256(63 - (x >> 64)));
			require(result <= uint256(int256(MAX_64x64)));

			return int128(int256(result));
		}
	}

	/**
	 * Calculate natural exponent of x.  Revert on overflow.
	 *
	 * @param x signed 64.64-bit fixed point number
	 * @return signed 64.64-bit fixed point number
	 */
	function exp(int128 x) internal pure returns (int128) {
		unchecked {
			require(x < 0x400000000000000000); // Overflow

			if (x < -0x400000000000000000) return 0; // Underflow

			return
				exp_2(
					int128(
						(int256(x) * 0x171547652B82FE1777D0FFDA0D23A7D12) >> 128
					)
				);
		}
	}

	/**
	 * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit
	 * integer numbers.  Revert on overflow or when y is zero.
	 *
	 * @param x unsigned 256-bit integer number
	 * @param y unsigned 256-bit integer number
	 * @return unsigned 64.64-bit fixed point number
	 */
	function divuu(uint256 x, uint256 y) private pure returns (uint128) {
		unchecked {
			require(y != 0);

			uint256 result;

			if (x <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
				result = (x << 64) / y;
			else {
				uint256 msb = 192;
				uint256 xc = x >> 192;
				if (xc >= 0x100000000) {
					xc >>= 32;
					msb += 32;
				}
				if (xc >= 0x10000) {
					xc >>= 16;
					msb += 16;
				}
				if (xc >= 0x100) {
					xc >>= 8;
					msb += 8;
				}
				if (xc >= 0x10) {
					xc >>= 4;
					msb += 4;
				}
				if (xc >= 0x4) {
					xc >>= 2;
					msb += 2;
				}
				if (xc >= 0x2) msb += 1; // No need to shift xc anymore

				result = (x << (255 - msb)) / (((y - 1) >> (msb - 191)) + 1);
				require(result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);

				uint256 hi = result * (y >> 128);
				uint256 lo = result * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);

				uint256 xh = x >> 192;
				uint256 xl = x << 64;

				if (xl < lo) xh -= 1;
				xl -= lo; // We rely on overflow behavior here
				lo = hi << 128;
				if (xl < lo) xh -= 1;
				xl -= lo; // We rely on overflow behavior here

				assert(xh == hi >> 128);

				result += xl / y;
			}

			require(result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
			return uint128(result);
		}
	}

	/**
	 * Calculate sqrt (x) rounding down, where x is unsigned 256-bit integer
	 * number.
	 *
	 * @param x unsigned 256-bit integer number
	 * @return unsigned 128-bit integer number
	 */
	function sqrtu(uint256 x) private pure returns (uint128) {
		unchecked {
			if (x == 0) return 0;
			else {
				uint256 xx = x;
				uint256 r = 1;
				if (xx >= 0x100000000000000000000000000000000) {
					xx >>= 128;
					r <<= 64;
				}
				if (xx >= 0x10000000000000000) {
					xx >>= 64;
					r <<= 32;
				}
				if (xx >= 0x100000000) {
					xx >>= 32;
					r <<= 16;
				}
				if (xx >= 0x10000) {
					xx >>= 16;
					r <<= 8;
				}
				if (xx >= 0x100) {
					xx >>= 8;
					r <<= 4;
				}
				if (xx >= 0x10) {
					xx >>= 4;
					r <<= 2;
				}
				if (xx >= 0x8) {
					r <<= 1;
				}
				r = (r + x / r) >> 1;
				r = (r + x / r) >> 1;
				r = (r + x / r) >> 1;
				r = (r + x / r) >> 1;
				r = (r + x / r) >> 1;
				r = (r + x / r) >> 1;
				r = (r + x / r) >> 1; // Seven iterations should be enough
				uint256 r1 = x / r;
				return uint128(r < r1 ? r : r1);
			}
		}
	}
}

contract StakingPool {
	using ABDKMath64x64 for int128;
	using RolesLibrary for address;

	address public claimManager;

	uint256 public start;
	uint256 public end;

	uint256 public hourlyRatio;
	uint256 public hardCap;
	uint256 public contributionLimit;

	uint256 public totalStaked;

	bytes32[] private patronRoles;
	bytes32 private ownerRole;

	uint256 private remainingRewards;
	uint256 private futureRewards;

	bool public sweeped;

	address internal initiator;

	struct Stake {
		uint256 deposit;
		uint256 compounded;
		uint256 time;
		uint256 futureReward;
	}

	event StakeAdded(address indexed sender, uint256 amount, uint256 time);
	event StakeWithdrawn(address indexed sender, uint256 amount);
	event StakingPoolInitialized(uint256 funded, uint256 timestamp);

	mapping(address => Stake) public stakes;

	modifier onlyOwner() virtual {
		// restrict to accounts enrolled as owner at energyweb
		require(
			msg.sender.isOwner(claimManager, ownerRole),
			"OnlyOwner: Not an owner"
		);
		_;
	}

	modifier onlyPatrons(address _agent) virtual {
		// checking patron role with claimManager
		require(
			_agent.hasRole(claimManager, patronRoles),
			"StakingPool: Not a patron"
		);
		_;
	}

	modifier belowContributionLimit() {
		require(
			stakes[msg.sender].deposit + msg.value <= contributionLimit,
			"Stake greater than contribution limit"
		);
		_;
	}

	modifier initialized() {
		require(start != 0, "Staking Pool not initialized");
		_;
	}

	modifier preventReset() {
		require(start == 0, "Staking Pool already initialized");
		_;
	}

	constructor(bytes32 _ownerRole, address _claimManager) {
		ownerRole = _ownerRole;
		claimManager = _claimManager;
	}

	function init(
		uint256 _start,
		uint256 _end,
		uint256 _hourlyRatio,
		uint256 _hardCap,
		uint256 _contributionLimit,
		bytes32[] memory _patronRoles
	) external payable onlyOwner preventReset {
		require(
			_start >= block.timestamp,
			"Start date should be at least current block timestamp"
		);
		// check if stake pool time is at least 1 day
		require(_end - _start >= 1 days, "Duration should be at least 1 day");
		require(_hardCap >= _contributionLimit, "hardCap exceeded");

		uint256 maxFutureRewards = compound(
			_hourlyRatio,
			_hardCap,
			_start,
			_end
		) - _hardCap;

		require(msg.value >= maxFutureRewards, "Rewards lower than expected");

		start = _start;
		end = _end;
		hourlyRatio = _hourlyRatio;
		hardCap = _hardCap;
		contributionLimit = _contributionLimit;
		patronRoles = _patronRoles;

		remainingRewards = msg.value;

		initiator = msg.sender;

		emit StakingPoolInitialized(msg.value, block.timestamp);
	}

	function terminate() external initialized onlyOwner {
		require(start >= block.timestamp, "Cannot terminate after start");

		uint256 payout = remainingRewards;
		address receipient = initiator;

		delete start;
		delete end;
		delete hourlyRatio;
		delete hardCap;
		delete contributionLimit;
		delete patronRoles;
		delete initiator;

		payable(receipient).transfer(payout);
	}

	function stake()
		public
		payable
		onlyPatrons(msg.sender)
		initialized
		belowContributionLimit
	{
		// check role with claimManager
		require(block.timestamp >= start, "Staking pool not yet started");
		require(block.timestamp <= end, "Staking pool already expired");

		require(hardCap - totalStaked >= msg.value, "Staking pool is full");

		(, uint256 compounded) = total();

		updateStake(
			stakes[msg.sender].deposit + msg.value,
			compounded + msg.value
		);
		accountFutureReward();

		totalStaked += msg.value;

		emit StakeAdded(msg.sender, msg.value, block.timestamp);
	}

	function unstake(uint256 value) public initialized {
		(uint256 deposit, uint256 compounded) = total();

		require(compounded > 0, "No funds available");

		require(
			compounded >= value,
			"Requested value above the compounded funds"
		);

		uint256 depositComponent = value <= deposit ? value : deposit;
		uint256 rewardComponent = value > deposit ? value - deposit : 0;

		if (value == compounded) {
			delete stakes[msg.sender];
		} else {
			updateStake(
				stakes[msg.sender].deposit - depositComponent,
				compounded - value
			);
			accountFutureReward();
		}

		futureRewards -= rewardComponent;
		remainingRewards -= rewardComponent;
		totalStaked -= depositComponent;

		payable(msg.sender).transfer(value);

		emit StakeWithdrawn(msg.sender, value);
	}

	//allow specifing the value
	function unstakeAll() public initialized {
		(, uint256 compounded) = total();

		unstake(compounded);
	}

	function sweep() public initialized onlyOwner {
		require(!sweeped, "Already sweeped");
		require(block.timestamp >= end, "Cannot sweep before expiry");

		uint256 payout = remainingRewards - futureRewards;

		sweeped = true;

		payable(initiator).transfer(payout);
	}

	function calculateFutureReward() private view returns (uint256) {
		return
			compound(
				hourlyRatio,
				stakes[msg.sender].compounded,
				block.timestamp,
				end
			) - stakes[msg.sender].deposit;
	}

	function accountFutureReward() private {
		uint256 futureReward = calculateFutureReward();

		futureRewards -= stakes[msg.sender].futureReward;
		futureRewards += futureReward;

		stakes[msg.sender].futureReward = futureReward;
	}

	function updateStake(uint256 deposit, uint256 compounded) private {
		stakes[msg.sender].deposit = deposit;
		stakes[msg.sender].compounded = compounded;
		if (block.timestamp - stakes[msg.sender].time >= 1 hours) {
			stakes[msg.sender].time = block.timestamp;
		}
	}

	function total() public view returns (uint256, uint256) {
		Stake memory senderStake = stakes[msg.sender];

		// checks if there is no stake added
		if (senderStake.time == 0) {
			return (0, 0);
		}

		uint256 compoundEnd = block.timestamp > end ? end : block.timestamp;

		uint256 compounded = compound(
			hourlyRatio,
			senderStake.compounded,
			senderStake.time,
			compoundEnd
		);

		return (senderStake.deposit, compounded);
	}

	function compound(
		uint256 ratio,
		uint256 principal,
		uint256 compoundStart,
		uint256 compoundEnd
	) public view returns (uint256) {
		uint256 n = (compoundEnd - compoundStart) / 1 hours;

		return
			ABDKMath64x64.mulu(
				ABDKMath64x64.pow(
					ABDKMath64x64.add(
						ABDKMath64x64.fromUInt(1),
						ABDKMath64x64.divu(ratio, 10**18)
					),
					n
				),
				principal
			);
	}
}

// File contracts/StakingPoolNoKYC.sol

contract StakingPoolNoKYC is StakingPool {
	modifier onlyOwner() override {
		// restrict to the account that was set as initiator
		require(msg.sender == initiator, "OnlyOwner: Not an owner");
		_;
	}

	modifier onlyPatrons(address _agent) override {
		// no role check, just pass
		_;
	}

	constructor(address _initiator) StakingPool(bytes32(0), address(0)) {
		require(_initiator != address(0));

		initiator = _initiator;
	}
}

contract StakingPoolPatronKYC is StakingPool {
	modifier onlyOwner() override {
		// restrict to the account that was set as initiator
		require(msg.sender == initiator, "OnlyOwner: Not an owner");
		_;
	}

	constructor(address _initiator, address _claimManager)
		StakingPool(bytes32(0), _claimManager)
	{
		require(_initiator != address(0));

		initiator = _initiator;
	}
}
        

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_initiator","internalType":"address"},{"type":"address","name":"_claimManager","internalType":"address"}]},{"type":"event","name":"StakeAdded","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"uint256","name":"time","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"StakeWithdrawn","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"StakingPoolInitialized","inputs":[{"type":"uint256","name":"funded","internalType":"uint256","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"claimManager","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"compound","inputs":[{"type":"uint256","name":"ratio","internalType":"uint256"},{"type":"uint256","name":"principal","internalType":"uint256"},{"type":"uint256","name":"compoundStart","internalType":"uint256"},{"type":"uint256","name":"compoundEnd","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"contributionLimit","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"end","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"hardCap","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"hourlyRatio","inputs":[]},{"type":"function","stateMutability":"payable","outputs":[],"name":"init","inputs":[{"type":"uint256","name":"_start","internalType":"uint256"},{"type":"uint256","name":"_end","internalType":"uint256"},{"type":"uint256","name":"_hourlyRatio","internalType":"uint256"},{"type":"uint256","name":"_hardCap","internalType":"uint256"},{"type":"uint256","name":"_contributionLimit","internalType":"uint256"},{"type":"bytes32[]","name":"_patronRoles","internalType":"bytes32[]"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"stake","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"deposit","internalType":"uint256"},{"type":"uint256","name":"compounded","internalType":"uint256"},{"type":"uint256","name":"time","internalType":"uint256"},{"type":"uint256","name":"futureReward","internalType":"uint256"}],"name":"stakes","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"start","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"sweep","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"sweeped","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"terminate","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"}],"name":"total","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalStaked","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unstake","inputs":[{"type":"uint256","name":"value","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unstakeAll","inputs":[]}]
            

Deployed ByteCode

0x6080604052600436106100fe5760003560e01c806368eb7a6911610095578063a9a36dcd11610064578063a9a36dcd146102c1578063be9a6555146102ec578063eb01393314610317578063efbe1c1c14610342578063fb86a4041461036d576100fe565b806368eb7a69146102035780637332e0771461022e578063817b1cd21461025957806384c18c8914610284576100fe565b80633455b92d116100d15780633455b92d146101af57806335322f37146101cb57806335faa416146101e25780633a4b66f1146101f9576100fe565b80630c08bf881461010357806316934fc41461011a5780632ddbd13a1461015a5780632e17de7814610186575b600080fd5b34801561010f57600080fd5b50610118610398565b005b34801561012657600080fd5b50610141600480360381019061013c9190611e6c565b61057d565b6040516101519493929190612572565b60405180910390f35b34801561016657600080fd5b5061016f6105ad565b60405161017d929190612549565b60405180910390f35b34801561019257600080fd5b506101ad60048036038101906101a89190611ec6565b610683565b005b6101c960048036038101906101c49190611f5a565b610952565b005b3480156101d757600080fd5b506101e0610c20565b005b3480156101ee57600080fd5b506101f7610c7f565b005b610201610e85565b005b34801561020f57600080fd5b506102186111f8565b604051610225919061252e565b60405180910390f35b34801561023a57600080fd5b506102436111fe565b604051610250919061252e565b60405180910390f35b34801561026557600080fd5b5061026e611204565b60405161027b919061252e565b60405180910390f35b34801561029057600080fd5b506102ab60048036038101906102a69190611ef3565b61120a565b6040516102b8919061252e565b60405180910390f35b3480156102cd57600080fd5b506102d6611269565b6040516102e391906122a1565b60405180910390f35b3480156102f857600080fd5b5061030161128d565b60405161030e919061252e565b60405180910390f35b34801561032357600080fd5b5061032c611293565b60405161033991906122f3565b60405180910390f35b34801561034e57600080fd5b506103576112a6565b604051610364919061252e565b60405180910390f35b34801561037957600080fd5b506103826112ac565b60405161038f919061252e565b60405180910390f35b600060015414156103de576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103d5906123ee565b60405180910390fd5b600b60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461046e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104659061248e565b60405180910390fd5b4260015410156104b3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104aa9061234e565b60405180910390fd5b600060095490506000600b60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506001600090556002600090556003600090556004600090556005600090556007600061050d9190611cef565b600b60016101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690558073ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f19350505050158015610578573d6000803e3d6000fd5b505050565b600c6020528060005260406000206000915090508060000154908060010154908060020154908060030154905084565b6000806000600c60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020604051806080016040529081600082015481526020016001820154815260200160028201548152602001600382015481525050905060008160400151141561064057600080925092505061067f565b600060025442116106515742610655565b6002545b9050600061066f600354846020015185604001518561120a565b9050826000015181945094505050505b9091565b600060015414156106c9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c0906123ee565b60405180910390fd5b6000806106d46105ad565b915091506000811161071b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610712906123ae565b60405180910390fd5b8281101561075e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107559061246e565b60405180910390fd5b60008284111561076e5782610770565b835b9050600083851161078257600061078f565b838561078e91906126a0565b5b90508285141561080057600c60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600080820160009055600182016000905560028201600090556003820160009055505061086b565b61086282600c60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000015461085191906126a0565b868561085d91906126a0565b6112b2565b61086a6113e2565b5b80600a600082825461087d91906126a0565b92505081905550806009600082825461089691906126a0565b9250508190555081600660008282546108af91906126a0565b925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc869081150290604051600060405180830381858888f193505050501580156108fc573d6000803e3d6000fd5b503373ffffffffffffffffffffffffffffffffffffffff167f8108595eb6bad3acefa9da467d90cc2217686d5c5ac85460f8b7849c840645fc86604051610943919061252e565b60405180910390a25050505050565b600b60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146109e2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109d99061248e565b60405180910390fd5b600060015414610a27576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a1e9061236e565b60405180910390fd5b42861015610a6a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a61906124ce565b60405180910390fd5b620151808686610a7a91906126a0565b1015610abb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ab2906123ce565b60405180910390fd5b81831015610afe576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610af59061232e565b60405180910390fd5b600083610b0d86868a8a61120a565b610b1791906126a0565b905080341015610b5c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b539061242e565b60405180910390fd5b86600181905550856002819055508460038190555083600481905550826005819055508160079080519060200190610b95929190611d10565b503460098190555033600b60016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f3d828625fed4f186627245530300f39c5b54220393511f345c505ee3ddf6fc603442604051610c0f929190612549565b60405180910390a150505050505050565b60006001541415610c66576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c5d906123ee565b60405180910390fd5b6000610c706105ad565b915050610c7c81610683565b50565b60006001541415610cc5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cbc906123ee565b60405180910390fd5b600b60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610d55576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d4c9061248e565b60405180910390fd5b600b60009054906101000a900460ff1615610da5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d9c906124ee565b60405180910390fd5b600254421015610dea576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610de19061244e565b60405180910390fd5b6000600a54600954610dfc91906126a0565b90506001600b60006101000a81548160ff021916908315150217905550600b60019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015610e81573d6000803e3d6000fd5b5050565b33610f2160008054906101000a900473ffffffffffffffffffffffffffffffffffffffff166007805480602002602001604051908101604052809291908181526020018280548015610ef657602002820191906000526020600020905b815481526020019060010190808311610ee2575b50505050508373ffffffffffffffffffffffffffffffffffffffff166114ac9092919063ffffffff16565b610f60576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f579061230e565b60405180910390fd5b60006001541415610fa6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f9d906123ee565b60405180910390fd5b60055434600c60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000154610ff79190612619565b1115611038576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161102f9061240e565b60405180910390fd5b60015442101561107d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110749061250e565b60405180910390fd5b6002544211156110c2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110b99061238e565b60405180910390fd5b346006546004546110d391906126a0565b1015611114576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161110b906124ae565b60405180910390fd5b600061111e6105ad565b91505061118334600c60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001546111729190612619565b348361117e9190612619565b6112b2565b61118b6113e2565b346006600082825461119d9190612619565b925050819055503373ffffffffffffffffffffffffffffffffffffffff167f270d6dd254edd1d985c81cf7861b8f28fb06b6d719df04d90464034d4341244034426040516111ec929190612549565b60405180910390a25050565b60035481565b60055481565b60065481565b600080610e10848461121c91906126a0565b611226919061266f565b905061125e61125861125261123b60016115aa565b61124d8a670de0b6b3a76400006115cd565b611635565b8361169c565b866119b1565b915050949350505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60015481565b600b60009054906101000a900460ff1681565b60025481565b60045481565b81600c60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000018190555080600c60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010181905550610e10600c60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600201544261139191906126a0565b106113de5742600c60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600201819055505b5050565b60006113ec611a6c565b9050600c60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060030154600a600082825461144291906126a0565b9250508190555080600a600082825461145b9190612619565b9250508190555080600c60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206003018190555050565b600080825114156114c057600190506115a3565b600083905060005b835181101561159c578173ffffffffffffffffffffffffffffffffffffffff166395df7b1e878684815181106115015761150061283f565b5b602002602001015160016040518463ffffffff1660e01b8152600401611529939291906122bc565b60206040518083038186803b15801561154157600080fd5b505afa158015611555573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115799190611e99565b15611589576001925050506115a3565b808061159490612769565b9150506114c8565b5060009150505b9392505050565b6000677fffffffffffffff8211156115c157600080fd5b604082901b9050919050565b6000808214156115dc57600080fd5b60006115e88484611b12565b90506f7fffffffffffffffffffffffffffffff6fffffffffffffffffffffffffffffffff16816fffffffffffffffffffffffffffffffff16111561162b57600080fd5b8091505092915050565b60008082600f0b84600f0b0190507fffffffffffffffffffffffffffffffff80000000000000000000000000000000600f0b811215801561168957506f7fffffffffffffffffffffffffffffff600f0b8113155b61169257600080fd5b8091505092915050565b600080600084600f0b1280156116b457506001808416145b905060008085600f0b126116c857846116cd565b846000035b6fffffffffffffffffffffffffffffffff169050600070010000000000000000000000000000000090506801000000000000000082116117a757603f82901b91505b6000851461179b576000600186161461172c57607f828202901c90505b607f828302901c91506000600286161461174a57607f828202901c90505b607f828302901c91506000600486161461176857607f828202901c90505b607f828302901c91506000600886161461178657607f828202901c90505b607f828302901c9150600485901c945061170f565b604081901c9050611941565b6000603f90506c010000000000000000000000008310156117d057602083901b92506020810390505b6e0100000000000000000000000000008310156117f557601083901b92506010810390505b6f0100000000000000000000000000000083101561181b57600883901b92506008810390505b6f1000000000000000000000000000000083101561184157600483901b92506004810390505b6f4000000000000000000000000000000083101561186757600283901b92506002810390505b6f8000000000000000000000000000000083101561188d57600183901b92506001810390505b60005b6000871461192857604082106118a557600080fd5b600060018816146118e657607f848402901c925081810190507001000000000000000000000000000000008311156118e557600183901c92506001810190505b5b607f848502901c9350600182901b9150700100000000000000000000000000000000841061191c57600184901c93506001820191505b600187901c9650611890565b6040811061193557600080fd5b8060400383901c925050505b60008361194e5781611953565b816000035b90507fffffffffffffffffffffffffffffffff80000000000000000000000000000000600f0b811215801561199b57506f7fffffffffffffffffffffffffffffff600f0b8113155b6119a457600080fd5b8094505050505092915050565b6000808214156119c45760009050611a66565b600083600f0b12156119d557600080fd5b600060406fffffffffffffffffffffffffffffffff841685600f0b02901c90506000608084901c85600f0b02905077ffffffffffffffffffffffffffffffffffffffffffffffff811115611a2857600080fd5b604081901b9050817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03811115611a5e57600080fd5b818101925050505b92915050565b6000600c60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000154611b03600354600c60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101544260025461120a565b611b0d91906126a0565b905090565b600080821415611b2157600080fd5b600077ffffffffffffffffffffffffffffffffffffffffffffffff8411611b5e5782604085901b81611b5657611b55612810565b5b049050611cc8565b600060c09050600060c086901c90506401000000008110611b8757602081901c90506020820191505b620100008110611b9f57601081901c90506010820191505b6101008110611bb657600881901c90506008820191505b60108110611bcc57600481901c90506004820191505b60048110611be257600281901c90506002820191505b60028110611bf1576001820191505b600160bf830360018703901c018260ff0387901b81611c1357611c12612810565b5b0492506fffffffffffffffffffffffffffffffff831115611c3357600080fd5b6000608086901c8402905060006fffffffffffffffffffffffffffffffff871685029050600060c089901c9050600060408a901b905082811015611c78576001820391505b8281039050608084901b925082811015611c93576001820391505b8281039050608084901c8214611cac57611cab6127b2565b5b888181611cbc57611cbb612810565b5b04870196505050505050505b6fffffffffffffffffffffffffffffffff811115611ce557600080fd5b8091505092915050565b5080546000825590600052602060002090810190611d0d9190611d5d565b50565b828054828255906000526020600020908101928215611d4c579160200282015b82811115611d4b578251825591602001919060010190611d30565b5b509050611d599190611d5d565b5090565b5b80821115611d76576000816000905550600101611d5e565b5090565b6000611d8d611d88846125dc565b6125b7565b90508083825260208201905082856020860282011115611db057611daf6128a2565b5b60005b85811015611de05781611dc68882611e42565b845260208401935060208301925050600181019050611db3565b5050509392505050565b600081359050611df981612c13565b92915050565b600082601f830112611e1457611e1361289d565b5b8135611e24848260208601611d7a565b91505092915050565b600081519050611e3c81612c2a565b92915050565b600081359050611e5181612c41565b92915050565b600081359050611e6681612c58565b92915050565b600060208284031215611e8257611e816128ac565b5b6000611e9084828501611dea565b91505092915050565b600060208284031215611eaf57611eae6128ac565b5b6000611ebd84828501611e2d565b91505092915050565b600060208284031215611edc57611edb6128ac565b5b6000611eea84828501611e57565b91505092915050565b60008060008060808587031215611f0d57611f0c6128ac565b5b6000611f1b87828801611e57565b9450506020611f2c87828801611e57565b9350506040611f3d87828801611e57565b9250506060611f4e87828801611e57565b91505092959194509250565b60008060008060008060c08789031215611f7757611f766128ac565b5b6000611f8589828a01611e57565b9650506020611f9689828a01611e57565b9550506040611fa789828a01611e57565b9450506060611fb889828a01611e57565b9350506080611fc989828a01611e57565b92505060a087013567ffffffffffffffff811115611fea57611fe96128a7565b5b611ff689828a01611dff565b9150509295509295509295565b61200c816126d4565b82525050565b61201b816126e6565b82525050565b61202a816126f2565b82525050565b61203981612726565b82525050565b600061204c601983612608565b9150612057826128c2565b602082019050919050565b600061206f601083612608565b915061207a826128eb565b602082019050919050565b6000612092601c83612608565b915061209d82612914565b602082019050919050565b60006120b5602083612608565b91506120c08261293d565b602082019050919050565b60006120d8601c83612608565b91506120e382612966565b602082019050919050565b60006120fb601283612608565b91506121068261298f565b602082019050919050565b600061211e602183612608565b9150612129826129b8565b604082019050919050565b6000612141601c83612608565b915061214c82612a07565b602082019050919050565b6000612164602583612608565b915061216f82612a30565b604082019050919050565b6000612187601b83612608565b915061219282612a7f565b602082019050919050565b60006121aa601a83612608565b91506121b582612aa8565b602082019050919050565b60006121cd602a83612608565b91506121d882612ad1565b604082019050919050565b60006121f0601783612608565b91506121fb82612b20565b602082019050919050565b6000612213601483612608565b915061221e82612b49565b602082019050919050565b6000612236603583612608565b915061224182612b72565b604082019050919050565b6000612259600f83612608565b915061226482612bc1565b602082019050919050565b600061227c601c83612608565b915061228782612bea565b602082019050919050565b61229b8161271c565b82525050565b60006020820190506122b66000830184612003565b92915050565b60006060820190506122d16000830186612003565b6122de6020830185612021565b6122eb6040830184612030565b949350505050565b60006020820190506123086000830184612012565b92915050565b600060208201905081810360008301526123278161203f565b9050919050565b6000602082019050818103600083015261234781612062565b9050919050565b6000602082019050818103600083015261236781612085565b9050919050565b60006020820190508181036000830152612387816120a8565b9050919050565b600060208201905081810360008301526123a7816120cb565b9050919050565b600060208201905081810360008301526123c7816120ee565b9050919050565b600060208201905081810360008301526123e781612111565b9050919050565b6000602082019050818103600083015261240781612134565b9050919050565b6000602082019050818103600083015261242781612157565b9050919050565b600060208201905081810360008301526124478161217a565b9050919050565b600060208201905081810360008301526124678161219d565b9050919050565b60006020820190508181036000830152612487816121c0565b9050919050565b600060208201905081810360008301526124a7816121e3565b9050919050565b600060208201905081810360008301526124c781612206565b9050919050565b600060208201905081810360008301526124e781612229565b9050919050565b600060208201905081810360008301526125078161224c565b9050919050565b600060208201905081810360008301526125278161226f565b9050919050565b60006020820190506125436000830184612292565b92915050565b600060408201905061255e6000830185612292565b61256b6020830184612292565b9392505050565b60006080820190506125876000830187612292565b6125946020830186612292565b6125a16040830185612292565b6125ae6060830184612292565b95945050505050565b60006125c16125d2565b90506125cd8282612738565b919050565b6000604051905090565b600067ffffffffffffffff8211156125f7576125f661286e565b5b602082029050602081019050919050565b600082825260208201905092915050565b60006126248261271c565b915061262f8361271c565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115612664576126636127e1565b5b828201905092915050565b600061267a8261271c565b91506126858361271c565b92508261269557612694612810565b5b828204905092915050565b60006126ab8261271c565b91506126b68361271c565b9250828210156126c9576126c86127e1565b5b828203905092915050565b60006126df826126fc565b9050919050565b60008115159050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60006127318261271c565b9050919050565b612741826128b1565b810181811067ffffffffffffffff821117156127605761275f61286e565b5b80604052505050565b60006127748261271c565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156127a7576127a66127e1565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f5374616b696e67506f6f6c3a204e6f74206120706174726f6e00000000000000600082015250565b7f6861726443617020657863656564656400000000000000000000000000000000600082015250565b7f43616e6e6f74207465726d696e61746520616674657220737461727400000000600082015250565b7f5374616b696e6720506f6f6c20616c726561647920696e697469616c697a6564600082015250565b7f5374616b696e6720706f6f6c20616c7265616479206578706972656400000000600082015250565b7f4e6f2066756e647320617661696c61626c650000000000000000000000000000600082015250565b7f4475726174696f6e2073686f756c64206265206174206c65617374203120646160008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b7f5374616b696e6720506f6f6c206e6f7420696e697469616c697a656400000000600082015250565b7f5374616b652067726561746572207468616e20636f6e747269627574696f6e2060008201527f6c696d6974000000000000000000000000000000000000000000000000000000602082015250565b7f52657761726473206c6f776572207468616e2065787065637465640000000000600082015250565b7f43616e6e6f74207377656570206265666f726520657870697279000000000000600082015250565b7f5265717565737465642076616c75652061626f76652074686520636f6d706f7560008201527f6e6465642066756e647300000000000000000000000000000000000000000000602082015250565b7f4f6e6c794f776e65723a204e6f7420616e206f776e6572000000000000000000600082015250565b7f5374616b696e6720706f6f6c2069732066756c6c000000000000000000000000600082015250565b7f537461727420646174652073686f756c64206265206174206c6561737420637560008201527f7272656e7420626c6f636b2074696d657374616d700000000000000000000000602082015250565b7f416c726561647920737765657065640000000000000000000000000000000000600082015250565b7f5374616b696e6720706f6f6c206e6f7420796574207374617274656400000000600082015250565b612c1c816126d4565b8114612c2757600080fd5b50565b612c33816126e6565b8114612c3e57600080fd5b50565b612c4a816126f2565b8114612c5557600080fd5b50565b612c618161271c565b8114612c6c57600080fd5b5056fea2646970667358221220e9eb18fa1e2e91ca7b01777cbb8139ad1a2461fe5dbb267d28a5739974953f4564736f6c63430008060033