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:
- SuperStakePHEX
- Optimization enabled
- true
- Compiler version
- v0.8.18+commit.87f61d96
- Optimization runs
- 50
- EVM Version
- default
- Verified at
- 2023-09-13T05:54:01.618786Z
Constructor Arguments
0x000000000000000000000000165c3410fc91ef562c50559f7d2289febed552d9
Arg [0] (address) : 0x165c3410fc91ef562c50559f7d2289febed552d9
contracts/SuperStakePHEX.sol
/**
* SuperStake: Hex
*
* https://superstake.win
*/
//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.15;
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@uniswap/v2-core/contracts/interfaces/IERC20.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol";
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol";
import "@uniswap/v2-periphery/contracts/interfaces/IWETH.sol";
import "@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolImmutables.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "./DPT/TokenDividendTracker.sol";
import "./SuperStakeImpl.sol";
import "./IMultisend.sol";
import "@gnosis.pm/safe-contracts/contracts/GnosisSafe.sol";
// Seriously if you audit this and ping it for "no safemath used" you're gonna out yourself as an idiot
// SafeMath is by default included in solidity 0.8, I've only included it for the transferFrom
contract SuperStakePHEX is Context, IERC20, Ownable, IERC20Permit, IMultisend {
/** START OF EIP2612/EIP712 VARS */
using Counters for Counters.Counter;
mapping(address => Counters.Counter) private _nonces;
/* solhint-disable var-name-mixedcase */
// Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
// invalidate the cached domain separator if the chain id changes.
bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
uint256 private immutable _CACHED_CHAIN_ID;
address private immutable _CACHED_THIS;
bytes32 private immutable _HASHED_NAME;
bytes32 private immutable _HASHED_VERSION;
bytes32 private immutable _TYPE_HASH;
/** END OF EIP2612/EIP712 VARS */
event Bought(address indexed buyer, uint256 amount);
event Sold(address indexed seller, uint256 amount);
using SafeMath for uint256;
// Constants
string private constant _name = "SuperStake: pHEX";
string private constant _symbol = "pSSH";
string private constant _max = "SSH: MAX";
string private constant _reinit = "SSH: REINIT";
// Standard decimals
uint8 private constant _decimals = 9;
// 55.55m
uint256 private constant initialSupply = 55550000 * 10**9;
// The actual current supply
uint256 public currentSupply;
address private constant _dead = 0x000000000000000000000000000000000000dEaD;
address private _wnative;
// Mappings
mapping(address => uint256) private tokensOwned;
mapping(address => mapping(address => uint256)) private _allowances;
struct mappingStructs {
bool _isExcludedFromFee;
bool _bots;
uint32 _lastTxBuy;
uint32 _lastTxSell;
uint32 botBlock;
bool isLPPair;
bool isInitialLP;
}
mapping(address => mappingStructs) private mappedAddresses;
// Arrays
address[] private lpPairs;
address[] private initialLPPairs;
// Global variables
// Block
address public dividendTracker;
// Default
uint32 private gasForProcessing = 300000;
uint16 private hexStakingRatio = 20;
uint16 private hexRewardRatio = 25;
uint16 private burnRatio = 10;
bool private disableAddToBlocklist = false;
// 8 bits remaining
// Storage block closed
// Block of 256 bits
address public stakingImpl;
uint64 launchTs;
// Storage block closed
// Block of 256 bits
// This is Hex
address private rewardToken = 0x2b591e99afE9f32eAA6214f7B7629768c40Eeb39;
uint32 private buyInfl = 5550;
uint32 private sellDefl = 5550;
bool private tradingOpen;
bool private inSwap = false;
bool private swapEnabled = false;
bool private removedLimits = false;
// Storage block closed
IUniswapV2Router02 private uniswapV2Router;
constructor(address router) {
launchTs = uint64(block.timestamp);
uniswapV2Router = IUniswapV2Router02(router);
// Set up EIP712
bytes32 hashedName = keccak256(bytes(_name));
bytes32 hashedVersion = keccak256(bytes("1"));
bytes32 typeHash = keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
_HASHED_NAME = hashedName;
_HASHED_VERSION = hashedVersion;
_CACHED_CHAIN_ID = block.chainid;
_CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
_CACHED_THIS = address(this);
_TYPE_HASH = typeHash;
tokensOwned[_msgSender()] = initialSupply;
currentSupply = initialSupply;
// Set up the dividends
TokenDividendTracker tracker = new TokenDividendTracker(rewardToken, 5555000000000);
dividendTracker = address(tracker);
// Create the SuperStakeImpl
SuperStakeImpl staker = new SuperStakeImpl(rewardToken, 60, dividendTracker, router);
stakingImpl = address(staker);
tracker.setStakingImpl(stakingImpl);
// Handle exclusion from dividends
tracker.excludeFromDividends(dividendTracker);
tracker.excludeFromDividends(address(this));
tracker.excludeFromDividends(owner());
tracker.excludeFromDividends(_dead);
// Set the struct values
mappedAddresses[_msgSender()] = mappingStructs({
_isExcludedFromFee: true,
_bots: false,
_lastTxBuy: 0,
_lastTxSell: 0,
botBlock: 0,
isLPPair: false,
isInitialLP: false
});
mappedAddresses[address(this)] = mappingStructs({
_isExcludedFromFee: true,
_bots: false,
_lastTxBuy: 0,
_lastTxSell: 0,
botBlock: 0,
isLPPair: false,
isInitialLP: false
});
mappedAddresses[dividendTracker] = mappingStructs({
_isExcludedFromFee: true,
_bots: false,
_lastTxBuy: 0,
_lastTxSell: 0,
botBlock: 0,
isLPPair: false,
isInitialLP: false
});
emit Transfer(address(0), _msgSender(), initialSupply);
}
function name() public pure returns (string memory) {
return _name;
}
function symbol() public pure returns (string memory) {
return _symbol;
}
function decimals() public pure returns (uint8) {
return _decimals;
}
function totalSupply() public view override returns (uint256) {
return currentSupply;
}
function balanceOf(address account) public view override returns (uint256) {
return tokensOwned[account];
}
function transfer(address recipient, uint256 amount)
public
override
returns (bool)
{
_transfer(_msgSender(), recipient, amount);
return true;
}
function allowance(address owner, address spender)
public
view
override
returns (uint256)
{
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount)
public
override
returns (bool)
{
_approve(_msgSender(), spender, amount);
return true;
}
function transferFrom(
address sender,
address recipient,
uint256 amount
) public override returns (bool) {
_transfer(sender, recipient, amount);
_approve(
sender,
_msgSender(),
_allowances[sender][_msgSender()].sub(
amount,
"ERC20: transfer amount exceeds allowance"
)
);
return true;
}
/// @notice Starts trading. Only callable by owner.
function openTrading(address nativeWrapped) public onlyOwner {
require(!tradingOpen, "OPEN");
_wnative = nativeWrapped;
// Exclude the router from dividends
TokenDividendTracker(dividendTracker).excludeFromDividends(address(uniswapV2Router));
_approve(address(this), address(uniswapV2Router), type(uint256).max);
address uniswapV2Pair = IUniswapV2Factory(uniswapV2Router.factory())
.createPair(address(this), _wnative);
// Exclude both pairs
TokenDividendTracker(dividendTracker).excludeFromDividends(address(uniswapV2Pair));
// Add Pair1Pct of the eth and LP to the first (ETH) pair
uniswapV2Router.addLiquidityETH{value: address(this).balance}(
address(this),
balanceOf(address(this)),
0,
0,
owner(),
block.timestamp
);
swapEnabled = true;
tradingOpen = true;
IERC20(uniswapV2Pair).approve(
address(uniswapV2Router),
type(uint256).max
);
// Add the pairs to the list
mappedAddresses[uniswapV2Pair] = mappingStructs({
_isExcludedFromFee: false,
_bots: false,
_lastTxBuy: 0,
_lastTxSell: 0,
botBlock: 0,
isLPPair: true,
isInitialLP: true
});
// Add to LP pair list
lpPairs.push(uniswapV2Pair);
// Add to initial LP pair list
initialLPPairs.push(uniswapV2Pair);
}
function _approve(
address owner,
address spender,
uint256 amount
) private {
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 _transfer(
address from,
address to,
uint256 amount
) private {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
require(amount > 0, "Transfer amount must be greater than zero");
uint32 _flAmt;
bool isSell = false;
if (
from != owner() &&
to != owner() &&
from != address(this) &&
!mappedAddresses[to]._isExcludedFromFee &&
!mappedAddresses[from]._isExcludedFromFee &&
!inSwap
) {
require(
!mappedAddresses[to]._bots && !mappedAddresses[from]._bots,
"SSH: Blocklisted."
);
if (mappedAddresses[from].isLPPair) {
_flAmt = buyInfl;
} else if (mappedAddresses[to].isLPPair) {
// Sell, or LP add
isSell = true;
_flAmt = sellDefl;
// Only allow one type of operation - buy, or sell, per tx
require(mappedAddresses[from]._lastTxBuy != uint32(block.number), "SSH: SWCH");
mappedAddresses[from]._lastTxSell = uint32(block.number);
} else {
// No inflation/deflation on transfers
_flAmt = 0;
// Check if this is going to become a new LP
uint8 lpType = isNewLP(to);
require(lpType != 2, "SSH: No v3 LP.");
if(lpType == 1) {
// V2 LP, so add the "to" address to the LP list for tracking
mappedAddresses[to].isLPPair = true;
lpPairs.push(to);
TokenDividendTracker(dividendTracker).excludeFromDividends(to);
} else {
// All good
}
}
} else {
// Only make it here if it's from or to owner, contract address, or something excluded somehow
_flAmt = 0;
}
_tokenTransfer(from, to, amount, _flAmt, isSell);
}
/// @notice Used to cleanly disengage restaking for recovery of stake pool. Has limitations on when this can be called.
function disengageRestaking() external onlyOwner {
// Can only be called within the first 6 months - given 60 day stakes
require((launchTs + 15228000) > block.timestamp, "SSH: Staking pool no longer disengagable.");
SuperStakeImpl(stakingImpl).disengageRestake();
}
/// @notice Used to withdraw tokens from staking pool in case recovery is necessary. Can only be called if the stake is disengaged - meaning it is also tied to the 6 month time limit.
/// @param recipient the recipient of the withdrawn tokens
function withdrawStaking(address recipient) external onlyOwner {
SuperStakeImpl stakingCa = SuperStakeImpl(stakingImpl);
bool stakeDisengaged = stakingCa.stakeDisengaged();
require(stakeDisengaged, "SSH: Staking pool not disengaged.");
stakingCa.withdrawTokens(recipient);
}
// To be called if needed to move the staking pool to a new contract
function transferOwnerOfStakingPool(address newOwner) external onlyOwner {
SuperStakeImpl(stakingImpl).transferOwnership(newOwner);
}
function doTaxes(uint256 tokenAmount) private {
// To guard against possibility we get called even if we're in swap, don't do taxes
if(inSwap) {
return;
}
// Reentrancy guard/stop infinite tax sells mainly
inSwap = true;
// Check if we're doing a burn ratio
uint256 sellAmt = tokenAmount;
if(burnRatio > 0) {
uint32 ratio = burnRatio + hexStakingRatio + hexRewardRatio;
uint256 burnAmt = (tokenAmount * burnRatio) / ratio;
sellAmt = tokenAmount - burnAmt;
tokensOwned[address(this)] = tokensOwned[address(this)] - burnAmt;
tokensOwned[address(0x000000000000000000000000000000000000dEaD)] = tokensOwned[address(0x000000000000000000000000000000000000dEaD)] + burnAmt;
emit Transfer(address(this), address(0x000000000000000000000000000000000000dEaD), burnAmt);
}
if(_allowances[address(this)][address(uniswapV2Router)] < sellAmt) {
// Our approvals run low, redo it
_approve(address(this), address(uniswapV2Router), type(uint256).max);
}
address[] memory path = new address[](3);
path[0] = address(this);
path[1] = _wnative;
path[2] = rewardToken;
// Swap direct to Hex
uniswapV2Router.swapExactTokensForTokensSupportingFeeOnTransferTokens(
sellAmt,
0,
path,
address(this),
block.timestamp
);
// Using a uint32 prevents an edge case where these uint16's could overflow
// burnRatio and not here as they don't make it to Hex tokens
uint32 divisor = hexRewardRatio + hexStakingRatio;
IERC20 hexToken = IERC20(rewardToken);
uint256 hexAmount = hexToken.balanceOf(address(this));
// Send them, split as required
hexToken.transfer(stakingImpl, (hexAmount * hexStakingRatio) / divisor);
SuperStakeImpl(stakingImpl).afterReceivedHex();
hexToken.transfer(dividendTracker, (hexAmount * hexRewardRatio) / divisor);
TokenDividendTracker(dividendTracker).afterReceivedHex((hexAmount * hexRewardRatio) / divisor);
inSwap = false;
}
receive() external payable {}
// Underlying transfer functions go here
function _tokenTransfer(
address sender,
address recipient,
uint256 amount,
uint32 _flAmt,
bool isSell
) private {
// Do the normal tax setup
uint256 taxAmount = calculateTaxesFee(amount, _flAmt);
uint256 receiverAmt = amount;
if (taxAmount > 0) {
// Reduce recipient amount
receiverAmt = amount - taxAmount;
// Actually put tokens in our balance
tokensOwned[address(this)] = tokensOwned[address(this)] + taxAmount;
// Tell the chain it happened
emit Transfer(sender, address(this), taxAmount);
}
// Edited so we only emit the Sold and Bought on actual sells/buys. Transfers will not emit these.
if(isSell && taxAmount > 0) {
TokenDividendTracker(dividendTracker).process(gasForProcessing);
emit Sold(sender, amount);
// Sell balance
if(balanceOf(address(this)) > 0) {
doTaxes(balanceOf(address(this)));
}
} else if (!isSell && taxAmount > 0) {
emit Bought(recipient, amount);
}
// Take sender tokens - we do this after doTaxes as if we do it before we mess with the sell swap
tokensOwned[sender] = tokensOwned[sender] - amount;
// Give recipient tokens
tokensOwned[recipient] = tokensOwned[recipient] + receiverAmt;
// Do the dividendtracking
try TokenDividendTracker(dividendTracker).setBalance(payable(sender), tokensOwned[sender]) {} catch {}
try TokenDividendTracker(dividendTracker).setBalance(payable(recipient), tokensOwned[recipient]) {} catch {}
// Emit transfers, because the specs say to
emit Transfer(sender, recipient, receiverAmt);
// Makes things far better tracked
}
function updateGasForProcessing(uint32 newValue) external onlyOwner {
require(newValue >= 200000 && newValue <= 500000, "200,000 < GFP < 500,000");
require(newValue != gasForProcessing, "Same");
gasForProcessing = newValue;
}
function updateClaimWait(uint256 claimWait) external onlyOwner {
TokenDividendTracker(dividendTracker).updateClaimWait(claimWait);
}
function excludeFromDividends(address account) external onlyOwner{
TokenDividendTracker(dividendTracker).excludeFromDividends(account);
}
function processDividendTracker(uint256 gas) external {
TokenDividendTracker(dividendTracker).process(gas);
}
function claim() external {
TokenDividendTracker(dividendTracker).processAccount(payable(msg.sender), false);
}
function calculateTaxesFee(uint256 _amount, uint32 _flAmt) private pure returns (uint256 tax) {
tax = (_amount * _flAmt) / 100000;
}
/// @notice Allows new pairs to be added to the "watcher" code
/// @param pair the address to add as the liquidity pair
function addNewLPPair(address pair) external onlyOwner {
mappedAddresses[pair].isLPPair = true;
lpPairs.push(pair);
}
/// @notice Irreversibly disables blocklist additions after launch has settled.
/// @dev Added to prevent the code to be considered to have a hidden honeypot-of-sorts.
function disableBlocklistAdd() external onlyOwner {
disableAddToBlocklist = true;
}
function isNewLP(address acc) internal view returns (uint8) {
/**
* The process of a LP being created is as follows:
* The router calls a low-level _addLiquidity function
* This function checks if a LP pair exists and if not, creates one
* After that, it checks the ratio and if none, sets to desired, otherwise gets optimal
* The rest doesn't matter
* So our transfer is called after the creation of the contract, meaning we can identify it is a contract
*
*/
if(Address.isContract(acc)) {
/**
* The next step of identifying if this is a LP is to attempt to probe the liquidity pair for its type
* We may not want a v3 liquidity being created, for example, and could revert the transfer
*/
IUniswapV2Pair testPair = IUniswapV2Pair(acc);
try testPair.getReserves() {
return 1;
} catch {
// Not v2 liq
// v3 has "fee()" request
IUniswapV3PoolImmutables test3Pair = IUniswapV3PoolImmutables(acc);
try test3Pair.fee() {
return 2;
} catch {
// Unknown contract type, not v2 or v3
return 0;
}
}
} else {
return 0;
}
}
/// @notice Sets an account exclusion or inclusion from fees.
/// @param account the account to change state on
/// @param isExcluded the boolean to set it to
function setExcludedFromFee(address account, bool isExcluded) external onlyOwner {
mappedAddresses[account]._isExcludedFromFee = isExcluded;
}
/// @notice Sets the buy tax, out of 100000. Only callable by owner. Max of 20000.
/// @param amount the tax out of 100000.
function setBuyTax(uint32 amount) external onlyOwner {
require(amount <= 20000, "SSH: Max 20%.");
buyInfl = amount;
}
/// @notice Sets the sell tax, out of 100000. Only callable by owner. Max of 20000.
/// @param amount the tax out of 100000.
function setSellTax(uint32 amount) external onlyOwner {
require(amount <= 20000, "SSH: Max 20%.");
sellDefl = amount;
}
/// @notice Sets the staking ratio. Only callable by owner.
/// @param amount staking ratio to set
function setStakingRatio(uint16 amount) external onlyOwner {
hexStakingRatio = amount;
}
/// @notice Sets the reward ratio. Only callable by owner.
/// @param amount rward ratio to set
function setRewardRatio(uint16 amount) external onlyOwner {
hexRewardRatio = amount;
}
function setBurnRatio(uint16 amount) external onlyOwner {
burnRatio = amount;
}
/// @notice Changes bot flag. Only callable by owner. Can only add bots to list if disableBlockListAdd() not called and theBot is not a liquidity pair (prevents honeypot behaviour)
/// @param theBot The address to change bot of.
/// @param toSet The value to set.
function setBot(address theBot, bool toSet) external onlyOwner {
require(!mappedAddresses[theBot].isLPPair, "SSH: FORBIDDEN");
if(toSet) {
require(!disableAddToBlocklist, "SSH: DISABLED");
}
mappedAddresses[theBot]._bots = toSet;
}
/// @notice Allows a multi-send to save on gas
/// @param addr array of addresses to send to
/// @param val array of values to go with addresses
function multisend(address[] calldata addr, uint256[] calldata val) external override {
require(addr.length == val.length, "SSH: MISMATCH");
for(uint i = 0; i < addr.length; i++) {
// There's gas savings to be had to do this - we bypass top-level checks
_tokenTransfer(_msgSender(), addr[i], val[i], 0, false);
}
}
/// @notice Allows a multi-send to save on gas on behalf of someone - need approvals
/// @param sender sender to use - must be approved to spend
/// @param addrRecipients array of addresses to send to
/// @param vals array of values to go with addresses
function multisendFrom(address sender, address[] calldata addrRecipients, uint256[] calldata vals) external override {
require(addrRecipients.length == vals.length, "SSH: MISMATCH");
for(uint i = 0; i < addrRecipients.length; i++) {
// More gas savings as we bypass top-level checks - we have to do approval subs tho
_tokenTransfer(sender, addrRecipients[i], vals[i], 0, false);
_approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(vals[i],"ERC20: transfer amount exceeds allowance"));
}
}
function checkBot(address bot) external view returns(bool) {
return mappedAddresses[bot]._bots;
}
/// @notice Returns if an account is excluded from fees.
/// @param account the account to check
function isExcludedFromFee(address account) external view returns (bool) {
return mappedAddresses[account]._isExcludedFromFee;
}
/// @dev debug code to get the LP pairs
function getLPPairs() external view returns (address[] memory lps) {
lps = lpPairs;
}
/** START OF EIP2612/EIP712 FUNCTIONS */
// These need to be here so it can access _approve, lol
/**
* @dev Returns the domain separator for the current chain.
*/
function _domainSeparatorV4() internal view returns (bytes32) {
if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {
return _CACHED_DOMAIN_SEPARATOR;
} else {
return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
}
}
function _buildDomainSeparator(
bytes32 typeHash,
bytes32 nameHash,
bytes32 versionHash
) private view returns (bytes32) {
return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
}
/**
* @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
* function returns the hash of the fully encoded EIP712 message for this domain.
*
* This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
*
* ```solidity
* bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
* keccak256("Mail(address to,string contents)"),
* mailTo,
* keccak256(bytes(mailContents))
* )));
* address signer = ECDSA.recover(digest, signature);
* ```
*/
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
}
// solhint-disable-next-line var-name-mixedcase
bytes32 private constant _PERMIT_TYPEHASH =
keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
/**
* @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`.
* However, to ensure consistency with the upgradeable transpiler, we will continue
* to reserve a slot.
* @custom:oz-renamed-from _PERMIT_TYPEHASH
*/
// solhint-disable-next-line var-name-mixedcase
bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT;
/**
* @dev See {IERC20Permit-permit}.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual override {
require(block.timestamp <= deadline, "ERC20Permit: expired deadline");
bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));
bytes32 hash = _hashTypedDataV4(structHash);
address signer = ECDSA.recover(hash, v, r, s);
require(signer == owner, "ERC20Permit: invalid signature");
_approve(owner, spender, value);
}
/**
* @dev See {IERC20Permit-nonces}.
*/
function nonces(address owner) public view virtual override returns (uint256) {
return _nonces[owner].current();
}
/**
* @dev See {IERC20Permit-DOMAIN_SEPARATOR}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view override returns (bytes32) {
return _domainSeparatorV4();
}
/**
* @dev "Consume a nonce": return the current value and increment.
*
* _Available since v4.1._
*/
function _useNonce(address owner) internal virtual returns (uint256 current) {
Counters.Counter storage nonce = _nonces[owner];
current = nonce.current();
nonce.increment();
}
/** END OF EIP2612/EIP712 FUNCTIONS */
}
@gnosis.pm/safe-contracts/contracts/base/Executor.sol
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
import "../common/Enum.sol";
/// @title Executor - A contract that can execute transactions
/// @author Richard Meissner - <richard@gnosis.pm>
contract Executor {
function execute(
address to,
uint256 value,
bytes memory data,
Enum.Operation operation,
uint256 txGas
) internal returns (bool success) {
if (operation == Enum.Operation.DelegateCall) {
// solhint-disable-next-line no-inline-assembly
assembly {
success := delegatecall(txGas, to, add(data, 0x20), mload(data), 0, 0)
}
} else {
// solhint-disable-next-line no-inline-assembly
assembly {
success := call(txGas, to, value, add(data, 0x20), mload(data), 0, 0)
}
}
}
}
@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router01.sol
pragma solidity >=0.6.2;
interface IUniswapV2Router01 {
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);
}
@openzeppelin/contracts/utils/Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
/**
* @dev String operations.
*/
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 `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);
}
}
@gnosis.pm/safe-contracts/contracts/base/GuardManager.sol
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
import "../common/Enum.sol";
import "../common/SelfAuthorized.sol";
interface Guard {
function checkTransaction(
address to,
uint256 value,
bytes memory data,
Enum.Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address payable refundReceiver,
bytes memory signatures,
address msgSender
) external;
function checkAfterExecution(bytes32 txHash, bool success) external;
}
/// @title Fallback Manager - A contract that manages fallback calls made to this contract
/// @author Richard Meissner - <richard@gnosis.pm>
contract GuardManager is SelfAuthorized {
event ChangedGuard(address guard);
// keccak256("guard_manager.guard.address")
bytes32 internal constant GUARD_STORAGE_SLOT = 0x4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c8;
/// @dev Set a guard that checks transactions before execution
/// @param guard The address of the guard to be used or the 0 address to disable the guard
function setGuard(address guard) external authorized {
bytes32 slot = GUARD_STORAGE_SLOT;
// solhint-disable-next-line no-inline-assembly
assembly {
sstore(slot, guard)
}
emit ChangedGuard(guard);
}
function getGuard() internal view returns (address guard) {
bytes32 slot = GUARD_STORAGE_SLOT;
// solhint-disable-next-line no-inline-assembly
assembly {
guard := sload(slot)
}
}
}
@openzeppelin/contracts/utils/Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
contracts/IMultisend.sol
/**
* A Multisend interface
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.8.15;
interface IMultisend {
/// @notice Allows a multi-send to save on gas
/// @param addr array of addresses to send to
/// @param val array of values to go with addresses
function multisend(address[] calldata addr, uint256[] calldata val) external;
/// @notice Allows a multi-send to save on gas on behalf of someone - need approvals
/// @param sender sender to use - must be approved to spend
/// @param addrRecipients array of addresses to send to
/// @param vals array of values to go with addresses
function multisendFrom(address sender, address[] calldata addrRecipients, uint256[] calldata vals) external;
}
@gnosis.pm/safe-contracts/contracts/base/ModuleManager.sol
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
import "../common/Enum.sol";
import "../common/SelfAuthorized.sol";
import "./Executor.sol";
/// @title Module Manager - A contract that manages modules that can execute transactions via this contract
/// @author Stefan George - <stefan@gnosis.pm>
/// @author Richard Meissner - <richard@gnosis.pm>
contract ModuleManager is SelfAuthorized, Executor {
event EnabledModule(address module);
event DisabledModule(address module);
event ExecutionFromModuleSuccess(address indexed module);
event ExecutionFromModuleFailure(address indexed module);
address internal constant SENTINEL_MODULES = address(0x1);
mapping(address => address) internal modules;
function setupModules(address to, bytes memory data) internal {
require(modules[SENTINEL_MODULES] == address(0), "GS100");
modules[SENTINEL_MODULES] = SENTINEL_MODULES;
if (to != address(0))
// Setup has to complete successfully or transaction fails.
require(execute(to, 0, data, Enum.Operation.DelegateCall, gasleft()), "GS000");
}
/// @dev Allows to add a module to the whitelist.
/// This can only be done via a Safe transaction.
/// @notice Enables the module `module` for the Safe.
/// @param module Module to be whitelisted.
function enableModule(address module) public authorized {
// Module address cannot be null or sentinel.
require(module != address(0) && module != SENTINEL_MODULES, "GS101");
// Module cannot be added twice.
require(modules[module] == address(0), "GS102");
modules[module] = modules[SENTINEL_MODULES];
modules[SENTINEL_MODULES] = module;
emit EnabledModule(module);
}
/// @dev Allows to remove a module from the whitelist.
/// This can only be done via a Safe transaction.
/// @notice Disables the module `module` for the Safe.
/// @param prevModule Module that pointed to the module to be removed in the linked list
/// @param module Module to be removed.
function disableModule(address prevModule, address module) public authorized {
// Validate module address and check that it corresponds to module index.
require(module != address(0) && module != SENTINEL_MODULES, "GS101");
require(modules[prevModule] == module, "GS103");
modules[prevModule] = modules[module];
modules[module] = address(0);
emit DisabledModule(module);
}
/// @dev Allows a Module to execute a Safe transaction without any further confirmations.
/// @param to Destination address of module transaction.
/// @param value Ether value of module transaction.
/// @param data Data payload of module transaction.
/// @param operation Operation type of module transaction.
function execTransactionFromModule(
address to,
uint256 value,
bytes memory data,
Enum.Operation operation
) public virtual returns (bool success) {
// Only whitelisted modules are allowed.
require(msg.sender != SENTINEL_MODULES && modules[msg.sender] != address(0), "GS104");
// Execute transaction without further confirmations.
success = execute(to, value, data, operation, gasleft());
if (success) emit ExecutionFromModuleSuccess(msg.sender);
else emit ExecutionFromModuleFailure(msg.sender);
}
/// @dev Allows a Module to execute a Safe transaction without any further confirmations and return data
/// @param to Destination address of module transaction.
/// @param value Ether value of module transaction.
/// @param data Data payload of module transaction.
/// @param operation Operation type of module transaction.
function execTransactionFromModuleReturnData(
address to,
uint256 value,
bytes memory data,
Enum.Operation operation
) public returns (bool success, bytes memory returnData) {
success = execTransactionFromModule(to, value, data, operation);
// solhint-disable-next-line no-inline-assembly
assembly {
// Load free memory location
let ptr := mload(0x40)
// We allocate memory for the return data by setting the free memory location to
// current free memory location + data size + 32 bytes for data size value
mstore(0x40, add(ptr, add(returndatasize(), 0x20)))
// Store the size
mstore(ptr, returndatasize())
// Store the data
returndatacopy(add(ptr, 0x20), 0, returndatasize())
// Point the return data to the correct memory location
returnData := ptr
}
}
/// @dev Returns if an module is enabled
/// @return True if the module is enabled
function isModuleEnabled(address module) public view returns (bool) {
return SENTINEL_MODULES != module && modules[module] != address(0);
}
/// @dev Returns array of modules.
/// @param start Start of the page.
/// @param pageSize Maximum number of modules that should be returned.
/// @return array Array of modules.
/// @return next Start of the next page.
function getModulesPaginated(address start, uint256 pageSize) external view returns (address[] memory array, address next) {
// Init array with max page size
array = new address[](pageSize);
// Populate return array
uint256 moduleCount = 0;
address currentModule = modules[start];
while (currentModule != address(0x0) && currentModule != SENTINEL_MODULES && moduleCount < pageSize) {
array[moduleCount] = currentModule;
currentModule = modules[currentModule];
moduleCount++;
}
next = currentModule;
// Set correct size of returned array
// solhint-disable-next-line no-inline-assembly
assembly {
mstore(array, moduleCount)
}
}
}
contracts/DPT/TokenDividendTracker.sol
import "./DividendPayingToken.sol";
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.15;
contract TokenDividendTracker is Ownable, DividendPayingToken {
using SafeMath for uint256;
using SafeMathInt for int256;
struct MAP {
address[] keys;
mapping(address => uint) values;
mapping(address => uint) indexOf;
mapping(address => bool) inserted;
}
MAP private tokenHoldersMap;
uint256 public lastProcessedIndex;
mapping(address => bool) public excludedFromDividends;
mapping(address => uint256) public lastClaimTimes;
uint256 public claimWait;
uint256 public minimumTokenBalanceForDividends;
event ExcludeFromDividends(address indexed account);
event ClaimWaitUpdated(uint256 indexed newValue, uint256 indexed oldValue);
event Claim(
address indexed account,
uint256 amount,
bool indexed automatic
);
constructor(
address _rewardTokenAddress,
uint256 _minimumTokenBalanceForDividends
)
DividendPayingToken(
_rewardTokenAddress
)
{
claimWait = 3600;
minimumTokenBalanceForDividends = _minimumTokenBalanceForDividends;
}
function _transfer(
address,
address,
uint256
) internal pure override {
require(false, "DT: FORBIDDEN");
}
function withdrawDividend() public pure override {
require(
false,
"DT: CLAIM."
);
}
function setMinimumTokenBalanceForDividends(uint256 val)
external
onlyOwner
{
minimumTokenBalanceForDividends = val;
}
function excludeFromDividends(address account) external onlyOwner {
require(!excludedFromDividends[account]);
excludedFromDividends[account] = true;
_setBalance(account, 0);
MAPRemove(account);
emit ExcludeFromDividends(account);
}
function updateClaimWait(uint256 newClaimWait) external onlyOwner {
require(
newClaimWait >= 3600 && newClaimWait <= 86400,
"DT: 1 < claimWait < 24"
);
require(
newClaimWait != claimWait,
"DT: Same"
);
emit ClaimWaitUpdated(newClaimWait, claimWait);
claimWait = newClaimWait;
}
function getLastProcessedIndex() external view returns (uint256) {
return lastProcessedIndex;
}
function getNumberOfTokenHolders() external view returns (uint256) {
return tokenHoldersMap.keys.length;
}
function isExcludedFromDividends(address account)
public
view
returns (bool)
{
return excludedFromDividends[account];
}
function getAccount(address _account)
public
view
returns (
address account,
int256 index,
int256 iterationsUntilProcessed,
uint256 withdrawableDividends,
uint256 totalDividends,
uint256 lastClaimTime,
uint256 nextClaimTime,
uint256 secondsUntilAutoClaimAvailable
)
{
account = _account;
index = MAPGetIndexOfKey(account);
iterationsUntilProcessed = -1;
if (index >= 0) {
if (uint256(index) > lastProcessedIndex) {
iterationsUntilProcessed = index.sub(
int256(lastProcessedIndex)
);
} else {
uint256 processesUntilEndOfArray = tokenHoldersMap.keys.length >
lastProcessedIndex
? tokenHoldersMap.keys.length.sub(lastProcessedIndex)
: 0;
iterationsUntilProcessed = index.add(
int256(processesUntilEndOfArray)
);
}
}
withdrawableDividends = withdrawableDividendOf(account);
totalDividends = accumulativeDividendOf(account);
lastClaimTime = lastClaimTimes[account];
nextClaimTime = lastClaimTime > 0 ? lastClaimTime.add(claimWait) : 0;
secondsUntilAutoClaimAvailable = nextClaimTime > block.timestamp
? nextClaimTime.sub(block.timestamp)
: 0;
}
function getAccountAtIndex(uint256 index)
public
view
returns (
address,
int256,
int256,
uint256,
uint256,
uint256,
uint256,
uint256
)
{
if (index >= MAPSize()) {
return (
0x0000000000000000000000000000000000000000,
-1,
-1,
0,
0,
0,
0,
0
);
}
address account = MAPGetKeyAtIndex(index);
return getAccount(account);
}
function canAutoClaim(uint256 lastClaimTime) private view returns (bool) {
if (lastClaimTime > block.timestamp) {
return false;
}
return block.timestamp.sub(lastClaimTime) >= claimWait;
}
function setBalance(address payable account, uint256 newBalance)
external
onlyOwner
{
if (excludedFromDividends[account]) {
return;
}
if (newBalance >= minimumTokenBalanceForDividends) {
_setBalance(account, newBalance);
MAPSet(account, newBalance);
} else {
_setBalance(account, 0);
MAPRemove(account);
}
processAccount(account, true);
}
function process(uint256 gas)
public
returns (
uint256,
uint256,
uint256
)
{
uint256 numberOfTokenHolders = tokenHoldersMap.keys.length;
if (numberOfTokenHolders == 0) {
return (0, 0, lastProcessedIndex);
}
uint256 _lastProcessedIndex = lastProcessedIndex;
uint256 gasUsed = 0;
uint256 gasLeft = gasleft();
uint256 iterations = 0;
uint256 claims = 0;
while (gasUsed < gas && iterations < numberOfTokenHolders) {
_lastProcessedIndex++;
if (_lastProcessedIndex >= tokenHoldersMap.keys.length) {
_lastProcessedIndex = 0;
}
address account = tokenHoldersMap.keys[_lastProcessedIndex];
if (canAutoClaim(lastClaimTimes[account])) {
if (processAccount(payable(account), true)) {
claims++;
}
}
iterations++;
uint256 newGasLeft = gasleft();
if (gasLeft > newGasLeft) {
gasUsed = gasUsed.add(gasLeft.sub(newGasLeft));
}
gasLeft = newGasLeft;
}
lastProcessedIndex = _lastProcessedIndex;
return (iterations, claims, lastProcessedIndex);
}
function processAccount(address payable account, bool automatic)
public
onlyOwner
returns (bool)
{
uint256 amount = _withdrawDividendOfUser(account);
if (amount > 0) {
lastClaimTimes[account] = block.timestamp;
emit Claim(account, amount, automatic);
return true;
}
return false;
}
function MAPGet(address key) public view returns (uint) {
return tokenHoldersMap.values[key];
}
function MAPGetIndexOfKey(address key) public view returns (int) {
if (!tokenHoldersMap.inserted[key]) {
return -1;
}
return int(tokenHoldersMap.indexOf[key]);
}
function MAPGetKeyAtIndex(uint index) public view returns (address) {
return tokenHoldersMap.keys[index];
}
function MAPSize() public view returns (uint) {
return tokenHoldersMap.keys.length;
}
function MAPSet(address key, uint val) internal {
if (tokenHoldersMap.inserted[key]) {
tokenHoldersMap.values[key] = val;
} else {
tokenHoldersMap.inserted[key] = true;
tokenHoldersMap.values[key] = val;
tokenHoldersMap.indexOf[key] = tokenHoldersMap.keys.length;
tokenHoldersMap.keys.push(key);
}
}
function MAPRemove(address key) internal {
if (!tokenHoldersMap.inserted[key]) {
return;
}
delete tokenHoldersMap.inserted[key];
delete tokenHoldersMap.values[key];
uint index = tokenHoldersMap.indexOf[key];
uint lastIndex = tokenHoldersMap.keys.length - 1;
address lastKey = tokenHoldersMap.keys[lastIndex];
tokenHoldersMap.indexOf[lastKey] = index;
delete tokenHoldersMap.indexOf[key];
tokenHoldersMap.keys[index] = lastKey;
tokenHoldersMap.keys.pop();
}
function distributeDividends() external payable override {}
}
contracts/DPT/math/SafeMathInt.sol
pragma solidity ^0.8.15;
// SPDX-License-Identifier: UNLICENSED
/**
* @title SafeMathInt
* @dev Math operations with safety checks that revert on error
* @dev SafeMath adapted for int256
* Based on code of https://github.com/RequestNetwork/requestNetwork/blob/master/packages/requestNetworkSmartContracts/contracts/base/math/SafeMathInt.sol
*/
library SafeMathInt {
function mul(int256 a, int256 b) internal pure returns (int256) {
// Prevent overflow when multiplying INT256_MIN with -1
// https://github.com/RequestNetwork/requestNetwork/issues/43
require(!(a == - 2**255 && b == -1) && !(b == - 2**255 && a == -1));
int256 c = a * b;
require((b == 0) || (c / b == a));
return c;
}
function div(int256 a, int256 b) internal pure returns (int256) {
// Prevent overflow when dividing INT256_MIN by -1
// https://github.com/RequestNetwork/requestNetwork/issues/43
require(!(a == - 2**255 && b == -1) && (b > 0));
return a / b;
}
function sub(int256 a, int256 b) internal pure returns (int256) {
require((b >= 0 && a - b <= a) || (b < 0 && a - b > a));
return a - b;
}
function add(int256 a, int256 b) internal pure returns (int256) {
int256 c = a + b;
require((b >= 0 && c >= a) || (b < 0 && c < a));
return c;
}
function toUint256Safe(int256 a) internal pure returns (uint256) {
require(a >= 0);
return uint256(a);
}
}
@gnosis.pm/safe-contracts/contracts/common/Singleton.sol
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
/// @title Singleton - Base for singleton contracts (should always be first super contract)
/// This contract is tightly coupled to our proxy contract (see `proxies/GnosisSafeProxy.sol`)
/// @author Richard Meissner - <richard@gnosis.io>
contract Singleton {
// singleton always needs to be first declared variable, to ensure that it is at the same location as in the Proxy contract.
// It should also always be ensured that the address is stored alone (uses a full word)
address private singleton;
}
@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol
pragma solidity >=0.6.2;
import './IUniswapV2Router01.sol';
interface IUniswapV2Router02 is IUniswapV2Router01 {
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;
}
contracts/DPT/DividendPayingTokenOptionalInterface.sol
pragma solidity ^0.8.15;
// SPDX-License-Identifier: UNLICENSED
/// @title Dividend-Paying Token Optional Interface
/// @author Roger Wu (https://github.com/roger-wu)
/// @dev OPTIONAL functions for a dividend-paying token contract.
interface DividendPayingTokenOptionalInterface {
/// @notice View the amount of dividend in wei that an address can withdraw.
/// @param _owner The address of a token holder.
/// @return The amount of dividend in wei that `_owner` can withdraw.
function withdrawableDividendOf(address _owner) external view returns(uint256);
/// @notice View the amount of dividend in wei that an address has withdrawn.
/// @param _owner The address of a token holder.
/// @return The amount of dividend in wei that `_owner` has withdrawn.
function withdrawnDividendOf(address _owner) external view returns(uint256);
/// @notice View the amount of dividend in wei that an address has earned in total.
/// @dev accumulativeDividendOf(_owner) = withdrawableDividendOf(_owner) + withdrawnDividendOf(_owner)
/// @param _owner The address of a token holder.
/// @return The amount of dividend in wei that `_owner` has earned in total.
function accumulativeDividendOf(address _owner) external view returns(uint256);
}
@openzeppelin/contracts/utils/cryptography/ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../Strings.sol";
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV // Deprecated in v4.8
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/
function recover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}
@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol
pragma solidity >=0.5.0;
interface IUniswapV2Factory {
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;
}
contracts/IHex.sol
/**
* Hex token interface
* Isn't Hex itself, only allows us to interface.
* SPDX-License-Identifier: BSD-3-Clause
*/
pragma solidity ^0.8.15;
interface IHex {
event StakeStart(
uint256 data0,
address indexed stakerAddr,
uint40 indexed stakeId
);
event StakeGoodAccounting(
uint256 data0,
uint256 data1,
address indexed stakerAddr,
uint40 indexed stakeId,
address indexed senderAddr
);
event StakeEnd(
uint256 data0,
uint256 data1,
address indexed stakerAddr,
uint40 indexed stakeId
);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function stakeLists(address, uint256) view external returns(uint40 stakeId, uint72 stakedHearts, uint72 stakeShares, uint16 lockedDay, uint16 stakedDays, uint16 unlockedDay, bool isAutoStake);
/**
* @dev PUBLIC FACING: Optionally update daily data for a smaller
* range to reduce gas cost for a subsequent operation
* @param beforeDay Only update days before this day number (optional; 0 for current day)
*/
function dailyDataUpdate(uint256 beforeDay) external;
/**
* @dev PUBLIC FACING: External helper to return multiple values of daily data with
* a single call. Ugly implementation due to limitations of the standard ABI encoder.
* @param beginDay First day of data range
* @param endDay Last day (non-inclusive) of data range
* @return list Fixed array of packed values
*/
function dailyDataRange(uint256 beginDay, uint256 endDay) external view returns (uint256[] memory list);
/**
* @dev PUBLIC FACING: External helper to return most global info with a single call.
* Ugly implementation due to limitations of the standard ABI encoder.
* @return Fixed array of values
*/
function globalInfo() external view returns (uint256[13] memory);
/**
* @dev PUBLIC FACING: External helper for the current day number since launch time
* @return Current day number (zero-based)
*/
function currentDay() external view returns (uint256);
/**
* @dev PUBLIC FACING: Open a stake.
* @param newStakedHearts Number of Hearts to stake
* @param newStakedDays Number of days to stake
*/
function stakeStart(uint256 newStakedHearts, uint256 newStakedDays) external;
/**
* @dev PUBLIC FACING: Unlocks a completed stake, distributing the proceeds of any penalty
* immediately. The staker must still call stakeEnd() to retrieve their stake return (if any).
* @param stakerAddr Address of staker
* @param stakeIndex Index of stake within stake list
* @param stakeIdParam The stake's id
*/
function stakeGoodAccounting(address stakerAddr, uint256 stakeIndex, uint40 stakeIdParam) external;
/**
* @dev PUBLIC FACING: Closes a stake. The order of the stake list can change so
* a stake id is used to reject stale indexes.
* @param stakeIndex Index of stake within stake list
* @param stakeIdParam The stake's id
*/
function stakeEnd(uint256 stakeIndex, uint40 stakeIdParam) external;
/**
* @dev PUBLIC FACING: Return the current stake count for a staker address
* @param stakerAddr Address of staker
*/
function stakeCount(address stakerAddr) external view returns (uint256);
}
@gnosis.pm/safe-contracts/contracts/base/OwnerManager.sol
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
import "../common/SelfAuthorized.sol";
/// @title OwnerManager - Manages a set of owners and a threshold to perform actions.
/// @author Stefan George - <stefan@gnosis.pm>
/// @author Richard Meissner - <richard@gnosis.pm>
contract OwnerManager is SelfAuthorized {
event AddedOwner(address owner);
event RemovedOwner(address owner);
event ChangedThreshold(uint256 threshold);
address internal constant SENTINEL_OWNERS = address(0x1);
mapping(address => address) internal owners;
uint256 internal ownerCount;
uint256 internal threshold;
/// @dev Setup function sets initial storage of contract.
/// @param _owners List of Safe owners.
/// @param _threshold Number of required confirmations for a Safe transaction.
function setupOwners(address[] memory _owners, uint256 _threshold) internal {
// Threshold can only be 0 at initialization.
// Check ensures that setup function can only be called once.
require(threshold == 0, "GS200");
// Validate that threshold is smaller than number of added owners.
require(_threshold <= _owners.length, "GS201");
// There has to be at least one Safe owner.
require(_threshold >= 1, "GS202");
// Initializing Safe owners.
address currentOwner = SENTINEL_OWNERS;
for (uint256 i = 0; i < _owners.length; i++) {
// Owner address cannot be null.
address owner = _owners[i];
require(owner != address(0) && owner != SENTINEL_OWNERS && owner != address(this) && currentOwner != owner, "GS203");
// No duplicate owners allowed.
require(owners[owner] == address(0), "GS204");
owners[currentOwner] = owner;
currentOwner = owner;
}
owners[currentOwner] = SENTINEL_OWNERS;
ownerCount = _owners.length;
threshold = _threshold;
}
/// @dev Allows to add a new owner to the Safe and update the threshold at the same time.
/// This can only be done via a Safe transaction.
/// @notice Adds the owner `owner` to the Safe and updates the threshold to `_threshold`.
/// @param owner New owner address.
/// @param _threshold New threshold.
function addOwnerWithThreshold(address owner, uint256 _threshold) public authorized {
// Owner address cannot be null, the sentinel or the Safe itself.
require(owner != address(0) && owner != SENTINEL_OWNERS && owner != address(this), "GS203");
// No duplicate owners allowed.
require(owners[owner] == address(0), "GS204");
owners[owner] = owners[SENTINEL_OWNERS];
owners[SENTINEL_OWNERS] = owner;
ownerCount++;
emit AddedOwner(owner);
// Change threshold if threshold was changed.
if (threshold != _threshold) changeThreshold(_threshold);
}
/// @dev Allows to remove an owner from the Safe and update the threshold at the same time.
/// This can only be done via a Safe transaction.
/// @notice Removes the owner `owner` from the Safe and updates the threshold to `_threshold`.
/// @param prevOwner Owner that pointed to the owner to be removed in the linked list
/// @param owner Owner address to be removed.
/// @param _threshold New threshold.
function removeOwner(
address prevOwner,
address owner,
uint256 _threshold
) public authorized {
// Only allow to remove an owner, if threshold can still be reached.
require(ownerCount - 1 >= _threshold, "GS201");
// Validate owner address and check that it corresponds to owner index.
require(owner != address(0) && owner != SENTINEL_OWNERS, "GS203");
require(owners[prevOwner] == owner, "GS205");
owners[prevOwner] = owners[owner];
owners[owner] = address(0);
ownerCount--;
emit RemovedOwner(owner);
// Change threshold if threshold was changed.
if (threshold != _threshold) changeThreshold(_threshold);
}
/// @dev Allows to swap/replace an owner from the Safe with another address.
/// This can only be done via a Safe transaction.
/// @notice Replaces the owner `oldOwner` in the Safe with `newOwner`.
/// @param prevOwner Owner that pointed to the owner to be replaced in the linked list
/// @param oldOwner Owner address to be replaced.
/// @param newOwner New owner address.
function swapOwner(
address prevOwner,
address oldOwner,
address newOwner
) public authorized {
// Owner address cannot be null, the sentinel or the Safe itself.
require(newOwner != address(0) && newOwner != SENTINEL_OWNERS && newOwner != address(this), "GS203");
// No duplicate owners allowed.
require(owners[newOwner] == address(0), "GS204");
// Validate oldOwner address and check that it corresponds to owner index.
require(oldOwner != address(0) && oldOwner != SENTINEL_OWNERS, "GS203");
require(owners[prevOwner] == oldOwner, "GS205");
owners[newOwner] = owners[oldOwner];
owners[prevOwner] = newOwner;
owners[oldOwner] = address(0);
emit RemovedOwner(oldOwner);
emit AddedOwner(newOwner);
}
/// @dev Allows to update the number of required confirmations by Safe owners.
/// This can only be done via a Safe transaction.
/// @notice Changes the threshold of the Safe to `_threshold`.
/// @param _threshold New threshold.
function changeThreshold(uint256 _threshold) public authorized {
// Validate that threshold is smaller than number of owners.
require(_threshold <= ownerCount, "GS201");
// There has to be at least one Safe owner.
require(_threshold >= 1, "GS202");
threshold = _threshold;
emit ChangedThreshold(threshold);
}
function getThreshold() public view returns (uint256) {
return threshold;
}
function isOwner(address owner) public view returns (bool) {
return owner != SENTINEL_OWNERS && owners[owner] != address(0);
}
/// @dev Returns array of owners.
/// @return Array of Safe owners.
function getOwners() public view returns (address[] memory) {
address[] memory array = new address[](ownerCount);
// populate return array
uint256 index = 0;
address currentOwner = owners[SENTINEL_OWNERS];
while (currentOwner != SENTINEL_OWNERS) {
array[index] = currentOwner;
currentOwner = owners[currentOwner];
index++;
}
return array;
}
}
@gnosis.pm/safe-contracts/contracts/common/SelfAuthorized.sol
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
/// @title SelfAuthorized - authorizes current contract to perform actions
/// @author Richard Meissner - <richard@gnosis.pm>
contract SelfAuthorized {
function requireSelfCall() private view {
require(msg.sender == address(this), "GS031");
}
modifier authorized() {
// This is a function call as it minimized the bytecode size
requireSelfCall();
_;
}
}
@gnosis.pm/safe-contracts/contracts/common/Enum.sol
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
/// @title Enum - Collection of enums
/// @author Richard Meissner - <richard@gnosis.pm>
contract Enum {
enum Operation {Call, DelegateCall}
}
@gnosis.pm/safe-contracts/contracts/base/FallbackManager.sol
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
import "../common/SelfAuthorized.sol";
/// @title Fallback Manager - A contract that manages fallback calls made to this contract
/// @author Richard Meissner - <richard@gnosis.pm>
contract FallbackManager is SelfAuthorized {
event ChangedFallbackHandler(address handler);
// keccak256("fallback_manager.handler.address")
bytes32 internal constant FALLBACK_HANDLER_STORAGE_SLOT = 0x6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d5;
function internalSetFallbackHandler(address handler) internal {
bytes32 slot = FALLBACK_HANDLER_STORAGE_SLOT;
// solhint-disable-next-line no-inline-assembly
assembly {
sstore(slot, handler)
}
}
/// @dev Allows to add a contract to handle fallback calls.
/// Only fallback calls without value and with data will be forwarded.
/// This can only be done via a Safe transaction.
/// @param handler contract to handle fallbacks calls.
function setFallbackHandler(address handler) public authorized {
internalSetFallbackHandler(handler);
emit ChangedFallbackHandler(handler);
}
// solhint-disable-next-line payable-fallback,no-complex-fallback
fallback() external {
bytes32 slot = FALLBACK_HANDLER_STORAGE_SLOT;
// solhint-disable-next-line no-inline-assembly
assembly {
let handler := sload(slot)
if iszero(handler) {
return(0, 0)
}
calldatacopy(0, 0, calldatasize())
// The msg.sender address is shifted to the left by 12 bytes to remove the padding
// Then the address without padding is stored right after the calldata
mstore(calldatasize(), shl(96, caller()))
// Add 20 bytes for the address appended add the end
let success := call(gas(), handler, 0, 0, add(calldatasize(), 20), 0, 0)
returndatacopy(0, 0, returndatasize())
if iszero(success) {
revert(0, returndatasize())
}
return(0, returndatasize())
}
}
}
@gnosis.pm/safe-contracts/contracts/common/SecuredTokenTransfer.sol
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
/// @title SecuredTokenTransfer - Secure token transfer
/// @author Richard Meissner - <richard@gnosis.pm>
contract SecuredTokenTransfer {
/// @dev Transfers a token and returns if it was a success
/// @param token Token that should be transferred
/// @param receiver Receiver to whom the token should be transferred
/// @param amount The amount of tokens that should be transferred
function transferToken(
address token,
address receiver,
uint256 amount
) internal returns (bool transferred) {
// 0xa9059cbb - keccack("transfer(address,uint256)")
bytes memory data = abi.encodeWithSelector(0xa9059cbb, receiver, amount);
// solhint-disable-next-line no-inline-assembly
assembly {
// We write the return value to scratch space.
// See https://docs.soliditylang.org/en/v0.7.6/internals/layout_in_memory.html#layout-in-memory
let success := call(sub(gas(), 10000), token, 0, add(data, 0x20), mload(data), 0, 0x20)
switch returndatasize()
case 0 {
transferred := success
}
case 0x20 {
transferred := iszero(or(iszero(success), iszero(mload(0))))
}
default {
transferred := 0
}
}
}
}
@gnosis.pm/safe-contracts/contracts/common/StorageAccessible.sol
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
/// @title StorageAccessible - generic base contract that allows callers to access all internal storage.
/// @notice See https://github.com/gnosis/util-contracts/blob/bb5fe5fb5df6d8400998094fb1b32a178a47c3a1/contracts/StorageAccessible.sol
contract StorageAccessible {
/**
* @dev Reads `length` bytes of storage in the currents contract
* @param offset - the offset in the current contract's storage in words to start reading from
* @param length - the number of words (32 bytes) of data to read
* @return the bytes that were read.
*/
function getStorageAt(uint256 offset, uint256 length) public view returns (bytes memory) {
bytes memory result = new bytes(length * 32);
for (uint256 index = 0; index < length; index++) {
// solhint-disable-next-line no-inline-assembly
assembly {
let word := sload(add(offset, index))
mstore(add(add(result, 0x20), mul(index, 0x20)), word)
}
}
return result;
}
/**
* @dev Performs a delegetecall on a targetContract in the context of self.
* Internally reverts execution to avoid side effects (making it static).
*
* This method reverts with data equal to `abi.encode(bool(success), bytes(response))`.
* Specifically, the `returndata` after a call to this method will be:
* `success:bool || response.length:uint256 || response:bytes`.
*
* @param targetContract Address of the contract containing the code to execute.
* @param calldataPayload Calldata that should be sent to the target contract (encoded method name and arguments).
*/
function simulateAndRevert(address targetContract, bytes memory calldataPayload) external {
// solhint-disable-next-line no-inline-assembly
assembly {
let success := delegatecall(gas(), targetContract, add(calldataPayload, 0x20), mload(calldataPayload), 0, 0)
mstore(0x00, success)
mstore(0x20, returndatasize())
returndatacopy(0x40, 0, returndatasize())
revert(0, add(returndatasize(), 0x40))
}
}
}
contracts/SuperStakeImpl.sol
/**
* SimpleStakingImpl
* Handles staking, unstaking, collecting rewards and re-staking Hex
* Holds the Hex pending staking in itself
*/
pragma solidity ^0.8.15;
import "@openzeppelin/contracts/access/Ownable.sol";
import "./IHex.sol";
//import "./IHedron.sol";
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import "./DPT/TokenDividendTracker.sol";
contract SuperStakeImpl is Ownable {
event StakingDisengaged();
// Block of 256 bits
address public token;
uint32 public stakingDays;
uint64 public lastStakedStart;
// Closed
// Block of 256 bits
address public dividendTracker;
bool public stakeDisengaged = false;
// Closed
address public router;
uint64 public launchTime;
constructor(
address stakingToken,
uint32 daysToStake,
address dividendTrackerToken,
address rtr
) {
token = stakingToken;
stakingDays = daysToStake;
lastStakedStart = uint64(IHex(token).currentDay());
dividendTracker = dividendTrackerToken;
router = rtr;
launchTime = uint64(block.timestamp) + 86400;
}
// Backup function to move the staking pool if needed
function adjustDivTracker(address newAddr) external onlyOwner {
dividendTracker = newAddr;
}
/// @notice Disengages the stake functionality, keeping tokens in the contract. This is a fail-safe to allow withdrawal of tokens. Can only be called by the parent contract.
function disengageRestake() external onlyOwner {
emit StakingDisengaged();
stakeDisengaged = true;
}
/// @notice Withdraws to-be-staked tokens. This is a failsafe to allow safe withdrawal of tokens. Can only be called by the parent contract.
function withdrawTokens(address recipient) external onlyOwner {
IHex stakingContract = IHex(token);
uint256 withdrawAmt = stakingContract.balanceOf(address(this));
stakingContract.transfer(recipient, withdrawAmt);
}
function afterReceivedHex() external onlyOwner {
// Called after Hex has been received
// We only ever have one stake in the list, but we get stakeCount anyway
IHex stakingContract = IHex(token);
// We check if there's a stake to resolve
uint256 stakeNumber = stakingContract.stakeCount(address(this));
if (stakeNumber > 0) {
// Something was staked last time so it's time to unstake it
// Unstake all of the stakes present, if there's more than one (there shouldn't be, but we have to assume)
uint256 currentDay = stakingContract.currentDay();
// Total stake output to accumulate
uint256 stakeRewards = 0;
for (uint i = 0; i < stakeNumber; i++) {
// Get the pre-unlock balance of tokens
uint256 oldBal = stakingContract.balanceOf(address(this));
// Grab the stakeId from the stakeLists
(uint40 stakeId, , , uint16 lockedDay, uint16 stakedDays, , ) = stakingContract.stakeLists(
address(this),
i
);
// If this is true, the stake is ready for unlock
if(currentDay >= lockedDay + stakedDays) {
// Run the "good" stake unlocker to not be penalised
stakingContract.stakeGoodAccounting(address(this), i, stakeId);
// Get the tokens back
stakingContract.stakeEnd(i, stakeId);
// Accumulate the stake rewards
stakeRewards = stakeRewards + (stakingContract.balanceOf(address(this)) - oldBal);
}
}
if(stakeRewards > 0) {
// Pay out 1% of the stake output to the dividend tracker
stakingContract.transfer(dividendTracker, stakeRewards / 100);
// Tell it there's some tokens to calculate
TokenDividendTracker(dividendTracker).afterReceivedHex(stakeRewards / 100);
// Now need to restake our holdings
if(!stakeDisengaged) {
uint256 stakeAmt = stakingContract.balanceOf(address(this));
stakingContract.stakeStart(stakeAmt, stakingDays);
}
}
} else {
// Give a day to fill pool
if(block.timestamp > launchTime && !stakeDisengaged) {
uint256 stakeAmt = stakingContract.balanceOf(address(this));
stakingContract.stakeStart(stakeAmt, stakingDays);
}
}
}
}
@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol
pragma solidity >=0.5.0;
interface IUniswapV2Pair {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
function transfer(address to, uint value) external returns (bool);
function transferFrom(address from, address to, uint value) external returns (bool);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint);
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
event Mint(address indexed sender, uint amount0, uint amount1);
event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
event Swap(
address indexed sender,
uint amount0In,
uint amount1In,
uint amount0Out,
uint amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function price0CumulativeLast() external view returns (uint);
function price1CumulativeLast() external view returns (uint);
function kLast() external view returns (uint);
function mint(address to) external returns (uint liquidity);
function burn(address to) external returns (uint amount0, uint amount1);
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
function skim(address to) external;
function sync() external;
function initialize(address, address) external;
}
contracts/DPT/DividendPayingTokenInterface.sol
pragma solidity ^0.8.15;
// SPDX-License-Identifier: UNLICENSED
/// @title Dividend-Paying Token Interface
/// @author Roger Wu (https://github.com/roger-wu)
/// @dev An interface for a dividend-paying token contract.
interface DividendPayingTokenInterface {
/// @notice View the amount of dividend in wei that an address can withdraw.
/// @param _owner The address of a token holder.
/// @return The amount of dividend in wei that `_owner` can withdraw.
function dividendOf(address _owner) external view returns(uint256);
/// @notice Distributes ether to token holders as dividends.
/// @dev SHOULD distribute the paid ether to token holders as dividends.
/// SHOULD NOT directly transfer ether to token holders in this function.
/// MUST emit a `DividendsDistributed` event when the amount of distributed ether is greater than 0.
function distributeDividends() external payable;
/// @notice Withdraws the ether distributed to the sender.
/// @dev SHOULD transfer `dividendOf(msg.sender)` wei to `msg.sender`, and `dividendOf(msg.sender)` SHOULD be 0 after the transfer.
/// MUST emit a `DividendWithdrawn` event if the amount of ether transferred is greater than 0.
function withdrawDividend() external;
/// @dev This event MUST emit when ether is distributed to token holders.
/// @param from The address which sends ether to this contract.
/// @param weiAmount The amount of distributed ether in wei.
event DividendsDistributed(
address indexed from,
uint256 weiAmount
);
/// @dev This event MUST emit when an address withdraws their dividend.
/// @param to The address which withdraws ether from this contract.
/// @param weiAmount The amount of withdrawn ether in wei.
event DividendWithdrawn(
address indexed to,
uint256 weiAmount
);
}
@gnosis.pm/safe-contracts/contracts/interfaces/ISignatureValidator.sol
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
contract ISignatureValidatorConstants {
// bytes4(keccak256("isValidSignature(bytes,bytes)")
bytes4 internal constant EIP1271_MAGIC_VALUE = 0x20c13b0b;
}
abstract contract ISignatureValidator is ISignatureValidatorConstants {
/**
* @dev Should return whether the signature provided is valid for the provided data
* @param _data Arbitrary length data signed on the behalf of address(this)
* @param _signature Signature byte array associated with _data
*
* MUST return the bytes4 magic value 0x20c13b0b when function passes.
* MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5)
* MUST allow external calls
*/
function isValidSignature(bytes memory _data, bytes memory _signature) public view virtual returns (bytes4);
}
@openzeppelin/contracts/utils/math/Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
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) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 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;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
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;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
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);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
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);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 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;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
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);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 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;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
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);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
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;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}
@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolImmutables.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Pool state that never changes
/// @notice These parameters are fixed for a pool forever, i.e., the methods will always return the same values
interface IUniswapV3PoolImmutables {
/// @notice The contract that deployed the pool, which must adhere to the IUniswapV3Factory interface
/// @return The contract address
function factory() external view returns (address);
/// @notice The first of the two tokens of the pool, sorted by address
/// @return The token contract address
function token0() external view returns (address);
/// @notice The second of the two tokens of the pool, sorted by address
/// @return The token contract address
function token1() external view returns (address);
/// @notice The pool's fee in hundredths of a bip, i.e. 1e-6
/// @return The fee
function fee() external view returns (uint24);
/// @notice The pool tick spacing
/// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive
/// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ...
/// This value is an int24 to avoid casting even though it is always positive.
/// @return The tick spacing
function tickSpacing() external view returns (int24);
/// @notice The maximum amount of position liquidity that can use any tick in the range
/// @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and
/// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool
/// @return The max amount of liquidity per tick
function maxLiquidityPerTick() external view returns (uint128);
}
@uniswap/v2-periphery/contracts/interfaces/IWETH.sol
pragma solidity >=0.5.0;
interface IWETH {
function deposit() external payable;
function transfer(address to, uint value) external returns (bool);
function withdraw(uint) external;
}
@gnosis.pm/safe-contracts/contracts/common/EtherPaymentFallback.sol
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
/// @title EtherPaymentFallback - A contract that has a fallback to accept ether payments
/// @author Richard Meissner - <richard@gnosis.pm>
contract EtherPaymentFallback {
event SafeReceived(address indexed sender, uint256 value);
/// @dev Fallback function accepts Ether transactions.
receive() external payable {
emit SafeReceived(msg.sender, msg.value);
}
}
@openzeppelin/contracts/utils/Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
@openzeppelin/contracts/utils/Counters.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)
pragma solidity ^0.8.0;
/**
* @title Counters
* @author Matt Condon (@shrugs)
* @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
* of elements in a mapping, issuing ERC721 ids, or counting request ids.
*
* Include with `using Counters for Counters.Counter;`
*/
library Counters {
struct Counter {
// This variable should never be directly accessed by users of the library: interactions must be restricted to
// the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
// this feature: see https://github.com/ethereum/solidity/issues/4637
uint256 _value; // default: 0
}
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;
}
}
@gnosis.pm/safe-contracts/contracts/common/SignatureDecoder.sol
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
/// @title SignatureDecoder - Decodes signatures that a encoded as bytes
/// @author Richard Meissner - <richard@gnosis.pm>
contract SignatureDecoder {
/// @dev divides bytes signature into `uint8 v, bytes32 r, bytes32 s`.
/// @notice Make sure to peform a bounds check for @param pos, to avoid out of bounds access on @param signatures
/// @param pos which signature to read. A prior bounds check of this parameter should be performed, to avoid out of bounds access
/// @param signatures concatenated rsv signatures
function signatureSplit(bytes memory signatures, uint256 pos)
internal
pure
returns (
uint8 v,
bytes32 r,
bytes32 s
)
{
// The signature format is a compact form of:
// {bytes32 r}{bytes32 s}{uint8 v}
// Compact means, uint8 is not padded to 32 bytes.
// solhint-disable-next-line no-inline-assembly
assembly {
let signaturePos := mul(0x41, pos)
r := mload(add(signatures, add(signaturePos, 0x20)))
s := mload(add(signatures, add(signaturePos, 0x40)))
// Here we are loading the last 32 bytes, including 31 bytes
// of 's'. There is no 'mload8' to do this.
//
// 'byte' is not working due to the Solidity parser, so lets
// use the second best option, 'and'
v := and(mload(add(signatures, add(signaturePos, 0x41))), 0xff)
}
}
}
@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
@openzeppelin/contracts/access/Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
@openzeppelin/contracts/utils/math/SafeMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)
pragma solidity ^0.8.0;
// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.
/**
* @dev Wrappers over Solidity's arithmetic operations.
*
* NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
* now has built in overflow checking.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator.
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}
contracts/DPT/math/SafeMathUint.sol
pragma solidity ^0.8.15;
// SPDX-License-Identifier: UNLICENSED
/**
* @title SafeMathUint
* @dev Math operations with safety checks that revert on error
*/
library SafeMathUint {
function toInt256Safe(uint256 a) internal pure returns (int256) {
int256 b = int256(a);
require(b >= 0);
return b;
}
}
@uniswap/v2-core/contracts/interfaces/IERC20.sol
pragma solidity >=0.5.0;
interface IERC20 {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
function transfer(address to, uint value) external returns (bool);
function transferFrom(address from, address to, uint value) external returns (bool);
}
@gnosis.pm/safe-contracts/contracts/external/GnosisSafeMath.sol
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
/**
* @title GnosisSafeMath
* @dev Math operations with safety checks that revert on error
* Renamed from SafeMath to GnosisSafeMath to avoid conflicts
* TODO: remove once open zeppelin update to solc 0.5.0
*/
library GnosisSafeMath {
/**
* @dev Multiplies two numbers, reverts on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b);
return c;
}
/**
* @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a);
uint256 c = a - b;
return c;
}
/**
* @dev Adds two numbers, reverts on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a);
return c;
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
}
contracts/DPT/DividendPayingToken.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.15;
import "@uniswap/v2-core/contracts/interfaces/IERC20.sol";
import "./DividendPayingTokenInterface.sol";
import "./DividendPayingTokenOptionalInterface.sol";
import "./math/SafeMathUint.sol";
import "./math/SafeMathInt.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
/// @title Dividend-Paying Token
/// @author Roger Wu (https://github.com/roger-wu)
/// @dev A mintable ERC20 token that allows anyone to pay and distribute tokens
/// to token holders as dividends and allows token holders to withdraw their dividends.
/// Reference: the source code of PoWH3D: https://etherscan.io/address/0xB3775fB83F7D12A36E0475aBdD1FCA35c091efBe#code
abstract contract DividendPayingToken is
Ownable,
DividendPayingTokenInterface,
DividendPayingTokenOptionalInterface
{
using SafeMath for uint256;
using SafeMathUint for uint256;
using SafeMathInt for int256;
address public REWARD_TOKEN;
address public stakingImpl;
// With `magnitude`, we can properly distribute dividends even if the amount of received ether is small.
// For more discussion about choosing the value of `magnitude`,
// see https://github.com/ethereum/EIPs/issues/1726#issuecomment-472352728
uint256 internal constant magnitude = 2 ** 128;
uint256 internal magnifiedDividendPerShare;
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_totalSupply += amount;
_balances[account] += amount;
magnifiedDividendCorrections[account] = magnifiedDividendCorrections[
account
].sub((magnifiedDividendPerShare.mul(amount)).toInt256Safe());
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
}
_totalSupply -= amount;
magnifiedDividendCorrections[account] = magnifiedDividendCorrections[
account
].add((magnifiedDividendPerShare.mul(amount)).toInt256Safe());
}
modifier onlySSHex() {
require(_msgSender() == owner() || _msgSender() == stakingImpl, "Only senders.");
_;
}
// About dividendCorrection:
// If the token balance of a `_user` is never changed, the dividend of `_user` can be computed with:
// `dividendOf(_user) = dividendPerShare * balanceOf(_user)`.
// When `balanceOf(_user)` is changed (via minting/burning/transferring tokens),
// `dividendOf(_user)` should not be changed,
// but the computed value of `dividendPerShare * balanceOf(_user)` is changed.
// To keep the `dividendOf(_user)` unchanged, we add a correction term:
// `dividendOf(_user) = dividendPerShare * balanceOf(_user) + dividendCorrectionOf(_user)`,
// where `dividendCorrectionOf(_user)` is updated whenever `balanceOf(_user)` is changed:
// `dividendCorrectionOf(_user) = dividendPerShare * (old balanceOf(_user)) - (new balanceOf(_user))`.
// So now `dividendOf(_user)` returns the same value before and after `balanceOf(_user)` is changed.
mapping(address => int256) internal magnifiedDividendCorrections;
mapping(address => uint256) internal withdrawnDividends;
uint256 public totalDividendsDistributed;
constructor(
address _rewardTokenAddress
) {
REWARD_TOKEN = _rewardTokenAddress;
}
function setStakingImpl(address impl) public onlyOwner {
stakingImpl = impl;
}
function afterReceivedHex(uint256 amount) public onlySSHex {
if (_totalSupply > 0 && amount > 0) {
magnifiedDividendPerShare = magnifiedDividendPerShare.add(
(amount).mul(magnitude) / _totalSupply
);
emit DividendsDistributed(msg.sender, amount);
totalDividendsDistributed = totalDividendsDistributed.add(amount);
}
}
/// @notice Withdraws the ether distributed to the sender.
/// @dev It emits a `DividendWithdrawn` event if the amount of withdrawn ether is greater than 0.
function withdrawDividend() public virtual override {
_withdrawDividendOfUser(payable(msg.sender));
}
/// @notice Withdraws the ether distributed to the sender.
/// @dev It emits a `DividendWithdrawn` event if the amount of withdrawn ether is greater than 0.
function _withdrawDividendOfUser(
address payable user
) internal returns (uint256) {
uint256 _withdrawableDividend = withdrawableDividendOf(user);
if (_withdrawableDividend > 0) {
withdrawnDividends[user] = withdrawnDividends[user].add(
_withdrawableDividend
);
emit DividendWithdrawn(user, _withdrawableDividend);
bool success = IERC20(REWARD_TOKEN).transfer(
user,
_withdrawableDividend
);
if (!success) {
withdrawnDividends[user] = withdrawnDividends[user].sub(
_withdrawableDividend
);
return 0;
}
return _withdrawableDividend;
}
return 0;
}
/// @notice View the amount of dividend in wei that an address can withdraw.
/// @param _owner The address of a token holder.
/// @return The amount of dividend in wei that `_owner` can withdraw.
function dividendOf(address _owner) public view override returns (uint256) {
return withdrawableDividendOf(_owner);
}
/// @notice View the amount of dividend in wei that an address can withdraw.
/// @param _owner The address of a token holder.
/// @return The amount of dividend in wei that `_owner` can withdraw.
function withdrawableDividendOf(
address _owner
) public view override returns (uint256) {
return accumulativeDividendOf(_owner).sub(withdrawnDividends[_owner]);
}
/// @notice View the amount of dividend in wei that an address has withdrawn.
/// @param _owner The address of a token holder.
/// @return The amount of dividend in wei that `_owner` has withdrawn.
function withdrawnDividendOf(
address _owner
) public view override returns (uint256) {
return withdrawnDividends[_owner];
}
/// @notice View the amount of dividend in wei that an address has earned in total.
/// @dev accumulativeDividendOf(_owner) = withdrawableDividendOf(_owner) + withdrawnDividendOf(_owner)
/// = (magnifiedDividendPerShare * balanceOf(_owner) + magnifiedDividendCorrections[_owner]) / magnitude
/// @param _owner The address of a token holder.
/// @return The amount of dividend in wei that `_owner` has earned in total.
function accumulativeDividendOf(
address _owner
) public view override returns (uint256) {
return
magnifiedDividendPerShare
.mul(_balances[_owner])
.toInt256Safe()
.add(magnifiedDividendCorrections[_owner])
.toUint256Safe() / magnitude;
}
/// @dev Internal function that transfer tokens from one address to another.
/// Update magnifiedDividendCorrections to keep dividends unchanged.
/// @param from The address to transfer from.
/// @param to The address to transfer to.
/// @param value The amount to be transferred.
function _transfer(
address from,
address to,
uint256 value
) internal virtual {
require(false);
int256 _magCorrection = magnifiedDividendPerShare
.mul(value)
.toInt256Safe();
magnifiedDividendCorrections[from] = magnifiedDividendCorrections[from]
.add(_magCorrection);
magnifiedDividendCorrections[to] = magnifiedDividendCorrections[to].sub(
_magCorrection
);
}
function _setBalance(address account, uint256 newBalance) internal {
uint256 currentBalance = _balances[account];
if (newBalance > currentBalance) {
uint256 mintAmount = newBalance.sub(currentBalance);
_mint(account, mintAmount);
} else if (newBalance < currentBalance) {
uint256 burnAmount = currentBalance.sub(newBalance);
_burn(account, burnAmount);
}
}
}
@gnosis.pm/safe-contracts/contracts/GnosisSafe.sol
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
import "./base/ModuleManager.sol";
import "./base/OwnerManager.sol";
import "./base/FallbackManager.sol";
import "./base/GuardManager.sol";
import "./common/EtherPaymentFallback.sol";
import "./common/Singleton.sol";
import "./common/SignatureDecoder.sol";
import "./common/SecuredTokenTransfer.sol";
import "./common/StorageAccessible.sol";
import "./interfaces/ISignatureValidator.sol";
import "./external/GnosisSafeMath.sol";
/// @title Gnosis Safe - A multisignature wallet with support for confirmations using signed messages based on ERC191.
/// @author Stefan George - <stefan@gnosis.io>
/// @author Richard Meissner - <richard@gnosis.io>
contract GnosisSafe is
EtherPaymentFallback,
Singleton,
ModuleManager,
OwnerManager,
SignatureDecoder,
SecuredTokenTransfer,
ISignatureValidatorConstants,
FallbackManager,
StorageAccessible,
GuardManager
{
using GnosisSafeMath for uint256;
string public constant VERSION = "1.3.0";
// keccak256(
// "EIP712Domain(uint256 chainId,address verifyingContract)"
// );
bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH = 0x47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218;
// keccak256(
// "SafeTx(address to,uint256 value,bytes data,uint8 operation,uint256 safeTxGas,uint256 baseGas,uint256 gasPrice,address gasToken,address refundReceiver,uint256 nonce)"
// );
bytes32 private constant SAFE_TX_TYPEHASH = 0xbb8310d486368db6bd6f849402fdd73ad53d316b5a4b2644ad6efe0f941286d8;
event SafeSetup(address indexed initiator, address[] owners, uint256 threshold, address initializer, address fallbackHandler);
event ApproveHash(bytes32 indexed approvedHash, address indexed owner);
event SignMsg(bytes32 indexed msgHash);
event ExecutionFailure(bytes32 txHash, uint256 payment);
event ExecutionSuccess(bytes32 txHash, uint256 payment);
uint256 public nonce;
bytes32 private _deprecatedDomainSeparator;
// Mapping to keep track of all message hashes that have been approve by ALL REQUIRED owners
mapping(bytes32 => uint256) public signedMessages;
// Mapping to keep track of all hashes (message or transaction) that have been approve by ANY owners
mapping(address => mapping(bytes32 => uint256)) public approvedHashes;
// This constructor ensures that this contract can only be used as a master copy for Proxy contracts
constructor() {
// By setting the threshold it is not possible to call setup anymore,
// so we create a Safe with 0 owners and threshold 1.
// This is an unusable Safe, perfect for the singleton
threshold = 1;
}
/// @dev Setup function sets initial storage of contract.
/// @param _owners List of Safe owners.
/// @param _threshold Number of required confirmations for a Safe transaction.
/// @param to Contract address for optional delegate call.
/// @param data Data payload for optional delegate call.
/// @param fallbackHandler Handler for fallback calls to this contract
/// @param paymentToken Token that should be used for the payment (0 is ETH)
/// @param payment Value that should be paid
/// @param paymentReceiver Adddress that should receive the payment (or 0 if tx.origin)
function setup(
address[] calldata _owners,
uint256 _threshold,
address to,
bytes calldata data,
address fallbackHandler,
address paymentToken,
uint256 payment,
address payable paymentReceiver
) external {
// setupOwners checks if the Threshold is already set, therefore preventing that this method is called twice
setupOwners(_owners, _threshold);
if (fallbackHandler != address(0)) internalSetFallbackHandler(fallbackHandler);
// As setupOwners can only be called if the contract has not been initialized we don't need a check for setupModules
setupModules(to, data);
if (payment > 0) {
// To avoid running into issues with EIP-170 we reuse the handlePayment function (to avoid adjusting code of that has been verified we do not adjust the method itself)
// baseGas = 0, gasPrice = 1 and gas = payment => amount = (payment + 0) * 1 = payment
handlePayment(payment, 0, 1, paymentToken, paymentReceiver);
}
emit SafeSetup(msg.sender, _owners, _threshold, to, fallbackHandler);
}
/// @dev Allows to execute a Safe transaction confirmed by required number of owners and then pays the account that submitted the transaction.
/// Note: The fees are always transferred, even if the user transaction fails.
/// @param to Destination address of Safe transaction.
/// @param value Ether value of Safe transaction.
/// @param data Data payload of Safe transaction.
/// @param operation Operation type of Safe transaction.
/// @param safeTxGas Gas that should be used for the Safe transaction.
/// @param baseGas Gas costs that are independent of the transaction execution(e.g. base transaction fee, signature check, payment of the refund)
/// @param gasPrice Gas price that should be used for the payment calculation.
/// @param gasToken Token address (or 0 if ETH) that is used for the payment.
/// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
/// @param signatures Packed signature data ({bytes32 r}{bytes32 s}{uint8 v})
function execTransaction(
address to,
uint256 value,
bytes calldata data,
Enum.Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address payable refundReceiver,
bytes memory signatures
) public payable virtual returns (bool success) {
bytes32 txHash;
// Use scope here to limit variable lifetime and prevent `stack too deep` errors
{
bytes memory txHashData =
encodeTransactionData(
// Transaction info
to,
value,
data,
operation,
safeTxGas,
// Payment info
baseGas,
gasPrice,
gasToken,
refundReceiver,
// Signature info
nonce
);
// Increase nonce and execute transaction.
nonce++;
txHash = keccak256(txHashData);
checkSignatures(txHash, txHashData, signatures);
}
address guard = getGuard();
{
if (guard != address(0)) {
Guard(guard).checkTransaction(
// Transaction info
to,
value,
data,
operation,
safeTxGas,
// Payment info
baseGas,
gasPrice,
gasToken,
refundReceiver,
// Signature info
signatures,
msg.sender
);
}
}
// We require some gas to emit the events (at least 2500) after the execution and some to perform code until the execution (500)
// We also include the 1/64 in the check that is not send along with a call to counteract potential shortings because of EIP-150
require(gasleft() >= ((safeTxGas * 64) / 63).max(safeTxGas + 2500) + 500, "GS010");
// Use scope here to limit variable lifetime and prevent `stack too deep` errors
{
uint256 gasUsed = gasleft();
// If the gasPrice is 0 we assume that nearly all available gas can be used (it is always more than safeTxGas)
// We only substract 2500 (compared to the 3000 before) to ensure that the amount passed is still higher than safeTxGas
success = execute(to, value, data, operation, gasPrice == 0 ? (gasleft() - 2500) : safeTxGas);
gasUsed = gasUsed.sub(gasleft());
// If no safeTxGas and no gasPrice was set (e.g. both are 0), then the internal tx is required to be successful
// This makes it possible to use `estimateGas` without issues, as it searches for the minimum gas where the tx doesn't revert
require(success || safeTxGas != 0 || gasPrice != 0, "GS013");
// We transfer the calculated tx costs to the tx.origin to avoid sending it to intermediate contracts that have made calls
uint256 payment = 0;
if (gasPrice > 0) {
payment = handlePayment(gasUsed, baseGas, gasPrice, gasToken, refundReceiver);
}
if (success) emit ExecutionSuccess(txHash, payment);
else emit ExecutionFailure(txHash, payment);
}
{
if (guard != address(0)) {
Guard(guard).checkAfterExecution(txHash, success);
}
}
}
function handlePayment(
uint256 gasUsed,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address payable refundReceiver
) private returns (uint256 payment) {
// solhint-disable-next-line avoid-tx-origin
address payable receiver = refundReceiver == address(0) ? payable(tx.origin) : refundReceiver;
if (gasToken == address(0)) {
// For ETH we will only adjust the gas price to not be higher than the actual used gas price
payment = gasUsed.add(baseGas).mul(gasPrice < tx.gasprice ? gasPrice : tx.gasprice);
require(receiver.send(payment), "GS011");
} else {
payment = gasUsed.add(baseGas).mul(gasPrice);
require(transferToken(gasToken, receiver, payment), "GS012");
}
}
/**
* @dev Checks whether the signature provided is valid for the provided data, hash. Will revert otherwise.
* @param dataHash Hash of the data (could be either a message hash or transaction hash)
* @param data That should be signed (this is passed to an external validator contract)
* @param signatures Signature data that should be verified. Can be ECDSA signature, contract signature (EIP-1271) or approved hash.
*/
function checkSignatures(
bytes32 dataHash,
bytes memory data,
bytes memory signatures
) public view {
// Load threshold to avoid multiple storage loads
uint256 _threshold = threshold;
// Check that a threshold is set
require(_threshold > 0, "GS001");
checkNSignatures(dataHash, data, signatures, _threshold);
}
/**
* @dev Checks whether the signature provided is valid for the provided data, hash. Will revert otherwise.
* @param dataHash Hash of the data (could be either a message hash or transaction hash)
* @param data That should be signed (this is passed to an external validator contract)
* @param signatures Signature data that should be verified. Can be ECDSA signature, contract signature (EIP-1271) or approved hash.
* @param requiredSignatures Amount of required valid signatures.
*/
function checkNSignatures(
bytes32 dataHash,
bytes memory data,
bytes memory signatures,
uint256 requiredSignatures
) public view {
// Check that the provided signature data is not too short
require(signatures.length >= requiredSignatures.mul(65), "GS020");
// There cannot be an owner with address 0.
address lastOwner = address(0);
address currentOwner;
uint8 v;
bytes32 r;
bytes32 s;
uint256 i;
for (i = 0; i < requiredSignatures; i++) {
(v, r, s) = signatureSplit(signatures, i);
if (v == 0) {
// If v is 0 then it is a contract signature
// When handling contract signatures the address of the contract is encoded into r
currentOwner = address(uint160(uint256(r)));
// Check that signature data pointer (s) is not pointing inside the static part of the signatures bytes
// This check is not completely accurate, since it is possible that more signatures than the threshold are send.
// Here we only check that the pointer is not pointing inside the part that is being processed
require(uint256(s) >= requiredSignatures.mul(65), "GS021");
// Check that signature data pointer (s) is in bounds (points to the length of data -> 32 bytes)
require(uint256(s).add(32) <= signatures.length, "GS022");
// Check if the contract signature is in bounds: start of data is s + 32 and end is start + signature length
uint256 contractSignatureLen;
// solhint-disable-next-line no-inline-assembly
assembly {
contractSignatureLen := mload(add(add(signatures, s), 0x20))
}
require(uint256(s).add(32).add(contractSignatureLen) <= signatures.length, "GS023");
// Check signature
bytes memory contractSignature;
// solhint-disable-next-line no-inline-assembly
assembly {
// The signature data for contract signatures is appended to the concatenated signatures and the offset is stored in s
contractSignature := add(add(signatures, s), 0x20)
}
require(ISignatureValidator(currentOwner).isValidSignature(data, contractSignature) == EIP1271_MAGIC_VALUE, "GS024");
} else if (v == 1) {
// If v is 1 then it is an approved hash
// When handling approved hashes the address of the approver is encoded into r
currentOwner = address(uint160(uint256(r)));
// Hashes are automatically approved by the sender of the message or when they have been pre-approved via a separate transaction
require(msg.sender == currentOwner || approvedHashes[currentOwner][dataHash] != 0, "GS025");
} else if (v > 30) {
// If v > 30 then default va (27,28) has been adjusted for eth_sign flow
// To support eth_sign and similar we adjust v and hash the messageHash with the Ethereum message prefix before applying ecrecover
currentOwner = ecrecover(keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", dataHash)), v - 4, r, s);
} else {
// Default is the ecrecover flow with the provided data hash
// Use ecrecover with the messageHash for EOA signatures
currentOwner = ecrecover(dataHash, v, r, s);
}
require(currentOwner > lastOwner && owners[currentOwner] != address(0) && currentOwner != SENTINEL_OWNERS, "GS026");
lastOwner = currentOwner;
}
}
/// @dev Allows to estimate a Safe transaction.
/// This method is only meant for estimation purpose, therefore the call will always revert and encode the result in the revert data.
/// Since the `estimateGas` function includes refunds, call this method to get an estimated of the costs that are deducted from the safe with `execTransaction`
/// @param to Destination address of Safe transaction.
/// @param value Ether value of Safe transaction.
/// @param data Data payload of Safe transaction.
/// @param operation Operation type of Safe transaction.
/// @return Estimate without refunds and overhead fees (base transaction and payload data gas costs).
/// @notice Deprecated in favor of common/StorageAccessible.sol and will be removed in next version.
function requiredTxGas(
address to,
uint256 value,
bytes calldata data,
Enum.Operation operation
) external returns (uint256) {
uint256 startGas = gasleft();
// We don't provide an error message here, as we use it to return the estimate
require(execute(to, value, data, operation, gasleft()));
uint256 requiredGas = startGas - gasleft();
// Convert response to string and return via error message
revert(string(abi.encodePacked(requiredGas)));
}
/**
* @dev Marks a hash as approved. This can be used to validate a hash that is used by a signature.
* @param hashToApprove The hash that should be marked as approved for signatures that are verified by this contract.
*/
function approveHash(bytes32 hashToApprove) external {
require(owners[msg.sender] != address(0), "GS030");
approvedHashes[msg.sender][hashToApprove] = 1;
emit ApproveHash(hashToApprove, msg.sender);
}
/// @dev Returns the chain id used by this contract.
function getChainId() public view returns (uint256) {
uint256 id;
// solhint-disable-next-line no-inline-assembly
assembly {
id := chainid()
}
return id;
}
function domainSeparator() public view returns (bytes32) {
return keccak256(abi.encode(DOMAIN_SEPARATOR_TYPEHASH, getChainId(), this));
}
/// @dev Returns the bytes that are hashed to be signed by owners.
/// @param to Destination address.
/// @param value Ether value.
/// @param data Data payload.
/// @param operation Operation type.
/// @param safeTxGas Gas that should be used for the safe transaction.
/// @param baseGas Gas costs for that are independent of the transaction execution(e.g. base transaction fee, signature check, payment of the refund)
/// @param gasPrice Maximum gas price that should be used for this transaction.
/// @param gasToken Token address (or 0 if ETH) that is used for the payment.
/// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
/// @param _nonce Transaction nonce.
/// @return Transaction hash bytes.
function encodeTransactionData(
address to,
uint256 value,
bytes calldata data,
Enum.Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address refundReceiver,
uint256 _nonce
) public view returns (bytes memory) {
bytes32 safeTxHash =
keccak256(
abi.encode(
SAFE_TX_TYPEHASH,
to,
value,
keccak256(data),
operation,
safeTxGas,
baseGas,
gasPrice,
gasToken,
refundReceiver,
_nonce
)
);
return abi.encodePacked(bytes1(0x19), bytes1(0x01), domainSeparator(), safeTxHash);
}
/// @dev Returns hash to be signed by owners.
/// @param to Destination address.
/// @param value Ether value.
/// @param data Data payload.
/// @param operation Operation type.
/// @param safeTxGas Fas that should be used for the safe transaction.
/// @param baseGas Gas costs for data used to trigger the safe transaction.
/// @param gasPrice Maximum gas price that should be used for this transaction.
/// @param gasToken Token address (or 0 if ETH) that is used for the payment.
/// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
/// @param _nonce Transaction nonce.
/// @return Transaction hash.
function getTransactionHash(
address to,
uint256 value,
bytes calldata data,
Enum.Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address refundReceiver,
uint256 _nonce
) public view returns (bytes32) {
return keccak256(encodeTransactionData(to, value, data, operation, safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, _nonce));
}
}
Compiler Settings
{"viaIR":false,"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers"]}},"optimizer":{"runs":50,"enabled":true},"libraries":{}}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"router","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":"Bought","inputs":[{"type":"address","name":"buyer","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Sold","inputs":[{"type":"address","name":"seller","internalType":"address","indexed":true},{"type":"uint256","name":"amount","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":"bytes32","name":"","internalType":"bytes32"}],"name":"DOMAIN_SEPARATOR","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addNewLPPair","inputs":[{"type":"address","name":"pair","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"allowance","inputs":[{"type":"address","name":"owner","internalType":"address"},{"type":"address","name":"spender","internalType":"address"}]},{"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":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"checkBot","inputs":[{"type":"address","name":"bot","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claim","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"currentSupply","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"decimals","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"disableBlocklistAdd","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"disengageRestaking","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"dividendTracker","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"excludeFromDividends","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"lps","internalType":"address[]"}],"name":"getLPPairs","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isExcludedFromFee","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"multisend","inputs":[{"type":"address[]","name":"addr","internalType":"address[]"},{"type":"uint256[]","name":"val","internalType":"uint256[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"multisendFrom","inputs":[{"type":"address","name":"sender","internalType":"address"},{"type":"address[]","name":"addrRecipients","internalType":"address[]"},{"type":"uint256[]","name":"vals","internalType":"uint256[]"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"name","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"nonces","inputs":[{"type":"address","name":"owner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"openTrading","inputs":[{"type":"address","name":"nativeWrapped","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"permit","inputs":[{"type":"address","name":"owner","internalType":"address"},{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"uint256","name":"deadline","internalType":"uint256"},{"type":"uint8","name":"v","internalType":"uint8"},{"type":"bytes32","name":"r","internalType":"bytes32"},{"type":"bytes32","name":"s","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"processDividendTracker","inputs":[{"type":"uint256","name":"gas","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setBot","inputs":[{"type":"address","name":"theBot","internalType":"address"},{"type":"bool","name":"toSet","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setBurnRatio","inputs":[{"type":"uint16","name":"amount","internalType":"uint16"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setBuyTax","inputs":[{"type":"uint32","name":"amount","internalType":"uint32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setExcludedFromFee","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"bool","name":"isExcluded","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRewardRatio","inputs":[{"type":"uint16","name":"amount","internalType":"uint16"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setSellTax","inputs":[{"type":"uint32","name":"amount","internalType":"uint32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setStakingRatio","inputs":[{"type":"uint16","name":"amount","internalType":"uint16"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"stakingImpl","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":"nonpayable","outputs":[],"name":"transferOwnerOfStakingPool","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateClaimWait","inputs":[{"type":"uint256","name":"claimWait","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateGasForProcessing","inputs":[{"type":"uint32","name":"newValue","internalType":"uint32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawStaking","inputs":[{"type":"address","name":"recipient","internalType":"address"}]},{"type":"receive","stateMutability":"payable"}]
Contract Creation Code
0x61014060405260098054600160a01b600160f81b031916675000c800a000249f60a51b179055600b805460ff60e01b167915ae000015ae2b591e99afe9f32eaa6214f7b7629768c40eeb391790553480156200005a57600080fd5b5060405162006836380380620068368339810160408190526200007d9162000a19565b62000088336200099e565b600a8054600160a01b600160e01b031916600160a01b426001600160401b031602179055600c80546001600160a01b0319166001600160a01b038316179055604080518082018252601081526f0a6eae0cae4a6e8c2d6ca7440e0908ab60831b602091820152815180830190925260018252603160f81b9101527f1f1814183d746334cc745028bdaa07f5b137c2c6b9424bd683263e8340b8733360e08190527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66101008190524660a0527f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f620001c48184846040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090509392505050565b6080523060c0526101208190523360009081526004602052604080822066c55a6e4145e00090819055600255600b5490516001600160a01b039091169065050d5fcd3e00906200021490620009fd565b6001600160a01b0390921682526020820152604001604051809103906000f08015801562000246573d6000803e3d6000fd5b50600980546001600160a01b0319166001600160a01b03838116918217909255600b54604051939450600093921691603c91908990620002869062000a0b565b6001600160a01b03948516815263ffffffff90931660208401529083166040830152919091166060820152608001604051809103906000f080158015620002d1573d6000803e3d6000fd5b50600a80546001600160a01b0319166001600160a01b038381169182179092556040516301ae994760e21b815260048101919091529192508316906306ba651c90602401600060405180830381600087803b1580156200033057600080fd5b505af115801562000345573d6000803e3d6000fd5b505060095460405163031e79db60e41b81526001600160a01b03918216600482015290851692506331e79db09150602401600060405180830381600087803b1580156200039157600080fd5b505af1158015620003a6573d6000803e3d6000fd5b505060405163031e79db60e41b81523060048201526001600160a01b03851692506331e79db09150602401600060405180830381600087803b158015620003ec57600080fd5b505af115801562000401573d6000803e3d6000fd5b50505050816001600160a01b03166331e79db062000424620009ee60201b60201c565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401600060405180830381600087803b1580156200046657600080fd5b505af11580156200047b573d6000803e3d6000fd5b505060405163031e79db60e41b815261dead60048201526001600160a01b03851692506331e79db09150602401600060405180830381600087803b158015620004c357600080fd5b505af1158015620004d8573d6000803e3d6000fd5b50506040805160e08101825260018152600060208201819052918101829052606081018290526080810182905260a0810182905260c08101829052925060069150336001600160a01b03166001600160a01b0316815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548160ff02191690831515021790555060408201518160000160026101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160066101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001600a6101000a81548163ffffffff021916908363ffffffff16021790555060a082015181600001600e6101000a81548160ff02191690831515021790555060c082015181600001600f6101000a81548160ff0219169083151502179055509050506040518060e00160405280600115158152602001600015158152602001600063ffffffff168152602001600063ffffffff168152602001600063ffffffff1681526020016000151581526020016000151581525060066000306001600160a01b03166001600160a01b0316815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548160ff02191690831515021790555060408201518160000160026101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160066101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001600a6101000a81548163ffffffff021916908363ffffffff16021790555060a082015181600001600e6101000a81548160ff02191690831515021790555060c082015181600001600f6101000a81548160ff0219169083151502179055509050506040518060e00160405280600115158152602001600015158152602001600063ffffffff168152602001600063ffffffff168152602001600063ffffffff1681526020016000151581526020016000151581525060066000600960009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548160ff02191690831515021790555060408201518160000160026101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160066101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001600a6101000a81548163ffffffff021916908363ffffffff16021790555060a082015181600001600e6101000a81548160ff02191690831515021790555060c082015181600001600f6101000a81548160ff021916908315150217905550905050620009396200099a60201b60201c565b6001600160a01b031660006001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef66c55a6e4145e0006040516200098691815260200190565b60405180910390a350505050505062000a4b565b3390565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000546001600160a01b031690565b6119178062003f1283390190565b61100d806200582983390190565b60006020828403121562000a2c57600080fd5b81516001600160a01b038116811462000a4457600080fd5b9392505050565b60805160a05160c05160e051610100516101205161347762000a9b6000396000611fa601526000611ff501526000611fd001526000611f2901526000611f5301526000611f7d01526134776000f3fe60806040526004361061020a5760003560e01c8063771282f611610119578063c8d1ef8a116100a6578063c8d1ef8a1461061e578063ca72a4e71461063e578063d505accf1461065e578063db932ae21461067e578063dd62ed3e1461069e578063e98030c7146106e4578063e9cb414f14610704578063f200e29d14610724578063f2fde38b14610746578063f8ea410614610766578063fe82b5e01461078657600080fd5b8063771282f6146104c85780637ecebe00146104de5780638da5cb5b146104fe5780638fb5043d1461051357806395d89b4114610533578063a9059cbb14610560578063aad41a4114610580578063b1a4e0dc146105a0578063b4113cc8146105de578063bb1789d6146105fe57600080fd5b80633644e515116101975780633644e5151461039b5780634e71d92d146103b05780635342acb4146103c55780636612e66f146103fe578063700bb1911461041e57806370a082311461043e57806370bfdd9d1461045e578063715018a61461047357806373ae740e1461048857806376b3617b146104a857600080fd5b806306fdde0314610216578063095ea7b31461026157806312a659e21461029157806318160ddd146102b3578063222d3b05146102d257806323b872dd146102f25780632c1f521614610312578063313ce5671461033f57806331e79db01461035b578063342aa8b51461037b57600080fd5b3661021157005b600080fd5b34801561022257600080fd5b5060408051808201909152601081526f0a6eae0cae4a6e8c2d6ca7440e0908ab60831b60208201525b6040516102589190612d4e565b60405180910390f35b34801561026d57600080fd5b5061028161027c366004612db1565b61079b565b6040519015158152602001610258565b34801561029d57600080fd5b506102b16102ac366004612ddd565b6107b2565b005b3480156102bf57600080fd5b506002545b604051908152602001610258565b3480156102de57600080fd5b506102b16102ed366004612e01565b6107dc565b3480156102fe57600080fd5b5061028161030d366004612e1e565b610918565b34801561031e57600080fd5b50600954610332906001600160a01b031681565b6040516102589190612e5f565b34801561034b57600080fd5b5060405160098152602001610258565b34801561036757600080fd5b506102b1610376366004612e01565b610992565b34801561038757600080fd5b506102b1610396366004612e81565b6109ff565b3480156103a757600080fd5b506102c4610ae9565b3480156103bc57600080fd5b506102b1610af8565b3480156103d157600080fd5b506102816103e0366004612e01565b6001600160a01b031660009081526006602052604090205460ff1690565b34801561040a57600080fd5b506102b1610419366004612e81565b610b70565b34801561042a57600080fd5b506102b1610439366004612eba565b610ba3565b34801561044a57600080fd5b506102c4610459366004612e01565b610c1b565b34801561046a57600080fd5b506102b1610c36565b34801561047f57600080fd5b506102b1610c53565b34801561049457600080fd5b506102b16104a3366004612f1e565b610c67565b3480156104b457600080fd5b506102b16104c3366004612fb2565b610d50565b3480156104d457600080fd5b506102c460025481565b3480156104ea57600080fd5b506102c46104f9366004612e01565b610e31565b34801561050a57600080fd5b50610332610e4f565b34801561051f57600080fd5b506102b161052e366004612ddd565b610e5e565b34801561053f57600080fd5b506040805180820190915260048152630e0a6a6960e31b602082015261024b565b34801561056c57600080fd5b5061028161057b366004612db1565b610e88565b34801561058c57600080fd5b506102b161059b366004612fcf565b610e95565b3480156105ac57600080fd5b506102816105bb366004612e01565b6001600160a01b0316600090815260066020526040902054610100900460ff1690565b3480156105ea57600080fd5b50600a54610332906001600160a01b031681565b34801561060a57600080fd5b506102b1610619366004612fb2565b610ee7565b34801561062a57600080fd5b506102b1610639366004612ddd565b610f3d565b34801561064a57600080fd5b506102b1610659366004612e01565b610f67565b34801561066a57600080fd5b506102b161067936600461303a565b611441565b34801561068a57600080fd5b506102b1610699366004612fb2565b6115c4565b3480156106aa57600080fd5b506102c46106b93660046130b1565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205490565b3480156106f057600080fd5b506102b16106ff366004612eba565b61161a565b34801561071057600080fd5b506102b161071f366004612e01565b611653565b34801561073057600080fd5b506107396116b2565b6040516102589190613123565b34801561075257600080fd5b506102b1610761366004612e01565b611714565b34801561077257600080fd5b506102b1610781366004612e01565b61178a565b34801561079257600080fd5b506102b16117c2565b60006107a83384846118b8565b5060015b92915050565b6107ba6119dc565b6009805461ffff909216600160e01b0261ffff60e01b19909216919091179055565b6107e46119dc565b600a546040805163575b8b9760e11b815290516001600160a01b0390921691600091839163aeb7172e916004808201926020929091908290030181865afa158015610833573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108579190613136565b9050806108b55760405162461bcd60e51b815260206004820152602160248201527f5353483a205374616b696e6720706f6f6c206e6f7420646973656e67616765646044820152601760f91b60648201526084015b60405180910390fd5b604051631277dca360e21b81526001600160a01b038316906349df728c906108e1908690600401612e5f565b600060405180830381600087803b1580156108fb57600080fd5b505af115801561090f573d6000803e3d6000fd5b50505050505050565b6000610925848484611a3b565b6109888433610983856040518060600160405280602881526020016133fa602891396001600160a01b038a16600090815260056020526040812090335b6001600160a01b031681526020810191909152604001600020549190611ef0565b6118b8565b5060019392505050565b61099a6119dc565b60095460405163031e79db60e41b81526001600160a01b03909116906331e79db0906109ca908490600401612e5f565b600060405180830381600087803b1580156109e457600080fd5b505af11580156109f8573d6000803e3d6000fd5b5050505050565b610a076119dc565b6001600160a01b038216600090815260066020526040902054600160701b900460ff1615610a685760405162461bcd60e51b815260206004820152600e60248201526d29a9a41d102327a92124a22222a760911b60448201526064016108ac565b8015610ab857600954600160f01b900460ff1615610ab85760405162461bcd60e51b815260206004820152600d60248201526c14d4d20e88111254d050931151609a1b60448201526064016108ac565b6001600160a01b03909116600090815260066020526040902080549115156101000261ff0019909216919091179055565b6000610af3611f1c565b905090565b60095460405163bc4c4b3760e01b8152336004820152600060248201526001600160a01b039091169063bc4c4b37906044016020604051808303816000875af1158015610b49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b6d9190613136565b50565b610b786119dc565b6001600160a01b03919091166000908152600660205260409020805460ff1916911515919091179055565b6009546040516001624d3b8760e01b03198152600481018390526001600160a01b039091169063ffb2c479906024016060604051808303816000875af1158015610bf1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c159190613153565b50505050565b6001600160a01b031660009081526004602052604090205490565b610c3e6119dc565b6009805460ff60f01b1916600160f01b179055565b610c5b6119dc565b610c656000612043565b565b828114610c865760405162461bcd60e51b81526004016108ac90613181565b60005b83811015610d4857610cdd86868684818110610ca757610ca76131a8565b9050602002016020810190610cbc9190612e01565b858585818110610cce57610cce6131a8565b90506020020135600080612093565b610d368633610983868686818110610cf757610cf76131a8565b905060200201356040518060600160405280602881526020016133fa602891396001600160a01b038c1660009081526005602052604081209033610962565b80610d40816131d4565b915050610c89565b505050505050565b610d586119dc565b62030d408163ffffffff1610158015610d7a57506207a1208163ffffffff1611155b610dc05760405162461bcd60e51b815260206004820152601760248201527603230302c303030203c20474650203c203530302c30303604c1b60448201526064016108ac565b60095463ffffffff600160a01b909104811690821603610e0b5760405162461bcd60e51b81526004016108ac9060208082526004908201526353616d6560e01b604082015260600190565b6009805463ffffffff909216600160a01b0263ffffffff60a01b19909216919091179055565b6001600160a01b0381166000908152600160205260408120546107ac565b6000546001600160a01b031690565b610e666119dc565b6009805461ffff909216600160c01b0261ffff60c01b19909216919091179055565b60006107a8338484611a3b565b828114610eb45760405162461bcd60e51b81526004016108ac90613181565b60005b838110156109f857610ed533868684818110610ca757610ca76131a8565b80610edf816131d4565b915050610eb7565b610eef6119dc565b614e208163ffffffff161115610f175760405162461bcd60e51b81526004016108ac906131ed565b600b805463ffffffff909216600160c01b0263ffffffff60c01b19909216919091179055565b610f456119dc565b6009805461ffff909216600160d01b0261ffff60d01b19909216919091179055565b610f6f6119dc565b600b54600160e01b900460ff1615610fb25760405162461bcd60e51b81526004016108ac9060208082526004908201526327a822a760e11b604082015260600190565b600380546001600160a01b0319166001600160a01b0383811691909117909155600954600c5460405163031e79db60e41b8152918316926331e79db092610fff9290911690600401612e5f565b600060405180830381600087803b15801561101957600080fd5b505af115801561102d573d6000803e3d6000fd5b5050600c5461104b92503091506001600160a01b03166000196118b8565b600c546040805163c45a015560e01b815290516000926001600160a01b03169163c45a01559160048083019260209291908290030181865afa158015611095573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b99190613214565b6003546040516364e329cb60e11b81523060048201526001600160a01b03918216602482015291169063c9c65396906044016020604051808303816000875af115801561110a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112e9190613214565b60095460405163031e79db60e41b81529192506001600160a01b0316906331e79db09061115f908490600401612e5f565b600060405180830381600087803b15801561117957600080fd5b505af115801561118d573d6000803e3d6000fd5b5050600c546001600160a01b0316915063f305d719905047306111af81610c1b565b6000806111ba610e4f565b60405160e088901b6001600160e01b03191681526001600160a01b03958616600482015260248101949094526044840192909252606483015290911660848201524260a482015260c40160606040518083038185885af1158015611222573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906112479190613153565b5050600b805462ff00ff60e01b19166201000160e01b17905550600c5460405163095ea7b360e01b81526001600160a01b038381169263095ea7b392611297929091169060001990600401613231565b6020604051808303816000875af11580156112b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112da9190613136565b506040805160e081018252600080825260208083018281528385018381526060850184815260808601858152600160a0880181815260c089018281526001600160a01b039b909b16808952600690975298872097518854955194519351925199519a5161ffff1990961690151561ff00191617610100941515949094029390931769ffffffffffffffff000019166201000063ffffffff9384160263ffffffff60301b191617600160301b918316919091021764ffffffffff60501b1916600160501b919097160260ff60701b191695909517600160701b961515969096029590951760ff60781b1916600160781b9515159590950294909417909155600780548084019091556000805160206133da8339815191520180546001600160a01b031990811685179091556008805493840181559091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee39091018054909116909117905550565b834211156114915760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e6500000060448201526064016108ac565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98888886114df8c6001600160a01b031660009081526001602081905260409091208054918201905590565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e001604051602081830303815290604052805190602001209050600061153a826123f2565b9050600061154a82878787612440565b9050896001600160a01b0316816001600160a01b0316146115ad5760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e6174757265000060448201526064016108ac565b6115b88a8a8a6118b8565b50505050505050505050565b6115cc6119dc565b614e208163ffffffff1611156115f45760405162461bcd60e51b81526004016108ac906131ed565b600b805463ffffffff909216600160a01b0263ffffffff60a01b19909216919091179055565b6116226119dc565b60095460405163e98030c760e01b8152600481018390526001600160a01b039091169063e98030c7906024016109ca565b61165b6119dc565b6001600160a01b03166000818152600660205260408120805460ff60701b1916600160701b1790556007805460018101825591526000805160206133da8339815191520180546001600160a01b0319169091179055565b6060600780548060200260200160405190810160405280929190818152602001828054801561170a57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116116ec575b5050505050905090565b61171c6119dc565b6001600160a01b0381166117815760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016108ac565b610b6d81612043565b6117926119dc565b600a5460405163f2fde38b60e01b81526001600160a01b039091169063f2fde38b906109ca908490600401612e5f565b6117ca6119dc565b600a5442906117ec90600160a01b90046001600160401b031662e85c6061324a565b6001600160401b0316116118545760405162461bcd60e51b815260206004820152602960248201527f5353483a205374616b696e6720706f6f6c206e6f206c6f6e67657220646973656044820152683733b0b3b0b136329760b91b60648201526084016108ac565b600a60009054906101000a90046001600160a01b03166001600160a01b031663bc75e7066040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156118a457600080fd5b505af1158015610c15573d6000803e3d6000fd5b6001600160a01b03831661191a5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016108ac565b6001600160a01b03821661197b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016108ac565b6001600160a01b0383811660008181526005602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b336119e5610e4f565b6001600160a01b031614610c655760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016108ac565b6001600160a01b038316611a9f5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016108ac565b6001600160a01b038216611b015760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016108ac565b60008111611b635760405162461bcd60e51b815260206004820152602960248201527f5472616e7366657220616d6f756e74206d7573742062652067726561746572206044820152687468616e207a65726f60b81b60648201526084016108ac565b600080611b6e610e4f565b6001600160a01b0316856001600160a01b031614158015611ba85750611b92610e4f565b6001600160a01b0316846001600160a01b031614155b8015611bbd57506001600160a01b0385163014155b8015611be257506001600160a01b03841660009081526006602052604090205460ff16155b8015611c0757506001600160a01b03851660009081526006602052604090205460ff16155b8015611c1d5750600b54600160e81b900460ff16155b15611ede576001600160a01b038416600090815260066020526040902054610100900460ff16158015611c6e57506001600160a01b038516600090815260066020526040902054610100900460ff16155b611cae5760405162461bcd60e51b815260206004820152601160248201527029a9a41d10213637b1b5b634b9ba32b21760791b60448201526064016108ac565b6001600160a01b038516600090815260066020526040902054600160701b900460ff1615611ced57600b54600160a01b900463ffffffff169150611ee3565b6001600160a01b038416600090815260066020526040902054600160701b900460ff1615611dc4575050600b546001600160a01b038416600090815260066020526040902054600160c01b90910463ffffffff90811691600191438116620100009092041603611d8b5760405162461bcd60e51b81526020600482015260096024820152680a6a6907440a6ae86960bb1b60448201526064016108ac565b6001600160a01b0385166000908152600660205260409020805463ffffffff60301b1916600160301b4363ffffffff1602179055611ee3565b600091506000611dd385612468565b90508060ff16600203611e195760405162461bcd60e51b815260206004820152600e60248201526d29a9a41d102737903b199026281760911b60448201526064016108ac565b8060ff16600103611ed8576001600160a01b03808616600081815260066020526040808220805460ff60701b1916600160701b1790556007805460018101825592526000805160206133da83398151915290910180546001600160a01b031916909217909155600954905163031e79db60e41b81529116906331e79db090611ea5908890600401612e5f565b600060405180830381600087803b158015611ebf57600080fd5b505af1158015611ed3573d6000803e3d6000fd5b505050505b50611ee3565b600091505b6109f88585858585612093565b60008184841115611f145760405162461bcd60e51b81526004016108ac9190612d4e565b505050900390565b6000306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015611f7557507f000000000000000000000000000000000000000000000000000000000000000046145b15611f9f57507f000000000000000000000000000000000000000000000000000000000000000090565b50604080517f00000000000000000000000000000000000000000000000000000000000000006020808301919091527f0000000000000000000000000000000000000000000000000000000000000000828401527f000000000000000000000000000000000000000000000000000000000000000060608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600061209f848461256e565b9050838115612118576120b28286613271565b306000908152600460205260409020549091506120d0908390613284565b30600081815260046020526040908190209290925590516001600160a01b038916906000805160206134228339815191529061210f9086815260200190565b60405180910390a35b8280156121255750600082115b15612214576009546040516001624d3b8760e01b03198152600160a01b820463ffffffff1660048201526001600160a01b039091169063ffb2c479906024016060604051808303816000875af1158015612183573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121a79190613153565b505050866001600160a01b03167fae92ab4b6f8f401ead768d3273e6bb937a13e39827d19c6376e8fd4512a05d9a866040516121e591815260200190565b60405180910390a260006121f830610c1b565b111561220f5761220f61220a30610c1b565b612595565b61226b565b821580156122225750600082115b1561226b57856001600160a01b03167fc55650ccda1011e1cdc769b1fbf546ebb8c97800b6072b49e06cd560305b1d678660405161226291815260200190565b60405180910390a25b6001600160a01b03871660009081526004602052604090205461228f908690613271565b6001600160a01b0380891660009081526004602052604080822093909355908816815220546122bf908290613284565b6001600160a01b038088166000908152600460208190526040808320949094556009548b84168352918490205493516338c110ef60e21b8152919092169263e30443bc92612310928c929101613231565b600060405180830381600087803b15801561232a57600080fd5b505af192505050801561233b575060015b506009546001600160a01b038781166000908152600460208190526040918290205491516338c110ef60e21b8152929093169263e30443bc92612382928b92909101613231565b600060405180830381600087803b15801561239c57600080fd5b505af19250505080156123ad575060015b50856001600160a01b0316876001600160a01b0316600080516020613422833981519152836040516123e191815260200190565b60405180910390a350505050505050565b60006107ac6123ff611f1c565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b600080600061245187878787612b4f565b9150915061245e81612c09565b5095945050505050565b60006001600160a01b0382163b15612561576000829050806001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa9250505080156124d9575060408051601f3d908101601f191682019092526124d6918101906132ae565b60015b612555576000839050806001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561253c575060408051601f3d908101601f19168201909252612539918101906132f5565b60015b61254a575060009392505050565b506002949350505050565b50600195945050505050565b506000919050565b919050565b6000620186a061258463ffffffff84168561331a565b61258e9190613331565b9392505050565b600b54600160e81b900460ff16156125aa5750565b600b805460ff60e81b1916600160e81b179055600954819061ffff600160e01b90910416156127065760095460009061ffff600160d01b820481169161260191600160c01b8204811691600160e01b900416613353565b61260b9190613353565b60095461ffff9182169250600091839161262e91600160e01b909104168661331a565b6126389190613331565b90506126448185613271565b30600090815260046020526040902054909350612662908290613271565b3060009081526004602052604081209190915561dead90527f42c63635470f1fb1d6d4b6441c413cb435b1ebb6fedd1896dd5e25d1399147dd546126a7908290613284565b61dead600081905260046020527f42c63635470f1fb1d6d4b6441c413cb435b1ebb6fedd1896dd5e25d1399147dd919091556040513090600080516020613422833981519152906126fb9085815260200190565b60405180910390a350505b306000908152600560209081526040808320600c546001600160a01b0316845290915290205481111561274d57600c5461274d9030906001600160a01b03166000196118b8565b60408051600380825260808201909252600091602082016060803683370190505090503081600081518110612784576127846131a8565b6001600160a01b0392831660209182029290920101526003548251911690829060019081106127b5576127b56131a8565b6001600160a01b039283166020918202929092010152600b548251911690829060029081106127e6576127e66131a8565b6001600160a01b039283166020918202929092010152600c54604051635c11d79560e01b8152911690635c11d7959061282c90859060009086903090429060040161336e565b600060405180830381600087803b15801561284657600080fd5b505af115801561285a573d6000803e3d6000fd5b505060095460009250612882915061ffff600160c01b8204811691600160d01b900416613353565b600b546040516370a0823160e01b815261ffff9290921692506001600160a01b03169060009082906370a08231906128be903090600401612e5f565b602060405180830381865afa1580156128db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128ff91906133aa565b600a546009549192506001600160a01b038085169263a9059cbb929091169063ffffffff87169061293c9061ffff600160c01b909104168661331a565b6129469190613331565b6040518363ffffffff1660e01b8152600401612963929190613231565b6020604051808303816000875af1158015612982573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129a69190613136565b50600a60009054906101000a90046001600160a01b03166001600160a01b03166327bf17586040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156129f757600080fd5b505af1158015612a0b573d6000803e3d6000fd5b50506009546001600160a01b03858116935063a9059cbb925081169063ffffffff871690612a4490600160d01b900461ffff168661331a565b612a4e9190613331565b6040518363ffffffff1660e01b8152600401612a6b929190613231565b6020604051808303816000875af1158015612a8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aae9190613136565b506009546001600160a01b038116906305910bee9063ffffffff861690612ae090600160d01b900461ffff168561331a565b612aea9190613331565b6040518263ffffffff1660e01b8152600401612b0891815260200190565b600060405180830381600087803b158015612b2257600080fd5b505af1158015612b36573d6000803e3d6000fd5b5050600b805460ff60e81b191690555050505050505050565b6000806fa2a8918ca85bafe22016d0b997e4df60600160ff1b03831115612b7c5750600090506003612c00565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015612bd0573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116612bf957600060019250925050612c00565b9150600090505b94509492505050565b6000816004811115612c1d57612c1d6133c3565b03612c255750565b6001816004811115612c3957612c396133c3565b03612c815760405162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b60448201526064016108ac565b6002816004811115612c9557612c956133c3565b03612ce25760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016108ac565b6003816004811115612cf657612cf66133c3565b03610b6d5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016108ac565b600060208083528351808285015260005b81811015612d7b57858101830151858201604001528201612d5f565b506000604082860101526040601f19601f8301168501019250505092915050565b6001600160a01b0381168114610b6d57600080fd5b60008060408385031215612dc457600080fd5b8235612dcf81612d9c565b946020939093013593505050565b600060208284031215612def57600080fd5b813561ffff8116811461258e57600080fd5b600060208284031215612e1357600080fd5b813561258e81612d9c565b600080600060608486031215612e3357600080fd5b8335612e3e81612d9c565b92506020840135612e4e81612d9c565b929592945050506040919091013590565b6001600160a01b0391909116815260200190565b8015158114610b6d57600080fd5b60008060408385031215612e9457600080fd5b8235612e9f81612d9c565b91506020830135612eaf81612e73565b809150509250929050565b600060208284031215612ecc57600080fd5b5035919050565b60008083601f840112612ee557600080fd5b5081356001600160401b03811115612efc57600080fd5b6020830191508360208260051b8501011115612f1757600080fd5b9250929050565b600080600080600060608688031215612f3657600080fd5b8535612f4181612d9c565b945060208601356001600160401b0380821115612f5d57600080fd5b612f6989838a01612ed3565b90965094506040880135915080821115612f8257600080fd5b50612f8f88828901612ed3565b969995985093965092949392505050565b63ffffffff81168114610b6d57600080fd5b600060208284031215612fc457600080fd5b813561258e81612fa0565b60008060008060408587031215612fe557600080fd5b84356001600160401b0380821115612ffc57600080fd5b61300888838901612ed3565b9096509450602087013591508082111561302157600080fd5b5061302e87828801612ed3565b95989497509550505050565b600080600080600080600060e0888a03121561305557600080fd5b873561306081612d9c565b9650602088013561307081612d9c565b95506040880135945060608801359350608088013560ff8116811461309457600080fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156130c457600080fd5b82356130cf81612d9c565b91506020830135612eaf81612d9c565b600081518084526020808501945080840160005b838110156131185781516001600160a01b0316875295820195908201906001016130f3565b509495945050505050565b60208152600061258e60208301846130df565b60006020828403121561314857600080fd5b815161258e81612e73565b60008060006060848603121561316857600080fd5b8351925060208401519150604084015190509250925092565b6020808252600d908201526c0a6a69074409a92a69a82a8869609b1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016131e6576131e66131be565b5060010190565b6020808252600d908201526c29a9a41d1026b0bc101918129760991b604082015260600190565b60006020828403121561322657600080fd5b815161258e81612d9c565b6001600160a01b03929092168252602082015260400190565b6001600160401b0381811683821601908082111561326a5761326a6131be565b5092915050565b818103818111156107ac576107ac6131be565b808201808211156107ac576107ac6131be565b80516001600160701b038116811461256957600080fd5b6000806000606084860312156132c357600080fd5b6132cc84613297565b92506132da60208501613297565b915060408401516132ea81612fa0565b809150509250925092565b60006020828403121561330757600080fd5b815162ffffff8116811461258e57600080fd5b80820281158282048414176107ac576107ac6131be565b60008261334e57634e487b7160e01b600052601260045260246000fd5b500490565b61ffff81811683821601908082111561326a5761326a6131be565b85815284602082015260a06040820152600061338d60a08301866130df565b6001600160a01b0394909416606083015250608001529392505050565b6000602082840312156133bc57600080fd5b5051919050565b634e487b7160e01b600052602160045260246000fdfea66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68845524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e6365ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220ed809645c109fc3186c1c06ed0c2a6c1fd9b8b71c5faaa0964c6da864429266964736f6c63430008120033608060405234801561001057600080fd5b5060405161191738038061191783398101604081905261002f916100b8565b8161003933610068565b600180546001600160a01b0319166001600160a01b0392909216919091179055610e10601155601255506100f2565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600080604083850312156100cb57600080fd5b82516001600160a01b03811681146100e257600080fd5b6020939093015192949293505050565b611816806101016000396000f3fe6080604052600436106101b95760003560e01c80638da5cb5b116100ed578063bc4c4b3711610090578063bc4c4b371461051b578063be10b6141461053b578063c705c56914610551578063e30443bc1461058a578063e7841ec0146105aa578063e98030c7146105bf578063f2fde38b146105df578063fbcbc0f1146105ff578063ffb2c4791461061f57600080fd5b80638da5cb5b1461043057806391b89fba1461044557806399248ea714610465578063a3395cb414610485578063a8b9d240146104a5578063aafd847a146104c5578063b1181e5514610200578063b4113cc8146104fb57600080fd5b806331e79db01161016057806331e79db0146102bf5780634e7b827f146102df5780635183d6fd1461031f578063556cafb0146103845780635ebf4db9146103ba5780636a474002146103da5780636f2789ec146103ef578063715018a61461040557806385a6b3ae1461041a57600080fd5b806303c83302146101be57806305910bee146101c057806306ba651c146101e057806309bbedde1461020057806310a8c46b14610224578063226cfa3d1461025c57806327ce0147146102895780633009a609146102a9575b600080fd5b005b3480156101cc57600080fd5b506101be6101db366004611603565b61065c565b3480156101ec57600080fd5b506101be6101fb366004611631565b610762565b34801561020c57600080fd5b50600a545b6040519081526020015b60405180910390f35b34801561023057600080fd5b5061024461023f366004611603565b61078c565b6040516001600160a01b03909116815260200161021b565b34801561026857600080fd5b50610211610277366004611631565b60106020526000908152604090205481565b34801561029557600080fd5b506102116102a4366004611631565b6107bf565b3480156102b557600080fd5b50610211600e5481565b3480156102cb57600080fd5b506101be6102da366004611631565b610822565b3480156102eb57600080fd5b5061030f6102fa366004611631565b600f6020526000908152604090205460ff1681565b604051901515815260200161021b565b34801561032b57600080fd5b5061033f61033a366004611603565b6108be565b604080516001600160a01b0390991689526020890197909752958701949094526060860192909252608085015260a084015260c083015260e08201526101000161021b565b34801561039057600080fd5b5061021161039f366004611631565b6001600160a01b03166000908152600b602052604090205490565b3480156103c657600080fd5b506101be6103d5366004611603565b61092b565b3480156103e657600080fd5b506101be610938565b3480156103fb57600080fd5b5061021160115481565b34801561041157600080fd5b506101be61096d565b34801561042657600080fd5b5061021160095481565b34801561043c57600080fd5b5061024461097f565b34801561045157600080fd5b50610211610460366004611631565b61098e565b34801561047157600080fd5b50600154610244906001600160a01b031681565b34801561049157600080fd5b506102116104a0366004611631565b610999565b3480156104b157600080fd5b506102116104c0366004611631565b6109de565b3480156104d157600080fd5b506102116104e0366004611631565b6001600160a01b031660009081526008602052604090205490565b34801561050757600080fd5b50600254610244906001600160a01b031681565b34801561052757600080fd5b5061030f61053636600461165c565b610a0a565b34801561054757600080fd5b5061021160125481565b34801561055d57600080fd5b5061030f61056c366004611631565b6001600160a01b03166000908152600f602052604090205460ff1690565b34801561059657600080fd5b506101be6105a5366004611695565b610a95565b3480156105b657600080fd5b50600e54610211565b3480156105cb57600080fd5b506101be6105da366004611603565b610b04565b3480156105eb57600080fd5b506101be6105fa366004611631565b610bd5565b34801561060b57600080fd5b5061033f61061a366004611631565b610c4b565b34801561062b57600080fd5b5061063f61063a366004611603565b610d32565b6040805193845260208401929092529082015260600161021b565b565b61066461097f565b6001600160a01b0316336001600160a01b0316148061069657506002546001600160a01b0316336001600160a01b0316145b6106d75760405162461bcd60e51b815260206004820152600d60248201526c27b7363c9039b2b73232b9399760991b60448201526064015b60405180910390fd5b60006006541180156106e95750600081115b1561075f576006546107169061070383600160801b610e4f565b61070d91906116d7565b60035490610e62565b60035560405181815233907fa493a9229478c3fcd73f66d2cdeb7f94fd0f341da924d1054236d784541165119060200160405180910390a260095461075b9082610e62565b6009555b50565b61076a610e6e565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6000600a60000182815481106107a4576107a46116f9565b6000918252602090912001546001600160a01b031692915050565b6001600160a01b0381166000908152600760209081526040808320546004909252822054600354600160801b926108129261080d92610807916108029190610e4f565b610ecd565b90610edd565b610f1b565b61081c91906116d7565b92915050565b61082a610e6e565b6001600160a01b0381166000908152600f602052604090205460ff161561085057600080fd5b6001600160a01b0381166000908152600f60205260408120805460ff1916600117905561087e908290610f2e565b61088781610f93565b6040516001600160a01b038216907fa878b31040b2e6d0a9a3d3361209db3908ba62014b0dca52adbaee451d128b2590600090a250565b6000806000806000806000806108d3600a5490565b89106108f8575060009650600019955085945086935083925082915081905080610920565b60006109038a61078c565b905061090e81610c4b565b98509850985098509850985098509850505b919395975091939597565b610933610e6e565b601255565b60405162461bcd60e51b815260206004820152600a602482015269222a1d1021a620a4a69760b11b60448201526064016106ce565b610975610e6e565b61065a60006110c6565b6000546001600160a01b031690565b600061081c826109de565b6001600160a01b0381166000908152600d602052604081205460ff166109c25750600019919050565b506001600160a01b03166000908152600c602052604090205490565b6001600160a01b03811660009081526008602052604081205461081c90610a04846107bf565b90611116565b6000610a14610e6e565b6000610a1f84611122565b90508015610a8b576001600160a01b038416600081815260106020526040908190204290555184151591907fa2c38e2d2fb7e3e1912d937fd1ca11ed6d51864dee4cfa7a7bf02becd7acf09290610a799085815260200190565b60405180910390a3600191505061081c565b5060009392505050565b610a9d610e6e565b6001600160a01b0382166000908152600f602052604090205460ff16610b00576012548110610adf57610ad08282610f2e565b610ada8282611287565b610af3565b610aea826000610f2e565b610af382610f93565b610afe826001610a0a565b505b5050565b610b0c610e6e565b610e108110158015610b215750620151808111155b610b665760405162461bcd60e51b815260206004820152601660248201527511150e880c480f0818db185a5b55d85a5d080f080c8d60521b60448201526064016106ce565b6011548103610ba25760405162461bcd60e51b815260206004820152600860248201526744543a2053616d6560c01b60448201526064016106ce565b60115460405182907f474ea64804364a1e29a4487ddb63c3342a2dd826ccd8acf48825e680a0e6f20f90600090a3601155565b610bdd610e6e565b6001600160a01b038116610c425760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016106ce565b61075f816110c6565b806000808080808080610c5d88610999565b9650600019955060008712610cbf57600e54871115610c8b57600e54610c84908890611345565b9550610cbf565b600e54600a5460009110610ca0576000610caf565b600e54600a54610caf91611116565b9050610cbb8882610edd565b9650505b610cc8886109de565b9450610cd3886107bf565b6001600160a01b038916600090815260106020526040902054909450925082610cfd576000610d0b565b601154610d0b908490610e62565b9150428211610d1b576000610d25565b610d258242611116565b9050919395975091939597565b600a5460009081908190808203610d54575050600e5460009250829150610e48565b600e546000805a90506000805b8984108015610d6f57508582105b15610e375784610d7e8161170f565b600a5490965086109050610d9157600094505b6000600a6000018681548110610da957610da96116f9565b60009182526020808320909101546001600160a01b03168083526010909152604090912054909150610dda90611391565b15610dfd57610dea816001610a0a565b15610dfd5781610df98161170f565b9250505b82610e078161170f565b93505060005a905080851115610e2e57610e2b610e248683611116565b8790610e62565b95505b9350610d619050565b600e85905590975095509193505050505b9193909250565b6000610e5b8284611728565b9392505050565b6000610e5b828461173f565b33610e7761097f565b6001600160a01b03161461065a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016106ce565b6000818181121561081c57600080fd5b600080610eea8385611752565b905060008312158015610efd5750838112155b80610f125750600083128015610f1257508381125b610e5b57600080fd5b600080821215610f2a57600080fd5b5090565b6001600160a01b03821660009081526004602052604090205480821115610f6d576000610f5b8383611116565b9050610f6784826113b8565b50610afe565b80821015610afe576000610f818284611116565b9050610f8d84826114a6565b50505050565b6001600160a01b0381166000908152600d602052604090205460ff16610fb65750565b6001600160a01b0381166000908152600d60209081526040808320805460ff19169055600b8252808320839055600c909152812054600a54909190610ffd9060019061177a565b90506000600a6000018281548110611017576110176116f9565b60009182526020808320909101546001600160a01b03908116808452600c90925260408084208790559087168352822091909155600a8054919250829185908110611064576110646116f9565b600091825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055600a80548061109e5761109e61178d565b600082815260209020810160001990810180546001600160a01b031916905501905550505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000610e5b828461177a565b60008061112e836109de565b9050801561127e576001600160a01b0383166000908152600860205260409020546111599082610e62565b6001600160a01b038416600081815260086020526040908190209290925590517fee503bee2bb6a87e57bc57db795f98137327401a0e7b7ce42e37926cc1a9ca4d906111a89084815260200190565b60405180910390a260015460405163a9059cbb60e01b81526001600160a01b03858116600483015260248201849052600092169063a9059cbb906044016020604051808303816000875af1158015611204573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061122891906117a3565b905080611277576001600160a01b0384166000908152600860205260409020546112529083611116565b6001600160a01b03909416600090815260086020526040812094909455509192915050565b5092915050565b50600092915050565b6001600160a01b0382166000908152600d602052604090205460ff16156112c5576001600160a01b03919091166000908152600b6020526040902055565b6001600160a01b0382166000818152600d60209081526040808320805460ff19166001908117909155600b8352818420869055600a8054600c909452918420839055820181559091527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a80180546001600160a01b03191690911790555050565b600080821215801561136057508261135d83826117c0565b13155b8061137e575060008212801561137e57508261137c83826117c0565b135b61138757600080fd5b610e5b82846117c0565b6000428211156113a357506000919050565b6011546113b04284611116565b101592915050565b6001600160a01b03821661140e5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016106ce565b8060066000828254611420919061173f565b90915550506001600160a01b0382166000908152600460205260408120805483929061144d90849061173f565b909155505060035461148690611467906108029084610e4f565b6001600160a01b03841660009081526007602052604090205490611345565b6001600160a01b0390921660009081526007602052604090209190915550565b6001600160a01b0382166115065760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016106ce565b6001600160a01b0382166000908152600460205260409020548181101561157a5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016106ce565b6001600160a01b03831660009081526004602052604081208383039055600680548492906115a990849061177a565b90915550506003546115e2906115c3906108029085610e4f565b6001600160a01b03851660009081526007602052604090205490610edd565b6001600160a01b039093166000908152600760205260409020929092555050565b60006020828403121561161557600080fd5b5035919050565b6001600160a01b038116811461075f57600080fd5b60006020828403121561164357600080fd5b8135610e5b8161161c565b801515811461075f57600080fd5b6000806040838503121561166f57600080fd5b823561167a8161161c565b9150602083013561168a8161164e565b809150509250929050565b600080604083850312156116a857600080fd5b82356116b38161161c565b946020939093013593505050565b634e487b7160e01b600052601160045260246000fd5b6000826116f457634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603260045260246000fd5b600060018201611721576117216116c1565b5060010190565b808202811582820484141761081c5761081c6116c1565b8082018082111561081c5761081c6116c1565b8082018281126000831280158216821582161715611772576117726116c1565b505092915050565b8181038181111561081c5761081c6116c1565b634e487b7160e01b600052603160045260246000fd5b6000602082840312156117b557600080fd5b8151610e5b8161164e565b8181036000831280158383131683831282161715611277576112776116c156fea2646970667358221220d8e01e364f403110c88a9b2a9b3c095d8ce89c5b04afa59b8a57a6fe259f838864736f6c6343000812003360806040526002805460ff60a01b191690553480156200001e57600080fd5b506040516200100d3803806200100d8339810160408190526200004191620001e7565b6200004c336200017a565b600180546001600160a01b038681166001600160c01b031990921691909117600160a01b63ffffffff871602179182905560408051635c9302c960e01b815290519290911691635c9302c9916004808201926020929091908290030181865afa158015620000be573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000e491906200024e565b600180546001600160401b0392909216600160c01b026001600160c01b03909216919091179055600280546001600160a01b038085166001600160a01b03199283161790925560038054928416929091169190911790556200014a426201518062000268565b600360146101000a8154816001600160401b0302191690836001600160401b03160217905550505050506200029e565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b0381168114620001e257600080fd5b919050565b60008060008060808587031215620001fe57600080fd5b6200020985620001ca565b9350602085015163ffffffff811681146200022357600080fd5b92506200023360408601620001ca565b91506200024360608601620001ca565b905092959194509250565b6000602082840312156200026157600080fd5b5051919050565b6001600160401b038181168382160190808211156200029757634e487b7160e01b600052601160045260246000fd5b5092915050565b610d5f80620002ae6000396000f3fe608060405234801561001057600080fd5b50600436106100ba5760003560e01c806327bf1758146100bf5780632c1f5216146100c957806349df728c146100f2578063715018a614610105578063790ca4131461010d578063831794281461013f5780638da5cb5b14610159578063963df3eb1461016a578063aeb7172e1461017d578063bc75e706146101a1578063c72ade2a146101a9578063f2fde38b146101d5578063f887ea40146101e8578063fc0c546a146101fb575b600080fd5b6100c761020e565b005b6002546100dc906001600160a01b031681565b6040516100e99190610b27565b60405180910390f35b6100c7610100366004610b3b565b610889565b6100c761097b565b60035461012790600160a01b90046001600160401b031681565b6040516001600160401b0390911681526020016100e9565b60015461012790600160c01b90046001600160401b031681565b6000546001600160a01b03166100dc565b6100c7610178366004610b3b565b61098f565b60025461019190600160a01b900460ff1681565b60405190151581526020016100e9565b6100c76109b9565b6001546101c090600160a01b900463ffffffff1681565b60405163ffffffff90911681526020016100e9565b6100c76101e3366004610b3b565b6109ff565b6003546100dc906001600160a01b031681565b6001546100dc906001600160a01b031681565b610216610a7d565b60015460405163033060d960e41b81526001600160a01b039091169060009082906333060d909061024b903090600401610b27565b602060405180830381865afa158015610268573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061028c9190610b6b565b90508015610770576000826001600160a01b0316635c9302c96040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102f89190610b6b565b90506000805b8381101561057d576040516370a0823160e01b81526000906001600160a01b038716906370a0823190610335903090600401610b27565b602060405180830381865afa158015610352573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103769190610b6b565b90506000806000886001600160a01b0316632607443b30876040518363ffffffff1660e01b81526004016103ab929190610b84565b60e060405180830381865afa1580156103c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103ec9190610bdd565b5050945094505050925080826104029190610c85565b61ffff168710610566576040516332e7b8d960e11b81523060048201526024810186905264ffffffffff841660448201526001600160a01b038a16906365cf71b290606401600060405180830381600087803b15801561046157600080fd5b505af1158015610475573d6000803e3d6000fd5b5050604051631a1804d160e11b81526004810188905264ffffffffff861660248201526001600160a01b038c16925063343009a29150604401600060405180830381600087803b1580156104c857600080fd5b505af11580156104dc573d6000803e3d6000fd5b50506040516370a0823160e01b81528692506001600160a01b038c1691506370a082319061050e903090600401610b27565b602060405180830381865afa15801561052b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061054f9190610b6b565b6105599190610ca7565b6105639087610cc0565b95505b50505050808061057590610cd3565b9150506102fe565b50801561076a576002546001600160a01b038086169163a9059cbb91166105a5606485610cec565b6040518363ffffffff1660e01b81526004016105c2929190610b84565b6020604051808303816000875af11580156105e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106059190610d0e565b506002546001600160a01b03166305910bee610622606484610cec565b6040518263ffffffff1660e01b815260040161064091815260200190565b600060405180830381600087803b15801561065a57600080fd5b505af115801561066e573d6000803e3d6000fd5b5050600254600160a01b900460ff16915061076a9050576040516370a0823160e01b81526000906001600160a01b038616906370a08231906106b4903090600401610b27565b602060405180830381865afa1580156106d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106f59190610b6b565b600154604051630a54871760e31b815260048101839052600160a01b90910463ffffffff1660248201529091506001600160a01b038616906352a438b890604401600060405180830381600087803b15801561075057600080fd5b505af1158015610764573d6000803e3d6000fd5b50505050505b50505050565b600354600160a01b90046001600160401b03164211801561079b5750600254600160a01b900460ff16155b15610885576040516370a0823160e01b81526000906001600160a01b038416906370a08231906107cf903090600401610b27565b602060405180830381865afa1580156107ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108109190610b6b565b600154604051630a54871760e31b815260048101839052600160a01b90910463ffffffff1660248201529091506001600160a01b038416906352a438b890604401600060405180830381600087803b15801561086b57600080fd5b505af115801561087f573d6000803e3d6000fd5b50505050505b5050565b610891610a7d565b6001546040516370a0823160e01b81526001600160a01b039091169060009082906370a08231906108c6903090600401610b27565b602060405180830381865afa1580156108e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109079190610b6b565b60405163a9059cbb60e01b81529091506001600160a01b0383169063a9059cbb906109389086908590600401610b84565b6020604051808303816000875af1158015610957573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061076a9190610d0e565b610983610a7d565b61098d6000610ad7565b565b610997610a7d565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6109c1610a7d565b6040517fe3a06166721e4401c7406b5a05eccdaad77f04137868154859e2bb711c6aadf490600090a16002805460ff60a01b1916600160a01b179055565b610a07610a7d565b6001600160a01b038116610a715760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b610a7a81610ad7565b50565b6000546001600160a01b0316331461098d5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a68565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b0391909116815260200190565b600060208284031215610b4d57600080fd5b81356001600160a01b0381168114610b6457600080fd5b9392505050565b600060208284031215610b7d57600080fd5b5051919050565b6001600160a01b03929092168252602082015260400190565b805168ffffffffffffffffff81168114610bb657600080fd5b919050565b805161ffff81168114610bb657600080fd5b80518015158114610bb657600080fd5b600080600080600080600060e0888a031215610bf857600080fd5b875164ffffffffff81168114610c0d57600080fd5b9650610c1b60208901610b9d565b9550610c2960408901610b9d565b9450610c3760608901610bbb565b9350610c4560808901610bbb565b9250610c5360a08901610bbb565b9150610c6160c08901610bcd565b905092959891949750929550565b634e487b7160e01b600052601160045260246000fd5b61ffff818116838216019080821115610ca057610ca0610c6f565b5092915050565b81810381811115610cba57610cba610c6f565b92915050565b80820180821115610cba57610cba610c6f565b600060018201610ce557610ce5610c6f565b5060010190565b600082610d0957634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215610d2057600080fd5b610b6482610bcd56fea26469706673582212209e29d998f5d511e2381c9b1bc22c2ba25fa5ed079c0d5ba6afda8cab6967c0f264736f6c63430008120033000000000000000000000000165c3410fc91ef562c50559f7d2289febed552d9
Deployed ByteCode
0x60806040526004361061020a5760003560e01c8063771282f611610119578063c8d1ef8a116100a6578063c8d1ef8a1461061e578063ca72a4e71461063e578063d505accf1461065e578063db932ae21461067e578063dd62ed3e1461069e578063e98030c7146106e4578063e9cb414f14610704578063f200e29d14610724578063f2fde38b14610746578063f8ea410614610766578063fe82b5e01461078657600080fd5b8063771282f6146104c85780637ecebe00146104de5780638da5cb5b146104fe5780638fb5043d1461051357806395d89b4114610533578063a9059cbb14610560578063aad41a4114610580578063b1a4e0dc146105a0578063b4113cc8146105de578063bb1789d6146105fe57600080fd5b80633644e515116101975780633644e5151461039b5780634e71d92d146103b05780635342acb4146103c55780636612e66f146103fe578063700bb1911461041e57806370a082311461043e57806370bfdd9d1461045e578063715018a61461047357806373ae740e1461048857806376b3617b146104a857600080fd5b806306fdde0314610216578063095ea7b31461026157806312a659e21461029157806318160ddd146102b3578063222d3b05146102d257806323b872dd146102f25780632c1f521614610312578063313ce5671461033f57806331e79db01461035b578063342aa8b51461037b57600080fd5b3661021157005b600080fd5b34801561022257600080fd5b5060408051808201909152601081526f0a6eae0cae4a6e8c2d6ca7440e0908ab60831b60208201525b6040516102589190612d4e565b60405180910390f35b34801561026d57600080fd5b5061028161027c366004612db1565b61079b565b6040519015158152602001610258565b34801561029d57600080fd5b506102b16102ac366004612ddd565b6107b2565b005b3480156102bf57600080fd5b506002545b604051908152602001610258565b3480156102de57600080fd5b506102b16102ed366004612e01565b6107dc565b3480156102fe57600080fd5b5061028161030d366004612e1e565b610918565b34801561031e57600080fd5b50600954610332906001600160a01b031681565b6040516102589190612e5f565b34801561034b57600080fd5b5060405160098152602001610258565b34801561036757600080fd5b506102b1610376366004612e01565b610992565b34801561038757600080fd5b506102b1610396366004612e81565b6109ff565b3480156103a757600080fd5b506102c4610ae9565b3480156103bc57600080fd5b506102b1610af8565b3480156103d157600080fd5b506102816103e0366004612e01565b6001600160a01b031660009081526006602052604090205460ff1690565b34801561040a57600080fd5b506102b1610419366004612e81565b610b70565b34801561042a57600080fd5b506102b1610439366004612eba565b610ba3565b34801561044a57600080fd5b506102c4610459366004612e01565b610c1b565b34801561046a57600080fd5b506102b1610c36565b34801561047f57600080fd5b506102b1610c53565b34801561049457600080fd5b506102b16104a3366004612f1e565b610c67565b3480156104b457600080fd5b506102b16104c3366004612fb2565b610d50565b3480156104d457600080fd5b506102c460025481565b3480156104ea57600080fd5b506102c46104f9366004612e01565b610e31565b34801561050a57600080fd5b50610332610e4f565b34801561051f57600080fd5b506102b161052e366004612ddd565b610e5e565b34801561053f57600080fd5b506040805180820190915260048152630e0a6a6960e31b602082015261024b565b34801561056c57600080fd5b5061028161057b366004612db1565b610e88565b34801561058c57600080fd5b506102b161059b366004612fcf565b610e95565b3480156105ac57600080fd5b506102816105bb366004612e01565b6001600160a01b0316600090815260066020526040902054610100900460ff1690565b3480156105ea57600080fd5b50600a54610332906001600160a01b031681565b34801561060a57600080fd5b506102b1610619366004612fb2565b610ee7565b34801561062a57600080fd5b506102b1610639366004612ddd565b610f3d565b34801561064a57600080fd5b506102b1610659366004612e01565b610f67565b34801561066a57600080fd5b506102b161067936600461303a565b611441565b34801561068a57600080fd5b506102b1610699366004612fb2565b6115c4565b3480156106aa57600080fd5b506102c46106b93660046130b1565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205490565b3480156106f057600080fd5b506102b16106ff366004612eba565b61161a565b34801561071057600080fd5b506102b161071f366004612e01565b611653565b34801561073057600080fd5b506107396116b2565b6040516102589190613123565b34801561075257600080fd5b506102b1610761366004612e01565b611714565b34801561077257600080fd5b506102b1610781366004612e01565b61178a565b34801561079257600080fd5b506102b16117c2565b60006107a83384846118b8565b5060015b92915050565b6107ba6119dc565b6009805461ffff909216600160e01b0261ffff60e01b19909216919091179055565b6107e46119dc565b600a546040805163575b8b9760e11b815290516001600160a01b0390921691600091839163aeb7172e916004808201926020929091908290030181865afa158015610833573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108579190613136565b9050806108b55760405162461bcd60e51b815260206004820152602160248201527f5353483a205374616b696e6720706f6f6c206e6f7420646973656e67616765646044820152601760f91b60648201526084015b60405180910390fd5b604051631277dca360e21b81526001600160a01b038316906349df728c906108e1908690600401612e5f565b600060405180830381600087803b1580156108fb57600080fd5b505af115801561090f573d6000803e3d6000fd5b50505050505050565b6000610925848484611a3b565b6109888433610983856040518060600160405280602881526020016133fa602891396001600160a01b038a16600090815260056020526040812090335b6001600160a01b031681526020810191909152604001600020549190611ef0565b6118b8565b5060019392505050565b61099a6119dc565b60095460405163031e79db60e41b81526001600160a01b03909116906331e79db0906109ca908490600401612e5f565b600060405180830381600087803b1580156109e457600080fd5b505af11580156109f8573d6000803e3d6000fd5b5050505050565b610a076119dc565b6001600160a01b038216600090815260066020526040902054600160701b900460ff1615610a685760405162461bcd60e51b815260206004820152600e60248201526d29a9a41d102327a92124a22222a760911b60448201526064016108ac565b8015610ab857600954600160f01b900460ff1615610ab85760405162461bcd60e51b815260206004820152600d60248201526c14d4d20e88111254d050931151609a1b60448201526064016108ac565b6001600160a01b03909116600090815260066020526040902080549115156101000261ff0019909216919091179055565b6000610af3611f1c565b905090565b60095460405163bc4c4b3760e01b8152336004820152600060248201526001600160a01b039091169063bc4c4b37906044016020604051808303816000875af1158015610b49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b6d9190613136565b50565b610b786119dc565b6001600160a01b03919091166000908152600660205260409020805460ff1916911515919091179055565b6009546040516001624d3b8760e01b03198152600481018390526001600160a01b039091169063ffb2c479906024016060604051808303816000875af1158015610bf1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c159190613153565b50505050565b6001600160a01b031660009081526004602052604090205490565b610c3e6119dc565b6009805460ff60f01b1916600160f01b179055565b610c5b6119dc565b610c656000612043565b565b828114610c865760405162461bcd60e51b81526004016108ac90613181565b60005b83811015610d4857610cdd86868684818110610ca757610ca76131a8565b9050602002016020810190610cbc9190612e01565b858585818110610cce57610cce6131a8565b90506020020135600080612093565b610d368633610983868686818110610cf757610cf76131a8565b905060200201356040518060600160405280602881526020016133fa602891396001600160a01b038c1660009081526005602052604081209033610962565b80610d40816131d4565b915050610c89565b505050505050565b610d586119dc565b62030d408163ffffffff1610158015610d7a57506207a1208163ffffffff1611155b610dc05760405162461bcd60e51b815260206004820152601760248201527603230302c303030203c20474650203c203530302c30303604c1b60448201526064016108ac565b60095463ffffffff600160a01b909104811690821603610e0b5760405162461bcd60e51b81526004016108ac9060208082526004908201526353616d6560e01b604082015260600190565b6009805463ffffffff909216600160a01b0263ffffffff60a01b19909216919091179055565b6001600160a01b0381166000908152600160205260408120546107ac565b6000546001600160a01b031690565b610e666119dc565b6009805461ffff909216600160c01b0261ffff60c01b19909216919091179055565b60006107a8338484611a3b565b828114610eb45760405162461bcd60e51b81526004016108ac90613181565b60005b838110156109f857610ed533868684818110610ca757610ca76131a8565b80610edf816131d4565b915050610eb7565b610eef6119dc565b614e208163ffffffff161115610f175760405162461bcd60e51b81526004016108ac906131ed565b600b805463ffffffff909216600160c01b0263ffffffff60c01b19909216919091179055565b610f456119dc565b6009805461ffff909216600160d01b0261ffff60d01b19909216919091179055565b610f6f6119dc565b600b54600160e01b900460ff1615610fb25760405162461bcd60e51b81526004016108ac9060208082526004908201526327a822a760e11b604082015260600190565b600380546001600160a01b0319166001600160a01b0383811691909117909155600954600c5460405163031e79db60e41b8152918316926331e79db092610fff9290911690600401612e5f565b600060405180830381600087803b15801561101957600080fd5b505af115801561102d573d6000803e3d6000fd5b5050600c5461104b92503091506001600160a01b03166000196118b8565b600c546040805163c45a015560e01b815290516000926001600160a01b03169163c45a01559160048083019260209291908290030181865afa158015611095573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b99190613214565b6003546040516364e329cb60e11b81523060048201526001600160a01b03918216602482015291169063c9c65396906044016020604051808303816000875af115801561110a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112e9190613214565b60095460405163031e79db60e41b81529192506001600160a01b0316906331e79db09061115f908490600401612e5f565b600060405180830381600087803b15801561117957600080fd5b505af115801561118d573d6000803e3d6000fd5b5050600c546001600160a01b0316915063f305d719905047306111af81610c1b565b6000806111ba610e4f565b60405160e088901b6001600160e01b03191681526001600160a01b03958616600482015260248101949094526044840192909252606483015290911660848201524260a482015260c40160606040518083038185885af1158015611222573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906112479190613153565b5050600b805462ff00ff60e01b19166201000160e01b17905550600c5460405163095ea7b360e01b81526001600160a01b038381169263095ea7b392611297929091169060001990600401613231565b6020604051808303816000875af11580156112b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112da9190613136565b506040805160e081018252600080825260208083018281528385018381526060850184815260808601858152600160a0880181815260c089018281526001600160a01b039b909b16808952600690975298872097518854955194519351925199519a5161ffff1990961690151561ff00191617610100941515949094029390931769ffffffffffffffff000019166201000063ffffffff9384160263ffffffff60301b191617600160301b918316919091021764ffffffffff60501b1916600160501b919097160260ff60701b191695909517600160701b961515969096029590951760ff60781b1916600160781b9515159590950294909417909155600780548084019091556000805160206133da8339815191520180546001600160a01b031990811685179091556008805493840181559091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee39091018054909116909117905550565b834211156114915760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e6500000060448201526064016108ac565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98888886114df8c6001600160a01b031660009081526001602081905260409091208054918201905590565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e001604051602081830303815290604052805190602001209050600061153a826123f2565b9050600061154a82878787612440565b9050896001600160a01b0316816001600160a01b0316146115ad5760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e6174757265000060448201526064016108ac565b6115b88a8a8a6118b8565b50505050505050505050565b6115cc6119dc565b614e208163ffffffff1611156115f45760405162461bcd60e51b81526004016108ac906131ed565b600b805463ffffffff909216600160a01b0263ffffffff60a01b19909216919091179055565b6116226119dc565b60095460405163e98030c760e01b8152600481018390526001600160a01b039091169063e98030c7906024016109ca565b61165b6119dc565b6001600160a01b03166000818152600660205260408120805460ff60701b1916600160701b1790556007805460018101825591526000805160206133da8339815191520180546001600160a01b0319169091179055565b6060600780548060200260200160405190810160405280929190818152602001828054801561170a57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116116ec575b5050505050905090565b61171c6119dc565b6001600160a01b0381166117815760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016108ac565b610b6d81612043565b6117926119dc565b600a5460405163f2fde38b60e01b81526001600160a01b039091169063f2fde38b906109ca908490600401612e5f565b6117ca6119dc565b600a5442906117ec90600160a01b90046001600160401b031662e85c6061324a565b6001600160401b0316116118545760405162461bcd60e51b815260206004820152602960248201527f5353483a205374616b696e6720706f6f6c206e6f206c6f6e67657220646973656044820152683733b0b3b0b136329760b91b60648201526084016108ac565b600a60009054906101000a90046001600160a01b03166001600160a01b031663bc75e7066040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156118a457600080fd5b505af1158015610c15573d6000803e3d6000fd5b6001600160a01b03831661191a5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016108ac565b6001600160a01b03821661197b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016108ac565b6001600160a01b0383811660008181526005602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b336119e5610e4f565b6001600160a01b031614610c655760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016108ac565b6001600160a01b038316611a9f5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016108ac565b6001600160a01b038216611b015760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016108ac565b60008111611b635760405162461bcd60e51b815260206004820152602960248201527f5472616e7366657220616d6f756e74206d7573742062652067726561746572206044820152687468616e207a65726f60b81b60648201526084016108ac565b600080611b6e610e4f565b6001600160a01b0316856001600160a01b031614158015611ba85750611b92610e4f565b6001600160a01b0316846001600160a01b031614155b8015611bbd57506001600160a01b0385163014155b8015611be257506001600160a01b03841660009081526006602052604090205460ff16155b8015611c0757506001600160a01b03851660009081526006602052604090205460ff16155b8015611c1d5750600b54600160e81b900460ff16155b15611ede576001600160a01b038416600090815260066020526040902054610100900460ff16158015611c6e57506001600160a01b038516600090815260066020526040902054610100900460ff16155b611cae5760405162461bcd60e51b815260206004820152601160248201527029a9a41d10213637b1b5b634b9ba32b21760791b60448201526064016108ac565b6001600160a01b038516600090815260066020526040902054600160701b900460ff1615611ced57600b54600160a01b900463ffffffff169150611ee3565b6001600160a01b038416600090815260066020526040902054600160701b900460ff1615611dc4575050600b546001600160a01b038416600090815260066020526040902054600160c01b90910463ffffffff90811691600191438116620100009092041603611d8b5760405162461bcd60e51b81526020600482015260096024820152680a6a6907440a6ae86960bb1b60448201526064016108ac565b6001600160a01b0385166000908152600660205260409020805463ffffffff60301b1916600160301b4363ffffffff1602179055611ee3565b600091506000611dd385612468565b90508060ff16600203611e195760405162461bcd60e51b815260206004820152600e60248201526d29a9a41d102737903b199026281760911b60448201526064016108ac565b8060ff16600103611ed8576001600160a01b03808616600081815260066020526040808220805460ff60701b1916600160701b1790556007805460018101825592526000805160206133da83398151915290910180546001600160a01b031916909217909155600954905163031e79db60e41b81529116906331e79db090611ea5908890600401612e5f565b600060405180830381600087803b158015611ebf57600080fd5b505af1158015611ed3573d6000803e3d6000fd5b505050505b50611ee3565b600091505b6109f88585858585612093565b60008184841115611f145760405162461bcd60e51b81526004016108ac9190612d4e565b505050900390565b6000306001600160a01b037f000000000000000000000000b5c4ecef450fd36d0eba1420f6a19dbfbee5292e16148015611f7557507f000000000000000000000000000000000000000000000000000000000000017146145b15611f9f57507fd36628e3aea14329930f00ee9323da7c25327903680f23eccf17a516eb4bda4490565b50604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091527f1f1814183d746334cc745028bdaa07f5b137c2c6b9424bd683263e8340b87333828401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600061209f848461256e565b9050838115612118576120b28286613271565b306000908152600460205260409020549091506120d0908390613284565b30600081815260046020526040908190209290925590516001600160a01b038916906000805160206134228339815191529061210f9086815260200190565b60405180910390a35b8280156121255750600082115b15612214576009546040516001624d3b8760e01b03198152600160a01b820463ffffffff1660048201526001600160a01b039091169063ffb2c479906024016060604051808303816000875af1158015612183573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121a79190613153565b505050866001600160a01b03167fae92ab4b6f8f401ead768d3273e6bb937a13e39827d19c6376e8fd4512a05d9a866040516121e591815260200190565b60405180910390a260006121f830610c1b565b111561220f5761220f61220a30610c1b565b612595565b61226b565b821580156122225750600082115b1561226b57856001600160a01b03167fc55650ccda1011e1cdc769b1fbf546ebb8c97800b6072b49e06cd560305b1d678660405161226291815260200190565b60405180910390a25b6001600160a01b03871660009081526004602052604090205461228f908690613271565b6001600160a01b0380891660009081526004602052604080822093909355908816815220546122bf908290613284565b6001600160a01b038088166000908152600460208190526040808320949094556009548b84168352918490205493516338c110ef60e21b8152919092169263e30443bc92612310928c929101613231565b600060405180830381600087803b15801561232a57600080fd5b505af192505050801561233b575060015b506009546001600160a01b038781166000908152600460208190526040918290205491516338c110ef60e21b8152929093169263e30443bc92612382928b92909101613231565b600060405180830381600087803b15801561239c57600080fd5b505af19250505080156123ad575060015b50856001600160a01b0316876001600160a01b0316600080516020613422833981519152836040516123e191815260200190565b60405180910390a350505050505050565b60006107ac6123ff611f1c565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b600080600061245187878787612b4f565b9150915061245e81612c09565b5095945050505050565b60006001600160a01b0382163b15612561576000829050806001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa9250505080156124d9575060408051601f3d908101601f191682019092526124d6918101906132ae565b60015b612555576000839050806001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561253c575060408051601f3d908101601f19168201909252612539918101906132f5565b60015b61254a575060009392505050565b506002949350505050565b50600195945050505050565b506000919050565b919050565b6000620186a061258463ffffffff84168561331a565b61258e9190613331565b9392505050565b600b54600160e81b900460ff16156125aa5750565b600b805460ff60e81b1916600160e81b179055600954819061ffff600160e01b90910416156127065760095460009061ffff600160d01b820481169161260191600160c01b8204811691600160e01b900416613353565b61260b9190613353565b60095461ffff9182169250600091839161262e91600160e01b909104168661331a565b6126389190613331565b90506126448185613271565b30600090815260046020526040902054909350612662908290613271565b3060009081526004602052604081209190915561dead90527f42c63635470f1fb1d6d4b6441c413cb435b1ebb6fedd1896dd5e25d1399147dd546126a7908290613284565b61dead600081905260046020527f42c63635470f1fb1d6d4b6441c413cb435b1ebb6fedd1896dd5e25d1399147dd919091556040513090600080516020613422833981519152906126fb9085815260200190565b60405180910390a350505b306000908152600560209081526040808320600c546001600160a01b0316845290915290205481111561274d57600c5461274d9030906001600160a01b03166000196118b8565b60408051600380825260808201909252600091602082016060803683370190505090503081600081518110612784576127846131a8565b6001600160a01b0392831660209182029290920101526003548251911690829060019081106127b5576127b56131a8565b6001600160a01b039283166020918202929092010152600b548251911690829060029081106127e6576127e66131a8565b6001600160a01b039283166020918202929092010152600c54604051635c11d79560e01b8152911690635c11d7959061282c90859060009086903090429060040161336e565b600060405180830381600087803b15801561284657600080fd5b505af115801561285a573d6000803e3d6000fd5b505060095460009250612882915061ffff600160c01b8204811691600160d01b900416613353565b600b546040516370a0823160e01b815261ffff9290921692506001600160a01b03169060009082906370a08231906128be903090600401612e5f565b602060405180830381865afa1580156128db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128ff91906133aa565b600a546009549192506001600160a01b038085169263a9059cbb929091169063ffffffff87169061293c9061ffff600160c01b909104168661331a565b6129469190613331565b6040518363ffffffff1660e01b8152600401612963929190613231565b6020604051808303816000875af1158015612982573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129a69190613136565b50600a60009054906101000a90046001600160a01b03166001600160a01b03166327bf17586040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156129f757600080fd5b505af1158015612a0b573d6000803e3d6000fd5b50506009546001600160a01b03858116935063a9059cbb925081169063ffffffff871690612a4490600160d01b900461ffff168661331a565b612a4e9190613331565b6040518363ffffffff1660e01b8152600401612a6b929190613231565b6020604051808303816000875af1158015612a8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aae9190613136565b506009546001600160a01b038116906305910bee9063ffffffff861690612ae090600160d01b900461ffff168561331a565b612aea9190613331565b6040518263ffffffff1660e01b8152600401612b0891815260200190565b600060405180830381600087803b158015612b2257600080fd5b505af1158015612b36573d6000803e3d6000fd5b5050600b805460ff60e81b191690555050505050505050565b6000806fa2a8918ca85bafe22016d0b997e4df60600160ff1b03831115612b7c5750600090506003612c00565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015612bd0573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116612bf957600060019250925050612c00565b9150600090505b94509492505050565b6000816004811115612c1d57612c1d6133c3565b03612c255750565b6001816004811115612c3957612c396133c3565b03612c815760405162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b60448201526064016108ac565b6002816004811115612c9557612c956133c3565b03612ce25760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016108ac565b6003816004811115612cf657612cf66133c3565b03610b6d5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016108ac565b600060208083528351808285015260005b81811015612d7b57858101830151858201604001528201612d5f565b506000604082860101526040601f19601f8301168501019250505092915050565b6001600160a01b0381168114610b6d57600080fd5b60008060408385031215612dc457600080fd5b8235612dcf81612d9c565b946020939093013593505050565b600060208284031215612def57600080fd5b813561ffff8116811461258e57600080fd5b600060208284031215612e1357600080fd5b813561258e81612d9c565b600080600060608486031215612e3357600080fd5b8335612e3e81612d9c565b92506020840135612e4e81612d9c565b929592945050506040919091013590565b6001600160a01b0391909116815260200190565b8015158114610b6d57600080fd5b60008060408385031215612e9457600080fd5b8235612e9f81612d9c565b91506020830135612eaf81612e73565b809150509250929050565b600060208284031215612ecc57600080fd5b5035919050565b60008083601f840112612ee557600080fd5b5081356001600160401b03811115612efc57600080fd5b6020830191508360208260051b8501011115612f1757600080fd5b9250929050565b600080600080600060608688031215612f3657600080fd5b8535612f4181612d9c565b945060208601356001600160401b0380821115612f5d57600080fd5b612f6989838a01612ed3565b90965094506040880135915080821115612f8257600080fd5b50612f8f88828901612ed3565b969995985093965092949392505050565b63ffffffff81168114610b6d57600080fd5b600060208284031215612fc457600080fd5b813561258e81612fa0565b60008060008060408587031215612fe557600080fd5b84356001600160401b0380821115612ffc57600080fd5b61300888838901612ed3565b9096509450602087013591508082111561302157600080fd5b5061302e87828801612ed3565b95989497509550505050565b600080600080600080600060e0888a03121561305557600080fd5b873561306081612d9c565b9650602088013561307081612d9c565b95506040880135945060608801359350608088013560ff8116811461309457600080fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156130c457600080fd5b82356130cf81612d9c565b91506020830135612eaf81612d9c565b600081518084526020808501945080840160005b838110156131185781516001600160a01b0316875295820195908201906001016130f3565b509495945050505050565b60208152600061258e60208301846130df565b60006020828403121561314857600080fd5b815161258e81612e73565b60008060006060848603121561316857600080fd5b8351925060208401519150604084015190509250925092565b6020808252600d908201526c0a6a69074409a92a69a82a8869609b1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016131e6576131e66131be565b5060010190565b6020808252600d908201526c29a9a41d1026b0bc101918129760991b604082015260600190565b60006020828403121561322657600080fd5b815161258e81612d9c565b6001600160a01b03929092168252602082015260400190565b6001600160401b0381811683821601908082111561326a5761326a6131be565b5092915050565b818103818111156107ac576107ac6131be565b808201808211156107ac576107ac6131be565b80516001600160701b038116811461256957600080fd5b6000806000606084860312156132c357600080fd5b6132cc84613297565b92506132da60208501613297565b915060408401516132ea81612fa0565b809150509250925092565b60006020828403121561330757600080fd5b815162ffffff8116811461258e57600080fd5b80820281158282048414176107ac576107ac6131be565b60008261334e57634e487b7160e01b600052601260045260246000fd5b500490565b61ffff81811683821601908082111561326a5761326a6131be565b85815284602082015260a06040820152600061338d60a08301866130df565b6001600160a01b0394909416606083015250608001529392505050565b6000602082840312156133bc57600080fd5b5051919050565b634e487b7160e01b600052602160045260246000fdfea66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68845524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e6365ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220ed809645c109fc3186c1c06ed0c2a6c1fd9b8b71c5faaa0964c6da864429266964736f6c63430008120033