Transaction Hash:
Block:
12128898 at Mar-28-2021 05:08:03 PM +UTC
Transaction Fee:
0.0333107478 ETH
$80.58
Gas Used:
186,929 Gas / 178.2 Gwei
Emitted Events:
146 |
TransparentUpgradeableProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000dafce5670d3f67da9a3a44fe6bc36992e5e2beab, 0x0000000000000000000000009fe9bb6b66958f2271c4b0ad23f6e8dda8c221be, 0000000000000000000000000000000000000000000000003b58a7b0d4ff3500 )
|
147 |
TransparentUpgradeableProxy.0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925( 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925, 0x000000000000000000000000dafce5670d3f67da9a3a44fe6bc36992e5e2beab, 0x0000000000000000000000009fe9bb6b66958f2271c4b0ad23f6e8dda8c221be, fffffffffffffffffffffffffffffffffffffffffffff51a70cb60e79312b41f )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x48Eb818C...c3e36951b |
0.050815309577587079 Eth
Nonce: 45
|
0.017504561777587079 Eth
Nonce: 46
| 0.0333107478 | ||
0x9fE9Bb6B...DA8C221BE | |||||
0xc8F595E2...25223b7C9
Miner
| (Miner: 0xc8F...7C9) | 4,159.924179210464658767 Eth | 4,159.957489958264658767 Eth | 0.0333107478 | |
0xdaFCE567...2e5E2beaB | |||||
0xfcfC434e...74Ea7cfbA |
Execution Trace
DELTA_Limited_Staking_Window.claimOrStakeAndClaimLP( claimToWalletInstead=False )
TransparentUpgradeableProxy.4cf5fbf5( )
DELTA_Deep_Farming_Vault.depositFor( person=0x48Eb818C6DD0c53E7bF9bdb274bA69fc3e36951b, numberRLP=4276352224117863680, numberDELTA=0 )
-
DELTAToken.STATICCALL( )
DELTA_Distributor.CALL( )
DELTAToken.balanceOf( account=0xa4079d05467dc8b68F93dFF1eB024ab1196F7cB0 ) => ( 0 )
OVLLPRebasingBalanceHandler.handleBalanceCalculations( account=0xa4079d05467dc8b68F93dFF1eB024ab1196F7cB0, 0xa4079d05467dc8b68F93dFF1eB024ab1196F7cB0 ) => ( 0 )
-
DELTAToken.getUserInfo( user=0xa4079d05467dc8b68F93dFF1eB024ab1196F7cB0 ) => ( [{name:maturedBalance, type:uint256, order:1, indexed:false, value:0, valueString:0}, {name:maxBalance, type:uint256, order:2, indexed:false, value:0, valueString:0}, {name:mostMatureTxIndex, type:uint256, order:3, indexed:false, value:0, valueString:0}, {name:lastInTxIndex, type:uint256, order:4, indexed:false, value:0, valueString:0}] )
-
TransparentUpgradeableProxy.23b872dd( )
-
DELTA_Rebasing_Liquidity_Token.transferFrom( sender=0xdaFCE5670d3F67da9A3A44FE6bc36992e5E2beaB, recipient=0x9fE9Bb6B66958f2271C4B0aD23F6E8DDA8C221BE, amount=4276352224117863680 ) => ( True )
-
-
File 1 of 8: DELTA_Limited_Staking_Window
File 2 of 8: TransparentUpgradeableProxy
File 3 of 8: TransparentUpgradeableProxy
File 4 of 8: DELTA_Deep_Farming_Vault
File 5 of 8: DELTAToken
File 6 of 8: DELTA_Distributor
File 7 of 8: OVLLPRebasingBalanceHandler
File 8 of 8: DELTA_Rebasing_Liquidity_Token
// SPDX-License-Identifier: No // File: @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; } // File: @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; } // File: @openzeppelin/contracts/token/ERC20/IERC20.sol pragma solidity ^0.6.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // File: @openzeppelin/contracts-ethereum-package/contracts/math/SafeMath.sol pragma solidity ^0.6.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @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) { // 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 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts 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) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts 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 mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message 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, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } // File: contracts/v612/DELTA/Periphery/DELTA_Limited_Staking_Window.sol pragma experimental ABIEncoderV2; interface IWETH { function deposit() external payable; function transfer(address to, uint value) external returns (bool); function withdraw(uint) external; function balanceOf(address) external returns (uint256); } interface IRLP { function rebase() external; function wrap() external; function setBaseLPToken(address) external; function openRebasing() external; function balanceOf(address) external returns (uint256); function transfer(address, uint256) external returns (bool); } interface IDELTA_DEEP_FARMING_VAULT { function depositFor(address, uint256,uint256) external; } interface IRESERVE_VAULT { function setRatio(uint256) external; } contract DELTA_Limited_Staking_Window { using SafeMath for uint256; struct LiquidityContribution { address byWho; uint256 howMuchETHUnits; uint256 contributionTimestamp; uint256 creditsAdded; } ////////// // STORAGE ////////// /////////// // Unchanging variables and constants /// @dev All this variables should be set only once. Anything else is a bug. // Constants address constant internal UNISWAP_FACTORY = 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f; address public DELTA_FINANCIAL_MULTISIG; /// @notice the person who sets the multisig wallet, happens only once // This person has no power over the contract only power to set the multisig wallet address immutable public INTERIM_ADMIN; IWETH constant public wETH = IWETH(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); address public reserveVaultAddress; address public deltaDeepFarmingVaultAddress; uint256 public LSW_RUN_TIME = 10 days; uint256 public constant MAX_ETH_POOL_SEED = 1500 ether; // @notice periode after the LSW is ended to claim the LP and the bonuses uint256 public constant CLAIMING_PERIOD = 30 days; uint256 public constant MAX_TIME_BONUS_PERCENT = 30; IRLP public rebasingLP; // Wrapped LP address public deltaTokenAddress; /////////// /////////// // Referral handling variables /// @dev Variables handling referral bonuses and IDs calculations /// @dev Sequential referral IDs (skipping 0) uint256 public totalReferralIDs; /// @dev mappings and reverse mapping handling the referral id ( for links to be smaller) mapping(uint256 => address) public referralCodeMappingIndexedByID; mapping(address => uint256) public referralCodeMappingIndexedByAddress; /// @dev we store bonus WETH in this variable because we don't want to send it until LSW is over... Because of the possibility of refund mapping(address => uint256) public referralBonusWETH; /// @dev boolean flag if the user already claimed his WETH bonus mapping(address => bool) public referralBonusWETHClaimed; uint256 public totalWETHEarmarkedForReferrers; /////////// /////////// // Liquidity contribution variables /// @dev variables for storing liquidity contributions and subsequent calculation for LP distribution /// @dev An array of all contributions with metadata LiquidityContribution [] public liquidityContributionsArray; /// @dev This is ETH contributed by the specific person, it doesn't include any bonuses this is used to handle refunds mapping(address => uint256) public liquidityContributedInETHUnitsMapping; /// @notice Each person has a credit based on their referrals and other bonuses as well as ETH contributions. This is what is used for owed LP mapping(address => uint256) public liquidityCreditsMapping; /// @dev a boolean flag for an address to signify they have already claimed LP owed to them mapping(address => bool) public claimedLP; /// @notice Calculated at the time of liquidity addition. RLP per each credit /// @dev stored multiplied by 1e12 for change uint256 public rlpPerCredit; /// @dev total Credit inside the smart contract used for ending calculation for rlpPerCredit uint256 public totalCreditValue; /////////// /////////// // Refund handling variables /// @notice Variables used for potential refund if the liquidity addition fails. This failover happens 2 days after LSW is supposed to be over, and its is not. /// @dev mapping of boolean flags if the user already claimed his refund mapping(address => bool) public refundClaimed; /// @notice boolean flag that can be initiated if LSW didnt end 2 days after it was supposed to calling the refund function. /// @dev This opens refunds, refunds do not adjust anything except the above mapping. Its important this variable is never triggered bool public refundsOpen; /////////// /////////// // Handling LSW timing variables /// @dev variables for length of LSW, separate from constant ones above bool public liquidityGenerationHasStarted; bool public liquidityGenerationHasEnded; /// @dev timestamps are not dynamic and generated upon calling the start function uint256 public liquidityGenerationStartTimestamp; uint256 public liquidityGenerationEndTimestamp; /////////// // constructor is only called by the token contract constructor() public { INTERIM_ADMIN = msg.sender; } /// @dev fallback on eth sent to the contract ( note WETH doesn't send ETH to this contract so no carveout is needed ) receive() external payable { revertBecauseUserDidNotProvideAgreement(); } function setMultisig(address multisig) public { onlyInterimAdmin(); require(DELTA_FINANCIAL_MULTISIG == address(0), "only set once"); DELTA_FINANCIAL_MULTISIG = multisig; } function onlyInterimAdmin() public view { require(INTERIM_ADMIN == msg.sender, "wrong"); } function setReserveVault(address reserveVault) public { onlyMultisig(); reserveVaultAddress = reserveVault; } /// Helper functions function setRLPWrap(address rlpAddress) public { onlyMultisig(); rebasingLP = IRLP(rlpAddress); } function setDELTAToken(address deltaToken, bool delegateCall) public { onlyMultisig(); if(delegateCall == false) { deltaTokenAddress = deltaToken; } else { bytes memory callData = abi.encodePacked(bytes4(keccak256(bytes("getTokenInfo()"))), ""); (,bytes memory addressDelta)= deltaToken.delegatecall(callData); deltaTokenAddress = abi.decode(addressDelta, (address)); } } function setFarmingVaultAddress(address farmingVault) public { onlyMultisig(); deltaDeepFarmingVaultAddress = farmingVault; require(address(rebasingLP) != address(0), "Need rlp to be set"); require(farmingVault != address(0), "Provide an address for farmingVault"); IERC20(address(rebasingLP)).approve(farmingVault, uint(-1)); } function extendLSWEndTime(uint256 numberSeconds) public { onlyMultisig(); liquidityGenerationEndTimestamp = liquidityGenerationEndTimestamp.add(numberSeconds); LSW_RUN_TIME = LSW_RUN_TIME.add(numberSeconds); } /// @notice This function starts the LSW and opens deposits and creates the RLP wrap function startLiquidityGeneration() public { onlyMultisig(); // We check that this is called by the correct authorithy /// @dev deltaToken has a time countdown in it that will make this function avaible to call require(liquidityGenerationHasStarted == false, "startLiquidityGeneration() called when LSW had already started"); // We start the LSW liquidityGenerationHasStarted = true; // Informational timestamp only written here // All calculations are based on the variable below end timestamp and run time which is used to bonus calculations liquidityGenerationStartTimestamp = block.timestamp; liquidityGenerationEndTimestamp = liquidityGenerationStartTimestamp + LSW_RUN_TIME; } /// @notice publically callable function that assigns a sequential shortened referral ID so a long one doesnt need to be provided in the URL function makeRefCode() public returns (uint256) { // If that address already has one, we dont make a new one if(referralCodeMappingIndexedByAddress[msg.sender] != 0){ return referralCodeMappingIndexedByAddress[msg.sender]; } else { return _makeRefCode(msg.sender); } } /// @dev Assigns a unique index to referrers, starting at 1 function _makeRefCode(address referrer) internal returns (uint256) { totalReferralIDs++; // lead to skip 0 code for the LSW // Populate reverse as well for lookup above referralCodeMappingIndexedByID[totalReferralIDs] = referrer; referralCodeMappingIndexedByAddress[msg.sender] = totalReferralIDs; return totalReferralIDs; } /// @dev Not using modifiers is a purposeful choice for code readability. function revertBecauseUserDidNotProvideAgreement() internal pure { revert("No agreement provided, please review the smart contract before interacting with it"); } function adminEndLSWAndRefundEveryone() public { onlyMultisig(); liquidityGenerationEndTimestamp = 0; openRefunds(); } function onlyMultisig() public view { require(msg.sender == DELTA_FINANCIAL_MULTISIG, "FBI OPEN UP"); } /// @notice a publically callable function that ends the LSW, adds liquidity and splits RLP for each credit. function endLiquidityDeployment() public { // Check if it already ended require(block.timestamp > liquidityGenerationEndTimestamp.add(5 minutes), "LSW Not over yet."); // Added few blocks here // Check if it was already run require(liquidityGenerationHasEnded == false, "LSW Already ended"); require(refundsOpen == false, "Refunds Opened, no ending"); // Check if all variable addresses are set // This includes the delta token // Rebasing lp wrap // Reserve vault which acts as options plunge insurance and floor price reserve // And operating capital for loans // And the farming vault which is used to auto stake in it require(deltaTokenAddress != address(0), "Delta Token is not set"); require(address(rebasingLP) != address(0), "Rlp is not set"); require(address(reserveVaultAddress) != address(0), "Reserve Vault is not set"); require(address(deltaDeepFarmingVaultAddress) != address(0), "Deep farming vault isn't set"); // We wrap the delta token in the interface IERC20 deltaToken = IERC20(deltaTokenAddress); // Check the balance we have // Note : if the process wan't complete correctly, the balance here would be wrong // Because DELTA token returns a balanace uint256 balanceOfDELTA = deltaToken.balanceOf(address(this)); // We make sure we for sure have the total supply require(balanceOfDELTA == deltaToken.totalSupply(), "Did not get the whole supply of deltaToken"); /// We mkake sure the supply is equal to the agreed on 45mln require(balanceOfDELTA == 45_000_000e18, "Did not get the whole supply of deltaToken"); // Optimistically get pair address deltaWethUniswapPair = IUniswapV2Factory(UNISWAP_FACTORY).getPair(deltaTokenAddress, address(wETH)); if(deltaWethUniswapPair == address(0)) { // Pair doesn't exist yet // create pair returns address deltaWethUniswapPair = IUniswapV2Factory(UNISWAP_FACTORY).createPair( deltaTokenAddress, address(wETH) ); } // Split between DELTA financial and pool // intented outcome 50% split between pool and further fund for tokens and WETH uint256 balanceWETHPreSplit = wETH.balanceOf(address(this)); require(balanceWETHPreSplit > 0, "Not enough WETH"); wETH.transfer(DELTA_FINANCIAL_MULTISIG, balanceWETHPreSplit.div(2)); // send half uint256 balanceWETHPostSplit = wETH.balanceOf(address(this)); // requery // We remove the WETH we had earmarked for referals uint256 balanceWETHPostReferal = balanceWETHPostSplit.sub(totalWETHEarmarkedForReferrers); /// @dev note this will revert if there is less than 1500 eth at this stage /// We just want refunds if that's the case cause it's not worth bothering uint256 balanceWETHForReserves = balanceWETHPostReferal.sub(MAX_ETH_POOL_SEED, "Not enough ETH"); /// @dev we check that bonuses are less than 5% of total deposited because they should be at max 5 /// Anything else is a issue /// Note added 1ETH for possible change require(totalWETHEarmarkedForReferrers <= balanceWETHPreSplit.div(20).add(1e18), "Sanity check failure 3"); wETH.transfer(reserveVaultAddress, balanceWETHForReserves); // We seed the pool with WETH wETH.transfer(deltaWethUniswapPair, MAX_ETH_POOL_SEED); require(wETH.balanceOf(address(this)) == totalWETHEarmarkedForReferrers, "Math Error"); // Transfer DELTA /// @dev this address is already mature as in it has 100% of DELTA in its balance uint256 deltaForPoolAndReserve = balanceOfDELTA.div(2); /// Smaller number / bigger number = float with 1000 for precision uint256 percentOfBalanceToReserves = MAX_ETH_POOL_SEED.mul(1000).div(balanceWETHPostReferal); // We take the precision out here uint256 delfaForPool = deltaForPoolAndReserve.mul(percentOfBalanceToReserves).div(1000); // transfer to pool deltaToken.transfer(deltaWethUniswapPair, delfaForPool); // We check if we are not sending 10% by mistake not whitelisting this address for whole sends // Note we don't check the rest because it should not deviate require(deltaToken.balanceOf(deltaWethUniswapPair) == delfaForPool, "LSW did not get permissions to send directly to balance"); // Transfer to team vesting deltaToken.transfer(DELTA_FINANCIAL_MULTISIG, balanceOfDELTA.div(2)); // transfer to floor/liqudation insurance reserves deltaToken.transfer(reserveVaultAddress, deltaToken.balanceOf(address(this))); // queried again in case of rounding problems /// This ratio is set as how much 1 whole eth buys /// Since eth is 1e18 and delta is same we can do this here /// Note that we don't expect 45mln eth so we dont really lose precision (delta supply is 45mln) IRESERVE_VAULT(reserveVaultAddress).setRatio( delfaForPool.div(MAX_ETH_POOL_SEED) ); // just wrapping in the interface IUniswapV2Pair newPair = IUniswapV2Pair(deltaWethUniswapPair); // Add liquidity newPair.mint(address(this)); //transfer LP here // WE approve the rlp to spend because thats what the wrap function uses (transferFor) newPair.approve(address(rebasingLP), uint(-1)); // We set the base token in a whitelist for rLP for LSW rebasingLP.setBaseLPToken(address(newPair)); /// @dev outside call, this function is supposed to wrap all LP of this address and issue rebasibngLP and send it to this address /// This switch is 1:1 1LP for 1 rebasingLP rebasingLP.wrap(); // Rebase liquidity /// @notice First rebase rebases RLP 3x. This means this would hit the gas limit if it was made in this call. /// So it just triggers a boolean flag to rebase and then trading is opened. /// @dev itended side effect of this is flipping a boolean flag inside the rebasingLP contract. It will open the rebasing function to be called about 30 times /// Until its called that amount of times trading or transfering of DELTA token will not be opened. /// This is done so price of RLP will be 3x that it was minted at instantly. Also will generate about 30bln in volume rebasingLP.openRebasing(); // Split LP per Credit uint256 totalRLP = rebasingLP.balanceOf(address(this)); require(totalRLP > 0, "Sanity check failure 1"); // We store as 1e12 more for change rlpPerCredit = totalRLP.mul(1e12).div(totalCreditValue); require(rlpPerCredit > 0, "Sanity check failure 2"); // Finalize to open claims (claimLP and ETH claiming for referal) liquidityGenerationHasEnded = true; } function claimOrStakeAndClaimLP(bool claimToWalletInstead) public { // Make sure the LSW ended ( this is set in fn endLiquidityDeployment() only) // And is only set when all checks have passed and we good require(liquidityGenerationHasEnded, "Liquidity Generation isn't over"); // Make sure the claiming period isn't over // Note that we hav ea claiming period here so rLP doesnt get stuck or ETH doesnt get stuck in thsi contract // This is because of the referal system having wrong addresses in it possibly require(block.timestamp < liquidityGenerationEndTimestamp.add(CLAIMING_PERIOD), "Claiming period is over"); // Make sure the person has something to claim require(liquidityContributedInETHUnitsMapping[msg.sender] > 0, "You have nothing to claim."); // Make sure the person hasnt already claimed require(claimedLP[msg.sender] == false, "You have already claimed."); // Set the already claimed flag claimedLP[msg.sender] = true; // We calculate the amount of rebasing LP due uint256 rlpDue = liquidityCreditsMapping[msg.sender].mul(rlpPerCredit).div(1e12); // And send it out // We check if the person wants to claim to the wallet, the default is to stake it for him in the vault if(claimToWalletInstead) { rebasingLP.transfer(msg.sender, rlpDue); } else { IDELTA_DEEP_FARMING_VAULT(deltaDeepFarmingVaultAddress).depositFor(msg.sender,rlpDue,0); } } /// @dev we loop over all liquidity contributions of a person and return them here for front end display /// Note this might suffer from gas limits on infura if there are enogh deposits and we are aware of that /// Its just a nice helper function that is not nessesary function allLiquidityContributionsOfAnAddress(address person) public view returns (LiquidityContribution [] memory liquidityContributionsOfPerson) { uint256 j; // Index of the memory array /// @dev we grab liquidity contributions at current index and compare to the provided address, and if it matches we push it to the array for(uint256 i = 0; i < liquidityContributionsArray.length; i++) { LiquidityContribution memory currentContribution = liquidityContributionsArray[i]; if(currentContribution.byWho == person) { liquidityContributionsOfPerson[j] = currentContribution; j++; } } } /// @notice Sends the bonus WETH to the referer after LSW is over. function getWETHBonusForReferrals() public { require(liquidityGenerationHasEnded == true, "LSW Not ended"); // Make sure the claiming period isn't over // This is done in case ETH is stuck with malformed addresses require(block.timestamp < liquidityGenerationEndTimestamp.add(CLAIMING_PERIOD), "Claiming period is over"); require(referralBonusWETHClaimed[msg.sender] == false, "Already claimed, check wETH balance not ETH"); require(referralBonusWETH[msg.sender] > 0, "nothing to claim"); /// @dev flag as claimed so no other calls is possible to this /// Note that even if reentry was possible here we set it first before sending out weth referralBonusWETHClaimed[msg.sender] = true; /// @dev wETH transfer( token ) has no hook possibility wETH.transfer(msg.sender, referralBonusWETH[msg.sender]); } /// @notice Transfer any remaining tokens in the contract /// This is done after the claiming period is over in case there are malformed not claimed referal amounts function finalizeLSW(address _token) public { onlyMultisig(); require(liquidityGenerationHasEnded == true, "LSW Not ended"); require(block.timestamp >= liquidityGenerationEndTimestamp.add(CLAIMING_PERIOD), "Claiming period is not over"); IERC20 token = IERC20(_token); /// @dev Transfer remaining tokens to the team. Those are tokens that has been /// unclaimed or transferred to the contract. token.transfer(DELTA_FINANCIAL_MULTISIG, token.balanceOf(address(this))); } /// @notice this function allows anyone to refund the eth deposited in case the contract cannot finish /// This is a nessesary function because of the contrract not having admin controls /// And is only here as a safety pillow failure function getRefund() public { require(refundsOpen, "Refunds are not open"); require(refundClaimed[msg.sender] == false, "Already got a refund, check your wETH balance."); refundClaimed[msg.sender] = true; // We send wETH9 here so there is no callback wETH.transfer(msg.sender, liquidityContributedInETHUnitsMapping[msg.sender]); } // This function opens refunds, if LSW didnt finish 2 days after it was supposed to. This means something went wrong. function openRefunds() public { require(liquidityGenerationHasEnded == false, "Liquidity generation has ended"); // We correctly ended the LSW require(liquidityGenerationHasStarted == true, "Liquidity generation has not started"); // Liquidity genertion should had ended 2 days ago! require(block.timestamp > liquidityGenerationEndTimestamp.add(2 days), "Post LSW grace period isn't over"); /// This can be set over and over again with no issue here refundsOpen = true; } /// @dev Returns bonus in credit units, and adds and calculates credit for the referrer /// @return credit units (something like wETH but in credit) this is for the referee ( person who was refered) function handleReferredDepositWithAddress(address referrerAddress) internal returns (uint256) { if(referrerAddress == msg.sender) { return 0; } //We dont let self referrals and bail here without any bonuses. require(msg.value > 0, "Sanity check failure"); uint256 wETHBonus = msg.value.div(20); // 5% uint256 creditBonus = wETHBonus; // Samesies totalWETHEarmarkedForReferrers = totalWETHEarmarkedForReferrers.add(wETHBonus); require(wETHBonus > 0 && creditBonus > 0 , "Sanity check failure 2"); // We give 5% wETH of the deposit to the person referralBonusWETH[referrerAddress] = referralBonusWETH[referrerAddress].add(wETHBonus); //We add credit liquidityCreditsMapping[referrerAddress] = liquidityCreditsMapping[referrerAddress].add(creditBonus); // Update total credits totalCreditValue = totalCreditValue.add(creditBonus); // We return 10% bonus for the person who was refered return creditBonus.mul(2); } /// @dev checks if a address for this referral ID exists, if it doesnt just returns 0 skipping the adding function function handleReferredDepositWithReferralID(uint256 referralID) internal returns (uint256 personWhoGotReferedBonus) { address referrerAddress = referralCodeMappingIndexedByID[referralID]; // We check if the referral number was registered, and if its not the same person. if(referrerAddress != address(0) && referrerAddress != msg.sender) { return handleReferredDepositWithAddress(referrerAddress); } else { return 0; } } function secondsLeftInLiquidityGenerationEvent() public view returns ( uint256 ) { if(block.timestamp >= liquidityGenerationEndTimestamp) { return 0; } return liquidityGenerationEndTimestamp - block.timestamp; } function liquidityGenerationParticipationAgreement() public pure returns (string memory) { return "I understand that I'm interacting with a smart contract. I understand that liquidity im providing is locked forever. I reviewed code of the smart contract and understand it fully. I agree to not hold developers or other people associated with the project to liable for any losses of misunderstandings"; } // referrerAddress or referralID must be provided, the unused parameter should be left as 0 function contributeLiquidity(bool readAndAgreedToLiquidityProviderAgreement, address referrerAddress, uint256 referralID) public payable { require(refundsOpen == false, "Refunds Opened, no deposit"); // We check that LSW has already started require(liquidityGenerationHasStarted, "Liquidity generation did not start"); // We check if liquidity generation didn't end require(liquidityGenerationHasEnded == false, "Liquidity generation has ended"); // We check if liquidity genration still has time in it require(secondsLeftInLiquidityGenerationEvent() > 0, "Liquidity generation has ended 2"); // We check if user agreed with the terms of the smart contract if(readAndAgreedToLiquidityProviderAgreement == false) { revertBecauseUserDidNotProvideAgreement(); } require(msg.value > 0, "Ethereum needs to be provided"); // We add credit bonus, which is 10% if user is referred // RefID takes precedence here uint256 creditBonus; if(referralID != 0) { creditBonus = handleReferredDepositWithReferralID(referralID); // TO REVIEW: handleReferredDepositWithReferralID returns the reward (referrer and referee) } else if (referrerAddress != address(0)){ creditBonus = handleReferredDepositWithAddress(referrerAddress); // TO REVIEW: handleReferredDepositWithReferralID returns the reward (referrer and referee) } // Else bonus is 0 // We add the time bonus to the credit creditBonus = creditBonus.add(calculateCreditBonusBasedOnCurrentTime(msg.value)); // Credit bonus should never be bigger than credit here. Max 30% + 10%. Aka 40% of msg.value // Note this is a magic number here, since we dont really want to read the max bonus again from storage require(msg.value.mul(41).div(100) > creditBonus, "Sanity check failure"); // We update the global number of credit so we can distribute LP later uint256 creditValue = msg.value.add(creditBonus); totalCreditValue = totalCreditValue.add(creditValue); // Give the person credit and the bonus liquidityCreditsMapping[msg.sender] = liquidityCreditsMapping[msg.sender].add(creditValue); // Save the persons deposit for refunds in case liquidityContributedInETHUnitsMapping[msg.sender] = liquidityContributedInETHUnitsMapping[msg.sender].add(msg.value); // We add it to array of all deposits liquidityContributionsArray.push(LiquidityContribution({ byWho : msg.sender, howMuchETHUnits : msg.value, contributionTimestamp : block.timestamp, creditsAdded : creditValue // Stores the deposit + the bonus })); // We turn ETH into WETH9 wETH.deposit{value : msg.value}(); } /// @dev intended return is the bonus credit in terms of ETH units // At the start of LSW is 30%, ramping down to 0% in the last 12 hours of LSW. function calculateCreditBonusBasedOnCurrentTime(uint256 depositValue) internal view returns (uint256) { uint256 secondsLeft = secondsLeftInLiquidityGenerationEvent(); uint256 totalSeconds = LSW_RUN_TIME; // We get percent left in the LSW uint256 percentLeft = secondsLeft.mul(100).div(totalSeconds); // 24 hours before LSW end, we get 7 for percentLeft - highest value for this possible is 100 (by a bot) // We calculate bonus based on percent left. Eg 100% of the time remaining, means a 30% bonus. 50% of the time remaining, means a 15% bonus. // MAX_TIME_BONUS_PERCENT is a constant set to 30 (double-check on review) // Max example with 1 ETH contribute: 30 * 100 * 1eth / 10000 = 0.3eth // Low end (towards the end of LSW) > 0 example MAX_TIME_BONUS_PERCENT == 7; // 30 * 7 * 1eth / 10000 = 0.021 eth // Min example MAX_TIME_BONUS_PERCENT == 0; returns 0 /// 100 % bonus /// 30*100*1e18/10000 == 0.3 * 1e18 /// Dust numbers /// 30*100*1/10000 == 0 uint256 bonus = MAX_TIME_BONUS_PERCENT.mul(percentLeft).mul(depositValue).div(10000); require(depositValue.mul(31).div(100) > bonus , "Sanity check failure bonus"); return bonus; } }
File 2 of 8: TransparentUpgradeableProxy
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "./UpgradeableProxy.sol"; /** * @dev This contract implements a proxy that is upgradeable by an admin. * * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector * clashing], which can potentially be used in an attack, this contract uses the * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two * things that go hand in hand: * * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if * that call matches one of the admin functions exposed by the proxy itself. * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the * implementation. If the admin tries to call a function on the implementation it will fail with an error that says * "admin cannot fallback to proxy target". * * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due * to sudden errors when trying to call a function from the proxy implementation. * * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way, * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy. */ contract TransparentUpgradeableProxy is UpgradeableProxy { /** * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and * optionally initialized with `_data` as explained in {UpgradeableProxy-constructor}. */ constructor(address _logic, address admin_, bytes memory _data) public payable UpgradeableProxy(_logic, _data) { assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1)); _setAdmin(admin_); } /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 private constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin. */ modifier ifAdmin() { if (msg.sender == _admin()) { _; } else { _fallback(); } } /** * @dev Returns the current admin. * * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` */ function admin() external ifAdmin returns (address admin_) { admin_ = _admin(); } /** * @dev Returns the current implementation. * * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc` */ function implementation() external ifAdmin returns (address implementation_) { implementation_ = _implementation(); } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. * * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}. */ function changeAdmin(address newAdmin) external virtual ifAdmin { require(newAdmin != address(0), "TransparentUpgradeableProxy: new admin is the zero address"); emit AdminChanged(_admin(), newAdmin); _setAdmin(newAdmin); } /** * @dev Upgrade the implementation of the proxy. * * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}. */ function upgradeTo(address newImplementation) external virtual ifAdmin { _upgradeTo(newImplementation); } /** * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the * proxied contract. * * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}. */ function upgradeToAndCall(address newImplementation, bytes calldata data) external payable virtual ifAdmin { _upgradeTo(newImplementation); Address.functionDelegateCall(newImplementation, data); } /** * @dev Returns the current admin. */ function _admin() internal view virtual returns (address adm) { bytes32 slot = _ADMIN_SLOT; // solhint-disable-next-line no-inline-assembly assembly { adm := sload(slot) } } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { bytes32 slot = _ADMIN_SLOT; // solhint-disable-next-line no-inline-assembly assembly { sstore(slot, newAdmin) } } /** * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}. */ function _beforeFallback() internal virtual override { require(msg.sender != _admin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target"); super._beforeFallback(); } } // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "./Proxy.sol"; import "../utils/Address.sol"; /** * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an * implementation address that can be changed. This address is stored in storage in the location specified by * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the * implementation behind the proxy. * * Upgradeability is only provided internally through {_upgradeTo}. For an externally upgradeable proxy see * {TransparentUpgradeableProxy}. */ contract UpgradeableProxy is Proxy { /** * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`. * * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded * function call, and allows initializating the storage of the proxy like a Solidity constructor. */ constructor(address _logic, bytes memory _data) public payable { assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1)); _setImplementation(_logic); if(_data.length > 0) { Address.functionDelegateCall(_logic, _data); } } /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 private constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Returns the current implementation address. */ function _implementation() internal view virtual override returns (address impl) { bytes32 slot = _IMPLEMENTATION_SLOT; // solhint-disable-next-line no-inline-assembly assembly { impl := sload(slot) } } /** * @dev Upgrades the proxy to a new implementation. * * Emits an {Upgraded} event. */ function _upgradeTo(address newImplementation) internal virtual { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { require(Address.isContract(newImplementation), "UpgradeableProxy: new implementation is not a contract"); bytes32 slot = _IMPLEMENTATION_SLOT; // solhint-disable-next-line no-inline-assembly assembly { sstore(slot, newImplementation) } } } // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to * be specified by overriding the virtual {_implementation} function. * * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a * different contract through the {_delegate} function. * * The success and return data of the delegated call will be returned back to the caller of the proxy. */ abstract contract Proxy { /** * @dev Delegates the current call to `implementation`. * * This function does not return to its internall call site, it will return directly to the external caller. */ function _delegate(address implementation) internal virtual { // solhint-disable-next-line no-inline-assembly assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize()) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize()) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } /** * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function * and {_fallback} should delegate. */ function _implementation() internal view virtual returns (address); /** * @dev Delegates the current call to the address returned by `_implementation()`. * * This function does not return to its internall call site, it will return directly to the external caller. */ function _fallback() internal virtual { _beforeFallback(); _delegate(_implementation()); } /** * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other * function in the contract matches the call data. */ fallback () external payable virtual { _fallback(); } /** * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data * is empty. */ receive () external payable virtual { _fallback(); } /** * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback` * call, or as part of the Solidity `fallback` or `receive` functions. * * If overriden should call `super._beforeFallback()`. */ function _beforeFallback() internal virtual { } } // SPDX-License-Identifier: MIT pragma solidity >=0.6.2 <0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
File 3 of 8: TransparentUpgradeableProxy
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "./UpgradeableProxy.sol"; /** * @dev This contract implements a proxy that is upgradeable by an admin. * * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector * clashing], which can potentially be used in an attack, this contract uses the * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two * things that go hand in hand: * * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if * that call matches one of the admin functions exposed by the proxy itself. * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the * implementation. If the admin tries to call a function on the implementation it will fail with an error that says * "admin cannot fallback to proxy target". * * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due * to sudden errors when trying to call a function from the proxy implementation. * * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way, * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy. */ contract TransparentUpgradeableProxy is UpgradeableProxy { /** * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and * optionally initialized with `_data` as explained in {UpgradeableProxy-constructor}. */ constructor(address _logic, address admin_, bytes memory _data) public payable UpgradeableProxy(_logic, _data) { assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1)); _setAdmin(admin_); } /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 private constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin. */ modifier ifAdmin() { if (msg.sender == _admin()) { _; } else { _fallback(); } } /** * @dev Returns the current admin. * * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` */ function admin() external ifAdmin returns (address admin_) { admin_ = _admin(); } /** * @dev Returns the current implementation. * * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc` */ function implementation() external ifAdmin returns (address implementation_) { implementation_ = _implementation(); } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. * * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}. */ function changeAdmin(address newAdmin) external virtual ifAdmin { require(newAdmin != address(0), "TransparentUpgradeableProxy: new admin is the zero address"); emit AdminChanged(_admin(), newAdmin); _setAdmin(newAdmin); } /** * @dev Upgrade the implementation of the proxy. * * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}. */ function upgradeTo(address newImplementation) external virtual ifAdmin { _upgradeTo(newImplementation); } /** * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the * proxied contract. * * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}. */ function upgradeToAndCall(address newImplementation, bytes calldata data) external payable virtual ifAdmin { _upgradeTo(newImplementation); Address.functionDelegateCall(newImplementation, data); } /** * @dev Returns the current admin. */ function _admin() internal view virtual returns (address adm) { bytes32 slot = _ADMIN_SLOT; // solhint-disable-next-line no-inline-assembly assembly { adm := sload(slot) } } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { bytes32 slot = _ADMIN_SLOT; // solhint-disable-next-line no-inline-assembly assembly { sstore(slot, newAdmin) } } /** * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}. */ function _beforeFallback() internal virtual override { require(msg.sender != _admin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target"); super._beforeFallback(); } } // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "./Proxy.sol"; import "../utils/Address.sol"; /** * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an * implementation address that can be changed. This address is stored in storage in the location specified by * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the * implementation behind the proxy. * * Upgradeability is only provided internally through {_upgradeTo}. For an externally upgradeable proxy see * {TransparentUpgradeableProxy}. */ contract UpgradeableProxy is Proxy { /** * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`. * * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded * function call, and allows initializating the storage of the proxy like a Solidity constructor. */ constructor(address _logic, bytes memory _data) public payable { assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1)); _setImplementation(_logic); if(_data.length > 0) { Address.functionDelegateCall(_logic, _data); } } /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 private constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Returns the current implementation address. */ function _implementation() internal view virtual override returns (address impl) { bytes32 slot = _IMPLEMENTATION_SLOT; // solhint-disable-next-line no-inline-assembly assembly { impl := sload(slot) } } /** * @dev Upgrades the proxy to a new implementation. * * Emits an {Upgraded} event. */ function _upgradeTo(address newImplementation) internal virtual { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { require(Address.isContract(newImplementation), "UpgradeableProxy: new implementation is not a contract"); bytes32 slot = _IMPLEMENTATION_SLOT; // solhint-disable-next-line no-inline-assembly assembly { sstore(slot, newImplementation) } } } // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to * be specified by overriding the virtual {_implementation} function. * * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a * different contract through the {_delegate} function. * * The success and return data of the delegated call will be returned back to the caller of the proxy. */ abstract contract Proxy { /** * @dev Delegates the current call to `implementation`. * * This function does not return to its internall call site, it will return directly to the external caller. */ function _delegate(address implementation) internal virtual { // solhint-disable-next-line no-inline-assembly assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize()) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize()) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } /** * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function * and {_fallback} should delegate. */ function _implementation() internal view virtual returns (address); /** * @dev Delegates the current call to the address returned by `_implementation()`. * * This function does not return to its internall call site, it will return directly to the external caller. */ function _fallback() internal virtual { _beforeFallback(); _delegate(_implementation()); } /** * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other * function in the contract matches the call data. */ fallback () external payable virtual { _fallback(); } /** * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data * is empty. */ receive () external payable virtual { _fallback(); } /** * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback` * call, or as part of the Solidity `fallback` or `receive` functions. * * If overriden should call `super._beforeFallback()`. */ function _beforeFallback() internal virtual { } } // SPDX-License-Identifier: MIT pragma solidity >=0.6.2 <0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
File 4 of 8: DELTA_Deep_Farming_Vault
// SPDX-License-Identifier: UNLICENSED // DELTA-BUG-BOUNTY pragma solidity ^0.7.6; pragma abicoder v2; import "./DELTA_Deep_Farming_Storage.sol"; import "../Upgradability/proxy/Initializable.sol"; import "../Upgradability/math/SafeMathUpgradeable.sol"; import "../../interfaces/IDeltaToken.sol"; import "../../interfaces/IDeepFarmingVault.sol"; import "../../interfaces/IDeltaDistributor.sol"; import "../../interfaces/IUniswapV2Pair.sol"; import "../../interfaces/IUniswapV2Pair.sol"; contract Enum { enum Operation { Call, DelegateCall } } // Each withdrawal creates its own contract and maturity time // Withdrawals are only possible via this method interface IPROXY_FACTORY { function createProxy(address) external returns (address); } interface IWITHDRAWAL_CONTRACT { function intitialize(address _owner, uint256 _matuartionTimeSeconds, uint256 _principledDelta, // Principle means the base amount that doesnt mature. IERC20 _DELTAToken) external; } interface IDELTA_MULTISIG { function execTransactionFromModule(address to, uint256 value, bytes memory data, Enum.Operation operation) external returns (bool); } contract DELTA_Deep_Farming_Vault is DELTA_Deep_Farming_Storage, IDeepFarmingVault, Initializable { using SafeMathUpgradeable for uint256; // Constants and immutables IERC20 constant public WETH = IERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); IERC20 immutable public RLP; address immutable public WITHDRAWAL_CONTRACT_MASTERCOPY; IPROXY_FACTORY immutable public WITHDRAWAL_PROXY_FACTORY; address constant internal DEAD_BEEF = 0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF; uint256 constant public RLP_RATIO = 200; uint256 constant public BOOST_MAX = 10; uint256 constant public BOOST_UP_WEEK = 1; uint256 constant public BOOST_DOWN_WEEK = 3; IDeltaToken public immutable DELTA; function allWithdrawalContractsOf(address person) public view returns (address [] memory) { return withdrawalContracts[person]; } constructor (address _proxyFactoryAddress, address _withdrawalContractMasterCopyAddress, address rlp, address delta) { require(BOOST_DOWN_WEEK <= BOOST_MAX, "Boost down per week cannot be bigger than max boost, overflow protection"); WITHDRAWAL_PROXY_FACTORY = IPROXY_FACTORY(_proxyFactoryAddress); WITHDRAWAL_CONTRACT_MASTERCOPY = _withdrawalContractMasterCopyAddress; RLP = IERC20(rlp); DELTA = IDeltaToken(delta); } function initialize() public initializer { require(farmingStartedTimestamp == 0, "Farming has already started"); _isNotPaniced = true; farmingStartedTimestamp = block.timestamp; setPrivileges(address(this), true,true,true); } function setPrivileges(address withdrawalContract, bool canSendToMatureBalances, bool canRecieveImmatureBalances, bool recievesBalancesWithoutVestingProcess) internal { address deltaAddress = address(DELTA); require(deltaAddress != address(0), "set delta first"); bool success = IDELTA_MULTISIG(DELTA.governance()).execTransactionFromModule( deltaAddress, 0, abi.encodeWithSignature("setWhitelists(address,bool,bool,bool)", withdrawalContract, canSendToMatureBalances,canRecieveImmatureBalances,recievesBalancesWithoutVestingProcess), Enum.Operation.Call ); require(success, "Did not sucessfully set privileges"); } /// @dev a normal deposit that will force multiplier to 1 if there is any function deposit(uint256 numberRLP, uint256 numberDELTA) override public { UserInformationDFV memory reciever = userInfo[msg.sender]; _deposit(reciever, msg.sender, numberRLP, numberDELTA, false); } // Deposit for a individual function depositFor(address person, uint256 numberRLP, uint256 numberDELTA) override public { require(person != address(0), "Can't deposit for noone"); UserInformationDFV memory reciever = userInfo[person]; if(numberDELTA > 0) { require(reciever.lastBooster < 2, "Cannot deposit for someone when they have a booster, use the depositWithBurn()"); } _deposit(reciever, person, numberRLP, numberDELTA, false); } function depositWithBurn(uint256 numberDELTA) override public { UserInformationDFV memory reciever = userInfo[msg.sender]; _deposit(reciever,msg.sender, 0, numberDELTA, true); } function depositForWithBurn(address person, uint256 numberDELTA) override public { require(person != address(0), "Can't deposit for noone"); UserInformationDFV memory reciever = userInfo[person]; require(reciever.lastBoosterDepositTimestamp > 0, "Can not deposit burned when the user didn't burn yet"); _deposit(reciever, person, 0, numberDELTA, true); } function addPermanentCredits(address person, uint256 amount) override public { require(msg.sender == DELTA.distributor(), "!distributor"); UserInformationDFV storage personStorage = userInfo[person]; UserInformationDFV memory personMemory = userInfo[person]; whenNotPanicked(); require(amount > 0, "Can't add nothing"); (uint256 accumulatedDELTAE12, uint256 accumulatedETHE12) = _updateVault(vaultInfo.totalFarmingPower); (uint256 newBooster, uint256 farmedDELTA, uint256 farmedWETH) = recycle(_realFarmedOfPerson(personMemory, accumulatedDELTAE12, accumulatedETHE12)); if(farmedWETH > 0) { sendETH(person, farmedWETH); } if(farmedDELTA > 0) { // No need to compound if there is no farmed, as this doesnt add ddeltadeposit newBooster = compoundFarmedAndHandleDELTADeposit(personMemory, personStorage, 0, farmedDELTA, newBooster, false); // We dont need to set burn booster to true because the farmed is 0 } personStorage.lastBooster = newBooster; // We add permanent balance personStorage.deltaPermanent = personStorage.deltaPermanent.add(amount); // And total balance personMemory.totalDelta = personMemory.totalDelta.add(amount); personStorage.totalDelta = personMemory.totalDelta; adjustFarmingPowerAndDebt(personStorage, personMemory, accumulatedDELTAE12, accumulatedETHE12, newBooster); } function _deposit(UserInformationDFV memory recieverMemory, address walletReciever, uint256 amountRLP, uint256 amountDELTA, bool isBurn) internal { whenNotPanicked(); UserInformationDFV storage recieverStorage = userInfo[walletReciever]; if(amountDELTA > 0) { // User specified he wants to deposit delta so we transfer it here require(DELTA.transferFrom(msg.sender, address(this), amountDELTA), "Coudn't transfer DELTA, allowance?"); } // We update the accumulated rewards in case its not updated so the person is owed (uint256 accumulatedDELTAE12, uint256 accumulatedETHE12) = _updateVault(vaultInfo.totalFarmingPower); (uint256 newBooster, uint256 farmedDELTA, uint256 farmedWETH) = recycle(_realFarmedOfPerson(recieverMemory, accumulatedDELTAE12, accumulatedETHE12)); newBooster = compoundFarmedAndHandleDELTADeposit(recieverMemory, recieverStorage, amountDELTA, farmedDELTA, newBooster, isBurn); if(farmedWETH > 0) { sendETH(walletReciever, farmedWETH); // This is to the person who farmed it not msg.sender.. } if(amountRLP > 0) { // User wants to deposit RLP so we transfer it from him here require(RLP.transferFrom(msg.sender, address(this), amountRLP), "Coudn't transfer RLP, allowance?"); // We write a new number or rlp to the user recieverMemory.rlp = recieverMemory.rlp.add(amountRLP); // THis is needed cause memory pointer is used in adjustFarmingPowerAndDebt recieverStorage.rlp = recieverMemory.rlp; } // Cap and write to storage // if(newBooster > BOOST_MAX) { newBooster = BOOST_MAX; } // already capped recieverStorage.lastBooster = newBooster; // We finished calculating total delta write it to stroage // Note we have to always write here because there might be compound even tho there was no deltadeposit recieverStorage.totalDelta = recieverMemory.totalDelta; adjustFarmingPowerAndDebt(recieverStorage, recieverMemory, accumulatedDELTAE12, accumulatedETHE12, newBooster); } function compound(address person) override public { require(person != address(0), "Provide an address"); UserInformationDFV storage personStruct = userInfo[person]; _deposit(personStruct, person, 0, 0, false); // Because of the 0 deposit we can get away with 0,0 while the user has compoundBurn on } /// @notice a function that withdraws everything user has in the vault /// And creates a withdrawl contract function exit() override public { whenNotPanicked(); UserInformationDFV storage exitingStorage = userInfo[msg.sender]; UserInformationDFV memory exitingMemory = userInfo[msg.sender]; (uint256 accumulatedDELTAE12, uint256 accumulatedETHE12) = _updateVault(vaultInfo.totalFarmingPower); uint256 oldFarmingPower = exitingMemory.farmingPower; (, uint256 farmedDELTA, uint256 farmedWETH) = recycle(_realFarmedOfPerson(exitingMemory, accumulatedDELTAE12, accumulatedETHE12)); if(farmedWETH > 0) { sendETH(msg.sender, farmedWETH); } if(exitingMemory.rlp > 0) { RLP.transfer(msg.sender, exitingMemory.rlp); } address withdrawalContract = WITHDRAWAL_PROXY_FACTORY.createProxy(WITHDRAWAL_CONTRACT_MASTERCOPY); withdrawalContracts[msg.sender].push(withdrawalContract); uint256 withdrawable = exitingMemory.deltaWithdrawable; setPrivileges(withdrawalContract, true,false,true); // We send withdrwable, vesting and whatever was farmed cause we dotn compound it uint256 totalToSendToWithdrawalContract = withdrawable.add(exitingMemory.deltaVesting).add(farmedDELTA); require(totalToSendToWithdrawalContract > 0, "Nothing to withdraw"); sendDELTA(withdrawalContract, totalToSendToWithdrawalContract); IWITHDRAWAL_CONTRACT(withdrawalContract).intitialize(msg.sender, 52 weeks, withdrawable, DELTA); uint256 permanentBalance = exitingMemory.deltaPermanent; // Note that we dont compound here so its fine that the compounding function sets it in storage because we dont use it here since we want to be fair to user delete userInfo[msg.sender]; // We have to handle permanetn balance of this user if(permanentBalance > 0){ exitingStorage.deltaPermanent = permanentBalance; exitingStorage.totalDelta = permanentBalance; exitingStorage.rewardDebtDELTA = accumulatedDELTAE12.mul(permanentBalance); exitingStorage.rewardDebtETH = accumulatedETHE12.mul(permanentBalance); exitingStorage.farmingPower = permanentBalance; vaultInfo.totalFarmingPower = vaultInfo.totalFarmingPower.sub(oldFarmingPower).add(permanentBalance); } else { // Delete is sufficient we just have to adjust total farming (user had no permanent balance) vaultInfo.totalFarmingPower = vaultInfo.totalFarmingPower.sub(oldFarmingPower); } } function withdrawRLP(uint256 amount) override public { whenNotPanicked(); UserInformationDFV storage withdrawerStorage = userInfo[msg.sender]; UserInformationDFV memory withdrawerMemory = userInfo[msg.sender]; require(amount > 0, "Cannot withdraw 0 "); require(withdrawerMemory.rlp >= amount, "Not enough to withdraw"); (uint256 accumulatedDELTAE12, uint256 accumulatedETHE12) = _updateVault(vaultInfo.totalFarmingPower); (uint256 newBooster, uint256 farmedDELTA, uint256 farmedWETH) = recycle(_realFarmedOfPerson(withdrawerMemory, accumulatedDELTAE12, accumulatedETHE12)); if(farmedWETH > 0) { sendETH(msg.sender, farmedWETH); } if(farmedDELTA > 0) { // No need to compound if we didnt farm cause this doesn't add delta newBooster = compoundFarmedAndHandleDELTADeposit(withdrawerMemory, withdrawerStorage, 0, farmedDELTA, newBooster, false); // We dont need to set burn booster to true because the farmed is 0 } withdrawerMemory.rlp = withdrawerMemory.rlp - amount; // safe cause require withdrawerStorage.rlp = withdrawerMemory.rlp; withdrawerStorage.lastBooster = newBooster; adjustFarmingPowerAndDebt(withdrawerStorage, withdrawerMemory, accumulatedDELTAE12, accumulatedETHE12, newBooster); RLP.transfer(msg.sender, amount); } //// // Helpers /// function realFarmedOfPerson(address person) public override view returns (RecycleInfo memory) { UserInformationDFV memory personStruct = userInfo[person]; (uint256 totalDELTApreAdjust, uint256 totalETHpreAdjust) = calculateFarmed( personStruct.farmingPower, vaultInfo.accumulatedDELTAPerShareE12, vaultInfo.accumulatedETHPerShareE12, personStruct.rewardDebtDELTA, personStruct.rewardDebtETH ); return adjustFarmedView(personStruct.lastBooster, totalDELTApreAdjust, totalETHpreAdjust, personStruct.lastBoosterDepositTimestamp, personStruct.totalDelta, personStruct.rlp, block.timestamp); } function adjustFarmingPowerAndDebt(UserInformationDFV storage personStorage, UserInformationDFV memory personMemory, uint256 accumulatedDELTAE12, uint256 accumulatedETHE12, uint256 newBooster) internal { uint256 newFarmingPower = personMemory.rlp.mul(RLP_RATIO).add( personMemory.totalDelta.mul(newBooster) ); // Remove old farming power and add new one vaultInfo.totalFarmingPower = vaultInfo.totalFarmingPower.sub(personMemory.farmingPower).add(newFarmingPower); // Set farming powers and debts personStorage.farmingPower = newFarmingPower; personStorage.rewardDebtDELTA = newFarmingPower.mul(accumulatedDELTAE12); personStorage.rewardDebtETH = newFarmingPower.mul(accumulatedETHE12); } function _realFarmedOfPerson(UserInformationDFV memory person, uint256 accumulatedDELTAE12, uint256 accumulatedETHE12) internal view returns (RecycleInfo memory) { (uint256 totalDELTApreAdjust, uint256 totalETHpreAdjust) = calculateFarmed(person.farmingPower, accumulatedDELTAE12, accumulatedETHE12, person.rewardDebtDELTA, person.rewardDebtETH); // adjustFarmedView(uint256 booster, uint256 farmedDELTA, uint256 farmedETH, uint256 lastBoosterDeposit, uint256 deltaPrinciple, uint256 amountRLP, uint256 currentTimestamp) return adjustFarmedView(person.lastBooster, totalDELTApreAdjust, totalETHpreAdjust, person.lastBoosterDepositTimestamp, person.totalDelta, person.rlp, block.timestamp); } function addNewRewards(uint256 amountDELTA, uint256 amountWETH) override public { if(amountWETH > 0) { pendingRewards.ETH = pendingRewards.ETH.add(amountWETH); require(WETH.transferFrom(msg.sender, address(this), amountWETH), "Couldn't transfer WETH, allowance?"); } if(amountDELTA > 0) { require(DELTA.transferFrom(msg.sender, address(this), amountDELTA), "Couldn't transfer DELTA, allowance?"); pendingRewards.DELTA = pendingRewards.DELTA.add(amountDELTA); } } function adminRescueTokens(address token, uint256 amount) override public { onlyMultisig(); if(_isNotPaniced == true) { require(token != address(RLP) && token != address(DELTA) && token != address(WETH), "Cannot withdraw tokens that are rewards or used in farming"); } IERC20(token).transfer(msg.sender, amount); } function setCompundBurn(bool shouldBurn) override public { whenNotPanicked(); UserInformationDFV storage recieverStorage = userInfo[msg.sender]; recieverStorage.compoundBurn = shouldBurn; } function recycledValuesFromFarmed(uint256 farmedDELTA, uint256 farmedETH, uint256 percentFarmedWithDELTA, uint256 booster, uint256 currentTimestamp, uint256 lastBoosterDeposit) internal pure returns (RecycledFarmingValues memory out) { (uint256 _calculatedBooster, uint256 _percentLegit) = howMuchOfFarmedPercentIsLegit(booster, currentTimestamp - lastBoosterDeposit); out.percentLegit = _percentLegit; out.calculatedBooster = _calculatedBooster; // 100 farmed * 60% * (100 - 50%legit ) / 1e4 = 30 out.delta = farmedDELTA.mul(percentFarmedWithDELTA).mul( 100 - _percentLegit ).div(1e4); // we can percentLegfit inside howMuchFarmed function to max 100 out.eth = farmedETH.mul(percentFarmedWithDELTA).mul( 100 - _percentLegit ).div(1e4); // 100 - percent legit means percent not legit.. aka the percent recycled. } function adjustFarmedView(uint256 booster, uint256 farmedDELTA, uint256 farmedETH, uint256 lastBoosterDeposit, uint256 totalDelta, uint256 amountRLP, uint256 currentTimestamp) internal pure returns (RecycleInfo memory) { uint256 farmingPowerRLP = amountRLP.mul(RLP_RATIO); uint256 farmingPowerDelta = totalDelta.mul(booster); // This code block has to be before adjustiing the booster uint256 percentFarmedWithDELTA = 100; if(farmingPowerRLP > 0) { percentFarmedWithDELTA = farmingPowerDelta.mul(100).div( farmingPowerRLP.add(farmingPowerDelta) ); } if(booster < 2) {//booster is smaller than 2 so 0 or 1 booster = 1; return RecycleInfo(booster, farmedDELTA, farmedETH, 0, 0); } // booster > 1 // We check how much of farmed is legit. // First we substract farmed with rLP from farmed // If the remainer is higher than 0 if(percentFarmedWithDELTA > 0) { // If there is nothing farmed with delta then we dont need to adjust because rLP doesnt have a booster // We adjust the remainer RecycledFarmingValues memory rValues = recycledValuesFromFarmed(farmedDELTA, farmedETH, percentFarmedWithDELTA, booster, currentTimestamp, lastBoosterDeposit); if(rValues.calculatedBooster != booster) { booster = rValues.calculatedBooster; farmedDELTA = farmedDELTA.sub(rValues.delta); farmedETH = farmedETH.sub(rValues.eth); return RecycleInfo(booster, farmedDELTA, farmedETH, rValues.delta, rValues.eth); } } return RecycleInfo(booster, farmedDELTA, farmedETH, 0, 0); } function compoundFarmedAndHandleDELTADeposit(UserInformationDFV memory personMemory, UserInformationDFV storage personStorage, uint256 depositDELTA, uint256 farmedDELTA, uint256 calculatedBooster, bool isBurn) internal returns (uint256) { // return new booster // Options for this: // -- // Normal deposit - adding delta to get additional farm power (multiplier set to 1) // Normal deposit w/ compounding burn (reverts - rekts their compounding) // Burning deposit (regular compounding) - adding 100% of delta to get farm power, but half burned (moved to permanent balance) - this maintains their booster if more than 10%, or creates 10x multiplier if initial deposit // note: must burn at least 100% of total delta so far in the 1x vesting. (if this is first boosted deposit - booster of 0) // example: if i have 100 coins farming at 1x, and then i do a 150 burning deposit, it reverts because that is less than burning 100% of their current coins // example 2: if i have 100 coins farming at 1x, and then i do a 200 burning deposit, it doesn't revert, but credits me and starts a 10x // Burning deposit w/ compounding burn - adds 100% of the deposited delta to farm power, burns half, and burns half of farmable during the compounding process. // note: must burn (sum 50% of deposit, 50% of farmable from comoounding) at least 100% of total delta so far in the 1x vesting. (if this is first boosted deposit - booster of 0) // Once deposited, coins can go to a few places: // -- // 1. Delta permanent - Can never remove, but it gives you farm power // 2. Delta vesting - Gained from farming. When you withdraw, it creates a contract, where it vests for a year, like delta tokens themselves. You can liquidate it early, and forfeit remainder. 15% goes to their permanent balance, 85% goes out to distributor (subject to change) // 3. Delta withdrawable - Withdraw in 2 weeks. This is initial deposit. (or 50% of initial deposit, if its a burning deposit) uint256 toBurn; // We can burn from deposit of compounding bool burningDeposit = isBurn && depositDELTA > 0; bool compondingBurn = personMemory.compoundBurn && farmedDELTA > 0; uint256 newBooster = calculatedBooster; if(burningDeposit) { // Its a burn deposit // we make sure it has non 0 deposit uint256 halfOfDeltaDeposit = depositDELTA / 2; personStorage.deltaWithdrawable = personMemory.deltaWithdrawable.add(halfOfDeltaDeposit); toBurn = toBurn.add(halfOfDeltaDeposit); } else if(depositDELTA > 0) { // This is a normal deposit, so we have to force booster to 1 require(!compondingBurn, "Can not do normal deposits when compoundBurn is on, uncheck it or do a burn deposit"); // We set into storage because it is not componding burn or normal deposit personStorage.deltaWithdrawable = personMemory.deltaWithdrawable.add(depositDELTA); newBooster = 1; // We set booster to 1 on normal deposit } if(compondingBurn) { // If this is a burning compound and we have farmed delta uint256 halfOfFarmedDelta = farmedDELTA / 2; toBurn = toBurn.add(halfOfFarmedDelta); // Is the compound and deposited bigger than 10% of total we increment booster // We burn half and add it personStorage.deltaVesting = personMemory.deltaVesting.add(halfOfFarmedDelta); } else if(farmedDELTA > 0) { // This is still a compound but a normal one since we have farmed. // Note that this will add to deltaVesting and not reduce the multiplier to 1 personStorage.deltaVesting = personMemory.deltaVesting.add(farmedDELTA); } // If this is a normal deposit and compounding burn it fails. So the OR is only when its a burning deposit and not compounding burn which still makes this logic sound if(burningDeposit || compondingBurn) { // We had a half and half // We burn here to save gas personStorage.deltaPermanent = personMemory.deltaPermanent.add(toBurn); burn(toBurn); // 5% of total = 10% of total burn deposit if(toBurn.mul(20) >= personMemory.totalDelta && block.timestamp >= personMemory.lastBoosterDepositTimestamp + 7 days) { personStorage.lastBoosterDepositTimestamp = block.timestamp; if(block.timestamp <= personMemory.lastBoosterDepositTimestamp + 14 days) { newBooster = personStorage.lastBooster + 1; // Unupdated storage variable (the hightened booster) } else { newBooster += BOOST_UP_WEEK; } } else if (compondingBurn) { // We are doing a compounding burn and we dont have enough to put the modifier up or there isnt enough time, we revert because thats abusable with depositFor require(block.timestamp >= personMemory.lastBoosterDepositTimestamp + 14 days, "Cannot use compounding burn without getting boost up, uncheck compounding burn, or wait 14 days"); } // Note if you farmed 2x your principle you can get fast tracked to burn easily // This means rLP can have a burn compound most likely forever until their principle gets huge compared to rlp stack if(personMemory.lastBoosterDepositTimestamp == 0) { // toBurn will be 50% of compound + deposiut if its burned // This means you have to deposit 2x that require(personMemory.totalDelta <= toBurn, "Uncheck compounding burn, or deposit more. You have to deposit and compound with burn at least 2x your total delta."); newBooster = BOOST_MAX; // we default to compound burn for users sake, they can change it if they please personStorage.compoundBurn = true; } } // We set total delta after the requirement statements so its not hightened personMemory.totalDelta = personMemory.totalDelta.add(depositDELTA).add(farmedDELTA); // Memory is used later personStorage.totalDelta = personMemory.totalDelta; if(newBooster > BOOST_MAX) { // Only place it can be higher than BOOST_MAX is here return BOOST_MAX; } return newBooster; } function sendETH(address person,uint256 amount) internal { WETH.transfer(person, amount); } function sendDELTA(address person, uint256 amount) internal { DELTA.transfer(person, amount); } function burn(uint256 amount) internal { sendDELTA(DEAD_BEEF, amount); } function recycle(RecycleInfo memory ri) internal returns (uint256 booster, uint256 farmedDELTA, uint256 farmedETH) { // We always send the recycled to msg.sender // This function is supposed to pay people to keep other people on their right multiplier // Thats why we pay msg.sender for 1% of recycled. if(ri.recycledETH > 0) { uint256 toSenderETH = ri.recycledETH / 100; sendETH(msg.sender, toSenderETH); pendingRewards.ETH = pendingRewards.ETH.add(ri.recycledETH - toSenderETH); } if(ri.recycledDelta > 0) { uint256 toSenderDELTA = ri.recycledDelta / 100; sendDELTA(msg.sender, toSenderDELTA); pendingRewards.DELTA = pendingRewards.DELTA.add(ri.recycledDelta - toSenderDELTA); } return (ri.booster, ri.farmedDelta, ri.farmedETH); } // Returns the total farmed not adjusted of person function calculateFarmed( uint256 farmingPower, uint256 accumulatedDELTAE12, uint256 accumulatedETHE12, uint256 rewardDebtDELTA, uint256 rewardDebtETH) internal pure returns(uint256 farmedDELTA, uint256 farmedETH) { farmedDELTA = (accumulatedDELTAE12.mul(farmingPower).sub(rewardDebtDELTA)) / 1e12; farmedETH = (accumulatedETHE12.mul(farmingPower).sub(rewardDebtETH)) / 1e12; } // This function updates the vault by : // Distributing from the delta distributor // Using the pending amounts and splitting them amongst all farming power which acts like shares of the pie function _updateVault(uint256 totalFarmingPower) internal returns (uint256 accumulatedDELTAE12, uint256 accumulatedETHE12) { // We add rewards from the distributor // To prevent various conditions with flash loans IDeltaDistributor(DELTA.distributor()).distribute(); uint256 pendingDELTA = pendingRewards.DELTA; uint256 pendingETH = pendingRewards.ETH; accumulatedDELTAE12 = vaultInfo.accumulatedDELTAPerShareE12; accumulatedETHE12 = vaultInfo.accumulatedETHPerShareE12; if(totalFarmingPower == 0) { return (accumulatedDELTAE12, accumulatedETHE12); // div by 0 errors } delete pendingRewards; if(pendingDELTA > 0) { accumulatedDELTAE12 = accumulatedDELTAE12.add( pendingDELTA.mul(1e12) / totalFarmingPower ); // total farming power isnt 0, so no need to safemath vaultInfo.accumulatedDELTAPerShareE12 = accumulatedDELTAE12; // write to storage } if(pendingETH > 0) { accumulatedETHE12 = accumulatedETHE12.add( pendingETH.mul(1e12) / totalFarmingPower ); // ditto vaultInfo.accumulatedETHPerShareE12 = accumulatedETHE12; // write to storage } } /// Styling choices are on purpose for code readability function whenNotPanicked() internal view { require(_isNotPaniced, "Farming currently awaiting developer input - all actions are paused temporarily"); } function onlyMultisig() private view { require(msg.sender == DELTA.governance(), "!governance"); } /// @notice a guardian can emergency shutdown the vault, only multisig can restore function emergencyShutdown(bool stopPanicMultisigOnly) public { /// Note this is in case a guardian is rogue, we rather have it shut down then have another guardian exploit it. if(stopPanicMultisigOnly) { onlyMultisig(); _isNotPaniced = true; return; } require(isAGuardian[msg.sender] || msg.sender == DELTA.governance(), "!guardian"); _isNotPaniced = false; } function editGuardianRole(address person, bool isGuardian) public { onlyMultisig(); isAGuardian[person] = isGuardian; } // How many boosts would have been lost in the given time frame function boostDecayQtyInDuration(uint256 secondsSinceLastBoost) internal pure returns (uint256) { return secondsSinceLastBoost.div(1 weeks).mul(BOOST_DOWN_WEEK); } // Calculate a booster after a given time frame has passed function boosterAfterDuration(uint256 secondsSinceLastBoost, uint256 previousBooster) internal pure returns (uint256) { uint256 boostDecayQty = boostDecayQtyInDuration(secondsSinceLastBoost); if(boostDecayQty >= previousBooster) { return 1; } return previousBooster - boostDecayQty; } /// @dev pure functions that returns recycled and claimed tokens function howMuchOfFarmedPercentIsLegit(uint256 previousBooster, uint256 secondsSinceLastBoost) internal pure returns (uint256 newBooster, uint256 percent) { // Get the total amount farmed on this inflated booster // To calculate ho wmuch to recycle, we take the last boost time // Then apply formula to reduce it until its 1 // we calculate a period of time under each booster // I start with 0% farmed and loop over all weeks to get the correct percentage, // i have 10x booster with that // But my real booster is now 8x // This means I spent 1 week with 10x booster // 1 week with 9x booster // incomplete week with 8x booster lets say 1 full week for ease of math // So i should be earning 100 * 10/10 33% = 33 // 100 * 9 /10 * 33% = 29.7 // 100 * 8 /10 * 33% = 26.4 // Total 89.1 // Determine the current booster/multiplier after decay has occurred since our last boost if(7 days > secondsSinceLastBoost) { return (previousBooster, 100); } newBooster = boosterAfterDuration(secondsSinceLastBoost, previousBooster); // If we are not going down from the booster, we just return the total amount and recycle nothing if(newBooster == previousBooster) { return (previousBooster, 100); } // We loop incrementing this variable // It represents 1 week spent at a specific booster uint256 weekNum; uint256 accumulatedBoostTimePercentages; // initializes to 0 while(true) { // Navigate down through the various boost levels until we hit 1 uint256 thisBooster; uint256 jumpDistance = weekNum * BOOST_DOWN_WEEK; if(previousBooster <= jumpDistance + 1) { thisBooster = 1; // Its 1 cause we would overflow instead } else { thisBooster = previousBooster - jumpDistance; } uint256 secondsThisBooster = 1 weeks; //Default is 1 week spent because that might be the most common case if(weekNum == secondsSinceLastBoost.div(1 weeks) || thisBooster == 1 ) { // this is the partial // or potentially multi week stuck at 1 // We are still actively in this week of decay (or just down to booster of 1) secondsThisBooster = secondsSinceLastBoost - weekNum * 1 weeks ; uint256 boosterRatioE2 = thisBooster.mul(1e2).div(previousBooster); // uint256 percentOfTimeSpentInThisBoosterE2 = secondsThisBooster.mul(1e2).div(secondsSinceLastBoost); uint256 percentOfTimeSpentInThisBoosterE2 = 100 - accumulatedBoostTimePercentages; percent = percent.add( uint256(100).mul(boosterRatioE2).mul(percentOfTimeSpentInThisBoosterE2).div(1e4) ); break; } else { // This entire week has passed uint256 percentOfTimeSpentInThisBoosterE2 = secondsThisBooster.mul(1e2).div(secondsSinceLastBoost); accumulatedBoostTimePercentages += percentOfTimeSpentInThisBoosterE2; uint256 boosterRatioE2 = thisBooster.mul(1e2).div(previousBooster); percent = percent.add( uint256(100).mul(boosterRatioE2).mul(percentOfTimeSpentInThisBoosterE2).div(1e4) ); } weekNum++; } require(percent <= 100, "DELTA_Deep_Farming_Vault: Percent should never exceed 100%"); require(percent >= 10, "DELTA_Deep_Farming_Vault: Percent should never be lower than 10%"); // Over time it approaches 10% never meets it but inprecision has to be accoutned for } receive() external payable { revert("ETH not allowed"); } }// SPDX-License-Identifier: UNLICENSED // DELTA-BUG-BOUNTY pragma solidity ^0.7.6; pragma abicoder v2; import "../../interfaces/IDeltaToken.sol"; // import "../../interfaces/IDeepFarmingVault.sol"; // import "../../interfaces/IDeltaDistributor.sol"; contract DELTA_Deep_Farming_Storage { struct UserInformationDFV { // Reward debts is used for math trick to achieve O(1) farmed amount // We set rewardDebts to exactly amount of accumulted*shares every time a claim is done uint256 rewardDebtETH; uint256 rewardDebtDELTA; // Users farming power this includes, multiplier, rlp,delta principle. And can be stale - meaning too high and // is adjusted every time there is a interaction uint256 farmingPower; // rlp*rlpratio + deltaTotal * multipleir // Delta balances and total of them to save gas uint256 deltaPermanent; // Never withdrawable uint256 deltaVesting; // Amount that needs to vest 12 months to be claimable uint256 deltaWithdrawable; // Amount that can be withdrawn right away (with 2 week vesting) uint256 totalDelta; // Sum of them all (delta only no rlp) uint256 rlp; // amount of rlp this user has uint256 lastBoosterDepositTimestamp; // timestamp of the last booster deposit uint256 lastBooster; // last booster recorded for this person, this might be too high and is subject to adjustment uint256 lastInteractionBlock; // Block of last interaction, we allow 1 interaction per block of an address bool compoundBurn; // A boolean that sets compounding effect, either burn maintaining multiplier or just adding. } struct VaultInformation { uint256 totalFarmingPower; // A sum of farming power of all users (includes stale ones) // rlp*rlpratio + deltaTotal * multipleir * all users // Accumulated balances of each reward token stored in e12 for change uint256 accumulatedDELTAPerShareE12; // pending rewards / totalshares *1e12 uint256 accumulatedETHPerShareE12; } struct Rewards { uint256 DELTA; uint256 ETH; } struct RecycledFarmingValues { uint256 delta; uint256 eth; uint256 percentLegit; uint256 calculatedBooster; } bool internal _isNotPaniced; uint256 public farmingStartedTimestamp; Rewards internal pendingRewards; // Rewards that are pending to be added to vault and splut per share with the updateVault() VaultInformation public vaultInfo; // Stores info of this vault mapping(address => address []) public withdrawalContracts; // All withdrawal contracts of a person mapping(address => UserInformationDFV) public userInfo; // stores all userinformation mapping(address => bool) public isAGuardian; }// SPDX-License-Identifier: MIT // solhint-disable-next-line compiler-version pragma solidity >=0.4.24 <0.8.0; import "../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } /// @dev Returns true if and only if the function is running in the constructor function _isConstructor() private view returns (bool) { return !AddressUpgradeable.isContract(address(this)); } }// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMathUpgradeable { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } }// SPDX-License-Identifier: UNLICENSED pragma experimental ABIEncoderV2; pragma solidity ^0.7.6; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../common/OVLTokenTypes.sol"; interface IDeltaToken is IERC20 { function vestingTransactions(address, uint256) external view returns (VestingTransaction memory); function getUserInfo(address) external view returns (UserInformationLite memory); function getMatureBalance(address, uint256) external view returns (uint256); function liquidityRebasingPermitted() external view returns (bool); function lpTokensInPair() external view returns (uint256); function governance() external view returns (address); function performLiquidityRebasing() external; function distributor() external view returns (address); function totalsForWallet(address ) external view returns (WalletTotals memory totals); function adjustBalanceOfNoVestingAccount(address, uint256,bool) external; function userInformation(address user) external view returns (UserInformation memory); }pragma abicoder v2; struct RecycleInfo { uint256 booster; uint256 farmedDelta; uint256 farmedETH; uint256 recycledDelta; uint256 recycledETH; } interface IDeepFarmingVault { function addPermanentCredits(address,uint256) external; function addNewRewards(uint256 amountDELTA, uint256 amountWETH) external; function adminRescueTokens(address token, uint256 amount) external; function setCompundBurn(bool shouldBurn) external; function compound(address person) external; function exit() external; function withdrawRLP(uint256 amount) external; function realFarmedOfPerson(address person) external view returns (RecycleInfo memory); function deposit(uint256 numberRLP, uint256 numberDELTA) external; function depositFor(address person, uint256 numberRLP, uint256 numberDELTA) external; function depositWithBurn(uint256 numberDELTA) external; function depositForWithBurn(address person, uint256 numberDELTA) external; } pragma solidity ^0.7.6; interface IDeltaDistributor { function creditUser(address,uint256) external; function addDevested(address, uint256) external; function distribute() external; }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; } // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // SPDX-License-Identifier: UNLICENSED // DELTA-BUG-BOUNTY pragma solidity ^0.7.6; struct VestingTransaction { uint256 amount; uint256 fullVestingTimestamp; } struct WalletTotals { uint256 mature; uint256 immature; uint256 total; } struct UserInformation { // This is going to be read from only [0] uint256 mostMatureTxIndex; uint256 lastInTxIndex; uint256 maturedBalance; uint256 maxBalance; bool fullSenderWhitelisted; // Note that recieving immature balances doesnt mean they recieve them fully vested just that senders can do it bool immatureReceiverWhitelisted; bool noVestingWhitelisted; } struct UserInformationLite { uint256 maturedBalance; uint256 maxBalance; uint256 mostMatureTxIndex; uint256 lastInTxIndex; } struct VestingTransactionDetailed { uint256 amount; uint256 fullVestingTimestamp; // uint256 percentVestedE4; uint256 mature; uint256 immature; } uint256 constant QTY_EPOCHS = 7; uint256 constant SECONDS_PER_EPOCH = 172800; // About 2days uint256 constant FULL_EPOCH_TIME = SECONDS_PER_EPOCH * QTY_EPOCHS; // Precision Multiplier -- this many zeros (23) seems to get all the precision needed for all 18 decimals to be only off by a max of 1 unit uint256 constant PM = 1e23; // SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
File 5 of 8: DELTAToken
// DELTA-BUG-BOUNTY pragma experimental ABIEncoderV2; pragma solidity ^0.7.6; import "../libs/Context.sol"; import "../../interfaces/IOVLBalanceHandler.sol"; import "../../interfaces/IOVLTransferHandler.sol"; import "../../interfaces/IOVLVestingCalculator.sol"; import "../../interfaces/IRebasingLiquidityToken.sol"; import "../../interfaces/IWETH.sol"; import "./Common/OVLBase.sol"; import "../../common/OVLTokenTypes.sol"; import "./Handlers/post_first_rebasing/OVLTransferHandler.sol"; import "./Handlers/post_first_rebasing/OVLBalanceHandler.sol"; import "./Handlers/pre_first_rebasing/OVLLPRebasingHandler.sol"; import "./Handlers/pre_first_rebasing/OVLLPRebasingBalanceHandler.sol"; // Implementation of the DELTA token responsible // for the CORE ecosystem options layer // guarding unlocked liquidity inside of the ecosystem // This token is time lock guarded by 90% FoT which disappears after 2 weeks to 0% // balanceOf will return the spendable amount outside of the fee on transfer. contract DELTAToken is OVLBase, Context, IERC20 { using SafeMath for uint256; using Address for address; address public governance; address public tokenTransferHandler; address public rebasingLPAddress; address public tokenBalanceHandler; address public pendingGovernance; // ERC-20 Variables string private constant NAME = "DELTA.financial - deep DeFi derivatives"; string private constant SYMBOL = "DELTA"; uint8 private constant DECIMALS = 18; uint256 private constant TOTAL_SUPPLY = 45_000_000e18; // Configuration address private constant WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; address private constant BURNER = 0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF; address private constant LSW_ADDRESS = 0xdaFCE5670d3F67da9A3A44FE6bc36992e5E2beaB; address private constant UNISWAP_V2_ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D; // Handler for activation after first rebasing address private immutable tokenBalanceHandlerMain; address private immutable tokenTransferHandlerMain; // Lookup for pair address immutable public _PAIR_ADDRESS; constructor (address rebasingLP, address multisig, address dfv) { require(address(this) < WETH_ADDRESS, "DELTAToken: Invalid Token Address"); require(multisig != address(0)); require(dfv != address(0)); require(rebasingLP != address(0)); // We get the pair address // token0 is the smaller address address uniswapPair = address(uint(keccak256(abi.encodePacked( hex'ff', 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f, // Mainnet uniswap factory keccak256(abi.encodePacked(address(this), WETH_ADDRESS)), hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f' // init code hash )))); // We whitelist the pair to have no vesting on reception governance = msg.sender; // bypass !gov checks _PAIR_ADDRESS = uniswapPair; setNoVestingWhitelist(uniswapPair, true); setNoVestingWhitelist(BURNER, true); setNoVestingWhitelist(rebasingLP, true); setNoVestingWhitelist(UNISWAP_V2_ROUTER, true); // We set the router to no vesting so we dont need to check it in the balance handler to return maxbalance. // Since we return maxbalance of everyone who has no vesting. setWhitelists(multisig, true, true, true); // We are not setting dfv here intentionally because we have a check inside the dfv that it has them // Since DFV needs to be able to set whitelists itself, so it needs to be a part of the modules setFullSenderWhitelist(LSW_ADDRESS, true); // Nessesary for lsw because it doesnt just send to the pair governance = multisig; rebasingLPAddress = rebasingLP; _provideInitialSupply(LSW_ADDRESS, TOTAL_SUPPLY); // Set post first rebasing ones now into private variables address transferHandler = address(new OVLTransferHandler(uniswapPair, dfv)); tokenTransferHandlerMain = transferHandler; tokenBalanceHandlerMain = address(new OVLBalanceHandler(IOVLTransferHandler(transferHandler), IERC20(uniswapPair))); //Set pre rebasing ones as main ones tokenTransferHandler = address(new OVLLPRebasingHandler(uniswapPair)); tokenBalanceHandler = address(new OVLLPRebasingBalanceHandler()); } function activatePostFirstRebasingState() public isGovernance() { require(distributor != address(0), "Set the distributor first!"); tokenTransferHandler = tokenTransferHandlerMain; tokenBalanceHandler = tokenBalanceHandlerMain; } 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 TOTAL_SUPPLY - balanceOf(BURNER); } function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } function matureAllTokensOf(UserInformation storage ui, address account) internal { delete vestingTransactions[account]; // remove all vesting buckets ui.maturedBalance = ui.maxBalance; } function setFullSenderWhitelist(address account, bool canSendToMatureBalances) public isGovernance() { UserInformation storage ui = _userInformation[account]; matureAllTokensOf(ui,account); ui.fullSenderWhitelisted = canSendToMatureBalances; } function setImmatureRecipentWhitelist(address account, bool canRecieveImmatureBalances) public isGovernance() { UserInformation storage ui = _userInformation[account]; matureAllTokensOf(ui,account); ui.immatureReceiverWhitelisted = canRecieveImmatureBalances; } function setNoVestingWhitelist(address account, bool recievesBalancesWithoutVestingProcess) public isGovernance() { UserInformation storage ui = _userInformation[account]; matureAllTokensOf(ui,account); ui.noVestingWhitelisted = recievesBalancesWithoutVestingProcess; } function setWhitelists(address account, bool canSendToMatureBalances, bool canRecieveImmatureBalances, bool recievesBalancesWithoutVestingProcess) public isGovernance() { UserInformation storage ui = _userInformation[account]; matureAllTokensOf(ui,account); ui.noVestingWhitelisted = recievesBalancesWithoutVestingProcess; ui.immatureReceiverWhitelisted = canRecieveImmatureBalances; ui.fullSenderWhitelisted = canSendToMatureBalances; } // Allows for liquidity rebasing atomically // Does a callback to rlp and closes right after function performLiquidityRebasing() public { onlyRLP(); // guarantees this call can be only done by the rebasing lp contract liquidityRebasingPermitted = true; IRebasingLiquidityToken(rebasingLPAddress).tokenCaller(); liquidityRebasingPermitted = false; // Rebasing will adjust the lp tokens balance of the pair. Most likely to 0. This means without setting this here there is an attack vector lpTokensInPair = IERC20(_PAIR_ADDRESS).balanceOf(_PAIR_ADDRESS); } // Allows the rebasing LP to change balance of an account // Nessesary for fee efficiency of the rebasing process function adjustBalanceOfNoVestingAccount(address account, uint256 amount, bool isAddition) public { onlyRLP(); // guarantees this call can be only done by the rebasing lp contract UserInformation storage ui = _userInformation[account]; require(ui.noVestingWhitelisted, "Account is a vesting address"); if(isAddition) { ui.maxBalance = ui.maxBalance.add(amount); ui.maturedBalance = ui.maturedBalance.add(amount); } else { ui.maxBalance = amount; ui.maturedBalance = amount; } } // allow only RLP to call functions that call this function function onlyRLP() internal view { require(msg.sender == rebasingLPAddress, "DELTAToken: Only Rebasing LP contract can call this function"); } function _transfer(address sender, address recipient, uint256 amount) internal virtual { bytes memory callData = abi.encodeWithSelector(IOVLTransferHandler.handleTransfer.selector, sender, recipient, amount); (bool success, bytes memory result) = tokenTransferHandler.delegatecall(callData); if (!success) { revert(_getRevertMsg(result)); } } function balanceOf(address account) public view override returns (uint256) { return IOVLBalanceHandler(tokenBalanceHandler).handleBalanceCalculations(account, msg.sender); } function _provideInitialSupply(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: supplying zero address"); UserInformation storage ui = _userInformation[account]; ui.maturedBalance = ui.maturedBalance.add(amount); ui.maxBalance = ui.maxBalance.add(amount); emit Transfer(address(0), account, amount); } function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /// @notice sets a new distributor potentially with new distribution rules function setDistributor(address _newDistributor) public isGovernance() { distributor = _newDistributor; setWhitelists(_newDistributor, true, true, true); } /// @notice initializes the change of governance function setPendingGovernance(address _newGov) public isGovernance() { pendingGovernance = _newGov; } function acceptGovernance() public { require(msg.sender == pendingGovernance); governance = msg.sender; setWhitelists(msg.sender, true, true, true); delete pendingGovernance; } /// @notice sets the function that calculates returns from balanceOF function setBalanceCalculator(address _newBalanceCalculator) public isGovernance() { tokenBalanceHandler = _newBalanceCalculator; } /// @notice sets a contract with new logic for transfer handlers (contract upgrade) function setTokenTransferHandler(address _newHandler) public isGovernance() { tokenTransferHandler = _newHandler; } function _getRevertMsg(bytes memory _returnData) internal pure returns (string memory) { // If the _res length is less than 68, then the transaction failed silently (without a revert message) if (_returnData.length < 68) return 'Transaction reverted silently'; assembly { // Slice the sighash. _returnData := add(_returnData, 0x04) } return abi.decode(_returnData, (string)); // All that remains is the revert string } function totalsForWallet(address account) public view returns (WalletTotals memory totals) { uint256 mature = _userInformation[account].maturedBalance; uint256 immature; for(uint256 i = 0; i < QTY_EPOCHS; i++) { uint256 amount = vestingTransactions[account][i].amount; uint256 matureTxBalance = IOVLVestingCalculator(tokenBalanceHandler).getMatureBalance(vestingTransactions[account][i], block.timestamp); mature = mature.add(matureTxBalance); immature = immature.add(amount.sub(matureTxBalance)); } totals.mature = mature; totals.immature = immature; totals.total = mature.add(immature); } // Optimization for Balance Handler function getUserInfo(address user) external view returns (UserInformationLite memory) { UserInformation storage info = _userInformation[user]; return UserInformationLite(info.maturedBalance, info.maxBalance, info.mostMatureTxIndex, info.lastInTxIndex); } // Optimization for `require` checks modifier isGovernance() { _isGovernance(); _; } function _isGovernance() private view { require(msg.sender == governance, "!gov"); } // Remaining for js tests only before refactor function getTransactionDetail(VestingTransaction memory _tx) public view returns (VestingTransactionDetailed memory dtx) { return IOVLVestingCalculator(tokenBalanceHandler).getTransactionDetails(_tx, block.timestamp); } function userInformation(address user) external view returns (UserInformation memory) { return _userInformation[user]; } } // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <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 GSN 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 payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } pragma experimental ABIEncoderV2; pragma solidity ^0.7.6; interface IOVLBalanceHandler { function handleBalanceCalculations(address, address) external view returns (uint256); }pragma experimental ABIEncoderV2; pragma solidity ^0.7.6; interface IOVLTransferHandler { function handleTransfer(address sender, address recipient, uint256 amount) external; }pragma solidity ^0.7.6; pragma abicoder v2; import "../common/OVLTokenTypes.sol"; interface IOVLVestingCalculator { function getTransactionDetails(VestingTransaction memory _tx) external view returns (VestingTransactionDetailed memory dtx); function getTransactionDetails(VestingTransaction memory _tx, uint256 _blockTimestamp) external pure returns (VestingTransactionDetailed memory dtx); function getMatureBalance(VestingTransaction memory _tx, uint256 _blockTimestamp) external pure returns (uint256 mature); function calculateTransactionDebit(VestingTransactionDetailed memory dtx, uint256 matureAmountNeeded, uint256 currentTimestamp) external pure returns (uint256 outputDebit); } pragma experimental ABIEncoderV2; pragma solidity ^0.7.6; import "./IERC20Upgradeable.sol"; interface IRebasingLiquidityToken is IERC20Upgradeable { function tokenCaller() external; function reserveCaller(uint256,uint256) external; function wrapWithReturn() external returns (uint256); function wrap() external; function rlpPerLP() external view returns (uint256); }pragma solidity >=0.6.0 <0.8.0; interface IWETH { function deposit() external payable; function transfer(address to, uint value) external returns (bool); function withdraw(uint) external; function balanceOf(address) external view returns (uint256); }// DELTA-BUG-BOUNTY pragma abicoder v2; pragma solidity ^0.7.6; import "./../../../common/OVLTokenTypes.sol"; contract OVLBase { // Shared state begin v0 mapping (address => VestingTransaction[QTY_EPOCHS]) public vestingTransactions; mapping (address => UserInformation) internal _userInformation; mapping (address => uint256) internal _maxPossibleBalances; mapping (address => mapping (address => uint256)) internal _allowances; address public distributor; uint256 public lpTokensInPair; bool public liquidityRebasingPermitted; uint256 [72] private _gap; // Shared state end of v0 }// SPDX-License-Identifier: UNLICENSED // DELTA-BUG-BOUNTY pragma solidity ^0.7.6; struct VestingTransaction { uint256 amount; uint256 fullVestingTimestamp; } struct WalletTotals { uint256 mature; uint256 immature; uint256 total; } struct UserInformation { // This is going to be read from only [0] uint256 mostMatureTxIndex; uint256 lastInTxIndex; uint256 maturedBalance; uint256 maxBalance; bool fullSenderWhitelisted; // Note that recieving immature balances doesnt mean they recieve them fully vested just that senders can do it bool immatureReceiverWhitelisted; bool noVestingWhitelisted; } struct UserInformationLite { uint256 maturedBalance; uint256 maxBalance; uint256 mostMatureTxIndex; uint256 lastInTxIndex; } struct VestingTransactionDetailed { uint256 amount; uint256 fullVestingTimestamp; // uint256 percentVestedE4; uint256 mature; uint256 immature; } uint256 constant QTY_EPOCHS = 7; uint256 constant SECONDS_PER_EPOCH = 172800; // About 2days uint256 constant FULL_EPOCH_TIME = SECONDS_PER_EPOCH * QTY_EPOCHS; // Precision Multiplier -- this many zeros (23) seems to get all the precision needed for all 18 decimals to be only off by a max of 1 unit uint256 constant PM = 1e23; // DELTA-BUG-BOUNTY pragma solidity ^0.7.6; pragma abicoder v2; import "../../../libs/Address.sol"; import "../../../libs/SafeMath.sol"; import "../../Common/OVLBase.sol"; import "../../../../common/OVLTokenTypes.sol"; import "../../Common/OVLVestingCalculator.sol"; import "../../../../interfaces/IOVLTransferHandler.sol"; import "../../../../interfaces/IDeltaDistributor.sol"; import "../../../../interfaces/IDeltaToken.sol"; contract OVLTransferHandler is OVLBase, OVLVestingCalculator, IOVLTransferHandler { using SafeMath for uint256; using Address for address; address public immutable UNI_DELTA_WETH_PAIR; address public immutable DEEP_FARMING_VAULT; event Transfer(address indexed from, address indexed to, uint256 value); constructor(address pair, address dfv) { UNI_DELTA_WETH_PAIR = pair; DEEP_FARMING_VAULT = dfv; } function _removeBalanceFromSender(UserInformation storage senderInfo, address sender, bool immatureReceiverWhitelisted, uint256 amount) internal returns (uint256 totalRemoved) { uint256 mostMatureTxIndex = senderInfo.mostMatureTxIndex; uint256 lastInTxIndex = senderInfo.lastInTxIndex; // We check if recipent can get immature tokens, if so we go from the most imature first to be most fair to the user if (immatureReceiverWhitelisted) { ////// //// // we go from the least mature balance to the msot mature meaning -- //// ///// uint256 accumulatedBalance; while (true) { uint256 leastMatureTxAmount = vestingTransactions[sender][lastInTxIndex].amount; // Can never underflow due to if conditional uint256 remainingBalanceNeeded = amount - accumulatedBalance; if (leastMatureTxAmount >= remainingBalanceNeeded) { // We got enough in this bucket to cover the amount // We remove it from total and dont adjust the fully vesting timestamp // Because there might be tokens left still in it totalRemoved += remainingBalanceNeeded; vestingTransactions[sender][lastInTxIndex].amount = leastMatureTxAmount - remainingBalanceNeeded; // safe math already checked // We got what we wanted we leave the loop break; } else { //we add the whole amount of this bucket to the accumulated balance accumulatedBalance = accumulatedBalance.add(leastMatureTxAmount); totalRemoved += leastMatureTxAmount; delete vestingTransactions[sender][lastInTxIndex]; // And go to the more mature tx if (lastInTxIndex == 0) { lastInTxIndex = QTY_EPOCHS; } lastInTxIndex--; // If we can't get enough in this tx and this is the last one, then we bail if (lastInTxIndex == mostMatureTxIndex) { // If we still have enough to cover in the mature balance we use that uint256 maturedBalanceNeeded = amount - accumulatedBalance; // Exhaustive underflow check senderInfo.maturedBalance = senderInfo.maturedBalance.sub(maturedBalanceNeeded, "OVLTransferHandler: Insufficient funds"); totalRemoved += maturedBalanceNeeded; break; } } } // We write to storage the lastTx Index, which was in memory and we looped over it (or not) senderInfo.lastInTxIndex = lastInTxIndex; return totalRemoved; // End of logic in case reciever is whitelisted ( return assures) } uint256 maturedBalance = senderInfo.maturedBalance; ////// //// // we go from the most mature balance up //// ///// if (maturedBalance >= amount) { senderInfo.maturedBalance = maturedBalance - amount; // safemath safe totalRemoved = amount; } else { // Possibly using a partially vested transaction uint256 accumulatedBalance = maturedBalance; totalRemoved = maturedBalance; // Use the entire balance to start senderInfo.maturedBalance = 0; while (amount > accumulatedBalance) { VestingTransaction memory mostMatureTx = vestingTransactions[sender][mostMatureTxIndex]; // Guaranteed by `while` condition uint256 remainingBalanceNeeded = amount - accumulatedBalance; // Reduce this transaction as the final one VestingTransactionDetailed memory dtx = getTransactionDetails(mostMatureTx, block.timestamp); // credit is how much i got from this bucket // So if i didnt get enough from this bucket here we zero it and move to the next one if (remainingBalanceNeeded >= dtx.mature) { totalRemoved += dtx.amount; accumulatedBalance = accumulatedBalance.add(dtx.mature); delete vestingTransactions[sender][mostMatureTxIndex]; // refund gas } else { // Remove the only needed amount // Calculating debt based on the actual clamped credit eliminates // the need for debit/credit ratio checks we initially had. // Big gas savings using this one weird trick. Vitalik HATES it. uint256 outputDebit = calculateTransactionDebit(dtx, remainingBalanceNeeded, block.timestamp); remainingBalanceNeeded = outputDebit.add(remainingBalanceNeeded); totalRemoved += remainingBalanceNeeded; // We dont need to adjust timestamp vestingTransactions[sender][mostMatureTxIndex].amount = mostMatureTx.amount.sub(remainingBalanceNeeded, "Removing too much from bucket"); break; } // If we just went throught he lasttx bucket, and we did not get enough then we bail // Note if its the lastTransaction it already had a break; if (mostMatureTxIndex == lastInTxIndex && accumulatedBalance < amount) { // accumulatedBalance < amount because of the case its exactly equal with first if // Avoid ever looping around a second time because that would be bad revert("OVLTransferHandler: Insufficient funds"); } // We just emptied this so most mature one must be the next one mostMatureTxIndex++; if(mostMatureTxIndex == QTY_EPOCHS) { mostMatureTxIndex = 0; } } // We remove the entire amount removed // We already added amount senderInfo.mostMatureTxIndex = mostMatureTxIndex; } } // function _transferTokensToRecipient(address recipient, UserInformation memory senderInfo, UserInformation memory recipientInfo, uint256 amount) internal { function _transferTokensToRecipient(UserInformation storage recipientInfo, bool isSenderWhitelisted, address recipient, uint256 amount) internal { // If the sender can send fully or this recipent is whitelisted to not get vesting we just add it to matured balance (bool noVestingWhitelisted, uint256 maturedBalance, uint256 lastTransactionIndex) = (recipientInfo.noVestingWhitelisted, recipientInfo.maturedBalance, recipientInfo.lastInTxIndex); if(isSenderWhitelisted || noVestingWhitelisted) { recipientInfo.maturedBalance = maturedBalance.add(amount); return; } VestingTransaction storage lastTransaction = vestingTransactions[recipient][lastTransactionIndex]; // Do i fit in this bucket? // conditions for fitting inside a bucket are // 1 ) Either its less than 2 days old // 2 ) Or its more than 14 days old // 3 ) Or we move to the next one - which is empty or already matured // Note that only the first bucket checked can logically be less than 2 days old, this is a important optimization // So lets take care of that case now, so its not checked in the loop. uint256 timestampNow = block.timestamp; uint256 fullVestingTimestamp = lastTransaction.fullVestingTimestamp; if (timestampNow >= fullVestingTimestamp) {// Its mature we move it to mature and override or we move to the next one, which is always either 0 or matured recipientInfo.maturedBalance = maturedBalance.add(lastTransaction.amount); lastTransaction.amount = amount; lastTransaction.fullVestingTimestamp = timestampNow + FULL_EPOCH_TIME; } else if (fullVestingTimestamp >= timestampNow + SECONDS_PER_EPOCH * (QTY_EPOCHS - 1)) {// we add 12 days // we avoid overflows from 0 fullyvestedtimestamp // if fullyVestingTimestamp is bigger than that we should increment // but not bigger than fullyVesting // This check is exhaustive // If this is the case we just put it in this bucket. lastTransaction.amount = lastTransaction.amount.add(amount); /// No need to adjust timestamp` } else { // We move into the next one lastTransactionIndex++; if (lastTransactionIndex == QTY_EPOCHS) { lastTransactionIndex = 0; } // Loop over recipientInfo.lastInTxIndex = lastTransactionIndex; // To figure out if this is a empty bucket or a stale one // Its either the most mature one // Or its 0 // There is no other logical options // If this is the most mature one then we go > with most mature uint256 mostMature = recipientInfo.mostMatureTxIndex; if (mostMature == lastTransactionIndex) { // It was the most mature one, so we have to increment the most mature index mostMature++; if (mostMature == QTY_EPOCHS) { mostMature = 0; } recipientInfo.mostMatureTxIndex = mostMature; } VestingTransaction storage evenLatestTransaction = vestingTransactions[recipient][lastTransactionIndex]; // Its mature we move it to mature and override or we move to the next one, which is always either 0 or matured recipientInfo.maturedBalance = maturedBalance.add(evenLatestTransaction.amount); evenLatestTransaction.amount = amount; evenLatestTransaction.fullVestingTimestamp = timestampNow + FULL_EPOCH_TIME; } } function addAllowanceToDFV(address sender) internal { // If you transferFrom from anyone even 1 gwei unit // This will force dfv to have infinite allowance // But this is not abug because DFV has defacto infinite allowance becaose of this function // So there is no change _allowances[sender][DEEP_FARMING_VAULT] = uint(-1); } function handleUniswapAdjustmenets() internal{ uint256 newLPSupply = IERC20(UNI_DELTA_WETH_PAIR).balanceOf(UNI_DELTA_WETH_PAIR); require(newLPSupply >= lpTokensInPair, "DELTAToken: Liquidity removals are forbidden"); // We allow people to bump the number of LP tokens inside the pair, but we dont allow them to go lower // Making liquidity withdrawals impossible // Because uniswap queries banaceOf before doing a burn, that means we can detect a inflow of LP tokens // But someone could send them and then reset with this function // This is why we "lock" the bigger amount here and dont allow a lower amount than the last time // Making it impossible to anyone who sent the liquidity tokens to the pair (which is nessesary to burn) not be able to burn them lpTokensInPair = newLPSupply; } // This function does not need authentication, because this is EXCLUSIVELY // ever meant to be called using delegatecall() from the main token. // The memory it modifies in DELTAToken is what effects user balances. function handleTransfer(address sender, address recipient, uint256 amount) external override { require(sender != recipient, "DELTAToken: Can not send DELTA to yourself"); require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); /// Liquidity removal protection if (!liquidityRebasingPermitted && (sender == UNI_DELTA_WETH_PAIR || recipient == UNI_DELTA_WETH_PAIR)) { handleUniswapAdjustmenets(); } if(recipient == DEEP_FARMING_VAULT) { addAllowanceToDFV(sender); } UserInformation storage recipientInfo = _userInformation[recipient]; UserInformation storage senderInfo = _userInformation[sender]; uint256 totalRemoved = _removeBalanceFromSender(senderInfo, sender, recipientInfo.immatureReceiverWhitelisted, amount); uint256 toDistributor = totalRemoved.sub(amount, "OVLTransferHandler: Insufficient funds"); // We remove from max balance totals senderInfo.maxBalance = senderInfo.maxBalance.sub(totalRemoved, "OVLTransferHandler: Insufficient funds"); // Sanity check require(totalRemoved >= amount, "OVLTransferHandler: Insufficient funds"); // Max is 90% of total removed require(amount.mul(9) >= toDistributor, "DELTAToken: Burned too many tokens"); _creditDistributor(sender, toDistributor); ////// /// We add tokens to the recipient ////// _transferTokensToRecipient(recipientInfo, senderInfo.fullSenderWhitelisted, recipient, amount); // We add to total balance for sanity checks and uniswap router recipientInfo.maxBalance = recipientInfo.maxBalance.add(amount); emit Transfer(sender, recipient, amount); } function _creditDistributor(address creditedBy, uint256 amount) internal { address _distributor = distributor; // gas savings for storage reads UserInformation storage distributorInfo = _userInformation[distributor]; distributorInfo.maturedBalance = distributorInfo.maturedBalance.add(amount); // Should trigger an event here distributorInfo.maxBalance = distributorInfo.maxBalance.add(amount); IDeltaDistributor(_distributor).creditUser(creditedBy, amount); emit Transfer(creditedBy, _distributor, amount); } }// DELTA-BUG-BOUNTY pragma solidity ^0.7.6; pragma abicoder v2; import "../../../../common/OVLTokenTypes.sol"; import "../../Common/OVLVestingCalculator.sol"; import "../../../../interfaces/IOVLBalanceHandler.sol"; import "../../../../interfaces/IOVLTransferHandler.sol"; import "../../../../interfaces/IRebasingLiquidityToken.sol"; import "../../../../interfaces/IDeltaToken.sol"; contract OVLBalanceHandler is OVLVestingCalculator, IOVLBalanceHandler { using SafeMath for uint256; IDeltaToken private immutable DELTA_TOKEN; IERC20 private immutable DELTA_X_WETH_PAIR; IOVLTransferHandler private immutable TRANSFER_HANDLER; constructor(IOVLTransferHandler transactionHandler, IERC20 pair) { DELTA_TOKEN = IDeltaToken(msg.sender); TRANSFER_HANDLER = transactionHandler; DELTA_X_WETH_PAIR = pair; } function handleBalanceCalculations(address account, address sender) external view override returns (uint256) { UserInformation memory ui = DELTA_TOKEN.userInformation(account); // LP Removal protection if(sender == address(DELTA_X_WETH_PAIR) && !DELTA_TOKEN.liquidityRebasingPermitted()) { // This guaranteed liquidity rebasing is not permitted and the sender whos calling is uniswap. // If the sender is uniswap and is querying balanceOf, this only happens first inside the burn function // This means if the balance of LP tokens here went up // We should revert // LP tokens supply can raise but it can never get lower with this method, if we detect a raise here we should revert // Rest of this code is inside the _transfer function require(DELTA_X_WETH_PAIR.balanceOf(address(DELTA_X_WETH_PAIR)) == DELTA_TOKEN.lpTokensInPair(), "DELTAToken: Liquidity removal is forbidden"); return ui.maxBalance; } // We trick the uniswap router path revert by returning the whole balance // As well as saving gas in noVesting callers like uniswap if(ui.noVestingWhitelisted) { return ui.maxBalance; } // potentially do i + 1 % epochs while (true) { uint256 mature = getMatureBalance(DELTA_TOKEN.vestingTransactions(account, ui.mostMatureTxIndex), block.timestamp); ui.maturedBalance = ui.maturedBalance.add(mature); // We go until we encounter a empty above most mature tx if(ui.mostMatureTxIndex == ui.lastInTxIndex) { break; } ui.mostMatureTxIndex++; if(ui.mostMatureTxIndex == QTY_EPOCHS) { ui.mostMatureTxIndex = 0; } } return ui.maturedBalance; } }// DELTA-BUG-BOUNTY pragma abicoder v2; pragma solidity ^0.7.6; import "../../../libs/Address.sol"; import "../../../libs/SafeMath.sol"; import "../../../../interfaces/IOVLTransferHandler.sol"; import "../../Common/OVLBase.sol"; import "../../../../common/OVLTokenTypes.sol"; contract OVLLPRebasingHandler is OVLBase, IOVLTransferHandler { using SafeMath for uint256; using Address for address; address private constant DEPLOYER = 0x5A16552f59ea34E44ec81E58b3817833E9fD5436; address private constant DELTA_LIMITED_STAKING_WINDOW = 0xdaFCE5670d3F67da9A3A44FE6bc36992e5E2beaB; address public immutable UNI_DELTA_WETH_PAIR; event Transfer(address indexed from, address indexed to, uint256 value); constructor(address pair) { UNI_DELTA_WETH_PAIR = pair; } // This function does not need authentication, because this is EXCLUSIVELY // ever meant to be called using delegatecall() from the main token. // The memory it modifies in DELTAToken is what effects user balances. // Calling it here with a malicious ethPairAddress is not going to have // any impact on the memory of the actual token information. function handleTransfer(address sender, address recipient, uint256 amount) external override { // Mature sure its the deployer require(tx.origin == DEPLOYER, "!authorised"); // require(sender == DELTA_LIMITED_STAKING_WINDOW || sender == UNI_DELTA_WETH_PAIR || recipient == UNI_DELTA_WETH_PAIR, "Transfers not to or from pair during rebasing is not allowed"); require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); require(sender != recipient, "DELTA: Transfer to self disallowed!"); UserInformation storage senderInfo = _userInformation[sender]; UserInformation storage recipientInfo = _userInformation[recipient]; senderInfo.maturedBalance = senderInfo.maturedBalance.sub(amount); senderInfo.maxBalance = senderInfo.maxBalance.sub(amount); recipientInfo.maturedBalance = recipientInfo.maturedBalance.add(amount); recipientInfo.maxBalance = recipientInfo.maxBalance.add(amount); emit Transfer(sender, recipient, amount); } }// DELTA-BUG-BOUNTY pragma abicoder v2; pragma solidity ^0.7.6; import "../../../../interfaces/IDeltaToken.sol"; import "../../../../interfaces/IOVLBalanceHandler.sol"; import "../../../../common/OVLTokenTypes.sol"; contract OVLLPRebasingBalanceHandler is IOVLBalanceHandler { IDeltaToken private immutable DELTA_TOKEN; constructor() { DELTA_TOKEN = IDeltaToken(msg.sender); } function handleBalanceCalculations(address account, address) external view override returns (uint256) { UserInformationLite memory ui = DELTA_TOKEN.getUserInfo(account); return ui.maxBalance; } }// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }// SPDX-License-Identifier: MIT pragma solidity >=0.6.2 <0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } } // DELTA-BUG-BOUNTY pragma solidity ^0.7.6; pragma abicoder v2; import "./../../../common/OVLTokenTypes.sol"; import "../../../interfaces/IOVLVestingCalculator.sol"; import "../../libs/SafeMath.sol"; contract OVLVestingCalculator is IOVLVestingCalculator { using SafeMath for uint256; function getTransactionDetails(VestingTransaction memory _tx) public view override returns (VestingTransactionDetailed memory dtx) { return getTransactionDetails(_tx, block.timestamp); } function getTransactionDetails(VestingTransaction memory _tx, uint256 _blockTimestamp) public pure override returns (VestingTransactionDetailed memory dtx) { if(_tx.fullVestingTimestamp == 0) { return dtx; } dtx.amount = _tx.amount; dtx.fullVestingTimestamp = _tx.fullVestingTimestamp; // at precision E4, 1000 is 10% uint256 timeRemaining; if(_blockTimestamp >= dtx.fullVestingTimestamp) { // Fully vested dtx.mature = _tx.amount; return dtx; } else { timeRemaining = dtx.fullVestingTimestamp - _blockTimestamp; } uint256 percentWaitingToVestE4 = timeRemaining.mul(1e4) / FULL_EPOCH_TIME; uint256 percentWaitingToVestE4Scaled = percentWaitingToVestE4.mul(90) / 100; dtx.immature = _tx.amount.mul(percentWaitingToVestE4Scaled) / 1e4; dtx.mature = _tx.amount.sub(dtx.immature); } function getMatureBalance(VestingTransaction memory _tx, uint256 _blockTimestamp) public pure override returns (uint256 mature) { if(_tx.fullVestingTimestamp == 0) { return 0; } uint256 timeRemaining; if(_blockTimestamp >= _tx.fullVestingTimestamp) { // Fully vested return _tx.amount; } else { timeRemaining = _tx.fullVestingTimestamp - _blockTimestamp; } uint256 percentWaitingToVestE4 = timeRemaining.mul(1e4) / FULL_EPOCH_TIME; uint256 percentWaitingToVestE4Scaled = percentWaitingToVestE4.mul(90) / 100; mature = _tx.amount.mul(percentWaitingToVestE4Scaled) / 1e4; mature = _tx.amount.sub(mature); // the subtracted value represents the immature balance at this point } function calculateTransactionDebit(VestingTransactionDetailed memory dtx, uint256 matureAmountNeeded, uint256 currentTimestamp) public pure override returns (uint256 outputDebit) { if(dtx.fullVestingTimestamp > currentTimestamp) { // This will be between 0 and 100*pm representing how much of the mature pool is needed uint256 percentageOfMatureCoinsConsumed = matureAmountNeeded.mul(PM).div(dtx.mature); require(percentageOfMatureCoinsConsumed <= PM, "OVLTransferHandler: Insufficient funds"); // Calculate the number of immature coins that need to be debited based on this ratio outputDebit = dtx.immature.mul(percentageOfMatureCoinsConsumed) / PM; } // shouldnt this use outputDebit require(dtx.amount <= dtx.mature.add(dtx.immature), "DELTAToken: Balance maximum problem"); // Just in case } } pragma solidity ^0.7.6; interface IDeltaDistributor { function creditUser(address,uint256) external; function addDevested(address, uint256) external; function distribute() external; }// SPDX-License-Identifier: UNLICENSED pragma experimental ABIEncoderV2; pragma solidity ^0.7.6; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../common/OVLTokenTypes.sol"; interface IDeltaToken is IERC20 { function vestingTransactions(address, uint256) external view returns (VestingTransaction memory); function getUserInfo(address) external view returns (UserInformationLite memory); function getMatureBalance(address, uint256) external view returns (uint256); function liquidityRebasingPermitted() external view returns (bool); function lpTokensInPair() external view returns (uint256); function governance() external view returns (address); function performLiquidityRebasing() external; function distributor() external view returns (address); function totalsForWallet(address ) external view returns (WalletTotals memory totals); function adjustBalanceOfNoVestingAccount(address, uint256,bool) external; function userInformation(address user) external view returns (UserInformation memory); }// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
File 6 of 8: DELTA_Distributor
// SPDX-License-Identifier: UNLICENSED // DELTA-BUG-BOUNTY pragma abicoder v2; import "../libs/SafeMath.sol"; import "../../interfaces/IUniswapV2Pair.sol"; import "../../interfaces/IDeltaToken.sol"; import "../../interfaces/IDeepFarmingVault.sol";// TODO REMOVE interface ICORE_VAULT { function addPendingRewards(uint256) external; } contract DELTA_Distributor { using SafeMath for uint256; // Immutableas and constants // defacto burn address, this one isnt used commonly so its easy to see burned amounts on just etherscan address constant internal DEAD_BEEF = 0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF; address constant public WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; address constant public CORE = 0x62359Ed7505Efc61FF1D56fEF82158CcaffA23D7; address constant public CORE_WETH_PAIR = 0x32Ce7e48debdccbFE0CD037Cc89526E4382cb81b; address constant public DELTA_MULTISIG = 0xB2d834dd31816993EF53507Eb1325430e67beefa; address constant public CORE_VAULT = 0xC5cacb708425961594B63eC171f4df27a9c0d8c9; // We sell 20% and distribute it thus uint256 constant public PERCENT_BURNED = 16; uint256 constant public PERCENT_DEV_FUND= 8; uint256 constant public PERCENT_DEEP_FARMING_VAULT = 56; uint256 constant public PERCENT_SOLD = 20; uint256 constant public PERCENT_OF_SOLD_DEV = 50; uint256 constant public PERCENT_OF_SOLD_CORE_BUY = 25; uint256 constant public PERCENT_OF_SOLD_DELTA_WETH_DEEP_FARMING_VAULT = 25; address immutable public DELTA_WETH_PAIR_UNISWAP; IDeltaToken immutable public DELTA_TOKEN; // storage variables address public deepFarmingVault; uint256 public pendingBurn; uint256 public pendingDev; uint256 public pendingTotal; mapping(address => uint256) public pendingCredits; mapping(address => bool) public isApprovedLiquidator; receive() external payable { revert("ETH not allowed"); } function distributeAndBurn() public { // Burn DELTA_TOKEN.transfer(DEAD_BEEF, pendingBurn); pendingTotal = pendingTotal.sub(pendingBurn); delete pendingBurn; // Transfer dev address deltaMultisig = DELTA_TOKEN.governance(); DELTA_TOKEN.transfer(deltaMultisig, pendingDev); pendingTotal = pendingTotal.sub(pendingDev); delete pendingDev; } /// @notice a function that distributes pending to all the vaults etdc // This is able to be called by anyone. // And is simply just here to save gas on the distribution math function distribute() public { uint256 amountDeltaNow = DELTA_TOKEN.balanceOf(address(this)); uint256 _pendingTotal = pendingTotal; uint256 amountAdded = amountDeltaNow.sub(_pendingTotal); // pendingSell stores in this variable and is not counted if(amountAdded < 1e18) { // We only add 1 DELTA + of rewards to save gas from the DFV calls. return; } uint256 toBurn = amountAdded.mul(PERCENT_BURNED).div(100); uint256 toDev = amountAdded.mul(PERCENT_DEV_FUND).div(100); uint256 toVault = amountAdded.mul(PERCENT_DEEP_FARMING_VAULT).div(100); // Not added to pending case we transfer it now pendingBurn = pendingBurn.add(toBurn); pendingDev = pendingDev.add(toDev); pendingTotal = _pendingTotal.add(amountAdded).sub(toVault); // We send to the vault and credit it IDeepFarmingVault(deepFarmingVault).addNewRewards(toVault, 0); // Reserve is how much we can sell thats remaining 20% } function setDeepFarmingVault(address _deepFarmingVault) public { onlyMultisig(); deepFarmingVault = _deepFarmingVault; // set infinite approvals refreshApprovals(); UserInformation memory ui = DELTA_TOKEN.userInformation(address(this)); require(ui.noVestingWhitelisted, "DFV :: Set no vesting whitelist!"); require(ui.fullSenderWhitelisted, "DFV :: Set full sender whitelist!"); require(ui.immatureReceiverWhitelisted, "DFV :: Set immature whitelist!"); } function refreshApprovals() public { DELTA_TOKEN.approve(deepFarmingVault, uint(-1)); IERC20(WETH).approve(deepFarmingVault, uint(-1)); } constructor (address _deltaToken) { DELTA_TOKEN = IDeltaToken(_deltaToken); // we check for a correct config require(PERCENT_SOLD + PERCENT_BURNED + PERCENT_DEV_FUND + PERCENT_DEEP_FARMING_VAULT == 100, "Amounts not proper"); require(PERCENT_OF_SOLD_DEV + PERCENT_OF_SOLD_CORE_BUY + PERCENT_OF_SOLD_DELTA_WETH_DEEP_FARMING_VAULT == 100 , "Amount of weth split not proper"); // calculate pair DELTA_WETH_PAIR_UNISWAP = address(uint(keccak256(abi.encodePacked( hex'ff', 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f, // Mainned uniswap factory keccak256(abi.encodePacked(_deltaToken, WETH)), hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f' // init code hash )))); } function getWETHForDeltaAndDistribute(uint256 amountToSellFullUnits, uint256 minAmountWETHForSellingDELTA, uint256 minAmountCOREUnitsPer1WETH) public { require(isApprovedLiquidator[msg.sender] == true, "!approved liquidator"); distribute(); // we call distribute to get rid of all coins that are not supposed to be sold distributeAndBurn(); // We swap and make sure we can get enough out // require(address(this) < wethAddress, "Invalid Token Address"); in DELTA token constructor IUniswapV2Pair pairDELTA = IUniswapV2Pair(DELTA_WETH_PAIR_UNISWAP); (uint256 reservesDELTA, uint256 reservesWETHinDELTA, ) = pairDELTA.getReserves(); uint256 deltaUnitsToSell = amountToSellFullUnits * 1 ether; uint256 balanceDelta = DELTA_TOKEN.balanceOf(address(this)); require(balanceDelta >= deltaUnitsToSell, "Amount is greater than reserves"); uint256 amountETHOut = getAmountOut(deltaUnitsToSell, reservesDELTA, reservesWETHinDELTA); require(amountETHOut >= minAmountWETHForSellingDELTA * 1 ether, "Did not get enough ETH to cover min"); // We swap for eth DELTA_TOKEN.transfer(DELTA_WETH_PAIR_UNISWAP, deltaUnitsToSell); pairDELTA.swap(0, amountETHOut, address(this), ""); address dfv = deepFarmingVault; // We transfer the splits of WETH IERC20 weth = IERC20(WETH); weth.transfer(DELTA_MULTISIG, amountETHOut.div(2)); IDeepFarmingVault(dfv).addNewRewards(0, amountETHOut.div(4)); /// Transfer here doesnt matter cause its taken from reserves and this does nto update weth.transfer(CORE_WETH_PAIR, amountETHOut.div(4)); // We swap WETH for CORE and send it to the vault and update the pending inside the vault IUniswapV2Pair pairCORE = IUniswapV2Pair(CORE_WETH_PAIR); (uint256 reservesCORE, uint256 reservesWETHCORE, ) = pairCORE.getReserves(); // function getAmountOut(uint256 amountIn, uint256 reserveIn, uint256 reserveOut) internal pure returns (uint256 amountOut) { uint256 coreOut = getAmountOut(amountETHOut.div(4), reservesWETHCORE, reservesCORE); uint256 coreOut1WETH = getAmountOut(1 ether, reservesWETHCORE, reservesCORE); require(coreOut1WETH >= minAmountCOREUnitsPer1WETH, "Did not get enough CORE check amountCOREUnitsBoughtFor1WETH() fn"); pairCORE.swap(coreOut, 0, CORE_VAULT, ""); // uint passed is deprecated ICORE_VAULT(CORE_VAULT).addPendingRewards(0); pendingTotal = pendingTotal.sub(deltaUnitsToSell); // we adjust the reserves // since we might had nto swapped everything } function editApprovedLiquidator(address liquidator, bool isLiquidator) public { onlyMultisig(); isApprovedLiquidator[liquidator] = isLiquidator; } function deltaGovernance() public view returns (address) { if(address(DELTA_TOKEN) == address(0)) {return address (0); } return DELTA_TOKEN.governance(); } function onlyMultisig() private view { require(msg.sender == deltaGovernance(), "!governance"); } function amountCOREUnitsBoughtFor1WETH() public view returns(uint256) { IUniswapV2Pair pair = IUniswapV2Pair(CORE_WETH_PAIR); // CORE is token0 (uint256 reservesCORE, uint256 reservesWETH, ) = pair.getReserves(); return getAmountOut(1 ether, reservesWETH, reservesCORE); } function getAmountOut(uint256 amountIn, uint256 reserveIn, uint256 reserveOut) internal pure returns (uint256 amountOut) { require(amountIn > 0, 'UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT'); require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY'); uint amountInWithFee = amountIn.mul(997); uint numerator = amountInWithFee.mul(reserveOut); uint denominator = reserveIn.mul(1000).add(amountInWithFee); amountOut = numerator / denominator; } function rescueTokens(address token) public { onlyMultisig(); IERC20(token).transfer(msg.sender, IERC20(token).balanceOf(address(this))); } // Allows users to claim free credit function claimCredit() public { uint256 pending = pendingCredits[msg.sender]; require(pending > 0, "Nothing to claim"); pendingCredits[msg.sender] = 0; IDeepFarmingVault(deepFarmingVault).addPermanentCredits(msg.sender, pending); } /// Credits user for burning tokens // Can only be called by the delta token // Note this is a inherently trusted function that does not do balance checks. function creditUser(address user, uint256 amount) public { require(msg.sender == address(DELTA_TOKEN), "KNOCK KNOCK"); pendingCredits[user] = pendingCredits[user].add(amount.mul(PERCENT_BURNED).div(100)); // we add the burned amount to perma credit } function addDevested(address user, uint256 amount) public { require(DELTA_TOKEN.transferFrom(msg.sender, address(this), amount), "Did not transfer enough"); pendingCredits[user] = pendingCredits[user].add(amount.mul(PERCENT_BURNED).div(100)); // we add the burned amount to perma credit } }// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } } 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; } // SPDX-License-Identifier: UNLICENSED pragma experimental ABIEncoderV2; pragma solidity ^0.7.6; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../common/OVLTokenTypes.sol"; interface IDeltaToken is IERC20 { function vestingTransactions(address, uint256) external view returns (VestingTransaction memory); function getUserInfo(address) external view returns (UserInformationLite memory); function getMatureBalance(address, uint256) external view returns (uint256); function liquidityRebasingPermitted() external view returns (bool); function lpTokensInPair() external view returns (uint256); function governance() external view returns (address); function performLiquidityRebasing() external; function distributor() external view returns (address); function totalsForWallet(address ) external view returns (WalletTotals memory totals); function adjustBalanceOfNoVestingAccount(address, uint256,bool) external; function userInformation(address user) external view returns (UserInformation memory); }pragma abicoder v2; struct RecycleInfo { uint256 booster; uint256 farmedDelta; uint256 farmedETH; uint256 recycledDelta; uint256 recycledETH; } interface IDeepFarmingVault { function addPermanentCredits(address,uint256) external; function addNewRewards(uint256 amountDELTA, uint256 amountWETH) external; function adminRescueTokens(address token, uint256 amount) external; function setCompundBurn(bool shouldBurn) external; function compound(address person) external; function exit() external; function withdrawRLP(uint256 amount) external; function realFarmedOfPerson(address person) external view returns (RecycleInfo memory); function deposit(uint256 numberRLP, uint256 numberDELTA) external; function depositFor(address person, uint256 numberRLP, uint256 numberDELTA) external; function depositWithBurn(uint256 numberDELTA) external; function depositForWithBurn(address person, uint256 numberDELTA) external; } // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // SPDX-License-Identifier: UNLICENSED // DELTA-BUG-BOUNTY pragma solidity ^0.7.6; struct VestingTransaction { uint256 amount; uint256 fullVestingTimestamp; } struct WalletTotals { uint256 mature; uint256 immature; uint256 total; } struct UserInformation { // This is going to be read from only [0] uint256 mostMatureTxIndex; uint256 lastInTxIndex; uint256 maturedBalance; uint256 maxBalance; bool fullSenderWhitelisted; // Note that recieving immature balances doesnt mean they recieve them fully vested just that senders can do it bool immatureReceiverWhitelisted; bool noVestingWhitelisted; } struct UserInformationLite { uint256 maturedBalance; uint256 maxBalance; uint256 mostMatureTxIndex; uint256 lastInTxIndex; } struct VestingTransactionDetailed { uint256 amount; uint256 fullVestingTimestamp; // uint256 percentVestedE4; uint256 mature; uint256 immature; } uint256 constant QTY_EPOCHS = 7; uint256 constant SECONDS_PER_EPOCH = 172800; // About 2days uint256 constant FULL_EPOCH_TIME = SECONDS_PER_EPOCH * QTY_EPOCHS; // Precision Multiplier -- this many zeros (23) seems to get all the precision needed for all 18 decimals to be only off by a max of 1 unit uint256 constant PM = 1e23;
File 7 of 8: OVLLPRebasingBalanceHandler
// DELTA-BUG-BOUNTY pragma abicoder v2; pragma solidity ^0.7.6; import "../../../../interfaces/IDeltaToken.sol"; import "../../../../interfaces/IOVLBalanceHandler.sol"; import "../../../../common/OVLTokenTypes.sol"; contract OVLLPRebasingBalanceHandler is IOVLBalanceHandler { IDeltaToken private immutable DELTA_TOKEN; constructor() { DELTA_TOKEN = IDeltaToken(msg.sender); } function handleBalanceCalculations(address account, address) external view override returns (uint256) { UserInformationLite memory ui = DELTA_TOKEN.getUserInfo(account); return ui.maxBalance; } }// SPDX-License-Identifier: UNLICENSED pragma experimental ABIEncoderV2; pragma solidity ^0.7.6; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../common/OVLTokenTypes.sol"; interface IDeltaToken is IERC20 { function vestingTransactions(address, uint256) external view returns (VestingTransaction memory); function getUserInfo(address) external view returns (UserInformationLite memory); function getMatureBalance(address, uint256) external view returns (uint256); function liquidityRebasingPermitted() external view returns (bool); function lpTokensInPair() external view returns (uint256); function governance() external view returns (address); function performLiquidityRebasing() external; function distributor() external view returns (address); function totalsForWallet(address ) external view returns (WalletTotals memory totals); function adjustBalanceOfNoVestingAccount(address, uint256,bool) external; function userInformation(address user) external view returns (UserInformation memory); }pragma experimental ABIEncoderV2; pragma solidity ^0.7.6; interface IOVLBalanceHandler { function handleBalanceCalculations(address, address) external view returns (uint256); }// SPDX-License-Identifier: UNLICENSED // DELTA-BUG-BOUNTY pragma solidity ^0.7.6; struct VestingTransaction { uint256 amount; uint256 fullVestingTimestamp; } struct WalletTotals { uint256 mature; uint256 immature; uint256 total; } struct UserInformation { // This is going to be read from only [0] uint256 mostMatureTxIndex; uint256 lastInTxIndex; uint256 maturedBalance; uint256 maxBalance; bool fullSenderWhitelisted; // Note that recieving immature balances doesnt mean they recieve them fully vested just that senders can do it bool immatureReceiverWhitelisted; bool noVestingWhitelisted; } struct UserInformationLite { uint256 maturedBalance; uint256 maxBalance; uint256 mostMatureTxIndex; uint256 lastInTxIndex; } struct VestingTransactionDetailed { uint256 amount; uint256 fullVestingTimestamp; // uint256 percentVestedE4; uint256 mature; uint256 immature; } uint256 constant QTY_EPOCHS = 7; uint256 constant SECONDS_PER_EPOCH = 172800; // About 2days uint256 constant FULL_EPOCH_TIME = SECONDS_PER_EPOCH * QTY_EPOCHS; // Precision Multiplier -- this many zeros (23) seems to get all the precision needed for all 18 decimals to be only off by a max of 1 unit uint256 constant PM = 1e23; // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
File 8 of 8: DELTA_Rebasing_Liquidity_Token
import "../../interfaces/IWETH.sol"; import "../../interfaces/IDeltaToken.sol"; import "../../interfaces/IRebasingLiquidityToken.sol"; import '../uniswapv2/libraries/UniswapV2Library.sol'; import '../Upgradability/token/ERC20/ERC20Upgradeable.sol'; interface IRESERVE_VAULT { function flashBorrowEverything() external; } interface IDELTA_LSW { function totalWETHEarmarkedForReferrers() external view returns (uint256); } contract DELTA_Rebasing_Liquidity_Token is IRebasingLiquidityToken, ERC20Upgradeable { using SafeMathUpgradeable for uint256; struct AddressCache { address deltaxWethPairAddress; IDeltaToken deltaToken; IUniswapV2Pair deltaxWethPair; } uint256 public override rlpPerLP; uint256 public _dailyVolumeTargetETH; uint256 private lastTargetUpdate; uint256 public ethVolumeRemaining; //immutables and contstancts IUniswapV2Pair public immutable DELTA_WETH_PAIR; IDeltaToken public immutable DELTA; address constant internal DEAD_BEEF = 0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF; address public constant LSW = 0xdaFCE5670d3F67da9A3A44FE6bc36992e5E2beaB; address public immutable RESERVE_VAULT; IWETH public constant WETH = IWETH(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); uint256 constant public _DAILY_PERCENTAGE_COST_INCREASE_TO_MINT_LP = 10; function initialize() public virtual initializer { __ERC20_init("Rebasing Liquidity Token - DELTA.financial", "DELTA rLP"); // Name, symbol // Initially set it to 1LP = 1RLP rlpPerLP = 1 ether; } // Rebasing LP is created before DELTA TOKEN is. constructor (address delta, address _reserveVault ) { //LSW call points RESERVE_VAULT = _reserveVault; DELTA = IDeltaToken(delta); DELTA_WETH_PAIR = IUniswapV2Pair(address(uint(keccak256(abi.encodePacked( hex'ff', 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f, // Mainnet uniswap factory keccak256(abi.encodePacked(delta, address(WETH))), hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f' // init code hash ))))); } function onlyLSW() public view { require(msg.sender == LSW, "!LSW GO AWAY"); } // Do not remove this as this is called from the LSW function setBaseLPToken(address) public { onlyLSW(); this; // sincence warnings } // @notice wraps all LP tokens of the caller, requires allowance // @dev intent of this function is to get the balance of the caller, and wrap his entire balance, update the basetoken supply, and issue the caller amount of tokens that we transfered from him function wrap() public override { _performWrap(); // This doesn't return because LSW doesn't expect a return value and we can't adjust it now. } function wrapWithReturn() external override returns (uint256) { return _performWrap(); } function _performWrap() internal returns (uint256) { uint256 balanceCaller = DELTA_WETH_PAIR.balanceOf(msg.sender); require(balanceCaller > 0, "No tokens to wrap"); // @dev from caller , to here , amount total of caller bool success = DELTA_WETH_PAIR.transferFrom(msg.sender, address(this), balanceCaller); require(success, "Transfer Failure"); uint256 garnishedBalance = balanceCaller.mul(rlpPerLP).div(1e18); _mint(msg.sender, garnishedBalance); return garnishedBalance; } function rebase() public { require(msg.sender == tx.origin, "Smart wallets cannot call this function"); uint256 deltaBalance = DELTA.balanceOf(address(this)); if(deltaBalance > 0) { // remove if we have DELTA in here for some reason DELTA.transfer(RESERVE_VAULT, deltaBalance); } // Collect pre-rebasing stats (uint256 preVolumeDELTAReserve, uint256 preVolumeWETHReserve,) = DELTA_WETH_PAIR.getReserves(); uint256 preVolumeLPSupply = DELTA_WETH_PAIR.totalSupply(); uint256 preVolumeLPBalance = DELTA_WETH_PAIR.balanceOf(address(this)); // Have the delta token allow for burning of LP, temporarily. // This will call tokenCaller and them proceed to call reserveCaller and to numberLoops of max transfers // And re-add LP tokens payback loan... hence we wrap this in few safety checks DELTA.performLiquidityRebasing(); // calls >tokenCaller >reserveCaller on this contract in order // Collect post-rebasing stats (uint256 postVolumeDELTAReserve, uint256 postVolumeWETHReserve,) = DELTA_WETH_PAIR.getReserves(); uint256 postVolumeLPSupply = DELTA_WETH_PAIR.totalSupply(); uint256 postVolumeLPBalance = DELTA_WETH_PAIR.balanceOf(address(this)); // All my homies hate division // WHERE IS MY FUCKING MONEY? require(postVolumeDELTAReserve == preVolumeDELTAReserve, "Delta reserve has changed"); require(preVolumeWETHReserve + 10 > postVolumeWETHReserve && postVolumeWETHReserve >= preVolumeWETHReserve , "WETH reserve out of bounds"); require(preVolumeLPBalance + 1e4 >= postVolumeLPBalance && postVolumeLPBalance + 1e5 > preVolumeLPBalance , "LP balance change not within bounds"); require(preVolumeLPSupply + 1e4 >= postVolumeLPSupply && postVolumeLPSupply + 1e5 > preVolumeLPSupply, "LP Supply change not within bounds"); } // Delta token calls this after performLiquidityRebasing is in the middle of execution on the token contract function tokenCaller() override public { require(msg.sender == address(DELTA)); IRESERVE_VAULT(RESERVE_VAULT).flashBorrowEverything(); } function volumeGeneratingTrades( IDeltaToken _delta, IUniswapV2Pair _pair, uint256 ethTradeVolumeNeededToHitTarget) internal returns (uint256 newVolumeETHRemaining) { uint256 balanceWETH = WETH.balanceOf(address(this)); (uint256 unsiwapReserveDelta, uint256 uniswapReserveWETH, ) = _pair.getReserves(); uint256 amount0In = unsiwapReserveDelta.mul(1e12).div(uniswapReserveWETH).mul(balanceWETH).div(1e12); // Amount DELTA to send every transfer to get balanceWETH if there was no fee uint256 amount0Out = amount0In * 10000/10161; // 0.6% slippage + ineffciencies; address addressPair = address(_pair); uint256 loops; while(ethTradeVolumeNeededToHitTarget > balanceWETH && loops < 50) { WETH.transfer(addressPair, balanceWETH); _delta.adjustBalanceOfNoVestingAccount(addressPair, amount0In, true); // Add the amountIn back uniswap treats it like a transfer and we dont have to guarantee that we have that delta // DELTA + WETH for DELTA * 0.994 + WETH // Quadruple WETH in volume _pair.swap(amount0Out, balanceWETH, address(this), ""); _delta.adjustBalanceOfNoVestingAccount(addressPair, unsiwapReserveDelta, false); // Adjust back to reserves ( would have higher else and print dragonflies) _pair.sync(); // Force reserves to show that // Note that WETH balance will not change if(balanceWETH > ethTradeVolumeNeededToHitTarget) { newVolumeETHRemaining = 0; break; } else { ethTradeVolumeNeededToHitTarget -= balanceWETH; loops++; } } // This can be non 0 if we are over 50 loops which is straining this algorithm newVolumeETHRemaining = ethTradeVolumeNeededToHitTarget; } function setUpDailyVolumeTarget(uint256 ethWholeUnits, bool hourlyRebaseRightAway) public { onlyMultisig(); _dailyVolumeTargetETH = ethWholeUnits * 1 ether; lastTargetUpdate = hourlyRebaseRightAway ? block.timestamp - 1 hours : block.timestamp; // can rebase right away rebase } function getRemainingETHInVolumeTarget() public view returns (uint256 remainingVolumeInETH, uint256 secondsSinceLastUpdate) { secondsSinceLastUpdate = (block.timestamp - lastTargetUpdate); uint256 hoursSinceLastUpdate = secondsSinceLastUpdate / 1 hours; remainingVolumeInETH = (_dailyVolumeTargetETH / 24).mul(hoursSinceLastUpdate).add(ethVolumeRemaining); // We dont allow partial hours to not have too much volume from calls } function updateRemainingETH() private returns (uint256) { (uint256 remainingVolumeInETH, uint256 secondsSinceLastUpdate) = getRemainingETHInVolumeTarget(); lastTargetUpdate = block.timestamp - (secondsSinceLastUpdate % 1 hours); // we carry over the rest of 1hour return remainingVolumeInETH; } function reduceLpRatio(uint256 percentReductionE12) private { uint256 ratio = rlpPerLP; rlpPerLP = ratio.sub( ratio.mul(percentReductionE12).div(1e14) ); } // The delta reserve calls this during execution in order to complete flash borrowing function reserveCaller(uint256 borrowedDELTA, uint256 borrowedWETH) public override { // Reserve vault calls this contract with the amount of DELTA and WETH it borrowed to us. // 1) We find a optimal DELTA to add with all the WETH to get LP tokens // 2) We burn half of all LP tokens we have ( the newly minted + ones in this contract) // Only half can be traded at a time because of uniswap reserve requirements // 3) We do loop of DELTA and WETH trades for DELTA and WETH. With every time removing 0.6% of delta we expect to pay the fee (0.3*2) // 4) We sell DELTA to get WETH // 5) We keep changing the uniswap balance and adding more and more liquidity in a loop until we have enough to cover what we had before // trading loses us lp tokens, because the ones remaining in the pool concentrate fees // 6) We adjust the uniswap balance to thee previos state in order to avoid price changing // 7) We repay the loan // 8) We adjust the uniswap DELTA reciever ratio, in order to make LP tokens more to mint // We have to take into account the totalSupply change in LP tokens require(msg.sender == RESERVE_VAULT); // We update the target timestamp and consume all remaining ETH that was unspent. uint256 ethTradeVolumeNeededToHitTarget = updateRemainingETH(); require(ethTradeVolumeNeededToHitTarget > 0, "Can't generate volume, wait until a full hour still last targetUpdate is up"); uint256 balanceLPBeforeMintingAndRebasing = DELTA_WETH_PAIR.balanceOf(address(this)); // We got a loan from reserve vault // We have to figure out how to utilize it (uint256 unsiwapReserveDelta, uint256 uniswapReserveWETH,) = DELTA_WETH_PAIR.getReserves(); // If we borrowed WETH, we mint if(borrowedWETH > 0) { uint256 balanceWETHWithLoan = WETH.balanceOf(address(this)); uint256 optimalDELTAToMatchAllWETH = UniswapV2Library.quote(balanceWETHWithLoan, uniswapReserveWETH, unsiwapReserveDelta); // Send everything to add liquidity DELTA.adjustBalanceOfNoVestingAccount(address(DELTA_WETH_PAIR), optimalDELTAToMatchAllWETH, true); WETH.transfer(address(DELTA_WETH_PAIR), balanceWETHWithLoan); DELTA_WETH_PAIR.mint(address(this)); } // We remove half of the liquidity // Note that half is the max because you cant get out more than reserves // Half is when we have all teh lp tokens DELTA_WETH_PAIR.transfer(address(DELTA_WETH_PAIR), DELTA_WETH_PAIR.balanceOf(address(this)) / 2); DELTA_WETH_PAIR.burn(address(this)); // Perform volume trades, and reduce LP ratio based on the volume that gets filled successfully { // scope for unfilledEthVolumeRemaining, newRatio uint256 unfilledEthVolumeRemaining = volumeGeneratingTrades(DELTA, DELTA_WETH_PAIR, ethTradeVolumeNeededToHitTarget); uint256 volumeFulfilled = ethTradeVolumeNeededToHitTarget.sub(unfilledEthVolumeRemaining); uint256 lpRatioPercentReductionE12 = volumeFulfilled.mul(1e12).div(_dailyVolumeTargetETH).mul(_DAILY_PERCENTAGE_COST_INCREASE_TO_MINT_LP); // Adjust the ratio by the remianing eth to trade // If its 10% a day this should return 10/24 for every hour of volume = 0.41 * 1e12 = 410000000000; reduceLpRatio(lpRatioPercentReductionE12); ethVolumeRemaining = unfilledEthVolumeRemaining; } // At this point we have either too much or too little LP tokens // Since we borrowed we might have too much // Or we might have too little depending on when borrowed is less adding it than we already have // We branch the logic dependent on it uint256 balanceLPNow = DELTA_WETH_PAIR.balanceOf(address(this)); if(balanceLPNow > balanceLPBeforeMintingAndRebasing) { // We have more or exactly the balance we had before // We burn the difference uint256 difference = balanceLPNow - balanceLPBeforeMintingAndRebasing; DELTA_WETH_PAIR.transfer(address(DELTA_WETH_PAIR), difference); DELTA_WETH_PAIR.burn(address(this)); DELTA.adjustBalanceOfNoVestingAccount(address(DELTA_WETH_PAIR), unsiwapReserveDelta, false); } else { // Since we dont let accumulation to happen in the tokens vy adjusting balances directly // we can safely assume we just need to give back the WETH and DELTA back to previous levels to get LP tokens we need // This assumpion is changed in a function wrapping this one (, uint256 currentUniswapReserveWETH,) = DELTA_WETH_PAIR.getReserves(); // Reserve has too little WETH // We need to send the difference // Note this is also the case when we have less LP tokens than we should // Fees have not accumulated in the remaining supply of tokens as the reserves did not change uint256 ethNeeded = uniswapReserveWETH.sub(currentUniswapReserveWETH); if(ethNeeded > 0) { WETH.transfer(address(DELTA_WETH_PAIR), ethNeeded); DELTA.adjustBalanceOfNoVestingAccount(address(DELTA_WETH_PAIR), unsiwapReserveDelta, false); DELTA_WETH_PAIR.mint(address(this)); } // Reserves now have as much DELTA and WETH as they should. } if(borrowedWETH > 0) { // repay weth loan // note that reserves match up with weth it coudnt have gone anywhere but to us, but this convinently tests that too WETH.transfer(RESERVE_VAULT, WETH.balanceOf(address(this))); // -1 inefficiencies DELTA.adjustBalanceOfNoVestingAccount(RESERVE_VAULT, borrowedDELTA, true); } DELTA_WETH_PAIR.sync(); // We directly set the balance of this address to 0 DELTA.adjustBalanceOfNoVestingAccount(address(this), 0, false); } /// @notice opens the first rebasing function openRebasing() public { onlyLSW(); require(rlpPerLP == 1e18, "Contract not initialized"); // we check how much LP we have // This call only happens once so we can assume a lot here uint256 totalETHInLSW = (1500 ether + WETH.balanceOf(RESERVE_VAULT) + IDELTA_LSW(LSW).totalWETHEarmarkedForReferrers()) * 2; uint256 totalInPairRatioE12 = uint256(1500 ether).mul(1e12).div(totalETHInLSW); rlpPerLP = totalInPairRatioE12.mul(1e6); // 18 - 12 //One LP equal RLP 86606638913000000 (0.0866066389130000) } function onlyMultisig() private view { require(msg.sender == DELTA.governance(), "!governance"); } } pragma solidity >=0.6.0 <0.8.0; interface IWETH { function deposit() external payable; function transfer(address to, uint value) external returns (bool); function withdraw(uint) external; function balanceOf(address) external view returns (uint256); }// SPDX-License-Identifier: UNLICENSED pragma experimental ABIEncoderV2; pragma solidity ^0.7.6; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../common/OVLTokenTypes.sol"; interface IDeltaToken is IERC20 { function vestingTransactions(address, uint256) external view returns (VestingTransaction memory); function getUserInfo(address) external view returns (UserInformationLite memory); function getMatureBalance(address, uint256) external view returns (uint256); function liquidityRebasingPermitted() external view returns (bool); function lpTokensInPair() external view returns (uint256); function governance() external view returns (address); function performLiquidityRebasing() external; function distributor() external view returns (address); function totalsForWallet(address ) external view returns (WalletTotals memory totals); function adjustBalanceOfNoVestingAccount(address, uint256,bool) external; function userInformation(address user) external view returns (UserInformation memory); }pragma experimental ABIEncoderV2; pragma solidity ^0.7.6; import "./IERC20Upgradeable.sol"; interface IRebasingLiquidityToken is IERC20Upgradeable { function tokenCaller() external; function reserveCaller(uint256,uint256) external; function wrapWithReturn() external returns (uint256); function wrap() external; function rlpPerLP() external view returns (uint256); }pragma solidity ^0.7.6; import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol'; import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol'; import "./SafeMath.sol"; library UniswapV2Library { using SafeMathUniswap for uint; // returns sorted token addresses, used to handle return values from pairs sorted in this order function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) { require(tokenA != tokenB, 'UniswapV2Library: IDENTICAL_ADDRESSES'); (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); require(token0 != address(0), 'UniswapV2Library: ZERO_ADDRESS'); } // calculates the CREATE2 address for a pair without making any external calls function pairFor(address factory, address tokenA, address tokenB) internal pure returns (address pair) { (address token0, address token1) = sortTokens(tokenA, tokenB); pair = address(uint(keccak256(abi.encodePacked( hex'ff', factory, keccak256(abi.encodePacked(token0, token1)), hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f' // init code hash )))); } // fetches and sorts the reserves for a pair function getReserves(address factory, address tokenA, address tokenB) internal view returns (uint reserveA, uint reserveB) { (address token0,) = sortTokens(tokenA, tokenB); (uint reserve0, uint reserve1,) = IUniswapV2Pair(IUniswapV2Factory(factory).getPair(tokenA, tokenB)).getReserves(); (reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0); } // given some amount of an asset and pair reserves, returns an equivalent amount of the other asset function quote(uint amountA, uint reserveA, uint reserveB) internal pure returns (uint amountB) { require(amountA > 0, 'UniswapV2Library: INSUFFICIENT_AMOUNT'); require(reserveA > 0 && reserveB > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY'); amountB = amountA.mul(reserveB) / reserveA; } // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) { require(amountIn > 0, 'UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT'); require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY'); uint amountInWithFee = amountIn.mul(997); uint numerator = amountInWithFee.mul(reserveOut); uint denominator = reserveIn.mul(1000).add(amountInWithFee); amountOut = numerator / denominator; } // given an output amount of an asset and pair reserves, returns a required input amount of the other asset function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) internal pure returns (uint amountIn) { require(amountOut > 0, 'UniswapV2Library: INSUFFICIENT_OUTPUT_AMOUNT'); require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY'); uint numerator = reserveIn.mul(amountOut).mul(1000); uint denominator = reserveOut.sub(amountOut).mul(997); amountIn = (numerator / denominator).add(1); } // performs chained getAmountOut calculations on any number of pairs function getAmountsOut(address factory, uint amountIn, address[] memory path) internal view returns (uint[] memory amounts) { require(path.length >= 2, 'UniswapV2Library: INVALID_PATH'); amounts = new uint[](path.length); amounts[0] = amountIn; for (uint i; i < path.length - 1; i++) { (uint reserveIn, uint reserveOut) = getReserves(factory, path[i], path[i + 1]); amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut); } } // performs chained getAmountIn calculations on any number of pairs function getAmountsIn(address factory, uint amountOut, address[] memory path) internal view returns (uint[] memory amounts) { require(path.length >= 2, 'UniswapV2Library: INVALID_PATH'); amounts = new uint[](path.length); amounts[amounts.length - 1] = amountOut; for (uint i = path.length - 1; i > 0; i--) { (uint reserveIn, uint reserveOut) = getReserves(factory, path[i - 1], path[i]); amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut); } } }// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; import "../../utils/ContextUpgradeable.sol"; import "../../../../interfaces/IERC20Upgradeable.sol"; import "../../math/SafeMathUpgradeable.sol"; import "../../proxy/Initializable.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable { using SafeMathUpgradeable for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for {name} and {symbol}, initializes {decimals} with * a default value of 18. * * To select a different value for {decimals}, use {_setupDecimals}. * * All three of these values are immutable: they can only be set once during * construction. */ function __ERC20_init(string memory name_, string memory symbol_) internal initializer { __Context_init_unchained(); __ERC20_init_unchained(name_, symbol_); } function __ERC20_init_unchained(string memory name_, string memory symbol_) internal initializer { _name = name_; _symbol = symbol_; _decimals = 18; } /** * @dev Returns the name of the token. */ function name() public view virtual returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual returns (uint8) { return _decimals; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * Requirements: * * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * 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"); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Sets {decimals} to a value other than the default one of 18. * * WARNING: This function should only be called from the constructor. Most * applications that interact with token contracts will not expect * {decimals} to ever change, and may work incorrectly if it does. */ function _setupDecimals(uint8 decimals_) internal virtual { _decimals = decimals_; } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be to transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } uint256[44] private __gap; }// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // SPDX-License-Identifier: UNLICENSED // DELTA-BUG-BOUNTY pragma solidity ^0.7.6; struct VestingTransaction { uint256 amount; uint256 fullVestingTimestamp; } struct WalletTotals { uint256 mature; uint256 immature; uint256 total; } struct UserInformation { // This is going to be read from only [0] uint256 mostMatureTxIndex; uint256 lastInTxIndex; uint256 maturedBalance; uint256 maxBalance; bool fullSenderWhitelisted; // Note that recieving immature balances doesnt mean they recieve them fully vested just that senders can do it bool immatureReceiverWhitelisted; bool noVestingWhitelisted; } struct UserInformationLite { uint256 maturedBalance; uint256 maxBalance; uint256 mostMatureTxIndex; uint256 lastInTxIndex; } struct VestingTransactionDetailed { uint256 amount; uint256 fullVestingTimestamp; // uint256 percentVestedE4; uint256 mature; uint256 immature; } uint256 constant QTY_EPOCHS = 7; uint256 constant SECONDS_PER_EPOCH = 172800; // About 2days uint256 constant FULL_EPOCH_TIME = SECONDS_PER_EPOCH * QTY_EPOCHS; // Precision Multiplier -- this many zeros (23) seems to get all the precision needed for all 18 decimals to be only off by a max of 1 unit uint256 constant PM = 1e23; // SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }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; } 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; } pragma solidity ^0.7.6; // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) library SafeMathUniswap { function add(uint x, uint y) internal pure returns (uint z) { require((z = x + y) >= x, 'ds-math-add-overflow'); } function sub(uint x, uint y) internal pure returns (uint z) { require((z = x - y) <= x, 'ds-math-sub-underflow'); } function mul(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow'); } } // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "../proxy/Initializable.sol"; /* * @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 GSN 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 ContextUpgradeable is Initializable { function __Context_init() internal initializer { __Context_init_unchained(); } function __Context_init_unchained() internal initializer { } function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } uint256[50] private __gap; }// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMathUpgradeable { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } }// SPDX-License-Identifier: MIT // solhint-disable-next-line compiler-version pragma solidity >=0.4.24 <0.8.0; import "../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } /// @dev Returns true if and only if the function is running in the constructor function _isConstructor() private view returns (bool) { return !AddressUpgradeable.isContract(address(this)); } }// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }