Transactions
Token Transfers
Tokens
Internal Transactions
Coin Balance History
Logs
Code
Read Contract
Write Contract
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- GoatToken
- Optimization enabled
- false
- Compiler version
- v0.8.17+commit.8df45f5f
- EVM Version
- default
- Verified at
- 2023-10-17T00:20:54.520564Z
Constructor Arguments
0x000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a27
Arg [0] (address) : 0xa1077a294dde1b09bb078844df40758a5d0f9a27
GoatToken.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "./IWPLS.sol";
import "./SafeERC20.sol";
import "./ReentrancyGuard.sol";
contract GoatToken is IERC20, ReentrancyGuard {
using SafeMath for uint256;
using SafeERC20 for IERC20;
IERC20 public immutable WPLS;
IWPLS public immutable WRAP;
// token data
string private constant _name = "Degen Protocol GOAT";
string private constant _symbol = "GOAT";
uint8 private constant _decimals = 18;
uint256 private constant precision = 10**18;
uint256 private _total_users;
uint256 private _total_txs;
uint256 private _totalSupply;
// storage
struct User {
uint256 lastEntryPrice; // Ratio at time of last deposit
uint256 deposited; // Deposited WPLS, from minting
uint256 withdrawn; // Withdrawn WPLS, from redemptions
}
// balances
mapping (address => User) private _stats;
mapping (address => uint8) private _users;
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowances;
// 5% mint and redeem Fees
uint256 public mintFee = 95000;
uint256 public sellFee = 95000;
uint256 private constant feeDenominator = 10**5;
// Events
event Burn(address from, uint256 amountBurned);
event GarbageCollected(uint256 amountBurned);
event Minted(address recipient, uint256 amountTKN);
event Redeemed(address seller, uint256 amountTKN, uint256 amountBASE);
event PriceChange(uint256 previousPrice, uint256 currentPrice, uint256 totalSupply);
////////////////////////////
// CONSTRUCTOR & FALLBACK //
////////////////////////////
constructor(address _base) {
WPLS = IERC20(address(_base));
WRAP = IWPLS(address(_base));
}
// WPLS sent to this contract gets converted into WPLS
// Then, WPLS is deposited and token is returned to the sender
receive () external payable {
address sender = msg.sender;
uint256 amount = msg.value;
WRAP.deposit{value: amount}();
_checkGarbageCollector(address(this));
_mintWithBacking(amount, sender);
}
////////////////////
// VIEW FUNCTIONS //
////////////////////
// Token Name
function name() public pure override returns (string memory) {
return _name;
}
// Token Ticker Symbol
function symbol() public pure override returns (string memory) {
return _symbol;
}
// Tokens decimals
function decimals() public pure override returns (uint8) {
return _decimals;
}
// Returns the total number of tokens in existence
function totalSupply() external view override returns (uint256) {
return _totalSupply;
}
// Returns the number of tokens owned by `account`
function balanceOf(address account) public view override returns (uint256) {
return _balances[account];
}
// Returns the number of tokens `spender` can transfer from `holder`
function allowance(address holder, address spender) external view override returns (uint256) {
return _allowances[holder][spender];
}
// Returns the amount of token given numtokens of WPLS; accounting for fees
function estimateMinted(uint256 numTokens) public view returns (uint256) {
uint balance = underlyingBalance();
return _totalSupply == 0 ? numTokens.mul(mintFee).div(feeDenominator) : _totalSupply.mul(numTokens).div(balance).mul(mintFee).div(feeDenominator);
}
// Returns the amount of WPLS given numtokens of token
function estimateRedeemed(uint256 numTokens) public view returns (uint256) {
return amountOut(numTokens.mul(sellFee).div(feeDenominator));
}
// Amount Of Underlying To Receive For `numTokens` of token
function amountOut(uint256 numTokens) public view returns (uint256) {
return _calculatePrice().mul(numTokens).div(precision);
}
// Returns the value of `holder`'s holdings
function getValueOfHoldings(address holder) public view returns(uint256) {
return amountOut(_balances[holder]);
}
// Underlying WPLS balance
function underlyingBalance() public view returns (uint256) {
return WPLS.balanceOf(address(this));
}
// Price Of token in WPLS
function calculatePrice() public view returns (uint256) {
return _calculatePrice();
}
// Returns basic contract stats
function getInfo() public view returns(uint256 users, uint256 txs, uint256 underlyingSupply, uint256 supply, uint256 price){
users = _total_users;
txs = _total_txs;
underlyingSupply = underlyingBalance();
supply = _totalSupply;
price = _calculatePrice();
}
// Last price a user minted at
function getLastEntryOf(address user) public view returns (uint256) {
return _stats[user].lastEntryPrice;
}
// Total WPLS deposited
function getDepositedOf(address user) public view returns (uint256) {
return _stats[user].deposited;
}
// Total WPLS withdrawn
function getWithdrawnOf(address user) public view returns (uint256) {
return _stats[user].withdrawn;
}
// Calculate tokens required to redeem for exact WPLS amount
function calculateTokensForExactWPLS(uint256 _amountOut) public view returns (uint256 _amountIn) {
require(_amountOut > 0, "WPLS amount must be greater than 0");
_amountIn = _amountOut.mul(precision).div(_calculatePrice()).mul(feeDenominator).div(sellFee);
}
/////////////////////
// WRITE FUNCTIONS //
/////////////////////
// Mint token Tokens For `recipient` By Depositing WPLS Into The Contract
function mintWithBacking(uint256 numTokens, address recipient) external nonReentrant returns (uint256) {
_checkGarbageCollector(address(this));
return _mintWithBacking(numTokens, recipient);
}
// Burns Sender's token Tokens and redeems their value in WPLS
function redeem(uint256 tokenAmount) external nonReentrant returns (uint256) {
return _sell(msg.sender, tokenAmount, msg.sender);
}
// Burns Sender's token Tokens and redeems their value in WPLS for `recipient`
function redeemTo(uint256 tokenAmount, address recipient) external nonReentrant returns (uint256) {
return _sell(msg.sender, tokenAmount, recipient);
}
// Allows A User To Erase Their Holdings From Supply - DOES NOT REDEEM UNDERLYING ASSET FOR USER
function burn(uint256 amount) external nonReentrant {
uint256 bal = _balances[msg.sender];
require(bal >= amount && bal > 0, 'Zero Holdings');
uint256 oldPrice = _calculatePrice();
_burn(msg.sender, amount);
_requirePriceRises(oldPrice);
emit Burn(msg.sender, amount);
}
// Approves `spender` to transfer `amount` tokens from caller
function approve(address spender, uint256 amount) public override returns (bool) {
_allowances[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
// Transfer Function
function transfer(address recipient, uint256 amount) external override nonReentrant returns (bool) {
return _transferFrom(msg.sender, recipient, amount);
}
// Transfer Function
function transferFrom(address sender, address recipient, uint256 amount) external override nonReentrant returns (bool) {
_allowances[sender][msg.sender] = _allowances[sender][msg.sender].sub(amount, 'Insufficient Allowance');
return _transferFrom(sender, recipient, amount);
}
////////////////////////
// INTERNAL FUNCTIONS //
////////////////////////
// Internal Transfer
function _transferFrom(address sender, address recipient, uint256 amount) internal returns (bool) {
require(recipient != address(0) && sender != address(0), "Transfer To Zero");
require(amount > 0, "Transfer Amt Zero");
uint256 oldPrice = _calculatePrice();
_balances[sender] = _balances[sender].sub(amount, "Insufficient Balance");
_balances[recipient] = _balances[recipient].add(amount);
_requirePriceRises(oldPrice);
_total_txs += 1;
emit Transfer(sender, recipient, amount);
return true;
}
// Stake Tokens and Deposits token in Sender's Address, Must Have Prior Approval For WPLS
function _mintWithBacking(uint256 amount, address recipient) internal returns (uint256) {
uint256 userTokenBalance = WPLS.balanceOf(msg.sender);
require(userTokenBalance > 0 && amount <= userTokenBalance, 'Insufficient Balance');
uint256 oldPrice = _calculatePrice();
uint256 amountUnderlying = underlyingBalance();
uint256 received = _transferIn(amount);
_stats[msg.sender].lastEntryPrice = oldPrice;
_stats[msg.sender].deposited = _stats[msg.sender].deposited.add(amount);
return _mintTo(recipient, received, amountUnderlying, oldPrice);
}
// Burns token Tokens And Deposits WPLS Tokens into Recipients's Address
function _sell(address seller, uint256 tokenAmount, address recipient) internal returns (uint256) {
require(tokenAmount > 0 && _balances[seller] >= tokenAmount);
require(seller != address(0) && recipient != address(0));
uint256 oldPrice = _calculatePrice();
uint256 tokensToSwap = tokenAmount.mul(sellFee).div(feeDenominator);
uint256 amountUnderlyingAsset = amountOut(tokensToSwap);
_burn(seller, tokenAmount);
require(WPLS.transfer(recipient, amountUnderlyingAsset), 'Underlying Transfer Failure');
_requirePriceRises(oldPrice);
_total_txs += 1;
_stats[recipient].withdrawn = _stats[recipient].withdrawn.add(amountUnderlyingAsset);
emit Redeemed(seller, tokenAmount, amountUnderlyingAsset);
return amountUnderlyingAsset;
}
// Handles Minting Logic To Create New token
function _mintTo(address recipient, uint256 received, uint256 totalBacking, uint256 oldPrice) private returns(uint256) {
uint256 tokensToMintNoTax = _totalSupply == 0 ? received : _totalSupply.mul(received).div(totalBacking);
uint256 tokensToMint = tokensToMintNoTax.mul(mintFee).div(feeDenominator);
require(tokensToMint > 0, 'Zero Amount');
_mint(recipient, tokensToMint);
_requirePriceRises(oldPrice);
_total_txs += 1;
// differentiate purchase
emit Minted(recipient, tokensToMint);
return tokensToMint;
}
// Requires The Price Of token To Rise For The Transaction To Conclude
function _requirePriceRises(uint256 oldPrice) internal {
uint256 newPrice = _calculatePrice();
require(newPrice >= oldPrice, 'Price Cannot Fall');
emit PriceChange(oldPrice, newPrice, _totalSupply);
}
// Transfers `desiredAmount` of `token` in and verifies the transaction success
function _transferIn(uint256 desiredAmount) internal returns (uint256) {
uint256 balBefore = underlyingBalance();
require(WPLS.transferFrom(msg.sender, address(this), desiredAmount), 'Failure Transfer From');
uint256 balAfter = underlyingBalance();
require(balAfter > balBefore, 'Zero Received');
return balAfter - balBefore;
}
// Mints Tokens to the Receivers Address
function _mint(address receiver, uint amount) private {
if (_users[receiver] == 0){
_users[receiver] = 1;
_total_users += 1;
}
_balances[receiver] = _balances[receiver].add(amount);
_totalSupply = _totalSupply.add(amount);
emit Transfer(address(0), receiver, amount);
}
// Burns `amount` of tokens from `account`
function _burn(address account, uint amount) private {
_balances[account] = _balances[account].sub(amount, 'Insufficient Balance');
_totalSupply = _totalSupply.sub(amount, 'Negative Supply');
emit Transfer(account, address(0), amount);
}
// Make Sure there's no Native Tokens in contract
function _checkGarbageCollector(address burnLocation) internal {
uint256 bal = _balances[burnLocation];
if (bal > 10**3) {
uint256 oldPrice = _calculatePrice();
_burn(burnLocation, bal);
emit GarbageCollected(bal);
emit PriceChange(oldPrice, _calculatePrice(), _totalSupply);
}
}
// Returns the Current Price of 1 Token
function _calculatePrice() internal view returns (uint256) {
return _totalSupply == 0 ? 10**18 : (underlyingBalance().mul(precision)).div(_totalSupply);
}
}
Migrations.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
contract Migrations {
address public owner = msg.sender;
uint public last_completed_migration;
modifier restricted() {
require(
msg.sender == owner,
"This function is restricted to the contract's owner"
);
_;
}
function setCompleted(uint completed) public restricted {
last_completed_migration = completed;
}
}
Ownable.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "./Context.sol";
abstract contract Ownable is Context {
modifier onlyOwner() {
require(_owner == _msgSender(), "Ownable: caller is not the owner");
_;
}
modifier isRunning() {
require(_paused == false, "Function unavailable because contract is paused");
_;
}
bool private _paused;
address private _owner;
address private _previousOwner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
event RunStatusUpdated(bool indexed paused);
constructor() {
address msgSender = _msgSender();
_owner = msgSender;
_paused = false;
emit RunStatusUpdated(_paused);
emit OwnershipTransferred(address(0), msgSender);
}
function owner() public view returns (address) {
return _owner;
}
function isPaused() public view returns (bool) {
return _paused;
}
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
function updateRunStatus(bool paused) public virtual onlyOwner {
emit RunStatusUpdated(paused);
_paused = paused;
}
}
YieldEngine.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "./IGOAT.sol";
import "./IERC20.sol";
import "./ITreasury.sol";
import "./ISponsorData.sol";
import "./IYieldEngine.sol";
import "./IReferralData.sol";
import "./IReferralReport.sol";
import "./ISwapRouter02.sol";
import "./SafeMath.sol";
import "./TransferHelper.sol";
import "./Whitelist.sol";
contract YieldEngine is Whitelist, IYieldEngine {
using SafeMath for uint256;
IERC20 public immutable dai;
IGOAT public immutable goat;
address public WPLS;
address public bufferPool;
address public goatPen;
bool public forceLiquidity = true;
ISwapRouter02 public swapRouter;
IReferralData public referralData;
ISponsorData public sponsorData;
event UpdateCollateralRouter(address indexed addr);
event NewSponsorship(address indexed from, address indexed to, uint256 amount);
event UpdateReferralData(address indexed addr);
event UpdateSponsorData(address indexed addr);
event UpdateForceLiquidity(bool value, bool new_value);
event debugEvent(uint256 value0, uint256 value1);
/* ========== INITIALIZER ========== */
constructor(
address _swapRouter,
address _goat,
address _dai,
address _weth,
address _goatPen,
address _bufferPool
) Ownable() {
goat = IGOAT(_goat);
dai = IERC20(_dai);
swapRouter = ISwapRouter02(_swapRouter);
goatPen = _goatPen;
bufferPool = _bufferPool;
WPLS = _weth;
}
//@dev Update the referral data for partner rewards
function updateReferralData(address referralDataAddress) external onlyOwner {
require(referralDataAddress != address(0), "Require valid non-zero addresses");
referralData = IReferralData(referralDataAddress);
emit UpdateReferralData(referralDataAddress);
}
//@dev Update the sponsor data used to distribute gifted / rewarded bonds
function updateSponsorData(address sponsorDataAddress) external onlyOwner {
require(sponsorDataAddress != address(0), "Require valid non-zero addresses");
sponsorData = ISponsorData(sponsorDataAddress);
emit UpdateSponsorData(sponsorDataAddress);
}
//@dev Forces the yield engine to topoff liquidity in the collateral buffer on every tx
//a test harness
function updateForceLiquidity(bool _force) external onlyOwner {
emit UpdateForceLiquidity(forceLiquidity, _force);
forceLiquidity = _force;
}
//@dev Update Core collateral liquidity can move from one contract location to another across major PCS releases
function updateCollateralRouter(address _router) public onlyOwner {
require(_router != address(0), "Router must be set");
swapRouter = ISwapRouter02(_router);
emit UpdateCollateralRouter(_router);
}
/********** Whitelisted Fuctions **************************************************/
//@dev Claim and payout using the reserve
//Sender must implement IReferralReport to succeed
function sendPayoutTo(address _recipient, uint256 _daiAmountOut) external onlyWhitelisted returns (uint yieldAmount) {
if (_daiAmountOut == 0) {
return 0;
}
// CollateralBuffer should be large enough to support daily yield
uint256 onePercentOfTheBufferPool = dai.balanceOf(bufferPool) / 100;
// Debugging
emit debugEvent(_daiAmountOut, onePercentOfTheBufferPool);
//if yield is greater than 1% of the buffer pool, liquidate GOAT to DAI
if (_daiAmountOut > onePercentOfTheBufferPool || forceLiquidity) {
// 110% of the requested amount
uint256 _thisMuch = (_daiAmountOut * 110 / 100);
// Redeem GOAT and buy DAI for the buffer pool
topUpBufferPool(_thisMuch);
// The end user balance will only go down by the delivered amount, the buffer will never be overrun
_daiAmountOut = _daiAmountOut.min(dai.balanceOf(bufferPool));
}
//Calculate user referral rewards
uint _referrals = _daiAmountOut / 100;
//Add referral bonus for referrer, 1%
processReferralBonus(_recipient, _referrals, msg.sender);
// Send _daiAmountOut of DAI from the buffer pool to the _recipient
ITreasury(bufferPool).withdrawTo(_recipient, _daiAmountOut);
return _daiAmountOut;
}
/********** Internal Fuctions **************************************************/
//@dev Add referral bonus if applicable
function processReferralBonus(address _user, uint256 _amount, address referral_report) private {
address _referrer = referralData.referrerOf(_user);
//Need to have an upline
if (_referrer == address(0)) {
return;
}
//partners split 50/50
uint256 _share = _amount.div(2);
//We operate side effect free and just add to pending sponsorships
sponsorData.add(_referrer, _share);
sponsorData.add(_user, _share);
//Report the reward distribution to the caller
IReferralReport report = IReferralReport(referral_report);
report.reward_distribution(_referrer, _user, _share, _share);
emit NewSponsorship(_user, _referrer, _share);
emit NewSponsorship(_referrer, _user, _share);
}
//@dev release GOAT from the GOAT Pen and swap the resulting WPLS for DAI, into the Buffer Pool
function topUpBufferPool(uint256 _thisMuch) private {
// Path for WPLS to DAI
address[] memory WPLSToDAIPath = new address[](2);
WPLSToDAIPath[0] = WPLS;
WPLSToDAIPath[1] = address(dai);
// Path for DAI to WPLS
address[] memory daiToWPLSPath = new address[](2);
daiToWPLSPath[0] = address(dai);
daiToWPLSPath[1] = WPLS;
// Step 1: Find out how much WPLS is required to get _thisMuch DAI
uint256[] memory amounts = swapRouter.getAmountsOut(_thisMuch, daiToWPLSPath);
// Step 2: Calculate how many GOAT tokens are needed to redeem, to receive that amount of WPLS
// Get the last element which is the WPLS amount
uint256 wplsAmount = amounts[1];
// Calculate the GOAT amount needed to redeem.
uint256 goatAmount = goat.calculateTokensForExactWPLS(wplsAmount);
// Step 3: Withdraw required GOAT from GOAT Treasury
ITreasury(goatPen).withdrawTo(address(this), goatAmount);
// Step 4: Redeem required GOAT
uint256 wplsFromRedeemingGOAT = goat.redeem(goatAmount);
// Step 5: Approve WPLS to swap
TransferHelper.safeApprove(WPLS, address(swapRouter), wplsFromRedeemingGOAT, 'approve');
// Swap WPLS for DAI
swapRouter.swapExactTokensForTokens(wplsFromRedeemingGOAT, 0, WPLSToDAIPath, bufferPool, block.timestamp);
}
}
SignedMath.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
library SignedMath {
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
function average(int256 a, int256 b) internal pure returns (int256) {
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
function abs(int256 n) internal pure returns (uint256) {
unchecked {
return uint256(n >= 0 ? n : -n);
}
}
}
Address.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly { size := extcodesize(account) }
return size > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
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");
}
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");
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(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 {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
IGOAT.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "./IERC20.sol";
interface IGOAT is IERC20 {
function mintWithBacking(uint256 numTokens, address recipient) external returns (uint256);
function redeem(uint256 tokenAmount) external returns (uint256);
function redeemTo(uint256 tokenAmount, address recipient) external returns (uint256);
function calculateTokensForExactWPLS(uint256 amount) external view returns (uint256);
function estimateMinted(uint256 numTokens) external view returns (uint256);
function estimateRedeemed(uint256 numTokens) external view returns (uint256);
function getValueOfHoldings(address holder) external view returns(uint256);
}
ERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "./IERC20.sol";
import "./SafeMath.sol";
import "./Context.sol";
contract ERC20 is Context, IERC20 {
using SafeMath for uint256;
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
uint8 private _decimals;
constructor (string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
_decimals = 18;
}
function name() public view virtual returns (string memory) {
return _name;
}
function symbol() public view virtual returns (string memory) {
return _symbol;
}
function decimals() public view virtual returns (uint8) {
return _decimals;
}
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), recipient, amount);
return true;
}
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public virtual override returns (bool) {
_approve(_msgSender(), spender, amount);
return true;
}
function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(sender, recipient, amount);
_approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
return true;
}
function _transfer(address sender, address recipient, uint256 amount) internal virtual {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
_balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
_balances[recipient] = _balances[recipient].add(amount);
emit Transfer(sender, recipient, amount);
}
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply = _totalSupply.add(amount);
_balances[account] = _balances[account].add(amount);
emit Transfer(address(0), account, amount);
}
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
_balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
_totalSupply = _totalSupply.sub(amount);
emit Transfer(account, address(0), amount);
}
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function _setupDecimals(uint8 decimals_) internal virtual {
_decimals = decimals_;
}
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}
Strings.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "./Math.sol";
import "./SignedMath.sol";
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}
GoatFeeder.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "./IGOAT.sol";
import "./IERC20.sol";
import "./ITreasury.sol";
import "./ISponsorData.sol";
import "./IYieldEngine.sol";
import "./IReferralReport.sol";
import "./ISwapRouter02.sol";
import "./SafeMath.sol";
import "./Whitelist.sol";
import "./TransferHelper.sol";
import "./ReentrancyGuard.sol";
struct FuturesUser {
bool exists; // has the user joined
uint deposits; // total inbound deposits
uint compound_deposits; // compound deposit; not fresh capital
uint current_balance; // current balance
uint payouts; // total yield payouts across all farms
uint rewards; // partner rewards
uint last_time; // last interaction
}
struct FuturesGlobals {
uint256 total_users;
uint256 total_deposited;
uint256 total_compound_deposited;
uint256 total_claimed;
uint256 total_rewards;
uint256 total_txs;
uint256 current_balance;
}
contract FuturesVault is Whitelist {
mapping(address => FuturesUser) private users; //Asset -> User
FuturesGlobals private globals;
mapping (address => Sponsorship) private sponsorships;
constructor() Ownable() {}
//@dev Get User info
function getUser(address _user) external view returns (FuturesUser memory) {
return users[_user];
}
//@dev Get FuturesGlobal info
function getGlobals() external view returns (FuturesGlobals memory) {
return globals;
}
//@dev Get Sponsorship info
function getSponsorship(address _user) external view returns (Sponsorship memory) {
return sponsorships[_user];
}
//@dev commit User Info
function commitUser(address _user, FuturesUser memory _user_data) onlyWhitelisted isRunning external {
users[_user].exists = _user_data.exists;
users[_user].deposits = _user_data.deposits;
users[_user].compound_deposits = _user_data.compound_deposits;
users[_user].current_balance = _user_data.current_balance;
users[_user].payouts = _user_data.payouts;
users[_user].rewards = _user_data.rewards;
users[_user].last_time = _user_data.last_time;
}
//@dev commit Globals Info
function commitGlobals(FuturesGlobals memory _globals) onlyWhitelisted isRunning external {
globals.total_users = _globals.total_users;
globals.total_deposited = _globals.total_deposited;
globals.total_compound_deposited = _globals.total_compound_deposited;
globals.total_claimed = _globals.total_claimed;
globals.total_rewards = _globals.total_rewards;
globals.total_txs = _globals.total_txs;
globals.current_balance = _globals.current_balance ;
}
}
contract FuturesEngine is Ownable, IReferralReport {
using SafeMath for uint256;
//Financial Model
uint256 public constant referenceApr = 182.5e18; //0.5% daily
uint256 public constant maxBalance = 1000000e18; //1M
uint256 public constant minimumDeposit = 200e18; //200+ deposits; will compound available rewards
uint256 public constant maxAvailable = 50000e18; //50K max claim daily, 10 days missed claims
uint256 public constant maxPayouts = (maxBalance * 5e18) / 2e18; //2.5M
//Immutable long term network contracts
ISwapRouter02 public immutable swapRouter;
ITreasury public immutable bufferPool;
ITreasury public immutable goatPen;
IERC20 public immutable dai;
IGOAT public goat;
//Updatable components
IYieldEngine public yieldEngine;
FuturesVault public vault;
ISponsorData public sponsors;
address public wpls;
address[] public pathDaiToPls;
bool public enforceMinimum = false;
//events
event Deposit(address indexed user, uint256 amount);
event CompoundDeposit(address indexed user, uint256 amount);
event Claim(address indexed user, uint256 amount);
event Transfer(address indexed user, address indexed new_user, uint256 current_balance);
event RewardDistribution(address referrer, address user, uint referrer_reward, uint user_reward);
event UpdateYieldEngine(address prev_engine, address engine);
event UpdateVault(address prev_vault, address vault);
event UpdateEnforceMinimum(bool prev_value, bool value);
constructor(
address _router,
address _dai,
address _goatPen,
address _bufferPool,
address _sponsorData
) Ownable() {
dai = IERC20(_dai);
swapRouter = ISwapRouter02(_router);
goatPen = ITreasury(_goatPen);
bufferPool = ITreasury(_bufferPool);
sponsors = ISponsorData(_sponsorData);
}
////////////////////
// View Functions //
////////////////////
//@dev Returns tax bracket and adjusted amount based on the bracket
function available(address _user) public view returns (uint256 _limiterRate, uint256 _adjustedAmount) {
//Load data
FuturesUser memory userData = vault.getUser(_user);
//calculate gross available
uint256 share;
if(userData.current_balance > 0) {
//Using 1e18 we capture all significant digits when calculating available divs
share = userData.current_balance //payout is asymptotic and uses the current balance
* referenceApr //convert to daily apr
/ (365 * 100e18)
/ 24 hours; //divide the profit by payout rate and seconds in the day;
_adjustedAmount = share * block.timestamp.safeSub(userData.last_time);
_adjustedAmount = maxAvailable.min(_adjustedAmount); //minimize red candles
}
//apply compound rate limiter
uint256 _comp_surplus = userData.compound_deposits.safeSub(userData.deposits);
if (_comp_surplus < 50000e18){
_limiterRate = 0;
} else if ( 50000e18 <= _comp_surplus && _comp_surplus < 250000e18 ){
_limiterRate = 10;
} else if ( 250000e18 <= _comp_surplus && _comp_surplus < 500000e18 ){
_limiterRate = 15;
} else if ( 500000e18 <= _comp_surplus && _comp_surplus < 750000e18 ){
_limiterRate = 25;
} else if ( 750000e18 <= _comp_surplus && _comp_surplus < 1000000e18 ){
_limiterRate = 35;
} else if (_comp_surplus >= 1000000e18 ){
_limiterRate = 50;
}
_adjustedAmount = _adjustedAmount * (100 - _limiterRate) / 100;
// payout greater than the balance just pay the balance
if(_adjustedAmount > userData.current_balance) {
_adjustedAmount = userData.current_balance;
}
}
//@dev Get User info
function getUser(address _user) external view returns (FuturesUser memory) {
return vault.getUser(_user);
}
//@dev Get contract snapshot
function getInfo() external view returns (FuturesGlobals memory) {
return vault.getGlobals();
}
////////////////////
// User Functions //
////////////////////
//@dev Deposit DAI
function deposit(uint _amount) isRunning nonReentrant external {
//Only the key holder can invest their funds
address _user = msg.sender;
FuturesUser memory userData = vault.getUser(_user);
FuturesGlobals memory globalsData = vault.getGlobals();
Sponsorship memory sponsorData = sponsors.getSponsorship(_user);
require(_amount >= minimumDeposit || enforceMinimum == false, "amount less than minimum deposit");
require(userData.current_balance + _amount <= maxBalance, "max balance exceeded" );
require(userData.payouts <= maxPayouts, "max payouts exceeded");
uint _share = _amount / 100;
uint _daiToSwapForWplsSoWeCanMintGOAT;
uint _daiToPutInTheBufferPool;
//90% goes directly to the treasury
_daiToSwapForWplsSoWeCanMintGOAT = _share * 90;
_daiToPutInTheBufferPool = _amount - _daiToSwapForWplsSoWeCanMintGOAT;
//Transfer 10% to Bufferpool, 90% to this contract
TransferHelper.safeTransferFrom(address(dai), _user, address(bufferPool), _daiToPutInTheBufferPool, 'Depot: deposit, transfer to buffer');
TransferHelper.safeTransferFrom(address(dai), _user, address(this), _daiToSwapForWplsSoWeCanMintGOAT, 'Depot: deposit, transfer to buffer');
// Approve swap router to spend this contract's DAI, and GOAT to spend WPLS
TransferHelper.safeApprove(address(wpls), address(goat), type(uint256).max, "Deposit: Cannot approve");
TransferHelper.safeApprove(address(dai), address(swapRouter), type(uint256).max, "Deposit: Cannot approve");
// Swap 90% of DAI into WPLS via swap
uint256[] memory amountsOut = swapRouter.swapExactTokensForTokens(_daiToSwapForWplsSoWeCanMintGOAT, 0, pathDaiToPls, address(this), block.timestamp + 3 minutes);
// Mint GOAT with resulting amount of WPLS from swap, into the GOAT Pen
goat.mintWithBacking(amountsOut[1], address(goatPen));
//update user stats
if (userData.exists == false) {
//attempt to migrate user
userData.exists = true;
globalsData.total_users += 1;
//commit updates
vault.commitUser(_user, userData);
vault.commitGlobals(globalsData);
}
//if user has an existing balance see if we have to claim yield before proceeding
//optimistically claim yield before reset
//if there is a balance we potentially have yield
if (userData.current_balance > 0){
_compoundFor(_user);
//reload user data after a mutable function
userData = vault.getUser(_user);
globalsData = vault.getGlobals();
}
//If we have a pending sponsorship let's settle
if (sponsorData.pending > 0) {
_amount += sponsorData.pending; //add pending sponsorship
sponsors.settle(_user);
}
//update user
userData.deposits += _amount;
userData.last_time = block.timestamp;
userData.current_balance += _amount;
globalsData.total_deposited += _amount;
globalsData.current_balance += _amount;
globalsData.total_txs += 1;
//commit updates
vault.commitUser(_user, userData);
vault.commitGlobals(globalsData);
//events
emit Deposit(_user, _amount);
}
//@dev Claims earned interest for the caller
function claim() nonReentrant external returns (bool success){
address _user = msg.sender; //Only the owner of funds can claim funds
FuturesUser memory userData = vault.getUser(_user);
//checks
require(userData.exists, "User is not registered");
require(userData.current_balance > 0, "balance is required to earn yield");
success = _claimFor(_user);
}
//@dev Transfer account to another wallet address
function transfer(address _newUser) nonReentrant external {
address _user = msg.sender;
FuturesUser memory userData = vault.getUser(_user);
FuturesUser memory newData = vault.getUser(_newUser);
FuturesGlobals memory globalsData = vault.getGlobals();
//Only the owner can transfer
require(userData.exists, "user must exists");
require(newData.exists == false && _newUser != address(0), "new address must not exist");
//Transfer
newData.exists = true;
newData.deposits = userData.deposits;
newData.current_balance = userData.current_balance;
newData.payouts = userData.payouts;
newData.compound_deposits = userData.compound_deposits;
newData.rewards = userData.rewards;
newData.last_time = userData.last_time;
//Zero out old account
userData.exists = true; //once an account is created source streams are only counted once
userData.deposits = 0;
userData.current_balance = 0;
userData.compound_deposits = 0;
userData.payouts = 0;
userData.rewards = 0;
userData.last_time = 0;
//house keeping
globalsData.total_txs += 1;
//commit
vault.commitUser(_user, userData);
vault.commitUser(_newUser, newData);
vault.commitGlobals(globalsData);
//log
emit Transfer(_user, _newUser, newData.current_balance);
}
//////////////////////////
// RESTRICTED FUNCTIONS //
//////////////////////////
//@dev Implements the IReferralReport interface which is called by the FarmEngine yield function back to the caller
function reward_distribution(address _referrer, address _user, uint _referrer_reward, uint _user_reward) external {
//checks
require(msg.sender == address(yieldEngine), "caller must be registered yield engine");
require(_referrer != address(0) && _user != address(0), "non-zero addresses required");
//Load data
FuturesUser memory userData = vault.getUser(_user);
FuturesUser memory referrerData = vault.getUser(_referrer);
FuturesGlobals memory globalsData = vault.getGlobals();
//track exclusive rewards which are paid out via Stampede airdrops
referrerData.rewards += _referrer_reward;
userData.rewards += _user_reward;
//track total rewards
globalsData.total_rewards += _referrer_reward + _user_reward;
//commit updates
vault.commitUser(_user, userData);
vault.commitUser(_referrer, referrerData);
vault.commitGlobals(globalsData);
emit RewardDistribution(_referrer, _user, _referrer_reward, _user_reward);
}
/////////////////////
// ADMIN FUNCTIONS //
/////////////////////
//@dev Set goat token
function setGoat(address _goat) external onlyOwner {
require(_goat != address(0), "goat must be non-zero");
goat = IGOAT(_goat);
}
//@dev Set WPLS token
function setWPLS(address _wpls) external onlyOwner {
require(_wpls != address(0), "WPLS must be non-zero");
wpls = _wpls;
}
//@dev Set swap path
function setSwapPath(address[] memory path) external onlyOwner {
pathDaiToPls = path;
}
//@dev Update enforce minimum
function updateEnforceMinimum(bool _enforceMinimum) external onlyOwner {
emit UpdateEnforceMinimum(enforceMinimum, _enforceMinimum);
enforceMinimum = _enforceMinimum;
}
//@dev Update the FuturesVault
function updateFuturesVault(address _vault) external onlyOwner {
require(_vault != address(0), "vault must be non-zero");
emit UpdateVault(address(vault), _vault);
vault = FuturesVault(_vault);
}
//@dev Update the farm engine which is used for quotes, yield calculations / distribution
function updateYieldEngine(address _engine) external onlyOwner {
require(_engine != address(0), "engine must be non-zero");
emit UpdateYieldEngine(address(yieldEngine), _engine);
yieldEngine = IYieldEngine(_engine);
}
////////////////////////
// Internal Functions //
////////////////////////
function _claimFor(address _recipient) private returns (bool success) {
FuturesUser memory userData = vault.getUser(_recipient);
FuturesGlobals memory globalsData = vault.getGlobals();
//get available
(, uint256 _daiAmountOut) = available(_recipient);
// payout remaining allowable divs if exceeds
if(userData.payouts + _daiAmountOut > maxPayouts) {
_daiAmountOut = maxPayouts.safeSub(userData.payouts);
_daiAmountOut = _daiAmountOut.min(userData.current_balance); //withdraw up to the current balance
}
//attempt to payout yield and update stats;
if (_daiAmountOut > 0) {
//transfer amount to user; mutable
_daiAmountOut = yieldEngine.sendPayoutTo(_recipient, _daiAmountOut);
//reload data after a mutable function
userData = vault.getUser(_recipient);
globalsData = vault.getGlobals();
if (_daiAmountOut > 0) { //second check with delivered yield
//user stats
userData.payouts += _daiAmountOut;
userData.current_balance = userData.current_balance.safeSub(_daiAmountOut);
userData.last_time = block.timestamp;
//total stats
globalsData.total_claimed += _daiAmountOut;
globalsData.total_txs += 1;
globalsData.current_balance = globalsData.current_balance.safeSub(_daiAmountOut);
//commit updates
vault.commitUser(_recipient, userData);
vault.commitGlobals(globalsData);
//log events
emit Claim(_recipient, _daiAmountOut);
return true;
}
}
//default
return false;
}
function _compoundFor(address _user) private returns (bool success) {
FuturesUser memory userData = vault.getUser(_user);
FuturesGlobals memory globalsData = vault.getGlobals();
//get available
( , uint256 _amount) = available(_user);
// payout remaining allowable divs if exceeds
if(userData.payouts + _amount > maxPayouts) {
_amount = maxPayouts.safeSub(userData.payouts);
}
//attempt to compound yield and update stats;
if (_amount > 0) {
//user stats
userData.deposits += 0; //compounding is not a deposit; here for clarity
userData.compound_deposits += _amount;
userData.payouts += _amount;
userData.current_balance += _amount;
userData.last_time = block.timestamp;
//total stats
globalsData.total_deposited += 0; //compounding doesn't move the needle; here for clarity
globalsData.total_compound_deposited += _amount;
globalsData.total_claimed += _amount;
globalsData.current_balance += _amount;
globalsData.total_txs += 1;
//commit updates
vault.commitUser(_user, userData);
vault.commitGlobals(globalsData);
//log events
emit Claim(_user, _amount);
emit CompoundDeposit(_user, _amount);
return true;
} else {
//do nothing upon failure
return false;
}
}
}
SafeERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "./IERC20.sol";
import "./Address.sol";
import "./SafeMath.sol";
library SafeERC20 {
using Address for address;
using SafeMath for uint256;
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));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
Whitelist.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "./Ownable.sol";
contract Whitelist is Ownable {
mapping(address => bool) public whitelist;
event WhitelistedAddressAdded(address addr);
event WhitelistedAddressRemoved(address addr);
modifier onlyWhitelisted() {
require(whitelist[msg.sender], "not whitelisted");
_;
}
function addAddressToWhitelist(address addr) public onlyOwner returns (bool success) {
if (!whitelist[addr]) {
whitelist[addr] = true;
emit WhitelistedAddressAdded(addr);
success = true;
}
}
function addAddressesToWhitelist(address[] memory addrs) public onlyOwner returns (bool success) {
for (uint256 i = 0; i < addrs.length; i++) {
if (addAddressToWhitelist(addrs[i])) {
success = true;
}
}
}
function removeAddressFromWhitelist(address addr) public onlyOwner returns (bool success) {
if (whitelist[addr]) {
whitelist[addr] = false;
emit WhitelistedAddressRemoved(addr);
success = true;
}
}
function removeAddressesFromWhitelist(address[] memory addrs) public onlyOwner returns (bool success) {
for (uint256 i = 0; i < addrs.length; i++) {
if (removeAddressFromWhitelist(addrs[i])) {
success = true;
}
}
}
}
IReferralData.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
interface IReferralData {
function referrerOf(address participant) external view returns (address);
}
SponsorData.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "./SafeMath.sol";
import "./Whitelist.sol";
import "./ReentrancyGuard.sol";
contract SponsorData is Whitelist {
using SafeMath for uint256;
struct Sponsorship {
uint256 pending;
uint256 total;
}
mapping(address => Sponsorship) public users;
uint256 public total_sponsored;
constructor() Ownable() {}
function getSponsorship(address _user) external view returns (Sponsorship memory) {
return users[_user];
}
function add(address _user, uint256 _amount) external onlyWhitelisted {
users[_user].pending += _amount;
users[_user].total += _amount;
total_sponsored += _amount;
}
function settle(address _user) external onlyWhitelisted {
users[_user].pending = 0;
}
}
ISwapRouter02.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "./ISwapRouter01.sol";
interface ISwapRouter02 is ISwapRouter01 {
function removeLiquidityETHSupportingFeeOnTransferTokens(address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline) external returns (uint amountETH);
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s) external returns (uint amountETH);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external;
}
FuturesVault.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "./Whitelist.sol";
contract FuturesVault is Whitelist {
struct FuturesUser {
bool exists; // has the user joined
uint deposits; // total inbound deposits
uint compound_deposits; // compound deposit; not fresh capital
uint current_balance; // current balance
uint payouts; // total yield payouts across all farms
uint rewards; // partner rewards
uint last_time; // last interaction
}
struct FuturesGlobals {
uint256 total_users;
uint256 total_deposited;
uint256 total_compound_deposited;
uint256 total_claimed;
uint256 total_rewards;
uint256 total_txs;
uint256 current_balance;
}
mapping(address => FuturesUser) private users; //Asset -> User
FuturesGlobals private globals;
constructor() Ownable() {}
//@dev Get User info
function getUser(address _user) external view returns (FuturesUser memory) {
return users[_user];
}
//@dev Get FuturesGlobal info
function getGlobals() external view returns (FuturesGlobals memory) {
return globals;
}
//@dev commit User Info
function commitUser(address _user, FuturesUser memory _user_data) onlyWhitelisted isRunning external {
users[_user].exists = _user_data.exists;
users[_user].deposits = _user_data.deposits;
users[_user].compound_deposits = _user_data.compound_deposits;
users[_user].current_balance = _user_data.current_balance;
users[_user].payouts = _user_data.payouts;
users[_user].rewards = _user_data.rewards;
users[_user].last_time = _user_data.last_time;
}
//@dev commit Globals Info
function commitGlobals(FuturesGlobals memory _globals) onlyWhitelisted isRunning external {
globals.total_users = _globals.total_users;
globals.total_deposited = _globals.total_deposited;
globals.total_compound_deposited = _globals.total_compound_deposited;
globals.total_claimed = _globals.total_claimed;
globals.total_rewards = _globals.total_rewards;
globals.total_txs = _globals.total_txs;
globals.current_balance = _globals.current_balance ;
}
}
ISwapFactory.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
interface ISwapFactory {
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function getPair(address tokenA, address tokenB) external view returns (address pair);
function allPairs(uint) external view returns (address pair);
function allPairsLength() external view returns (uint);
function createPair(address tokenA, address tokenB) external returns (address pair);
function setFeeTo(address) external;
function setFeeToSetter(address) external;
}
IYieldEngine.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
interface IYieldEngine {
function sendPayoutTo(address _user, uint256 _amount) external returns (uint256 yieldAmount);
}
ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
ReferralData.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
contract ReferralData {
event onReferralUpdate(address indexed participant, address indexed referrer);
mapping(address => address) private referrals;
mapping(address => uint256) private refCounts;
///@dev Updated the referrer of the participant
function updateReferral(address referrer) public {
//non-zero, no self, no duplicate
require(referrer != address(0) && referrer != msg.sender && referrals[msg.sender] != referrer, "INVALID ADDRESS");
address prevReferrer = referrals[msg.sender];
//decrement previous referrer
if (prevReferrer != address(0)) {
if (refCounts[prevReferrer] > 0) {
refCounts[prevReferrer] = refCounts[prevReferrer] - 1;
}
}
//increment new referrer
refCounts[referrer] = refCounts[referrer] + 1;
//update to new
referrals[msg.sender] = referrer;
emit onReferralUpdate(msg.sender, referrer);
}
///@dev Return the referral of the sender
function myReferrer() public view returns (address) {
return referrerOf(msg.sender);
}
//@dev Return true if referrer of user is sender
function isMyReferral(address _user) public view returns (bool) {
return referrerOf(_user) == msg.sender;
}
//@dev Return true if user has a referrer
function hasReferrer(address _user) public view returns (bool) {
return referrerOf(_user) != address(0);
}
///@dev Return the referral of a participant
function referrerOf(address participant) public view returns (address) {
return referrals[participant];
}
///@dev Return the referral count of a participant
function referralCountOf(address _user) public view returns (uint256) {
return refCounts[_user];
}
}
ITreasury.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
interface ITreasury {
function getBalance() external view returns (uint256);
function withdraw(uint256 tokenAmount) external;
function withdrawTo(address _to, uint256 _amount) external;
}
IERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
interface IERC20 {
function totalSupply() external view returns (uint256);
function symbol() external view returns(string memory);
function name() external view returns(string memory);
function balanceOf(address account) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
function decimals() external view returns (uint8);
function approve(address spender, uint256 amount) external returns (bool);
function transfer(address recipient, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
TransferHelper.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "./IERC20.sol";
library TransferHelper {
function safeTransferFrom(address token, address from, address to, uint256 value, string memory notes) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), string.concat('STF', notes));
}
function safeTransfer(address token, address to, uint256 value, string memory notes) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), string.concat('ST', notes));
}
function safeApprove(address token, address to, uint256 value, string memory notes) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), string.concat('SA', notes));
}
function safeTransferETH(address to, uint256 value, string memory notes) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, string.concat('STE', notes));
}
}
Counters.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
library Counters {
struct Counter {
uint256 _value;
}
function current(Counter storage counter) internal view returns (uint256) {
return counter._value;
}
function increment(Counter storage counter) internal {
unchecked {
counter._value += 1;
}
}
function decrement(Counter storage counter) internal {
uint256 value = counter._value;
require(value > 0, "Counter: decrement overflow");
unchecked {
counter._value = value - 1;
}
}
function reset(Counter storage counter) internal {
counter._value = 0;
}
}
ISwapRouter01.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
interface ISwapRouter01 {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function addLiquidity(address tokenA, address tokenB, uint amountADesired, uint amountBDesired, uint amountAMin, uint amountBMin, address to, uint deadline) external returns (uint amountA, uint amountB, uint liquidity);
function addLiquidityETH(address token, uint amountTokenDesired, uint amountTokenMin, uint amountETHMin, address to, uint deadline) external payable returns (uint amountToken, uint amountETH, uint liquidity);
function removeLiquidity(address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline) external returns (uint amountA, uint amountB);
function removeLiquidityETH(address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline) external returns (uint amountToken, uint amountETH);
function removeLiquidityWithPermit(address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s) external returns (uint amountA, uint amountB);
function removeLiquidityETHWithPermit(address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s) external returns (uint amountToken, uint amountETH);
function swapExactTokensForTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts);
function swapTokensForExactTokens(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts);
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts);
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts);
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts);
function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts);
function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}
IWPLS.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "./IERC20.sol";
interface IWPLS is IERC20 {
function deposit() external payable;
function transfer(address to, uint256 value) external returns (bool);
function withdraw(uint256) external;
}
SafeMath.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function safeSub(uint256 a, uint256 b) internal pure returns (uint256) {
if (b > a) {
return 0;
} else {
return a - b;
}
}
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;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
}
Math.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
}
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
return a == 0 ? 0 : (a - 1) / b + 1;
}
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}
Treasury.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
/*
,ooooooooooo,
,;OOOOOOOOOOOOOOo,
,ooOOOOOOOOOOOOOOOOOo;,,,,
,ooooOOOOOOOOOOOOOOOOOOOOooo(@`,
_ __ __;oooooo OOOOOOOOOOO; ;@@@@@@@o;@@`,
_______/@@@@@@@@@)ooOOOOOO) oOOOOOOOOOo; ;o@@@@@o;@@@:
/######)@@@@@@@@@@( _______ ( oOOOOOOOOOOo o@@@@@@`@@@`;
<######)@@@@@@@@@@@@(######/ `,;;; oOOOOOo @@@@@@o,\@@;
`\@@@@@@@@@@@@(######/ oO (@@@@\ oOOOOO;@@@@@@@, \@`,
))@@@@@@@@@@( oOOOo@@@@@@: ;;oo,`o@@@@@; (@)
) `@@@@@@@( ( ooOOOOOoo:@@@@@: ,' /###o@@@@;
( (0) (0) ) ooooooo /@@@@@/,` :####o@@@@;
) ( `'`'`'`'/@@@@@/ /###/:@@@@;
`, ,' /###/@@@@@/ :###; :@@@@@;
\_`_'_/ /###/@@@@/ :###; :@@@@@;
~~~~~ ;###;@@@@/ :##; `:@@@@;
;###;@@@@; / / :@@@;
/~~~~;@@@@; `-^-' / \
`-^--;@@@@/ `-^--'
:~~~~:
\/\_/
Degen Protocol GOAT
Single Asset Silo - v1.0.0
*/
import "./IERC20.sol";
import "./Whitelist.sol";
contract Treasury is Whitelist {
IERC20 public token;
string public label;
constructor(address token_addr, string memory _label) {
token = IERC20(token_addr);
label = _label;
}
function getBalance() external view returns (uint256) {
return token.balanceOf(address(this));
}
function withdraw(uint256 _amount) external onlyWhitelisted {
require(token.transfer(_msgSender(), _amount));
}
function withdrawTo(address _to, uint256 _amount) external onlyWhitelisted {
require(token.transfer(_to, _amount));
}
}
IWhitelist.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
interface IWhitelist {
function addAddressToWhitelist(address addr) external returns (bool success);
function addAddressesToWhitelist(address[] memory addrs) external returns (bool success);
function removeAddressFromWhitelist(address addr) external returns (bool success);
function removeAddressesFromWhitelist(address[] memory addrs) external returns (bool success);
}
IReferralReport.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
interface IReferralReport {
function reward_distribution(address _referrer, address _user, uint _referrer_reward, uint _user_reward) external;
}
Context.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "./ReentrancyGuard.sol";
abstract contract Context is ReentrancyGuard {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this;
return msg.data;
}
}
ISponsorData.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
struct Sponsorship {
uint256 pending;
uint256 total;
}
interface ISponsorData {
function add(address _user, uint256 _amount) external;
function settle(address _user) external;
function getSponsorship(address _user) external view returns (Sponsorship memory);
}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_base","internalType":"address"}]},{"type":"event","name":"Approval","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"address","name":"spender","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Burn","inputs":[{"type":"address","name":"from","internalType":"address","indexed":false},{"type":"uint256","name":"amountBurned","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"GarbageCollected","inputs":[{"type":"uint256","name":"amountBurned","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Minted","inputs":[{"type":"address","name":"recipient","internalType":"address","indexed":false},{"type":"uint256","name":"amountTKN","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"PriceChange","inputs":[{"type":"uint256","name":"previousPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"currentPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"totalSupply","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Redeemed","inputs":[{"type":"address","name":"seller","internalType":"address","indexed":false},{"type":"uint256","name":"amountTKN","internalType":"uint256","indexed":false},{"type":"uint256","name":"amountBASE","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IERC20"}],"name":"WPLS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IWPLS"}],"name":"WRAP","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"allowance","inputs":[{"type":"address","name":"holder","internalType":"address"},{"type":"address","name":"spender","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"amountOut","inputs":[{"type":"uint256","name":"numTokens","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"approve","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"burn","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"calculatePrice","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_amountIn","internalType":"uint256"}],"name":"calculateTokensForExactWPLS","inputs":[{"type":"uint256","name":"_amountOut","internalType":"uint256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"decimals","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"estimateMinted","inputs":[{"type":"uint256","name":"numTokens","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"estimateRedeemed","inputs":[{"type":"uint256","name":"numTokens","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getDepositedOf","inputs":[{"type":"address","name":"user","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"users","internalType":"uint256"},{"type":"uint256","name":"txs","internalType":"uint256"},{"type":"uint256","name":"underlyingSupply","internalType":"uint256"},{"type":"uint256","name":"supply","internalType":"uint256"},{"type":"uint256","name":"price","internalType":"uint256"}],"name":"getInfo","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getLastEntryOf","inputs":[{"type":"address","name":"user","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getValueOfHoldings","inputs":[{"type":"address","name":"holder","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getWithdrawnOf","inputs":[{"type":"address","name":"user","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"mintFee","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"mintWithBacking","inputs":[{"type":"uint256","name":"numTokens","internalType":"uint256"},{"type":"address","name":"recipient","internalType":"address"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"name","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"redeem","inputs":[{"type":"uint256","name":"tokenAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"redeemTo","inputs":[{"type":"uint256","name":"tokenAmount","internalType":"uint256"},{"type":"address","name":"recipient","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"sellFee","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"symbol","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSupply","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transfer","inputs":[{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transferFrom","inputs":[{"type":"address","name":"sender","internalType":"address"},{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"underlyingBalance","inputs":[]},{"type":"receive","stateMutability":"payable"}]
Contract Creation Code
0x60c060405262017318600855620173186009553480156200001f57600080fd5b50604051620033a5380380620033a5833981810160405281019062000045919062000126565b60016000819055508073ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff16815250505062000158565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620000ee82620000c1565b9050919050565b6200010081620000e1565b81146200010c57600080fd5b50565b6000815190506200012081620000f5565b92915050565b6000602082840312156200013f576200013e620000bc565b5b60006200014f848285016200010f565b91505092915050565b60805160a051613204620001a1600039600081816101cb01526112370152600081816109240152818161107b01528181611628015281816118360152611ff601526132046000f3fe6080604052600436106101ba5760003560e01c80636ba56b38116100ec578063d348b4091161008a578063e8bba4f611610064578063e8bba4f614610758578063ec58890914610795578063ed13b253146107d2578063ef8ef56f1461080f5761025f565b8063d348b409146106b3578063db006a75146106de578063dd62ed3e1461071b5761025f565b80637314f109116100c65780637314f109146105d157806375fe9fba1461060e57806395d89b411461064b578063a9059cbb146106765761025f565b80636ba56b381461052c5780636cba38841461056957806370a08231146105945761025f565b80632b14ca561161015957806352c08bb41161013357806352c08bb41461045857806359356c5c146104955780635a9b0b89146104c05780636b014f83146104ef5761025f565b80632b14ca56146103d9578063313ce5671461040457806342966c681461042f5761025f565b806313966db51161019557806313966db51461030957806318160ddd146103345780631f02a29c1461035f57806323b872dd1461039c5761025f565b806246516b1461026457806306fdde03146102a1578063095ea7b3146102cc5761025f565b3661025f57600033905060003490507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561023157600080fd5b505af1158015610245573d6000803e3d6000fd5b50505050506102533061083a565b61025d818361091f565b005b600080fd5b34801561027057600080fd5b5061028b60048036038101906102869190612545565b610b2c565b604051610298919061258b565b60405180910390f35b3480156102ad57600080fd5b506102b6610b78565b6040516102c39190612636565b60405180910390f35b3480156102d857600080fd5b506102f360048036038101906102ee9190612684565b610bb5565b60405161030091906126df565b60405180910390f35b34801561031557600080fd5b5061031e610ca7565b60405161032b919061258b565b60405180910390f35b34801561034057600080fd5b50610349610cad565b604051610356919061258b565b60405180910390f35b34801561036b57600080fd5b5061038660048036038101906103819190612545565b610cb7565b604051610393919061258b565b60405180910390f35b3480156103a857600080fd5b506103c360048036038101906103be91906126fa565b610d08565b6040516103d091906126df565b60405180910390f35b3480156103e557600080fd5b506103ee610eb9565b6040516103fb919061258b565b60405180910390f35b34801561041057600080fd5b50610419610ebf565b6040516104269190612769565b60405180910390f35b34801561043b57600080fd5b5061045660048036038101906104519190612784565b610ec8565b005b34801561046457600080fd5b5061047f600480360381019061047a91906127b1565b61100d565b60405161048c919061258b565b60405180910390f35b3480156104a157600080fd5b506104aa611077565b6040516104b7919061258b565b60405180910390f35b3480156104cc57600080fd5b506104d5611118565b6040516104e69594939291906127f1565b60405180910390f35b3480156104fb57600080fd5b5061051660048036038101906105119190612784565b61114a565b604051610523919061258b565b60405180910390f35b34801561053857600080fd5b50610553600480360381019061054e9190612545565b6111e9565b604051610560919061258b565b60405180910390f35b34801561057557600080fd5b5061057e611235565b60405161058b91906128a3565b60405180910390f35b3480156105a057600080fd5b506105bb60048036038101906105b69190612545565b611259565b6040516105c8919061258b565b60405180910390f35b3480156105dd57600080fd5b506105f860048036038101906105f391906127b1565b6112a2565b604051610605919061258b565b60405180910390f35b34801561061a57600080fd5b5061063560048036038101906106309190612784565b611314565b604051610642919061258b565b60405180910390f35b34801561065757600080fd5b50610660611351565b60405161066d9190612636565b60405180910390f35b34801561068257600080fd5b5061069d60048036038101906106989190612684565b61138e565b6040516106aa91906126df565b60405180910390f35b3480156106bf57600080fd5b506106c86113f8565b6040516106d5919061258b565b60405180910390f35b3480156106ea57600080fd5b5061070560048036038101906107009190612784565b611407565b604051610712919061258b565b60405180910390f35b34801561072757600080fd5b50610742600480360381019061073d91906128be565b611470565b60405161074f919061258b565b60405180910390f35b34801561076457600080fd5b5061077f600480360381019061077a9190612545565b6114f7565b60405161078c919061258b565b60405180910390f35b3480156107a157600080fd5b506107bc60048036038101906107b79190612784565b611543565b6040516107c9919061258b565b60405180910390f35b3480156107de57600080fd5b506107f960048036038101906107f49190612784565b6115eb565b604051610806919061258b565b60405180910390f35b34801561081b57600080fd5b50610824611626565b604051610831919061291f565b60405180910390f35b6000600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506103e881111561091b57600061089261164a565b905061089e838361169f565b7f8a1c945864c85a9dee42b8734075761f7a16095a8384ab751f2417c5767e227e826040516108cd919061258b565b60405180910390a17f046aa811b2923fd55b4ca06375b4045117d4584c66fc40880a8ab8ee32d88ed1816108ff61164a565b6003546040516109119392919061293a565b60405180910390a1505b5050565b6000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b815260040161097b9190612980565b602060405180830381865afa158015610998573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109bc91906129b0565b90506000811180156109ce5750808411155b610a0d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a0490612a29565b60405180910390fd5b6000610a1761164a565b90506000610a23611077565b90506000610a3087611827565b905082600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000181905550610ace87600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001015461197690919063ffffffff16565b600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010181905550610b20868284866119d4565b94505050505092915050565b6000600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001549050919050565b60606040518060400160405280601381526020017f446567656e2050726f746f636f6c20474f415400000000000000000000000000815250905090565b600081600760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051610c95919061258b565b60405180910390a36001905092915050565b60085481565b6000600354905090565b6000610d01600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611314565b9050919050565b6000600260005403610d4f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d4690612a95565b60405180910390fd5b6002600081905550610e1d826040518060400160405280601681526020017f496e73756666696369656e7420416c6c6f77616e636500000000000000000000815250600760008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611af59092919063ffffffff16565b600760008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610ea8848484611b59565b905060016000819055509392505050565b60095481565b60006012905090565b600260005403610f0d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f0490612a95565b60405180910390fd5b60026000819055506000600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050818110158015610f695750600081115b610fa8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f9f90612b01565b60405180910390fd5b6000610fb261164a565b9050610fbe338461169f565b610fc781611e47565b7fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca53384604051610ff8929190612b21565b60405180910390a15050600160008190555050565b6000600260005403611054576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161104b90612a95565b60405180910390fd5b6002600081905550611067338484611ed7565b9050600160008190555092915050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016110d29190612980565b602060405180830381865afa1580156110ef573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061111391906129b0565b905090565b600080600080600060015494506002549350611132611077565b9250600354915061114161164a565b90509091929394565b600080611155611077565b90506000600354146111b6576111b1620186a06111a360085461119585611187896003546121d790919063ffffffff16565b61225190919063ffffffff16565b6121d790919063ffffffff16565b61225190919063ffffffff16565b6111e1565b6111e0620186a06111d2600854866121d790919063ffffffff16565b61225190919063ffffffff16565b5b915050919050565b6000600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600201549050919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60006002600054036112e9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112e090612a95565b60405180910390fd5b60026000819055506112fa3061083a565b611304838361091f565b9050600160008190555092915050565b600061134a670de0b6b3a764000061133c8461132e61164a565b6121d790919063ffffffff16565b61225190919063ffffffff16565b9050919050565b60606040518060400160405280600481526020017f474f415400000000000000000000000000000000000000000000000000000000815250905090565b60006002600054036113d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113cc90612a95565b60405180910390fd5b60026000819055506113e8338484611b59565b9050600160008190555092915050565b600061140261164a565b905090565b600060026000540361144e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161144590612a95565b60405180910390fd5b6002600081905550611461338333611ed7565b90506001600081905550919050565b6000600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b6000600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101549050919050565b6000808211611587576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161157e90612bbc565b60405180910390fd5b6115e46009546115d6620186a06115c861159f61164a565b6115ba670de0b6b3a7640000896121d790919063ffffffff16565b61225190919063ffffffff16565b6121d790919063ffffffff16565b61225190919063ffffffff16565b9050919050565b600061161f61161a620186a061160c600954866121d790919063ffffffff16565b61225190919063ffffffff16565b611314565b9050919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b600080600354146116905761168b60035461167d670de0b6b3a764000061166f611077565b6121d790919063ffffffff16565b61225190919063ffffffff16565b61169a565b670de0b6b3a76400005b905090565b611728816040518060400160405280601481526020017f496e73756666696369656e742042616c616e6365000000000000000000000000815250600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611af59092919063ffffffff16565b600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506117b7816040518060400160405280600f81526020017f4e6567617469766520537570706c790000000000000000000000000000000000815250600354611af59092919063ffffffff16565b600381905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161181b919061258b565b60405180910390a35050565b600080611832611077565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166323b872dd3330866040518463ffffffff1660e01b815260040161189193929190612bdc565b6020604051808303816000875af11580156118b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d49190612c3f565b611913576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161190a90612cb8565b60405180910390fd5b600061191d611077565b9050818111611961576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161195890612d24565b60405180910390fd5b818161196d9190612d73565b92505050919050565b60008082846119859190612da7565b9050838110156119ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119c190612e27565b60405180910390fd5b8091505092915050565b600080600060035414611a0d57611a08846119fa876003546121d790919063ffffffff16565b61225190919063ffffffff16565b611a0f565b845b90506000611a3d620186a0611a2f600854856121d790919063ffffffff16565b61225190919063ffffffff16565b905060008111611a82576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a7990612e93565b60405180910390fd5b611a8c878261229b565b611a9584611e47565b600160026000828254611aa89190612da7565b925050819055507f30385c845b448a36257a6a1716e6ad2e1bc2cbe333cde1e69fe849ad6511adfe8782604051611ae0929190612b21565b60405180910390a18092505050949350505050565b6000838311158290611b3d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b349190612636565b60405180910390fd5b5060008385611b4c9190612d73565b9050809150509392505050565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614158015611bc45750600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614155b611c03576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bfa90612eff565b60405180910390fd5b60008211611c46576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c3d90612f6b565b60405180910390fd5b6000611c5061164a565b9050611cdb836040518060400160405280601481526020017f496e73756666696369656e742042616c616e6365000000000000000000000000815250600660008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611af59092919063ffffffff16565b600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550611d7083600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461197690919063ffffffff16565b600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550611dbc81611e47565b600160026000828254611dcf9190612da7565b925050819055508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef85604051611e33919061258b565b60405180910390a360019150509392505050565b6000611e5161164a565b905081811015611e96576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e8d90612fd7565b60405180910390fd5b7f046aa811b2923fd55b4ca06375b4045117d4584c66fc40880a8ab8ee32d88ed18282600354604051611ecb9392919061293a565b60405180910390a15050565b60008083118015611f27575082600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410155b611f3057600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614158015611f9a5750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b611fa357600080fd5b6000611fad61164a565b90506000611fdb620186a0611fcd600954886121d790919063ffffffff16565b61225190919063ffffffff16565b90506000611fe882611314565b9050611ff4878761169f565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb86836040518363ffffffff1660e01b815260040161204f929190612b21565b6020604051808303816000875af115801561206e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120929190612c3f565b6120d1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120c890613043565b60405180910390fd5b6120da83611e47565b6001600260008282546120ed9190612da7565b9250508190555061214981600460008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206002015461197690919063ffffffff16565b600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600201819055507ff3a670cd3af7d64b488926880889d08a8585a138ff455227af6737339a1ec2628787836040516121c293929190613063565b60405180910390a18093505050509392505050565b60008083036121e9576000905061224b565b600082846121f7919061309a565b9050828482612206919061310b565b14612246576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161223d906131ae565b60405180910390fd5b809150505b92915050565b600061229383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061247f565b905092915050565b6000600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1660ff1603612365576001600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600180600082825461235d9190612da7565b925050819055505b6123b781600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461197690919063ffffffff16565b600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061240f8160035461197690919063ffffffff16565b6003819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051612473919061258b565b60405180910390a35050565b600080831182906124c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124bd9190612636565b60405180910390fd5b50600083856124d5919061310b565b9050809150509392505050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000612512826124e7565b9050919050565b61252281612507565b811461252d57600080fd5b50565b60008135905061253f81612519565b92915050565b60006020828403121561255b5761255a6124e2565b5b600061256984828501612530565b91505092915050565b6000819050919050565b61258581612572565b82525050565b60006020820190506125a0600083018461257c565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156125e05780820151818401526020810190506125c5565b60008484015250505050565b6000601f19601f8301169050919050565b6000612608826125a6565b61261281856125b1565b93506126228185602086016125c2565b61262b816125ec565b840191505092915050565b6000602082019050818103600083015261265081846125fd565b905092915050565b61266181612572565b811461266c57600080fd5b50565b60008135905061267e81612658565b92915050565b6000806040838503121561269b5761269a6124e2565b5b60006126a985828601612530565b92505060206126ba8582860161266f565b9150509250929050565b60008115159050919050565b6126d9816126c4565b82525050565b60006020820190506126f460008301846126d0565b92915050565b600080600060608486031215612713576127126124e2565b5b600061272186828701612530565b935050602061273286828701612530565b92505060406127438682870161266f565b9150509250925092565b600060ff82169050919050565b6127638161274d565b82525050565b600060208201905061277e600083018461275a565b92915050565b60006020828403121561279a576127996124e2565b5b60006127a88482850161266f565b91505092915050565b600080604083850312156127c8576127c76124e2565b5b60006127d68582860161266f565b92505060206127e785828601612530565b9150509250929050565b600060a082019050612806600083018861257c565b612813602083018761257c565b612820604083018661257c565b61282d606083018561257c565b61283a608083018461257c565b9695505050505050565b6000819050919050565b600061286961286461285f846124e7565b612844565b6124e7565b9050919050565b600061287b8261284e565b9050919050565b600061288d82612870565b9050919050565b61289d81612882565b82525050565b60006020820190506128b86000830184612894565b92915050565b600080604083850312156128d5576128d46124e2565b5b60006128e385828601612530565b92505060206128f485828601612530565b9150509250929050565b600061290982612870565b9050919050565b612919816128fe565b82525050565b60006020820190506129346000830184612910565b92915050565b600060608201905061294f600083018661257c565b61295c602083018561257c565b612969604083018461257c565b949350505050565b61297a81612507565b82525050565b60006020820190506129956000830184612971565b92915050565b6000815190506129aa81612658565b92915050565b6000602082840312156129c6576129c56124e2565b5b60006129d48482850161299b565b91505092915050565b7f496e73756666696369656e742042616c616e6365000000000000000000000000600082015250565b6000612a136014836125b1565b9150612a1e826129dd565b602082019050919050565b60006020820190508181036000830152612a4281612a06565b9050919050565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00600082015250565b6000612a7f601f836125b1565b9150612a8a82612a49565b602082019050919050565b60006020820190508181036000830152612aae81612a72565b9050919050565b7f5a65726f20486f6c64696e677300000000000000000000000000000000000000600082015250565b6000612aeb600d836125b1565b9150612af682612ab5565b602082019050919050565b60006020820190508181036000830152612b1a81612ade565b9050919050565b6000604082019050612b366000830185612971565b612b43602083018461257c565b9392505050565b7f57504c5320616d6f756e74206d7573742062652067726561746572207468616e60008201527f2030000000000000000000000000000000000000000000000000000000000000602082015250565b6000612ba66022836125b1565b9150612bb182612b4a565b604082019050919050565b60006020820190508181036000830152612bd581612b99565b9050919050565b6000606082019050612bf16000830186612971565b612bfe6020830185612971565b612c0b604083018461257c565b949350505050565b612c1c816126c4565b8114612c2757600080fd5b50565b600081519050612c3981612c13565b92915050565b600060208284031215612c5557612c546124e2565b5b6000612c6384828501612c2a565b91505092915050565b7f4661696c757265205472616e736665722046726f6d0000000000000000000000600082015250565b6000612ca26015836125b1565b9150612cad82612c6c565b602082019050919050565b60006020820190508181036000830152612cd181612c95565b9050919050565b7f5a65726f20526563656976656400000000000000000000000000000000000000600082015250565b6000612d0e600d836125b1565b9150612d1982612cd8565b602082019050919050565b60006020820190508181036000830152612d3d81612d01565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000612d7e82612572565b9150612d8983612572565b9250828203905081811115612da157612da0612d44565b5b92915050565b6000612db282612572565b9150612dbd83612572565b9250828201905080821115612dd557612dd4612d44565b5b92915050565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000600082015250565b6000612e11601b836125b1565b9150612e1c82612ddb565b602082019050919050565b60006020820190508181036000830152612e4081612e04565b9050919050565b7f5a65726f20416d6f756e74000000000000000000000000000000000000000000600082015250565b6000612e7d600b836125b1565b9150612e8882612e47565b602082019050919050565b60006020820190508181036000830152612eac81612e70565b9050919050565b7f5472616e7366657220546f205a65726f00000000000000000000000000000000600082015250565b6000612ee96010836125b1565b9150612ef482612eb3565b602082019050919050565b60006020820190508181036000830152612f1881612edc565b9050919050565b7f5472616e7366657220416d74205a65726f000000000000000000000000000000600082015250565b6000612f556011836125b1565b9150612f6082612f1f565b602082019050919050565b60006020820190508181036000830152612f8481612f48565b9050919050565b7f50726963652043616e6e6f742046616c6c000000000000000000000000000000600082015250565b6000612fc16011836125b1565b9150612fcc82612f8b565b602082019050919050565b60006020820190508181036000830152612ff081612fb4565b9050919050565b7f556e6465726c79696e67205472616e73666572204661696c7572650000000000600082015250565b600061302d601b836125b1565b915061303882612ff7565b602082019050919050565b6000602082019050818103600083015261305c81613020565b9050919050565b60006060820190506130786000830186612971565b613085602083018561257c565b613092604083018461257c565b949350505050565b60006130a582612572565b91506130b083612572565b92508282026130be81612572565b915082820484148315176130d5576130d4612d44565b5b5092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600061311682612572565b915061312183612572565b925082613131576131306130dc565b5b828204905092915050565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f60008201527f7700000000000000000000000000000000000000000000000000000000000000602082015250565b60006131986021836125b1565b91506131a38261313c565b604082019050919050565b600060208201905081810360008301526131c78161318b565b905091905056fea2646970667358221220302cebdcbd51dc286e1b40be54f358e6e8aa3dd7b03461d38f46e68134e8e56c64736f6c63430008110033000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a27
Deployed ByteCode
0x6080604052600436106101ba5760003560e01c80636ba56b38116100ec578063d348b4091161008a578063e8bba4f611610064578063e8bba4f614610758578063ec58890914610795578063ed13b253146107d2578063ef8ef56f1461080f5761025f565b8063d348b409146106b3578063db006a75146106de578063dd62ed3e1461071b5761025f565b80637314f109116100c65780637314f109146105d157806375fe9fba1461060e57806395d89b411461064b578063a9059cbb146106765761025f565b80636ba56b381461052c5780636cba38841461056957806370a08231146105945761025f565b80632b14ca561161015957806352c08bb41161013357806352c08bb41461045857806359356c5c146104955780635a9b0b89146104c05780636b014f83146104ef5761025f565b80632b14ca56146103d9578063313ce5671461040457806342966c681461042f5761025f565b806313966db51161019557806313966db51461030957806318160ddd146103345780631f02a29c1461035f57806323b872dd1461039c5761025f565b806246516b1461026457806306fdde03146102a1578063095ea7b3146102cc5761025f565b3661025f57600033905060003490507f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a2773ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561023157600080fd5b505af1158015610245573d6000803e3d6000fd5b50505050506102533061083a565b61025d818361091f565b005b600080fd5b34801561027057600080fd5b5061028b60048036038101906102869190612545565b610b2c565b604051610298919061258b565b60405180910390f35b3480156102ad57600080fd5b506102b6610b78565b6040516102c39190612636565b60405180910390f35b3480156102d857600080fd5b506102f360048036038101906102ee9190612684565b610bb5565b60405161030091906126df565b60405180910390f35b34801561031557600080fd5b5061031e610ca7565b60405161032b919061258b565b60405180910390f35b34801561034057600080fd5b50610349610cad565b604051610356919061258b565b60405180910390f35b34801561036b57600080fd5b5061038660048036038101906103819190612545565b610cb7565b604051610393919061258b565b60405180910390f35b3480156103a857600080fd5b506103c360048036038101906103be91906126fa565b610d08565b6040516103d091906126df565b60405180910390f35b3480156103e557600080fd5b506103ee610eb9565b6040516103fb919061258b565b60405180910390f35b34801561041057600080fd5b50610419610ebf565b6040516104269190612769565b60405180910390f35b34801561043b57600080fd5b5061045660048036038101906104519190612784565b610ec8565b005b34801561046457600080fd5b5061047f600480360381019061047a91906127b1565b61100d565b60405161048c919061258b565b60405180910390f35b3480156104a157600080fd5b506104aa611077565b6040516104b7919061258b565b60405180910390f35b3480156104cc57600080fd5b506104d5611118565b6040516104e69594939291906127f1565b60405180910390f35b3480156104fb57600080fd5b5061051660048036038101906105119190612784565b61114a565b604051610523919061258b565b60405180910390f35b34801561053857600080fd5b50610553600480360381019061054e9190612545565b6111e9565b604051610560919061258b565b60405180910390f35b34801561057557600080fd5b5061057e611235565b60405161058b91906128a3565b60405180910390f35b3480156105a057600080fd5b506105bb60048036038101906105b69190612545565b611259565b6040516105c8919061258b565b60405180910390f35b3480156105dd57600080fd5b506105f860048036038101906105f391906127b1565b6112a2565b604051610605919061258b565b60405180910390f35b34801561061a57600080fd5b5061063560048036038101906106309190612784565b611314565b604051610642919061258b565b60405180910390f35b34801561065757600080fd5b50610660611351565b60405161066d9190612636565b60405180910390f35b34801561068257600080fd5b5061069d60048036038101906106989190612684565b61138e565b6040516106aa91906126df565b60405180910390f35b3480156106bf57600080fd5b506106c86113f8565b6040516106d5919061258b565b60405180910390f35b3480156106ea57600080fd5b5061070560048036038101906107009190612784565b611407565b604051610712919061258b565b60405180910390f35b34801561072757600080fd5b50610742600480360381019061073d91906128be565b611470565b60405161074f919061258b565b60405180910390f35b34801561076457600080fd5b5061077f600480360381019061077a9190612545565b6114f7565b60405161078c919061258b565b60405180910390f35b3480156107a157600080fd5b506107bc60048036038101906107b79190612784565b611543565b6040516107c9919061258b565b60405180910390f35b3480156107de57600080fd5b506107f960048036038101906107f49190612784565b6115eb565b604051610806919061258b565b60405180910390f35b34801561081b57600080fd5b50610824611626565b604051610831919061291f565b60405180910390f35b6000600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506103e881111561091b57600061089261164a565b905061089e838361169f565b7f8a1c945864c85a9dee42b8734075761f7a16095a8384ab751f2417c5767e227e826040516108cd919061258b565b60405180910390a17f046aa811b2923fd55b4ca06375b4045117d4584c66fc40880a8ab8ee32d88ed1816108ff61164a565b6003546040516109119392919061293a565b60405180910390a1505b5050565b6000807f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a2773ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b815260040161097b9190612980565b602060405180830381865afa158015610998573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109bc91906129b0565b90506000811180156109ce5750808411155b610a0d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a0490612a29565b60405180910390fd5b6000610a1761164a565b90506000610a23611077565b90506000610a3087611827565b905082600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000181905550610ace87600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001015461197690919063ffffffff16565b600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010181905550610b20868284866119d4565b94505050505092915050565b6000600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001549050919050565b60606040518060400160405280601381526020017f446567656e2050726f746f636f6c20474f415400000000000000000000000000815250905090565b600081600760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051610c95919061258b565b60405180910390a36001905092915050565b60085481565b6000600354905090565b6000610d01600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611314565b9050919050565b6000600260005403610d4f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d4690612a95565b60405180910390fd5b6002600081905550610e1d826040518060400160405280601681526020017f496e73756666696369656e7420416c6c6f77616e636500000000000000000000815250600760008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611af59092919063ffffffff16565b600760008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610ea8848484611b59565b905060016000819055509392505050565b60095481565b60006012905090565b600260005403610f0d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f0490612a95565b60405180910390fd5b60026000819055506000600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050818110158015610f695750600081115b610fa8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f9f90612b01565b60405180910390fd5b6000610fb261164a565b9050610fbe338461169f565b610fc781611e47565b7fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca53384604051610ff8929190612b21565b60405180910390a15050600160008190555050565b6000600260005403611054576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161104b90612a95565b60405180910390fd5b6002600081905550611067338484611ed7565b9050600160008190555092915050565b60007f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a2773ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016110d29190612980565b602060405180830381865afa1580156110ef573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061111391906129b0565b905090565b600080600080600060015494506002549350611132611077565b9250600354915061114161164a565b90509091929394565b600080611155611077565b90506000600354146111b6576111b1620186a06111a360085461119585611187896003546121d790919063ffffffff16565b61225190919063ffffffff16565b6121d790919063ffffffff16565b61225190919063ffffffff16565b6111e1565b6111e0620186a06111d2600854866121d790919063ffffffff16565b61225190919063ffffffff16565b5b915050919050565b6000600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600201549050919050565b7f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a2781565b6000600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60006002600054036112e9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112e090612a95565b60405180910390fd5b60026000819055506112fa3061083a565b611304838361091f565b9050600160008190555092915050565b600061134a670de0b6b3a764000061133c8461132e61164a565b6121d790919063ffffffff16565b61225190919063ffffffff16565b9050919050565b60606040518060400160405280600481526020017f474f415400000000000000000000000000000000000000000000000000000000815250905090565b60006002600054036113d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113cc90612a95565b60405180910390fd5b60026000819055506113e8338484611b59565b9050600160008190555092915050565b600061140261164a565b905090565b600060026000540361144e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161144590612a95565b60405180910390fd5b6002600081905550611461338333611ed7565b90506001600081905550919050565b6000600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b6000600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101549050919050565b6000808211611587576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161157e90612bbc565b60405180910390fd5b6115e46009546115d6620186a06115c861159f61164a565b6115ba670de0b6b3a7640000896121d790919063ffffffff16565b61225190919063ffffffff16565b6121d790919063ffffffff16565b61225190919063ffffffff16565b9050919050565b600061161f61161a620186a061160c600954866121d790919063ffffffff16565b61225190919063ffffffff16565b611314565b9050919050565b7f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a2781565b600080600354146116905761168b60035461167d670de0b6b3a764000061166f611077565b6121d790919063ffffffff16565b61225190919063ffffffff16565b61169a565b670de0b6b3a76400005b905090565b611728816040518060400160405280601481526020017f496e73756666696369656e742042616c616e6365000000000000000000000000815250600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611af59092919063ffffffff16565b600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506117b7816040518060400160405280600f81526020017f4e6567617469766520537570706c790000000000000000000000000000000000815250600354611af59092919063ffffffff16565b600381905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161181b919061258b565b60405180910390a35050565b600080611832611077565b90507f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a2773ffffffffffffffffffffffffffffffffffffffff166323b872dd3330866040518463ffffffff1660e01b815260040161189193929190612bdc565b6020604051808303816000875af11580156118b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d49190612c3f565b611913576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161190a90612cb8565b60405180910390fd5b600061191d611077565b9050818111611961576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161195890612d24565b60405180910390fd5b818161196d9190612d73565b92505050919050565b60008082846119859190612da7565b9050838110156119ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119c190612e27565b60405180910390fd5b8091505092915050565b600080600060035414611a0d57611a08846119fa876003546121d790919063ffffffff16565b61225190919063ffffffff16565b611a0f565b845b90506000611a3d620186a0611a2f600854856121d790919063ffffffff16565b61225190919063ffffffff16565b905060008111611a82576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a7990612e93565b60405180910390fd5b611a8c878261229b565b611a9584611e47565b600160026000828254611aa89190612da7565b925050819055507f30385c845b448a36257a6a1716e6ad2e1bc2cbe333cde1e69fe849ad6511adfe8782604051611ae0929190612b21565b60405180910390a18092505050949350505050565b6000838311158290611b3d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b349190612636565b60405180910390fd5b5060008385611b4c9190612d73565b9050809150509392505050565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614158015611bc45750600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614155b611c03576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bfa90612eff565b60405180910390fd5b60008211611c46576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c3d90612f6b565b60405180910390fd5b6000611c5061164a565b9050611cdb836040518060400160405280601481526020017f496e73756666696369656e742042616c616e6365000000000000000000000000815250600660008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611af59092919063ffffffff16565b600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550611d7083600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461197690919063ffffffff16565b600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550611dbc81611e47565b600160026000828254611dcf9190612da7565b925050819055508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef85604051611e33919061258b565b60405180910390a360019150509392505050565b6000611e5161164a565b905081811015611e96576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e8d90612fd7565b60405180910390fd5b7f046aa811b2923fd55b4ca06375b4045117d4584c66fc40880a8ab8ee32d88ed18282600354604051611ecb9392919061293a565b60405180910390a15050565b60008083118015611f27575082600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410155b611f3057600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614158015611f9a5750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b611fa357600080fd5b6000611fad61164a565b90506000611fdb620186a0611fcd600954886121d790919063ffffffff16565b61225190919063ffffffff16565b90506000611fe882611314565b9050611ff4878761169f565b7f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a2773ffffffffffffffffffffffffffffffffffffffff1663a9059cbb86836040518363ffffffff1660e01b815260040161204f929190612b21565b6020604051808303816000875af115801561206e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120929190612c3f565b6120d1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120c890613043565b60405180910390fd5b6120da83611e47565b6001600260008282546120ed9190612da7565b9250508190555061214981600460008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206002015461197690919063ffffffff16565b600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600201819055507ff3a670cd3af7d64b488926880889d08a8585a138ff455227af6737339a1ec2628787836040516121c293929190613063565b60405180910390a18093505050509392505050565b60008083036121e9576000905061224b565b600082846121f7919061309a565b9050828482612206919061310b565b14612246576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161223d906131ae565b60405180910390fd5b809150505b92915050565b600061229383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061247f565b905092915050565b6000600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1660ff1603612365576001600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600180600082825461235d9190612da7565b925050819055505b6123b781600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461197690919063ffffffff16565b600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061240f8160035461197690919063ffffffff16565b6003819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051612473919061258b565b60405180910390a35050565b600080831182906124c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124bd9190612636565b60405180910390fd5b50600083856124d5919061310b565b9050809150509392505050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000612512826124e7565b9050919050565b61252281612507565b811461252d57600080fd5b50565b60008135905061253f81612519565b92915050565b60006020828403121561255b5761255a6124e2565b5b600061256984828501612530565b91505092915050565b6000819050919050565b61258581612572565b82525050565b60006020820190506125a0600083018461257c565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156125e05780820151818401526020810190506125c5565b60008484015250505050565b6000601f19601f8301169050919050565b6000612608826125a6565b61261281856125b1565b93506126228185602086016125c2565b61262b816125ec565b840191505092915050565b6000602082019050818103600083015261265081846125fd565b905092915050565b61266181612572565b811461266c57600080fd5b50565b60008135905061267e81612658565b92915050565b6000806040838503121561269b5761269a6124e2565b5b60006126a985828601612530565b92505060206126ba8582860161266f565b9150509250929050565b60008115159050919050565b6126d9816126c4565b82525050565b60006020820190506126f460008301846126d0565b92915050565b600080600060608486031215612713576127126124e2565b5b600061272186828701612530565b935050602061273286828701612530565b92505060406127438682870161266f565b9150509250925092565b600060ff82169050919050565b6127638161274d565b82525050565b600060208201905061277e600083018461275a565b92915050565b60006020828403121561279a576127996124e2565b5b60006127a88482850161266f565b91505092915050565b600080604083850312156127c8576127c76124e2565b5b60006127d68582860161266f565b92505060206127e785828601612530565b9150509250929050565b600060a082019050612806600083018861257c565b612813602083018761257c565b612820604083018661257c565b61282d606083018561257c565b61283a608083018461257c565b9695505050505050565b6000819050919050565b600061286961286461285f846124e7565b612844565b6124e7565b9050919050565b600061287b8261284e565b9050919050565b600061288d82612870565b9050919050565b61289d81612882565b82525050565b60006020820190506128b86000830184612894565b92915050565b600080604083850312156128d5576128d46124e2565b5b60006128e385828601612530565b92505060206128f485828601612530565b9150509250929050565b600061290982612870565b9050919050565b612919816128fe565b82525050565b60006020820190506129346000830184612910565b92915050565b600060608201905061294f600083018661257c565b61295c602083018561257c565b612969604083018461257c565b949350505050565b61297a81612507565b82525050565b60006020820190506129956000830184612971565b92915050565b6000815190506129aa81612658565b92915050565b6000602082840312156129c6576129c56124e2565b5b60006129d48482850161299b565b91505092915050565b7f496e73756666696369656e742042616c616e6365000000000000000000000000600082015250565b6000612a136014836125b1565b9150612a1e826129dd565b602082019050919050565b60006020820190508181036000830152612a4281612a06565b9050919050565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00600082015250565b6000612a7f601f836125b1565b9150612a8a82612a49565b602082019050919050565b60006020820190508181036000830152612aae81612a72565b9050919050565b7f5a65726f20486f6c64696e677300000000000000000000000000000000000000600082015250565b6000612aeb600d836125b1565b9150612af682612ab5565b602082019050919050565b60006020820190508181036000830152612b1a81612ade565b9050919050565b6000604082019050612b366000830185612971565b612b43602083018461257c565b9392505050565b7f57504c5320616d6f756e74206d7573742062652067726561746572207468616e60008201527f2030000000000000000000000000000000000000000000000000000000000000602082015250565b6000612ba66022836125b1565b9150612bb182612b4a565b604082019050919050565b60006020820190508181036000830152612bd581612b99565b9050919050565b6000606082019050612bf16000830186612971565b612bfe6020830185612971565b612c0b604083018461257c565b949350505050565b612c1c816126c4565b8114612c2757600080fd5b50565b600081519050612c3981612c13565b92915050565b600060208284031215612c5557612c546124e2565b5b6000612c6384828501612c2a565b91505092915050565b7f4661696c757265205472616e736665722046726f6d0000000000000000000000600082015250565b6000612ca26015836125b1565b9150612cad82612c6c565b602082019050919050565b60006020820190508181036000830152612cd181612c95565b9050919050565b7f5a65726f20526563656976656400000000000000000000000000000000000000600082015250565b6000612d0e600d836125b1565b9150612d1982612cd8565b602082019050919050565b60006020820190508181036000830152612d3d81612d01565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000612d7e82612572565b9150612d8983612572565b9250828203905081811115612da157612da0612d44565b5b92915050565b6000612db282612572565b9150612dbd83612572565b9250828201905080821115612dd557612dd4612d44565b5b92915050565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000600082015250565b6000612e11601b836125b1565b9150612e1c82612ddb565b602082019050919050565b60006020820190508181036000830152612e4081612e04565b9050919050565b7f5a65726f20416d6f756e74000000000000000000000000000000000000000000600082015250565b6000612e7d600b836125b1565b9150612e8882612e47565b602082019050919050565b60006020820190508181036000830152612eac81612e70565b9050919050565b7f5472616e7366657220546f205a65726f00000000000000000000000000000000600082015250565b6000612ee96010836125b1565b9150612ef482612eb3565b602082019050919050565b60006020820190508181036000830152612f1881612edc565b9050919050565b7f5472616e7366657220416d74205a65726f000000000000000000000000000000600082015250565b6000612f556011836125b1565b9150612f6082612f1f565b602082019050919050565b60006020820190508181036000830152612f8481612f48565b9050919050565b7f50726963652043616e6e6f742046616c6c000000000000000000000000000000600082015250565b6000612fc16011836125b1565b9150612fcc82612f8b565b602082019050919050565b60006020820190508181036000830152612ff081612fb4565b9050919050565b7f556e6465726c79696e67205472616e73666572204661696c7572650000000000600082015250565b600061302d601b836125b1565b915061303882612ff7565b602082019050919050565b6000602082019050818103600083015261305c81613020565b9050919050565b60006060820190506130786000830186612971565b613085602083018561257c565b613092604083018461257c565b949350505050565b60006130a582612572565b91506130b083612572565b92508282026130be81612572565b915082820484148315176130d5576130d4612d44565b5b5092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600061311682612572565b915061312183612572565b925082613131576131306130dc565b5b828204905092915050565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f60008201527f7700000000000000000000000000000000000000000000000000000000000000602082015250565b60006131986021836125b1565b91506131a38261313c565b604082019050919050565b600060208201905081810360008301526131c78161318b565b905091905056fea2646970667358221220302cebdcbd51dc286e1b40be54f358e6e8aa3dd7b03461d38f46e68134e8e56c64736f6c63430008110033