Transaction Hash:
Block:
19405357 at Mar-10-2024 02:41:47 PM +UTC
Transaction Fee:
0.008334309883227327 ETH
$20.01
Gas Used:
112,419 Gas / 74.136132533 Gwei
Emitted Events:
226 |
veSYNC.Approval( owner=[Sender] 0x9057cb12392539c553ebe2148627f3d79f310553, spender=[Receiver] SyncusStaking, value=115792089237316195423570985008687907853269984665640564039457583428470674371695 )
|
227 |
veSYNC.Transfer( from=[Sender] 0x9057cb12392539c553ebe2148627f3d79f310553, to=[Receiver] SyncusStaking, value=200442455268240 )
|
228 |
Syncus.Transfer( from=[Receiver] SyncusStaking, to=[Sender] 0x9057cb12392539c553ebe2148627f3d79f310553, value=100221227634120 )
|
229 |
Syncus.Transfer( from=[Receiver] SyncusStaking, to=SyncusTreasury, value=100221227634120 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x216c9bb7...38d7e1Dc8 | |||||
0x4838B106...B0BAD5f97
Miner
| (Titan Builder) | 19.625456117915653278 Eth | 19.625466378094251978 Eth | 0.0000102601785987 | |
0x9057Cb12...79f310553 |
0.045321439542208751 Eth
Nonce: 152
|
0.036987129658981424 Eth
Nonce: 153
| 0.008334309883227327 | ||
0xa41d2f8E...c3287b7F0 |
Execution Trace
SyncusStaking.unstake( _amount=200442455268240, _trigger=True )
-
veSYNC.transferFrom( from=0x9057Cb12392539C553ebE2148627F3D79f310553, to=0xc738CDb5140d6b7F688ba05a25c8a51568622D96, value=200442455268240 ) => ( True )
-
Syncus.transfer( recipient=0x9057Cb12392539C553ebE2148627F3D79f310553, amount=100221227634120 ) => ( True )
-
Syncus.transfer( recipient=0xC00EC94e7746C6b695869580d6D2DB50cda86094, amount=100221227634120 ) => ( True )
unstake[SyncusStaking (ln:138)]
rebase[SyncusStaking (ln:140)]
rebase[SyncusStaking (ln:160)]
add32[SyncusStaking (ln:161)]
distribute[SyncusStaking (ln:164)]
contractBalance[SyncusStaking (ln:166)]
add[SyncusStaking (ln:180)]
balanceOf[SyncusStaking (ln:180)]
circulatingSupply[SyncusStaking (ln:167)]
sub[SyncusStaking (ln:171)]
safeTransferFrom[SyncusStaking (ln:142)]
div[SyncusStaking (ln:143)]
mul[SyncusStaking (ln:143)]
sub[SyncusStaking (ln:144)]
safeTransfer[SyncusStaking (ln:145)]
safeTransfer[SyncusStaking (ln:146)]
File 1 of 4: SyncusStaking
File 2 of 4: veSYNC
File 3 of 4: Syncus
File 4 of 4: SyncusTreasury
// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; import "./lib/SafeMath.sol"; import "./lib/Address.sol"; import "./lib/SafeERC20.sol"; import "./OwnableManagement.sol"; import "./lib/IERC20.sol"; import "./lib/ISyncus.sol"; import "./lib/IVESYNC.sol"; import "./lib/IDistributor.sol"; import "./lib/IWarmup.sol"; contract SyncusStaking is OwnableManagement { using SafeMath for uint256; using SafeMath for uint32; using SafeERC20 for IERC20; address public immutable Sync; address public immutable veSync; struct Epoch { uint number; uint distribute; uint32 length; uint32 endTime; } Epoch public epoch; address public distributor; address public locker; uint public totalBonus; address public warmupContract; uint public warmupPeriod; address taxReceiver; uint public taxOnStake = 250; // 2.5% uint public taxOnUnstake = 250; // 2.5% function setTaxOnStake(uint _taxOnStake) external onlyManager { require(_taxOnStake <= 10000, "Tax cannot be greater than 100%"); taxOnStake = _taxOnStake; } function setTaxOnUnstake(uint _taxOnUnstake) external onlyManager { require(_taxOnUnstake <= 10000, "Tax cannot be greater than 100%"); taxOnUnstake = _taxOnUnstake; } function setTaxReceiver(address _taxReceiver) external onlyManager { taxReceiver = _taxReceiver; } modifier onlyDistributor() { require(msg.sender == distributor, "Only distributor"); _; } constructor( address _Sync, address _veSync, uint32 _epochLength, uint _firstEpochNumber, uint32 _firstEpochTime, address _taxReceiver ) { require(_Sync != address(0)); Sync = _Sync; require(_veSync != address(0)); veSync = _veSync; epoch = Epoch({ length: _epochLength, number: _firstEpochNumber, endTime: _firstEpochTime, distribute: 0 }); taxReceiver = _taxReceiver; } struct Claim { uint deposit; uint gons; uint expiry; bool lock; // prevents malicious delays } mapping(address => Claim) public warmupInfo; /** @notice stake SYNC to enter warmup @param _amount uint @return bool */ function stake(uint _amount, address _recipient) external returns (bool) { rebase(); uint tax = _amount.mul(taxOnStake).div(10000); uint amountAfterTax = _amount.sub(tax); IERC20(Sync).safeTransferFrom( msg.sender, address(this), amountAfterTax ); IERC20(Sync).safeTransferFrom(msg.sender, taxReceiver, tax); Claim memory info = warmupInfo[_recipient]; require(!info.lock, "Deposits for account are locked"); warmupInfo[_recipient] = Claim({ deposit: info.deposit.add(amountAfterTax), gons: info.gons.add(IVESYNC(veSync).gonsForBalance(amountAfterTax)), expiry: epoch.number.add(warmupPeriod), lock: false }); IERC20(veSync).safeTransfer(warmupContract, amountAfterTax); return true; } /** @notice retrieve veSYNC from warmup @param _recipient address */ function claim(address _recipient) public { Claim memory info = warmupInfo[_recipient]; if (epoch.number >= info.expiry && info.expiry != 0) { delete warmupInfo[_recipient]; IWarmup(warmupContract).retrieve( _recipient, IVESYNC(veSync).balanceForGons(info.gons) ); } } /** @notice forfeit veSYNC in warmup and retrieve SYNC */ function forfeit() external { Claim memory info = warmupInfo[msg.sender]; delete warmupInfo[msg.sender]; IWarmup(warmupContract).retrieve( address(this), IVESYNC(veSync).balanceForGons(info.gons) ); IERC20(Sync).safeTransfer(msg.sender, info.deposit); } /** @notice prevent new deposits to address (protection from malicious activity) */ function toggleDepositLock() external { warmupInfo[msg.sender].lock = !warmupInfo[msg.sender].lock; } /** @notice redeem veSYNC for SYNC @param _amount uint @param _trigger bool */ function unstake(uint _amount, bool _trigger) external { if (_trigger) { rebase(); } IERC20(veSync).safeTransferFrom(msg.sender, address(this), _amount); uint tax = _amount.mul(taxOnUnstake).div(10000); uint amountAfterTax = _amount.sub(tax); IERC20(Sync).safeTransfer(msg.sender, amountAfterTax); IERC20(Sync).safeTransfer(taxReceiver, tax); } /** @notice returns the veSYNC index, which tracks rebase growth @return uint */ function index() public view returns (uint) { return IVESYNC(veSync).index(); } /** @notice trigger rebase if epoch over */ function rebase() public { if (epoch.endTime <= uint32(block.timestamp)) { IVESYNC(veSync).rebase(epoch.distribute, epoch.number); epoch.endTime = epoch.endTime.add32(epoch.length); epoch.number++; if (distributor != address(0)) { IDistributor(distributor).distribute(); } uint balance = contractBalance(); uint staked = IVESYNC(veSync).circulatingSupply(); if (balance <= staked) { epoch.distribute = 0; } else { epoch.distribute = balance.sub(staked); } } } /** @notice returns contract SYNC holdings, including bonuses provided @return uint */ function contractBalance() public view returns (uint) { return IERC20(Sync).balanceOf(address(this)).add(totalBonus); } /** @notice provide bonus to locked staking contract @param _amount uint */ function giveLockBonus(uint _amount) external { require(msg.sender == locker); totalBonus = totalBonus.add(_amount); IERC20(veSync).safeTransfer(locker, _amount); } /** @notice reclaim bonus from locked staking contract @param _amount uint */ function returnLockBonus(uint _amount) external { require(msg.sender == locker); totalBonus = totalBonus.sub(_amount); IERC20(veSync).safeTransferFrom(locker, address(this), _amount); } enum CONTRACTS { DISTRIBUTOR, WARMUP, LOCKER } /** @notice sets the contract address for LP staking @param _contract address */ function setContract( CONTRACTS _contract, address _address ) external onlyManager { if (_contract == CONTRACTS.DISTRIBUTOR) { // 0 distributor = _address; } else if (_contract == CONTRACTS.WARMUP) { // 1 require( warmupContract == address(0), "Warmup cannot be set more than once" ); warmupContract = _address; } else if (_contract == CONTRACTS.LOCKER) { // 2 require( locker == address(0), "Locker cannot be set more than once" ); locker = _address; } } /** * @notice set warmup period in epoch's numbers for new stakers * @param _warmupPeriod uint */ function setWarmup(uint _warmupPeriod) external onlyManager { warmupPeriod = _warmupPeriod; } } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; library SafeMath { function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } function add32(uint32 a, uint32 b) internal pure returns (uint32) { uint32 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } function sub( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } function sub32(uint32 a, uint32 b) internal pure returns (uint32) { return sub32(a, b, "SafeMath: subtraction overflow"); } function sub32( uint32 a, uint32 b, string memory errorMessage ) internal pure returns (uint32) { require(b <= a, errorMessage); uint32 c = a - b; return c; } function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } function mul32(uint32 a, uint32 b) internal pure returns (uint32) { if (a == 0) { return 0; } uint32 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } function div( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } function mod( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } function sqrrt(uint256 a) internal pure returns (uint c) { if (a > 3) { c = a; uint b = add(div(a, 2), 1); while (b < c) { c = b; b = div(add(div(a, b), b), 2); } } else if (a != 0) { c = 1; } } function percentageAmount( uint256 total_, uint8 percentage_ ) internal pure returns (uint256 percentAmount_) { return div(mul(total_, percentage_), 1000); } function substractPercentage( uint256 total_, uint8 percentageToSub_ ) internal pure returns (uint256 result_) { return sub(total_, div(mul(total_, percentageToSub_), 1000)); } function percentageOfTotal( uint256 part_, uint256 total_ ) internal pure returns (uint256 percent_) { return div(mul(part_, 100), total_); } function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow, so we distribute return (a / 2) + (b / 2) + (((a % 2) + (b % 2)) / 2); } function quadraticPricing( uint256 payment_, uint256 multiplier_ ) internal pure returns (uint256) { return sqrrt(mul(multiplier_, payment_)); } function bondingCurve( uint256 supply_, uint256 multiplier_ ) internal pure returns (uint256) { return mul(multiplier_, supply_); } } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; 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 in 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} */ 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). * * 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); } function _functionCallWithValue( address target, bytes memory data, uint256 weiValue, string memory errorMessage ) private returns (bytes memory) { require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{value: weiValue}( data ); 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); } } } /** * @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.3._ */ 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.3._ */ 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); } } } function addressToString( address _address ) internal pure returns (string memory) { bytes32 _bytes = bytes32(uint256(_address)); bytes memory HEX = "0123456789abcdef"; bytes memory _addr = new bytes(42); _addr[0] = "0"; _addr[1] = "x"; for (uint256 i = 0; i < 20; i++) { _addr[2 + i * 2] = HEX[uint8(_bytes[i + 12] >> 4)]; _addr[3 + i * 2] = HEX[uint8(_bytes[i + 12] & 0x0f)]; } return string(_addr); } } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; import "./SafeMath.sol"; import "./Address.sol"; import "./IERC20.sol"; library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. // A Solidity high level call has three parts: // 1. The target address is checked to verify it contains contract code // 2. The call itself is made, and success asserted // 3. The return value is decoded, which in turn checks the size of the returned data. // solhint-disable-next-line max-line-length require(address(token).isContract(), "SafeERC20: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = address(token).call(data); require(success, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; import "./lib/IOwnableManagement.sol"; contract OwnableManagement is IOwnableManagement { address internal _owner; address internal _newOwner; event OwnershipPushed(address indexed previousOwner, address indexed newOwner); event OwnershipPulled(address indexed previousOwner, address indexed newOwner); constructor () { _owner = msg.sender; emit OwnershipPushed( address(0), _owner ); } function manager() public view override returns (address) { return _owner; } modifier onlyManager() { require( _owner == msg.sender, "Ownable: caller is not the owner" ); _; } function renounceManagement() public virtual override onlyManager() { emit OwnershipPushed( _owner, address(0) ); _owner = address(0); } function pushManagement( address newOwner_ ) public virtual override onlyManager() { require( newOwner_ != address(0), "Ownable: new owner is the zero address"); emit OwnershipPushed( _owner, newOwner_ ); _newOwner = newOwner_; } function pullManagement() public virtual override { require( msg.sender == _newOwner, "Ownable: must be new owner to pull"); emit OwnershipPulled( _owner, _newOwner ); _owner = _newOwner; } }// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; interface IERC20 { function decimals() external view returns (uint8); /** * @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: AGPL-3.0-or-later pragma solidity 0.7.5; interface ISyncus { function burn(uint256 amount) external; function burnFrom(address account_, uint256 amount_) external; } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; interface IVESYNC { function rebase( uint256 ohmProfit_, uint epoch_) external returns (uint256); function circulatingSupply() external view returns (uint256); function balanceOf(address who) external view returns (uint256); function gonsForBalance( uint amount ) external view returns ( uint ); function balanceForGons( uint gons ) external view returns ( uint ); function index() external view returns ( uint ); }// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; interface IDistributor { function nextRewardAt(uint _rate) external view returns (uint); function nextRewardFor(address _recipient) external view returns (uint); function distribute() external returns (bool); function addRecipient(address _recipient, uint _rewardRate) external; function removeRecipient(uint _index, address _recipient) external; function setAdjustment( uint _index, bool _add, uint _rate, uint _target ) external; function updateCurrentRate(uint _index, uint _rate) external; } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; interface IWarmup { function retrieve( address staker_, uint amount_ ) external; }// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; interface IOwnableManagement { function manager() external view returns (address); function renounceManagement() external; function pushManagement(address newOwner_) external; function pullManagement() external; }
File 2 of 4: veSYNC
// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; import "./ERC20Permit.sol"; import "./lib/IOwnable.sol"; import "./OwnableManagement.sol"; contract veSYNC is ERC20Permit, OwnableManagement { using SafeMath for uint256; modifier onlyStakingContract() { require(msg.sender == stakingContract); _; } address public stakingContract; address public initializer; event LogSupply( uint256 indexed epoch, uint256 timestamp, uint256 totalSupply ); event LogRebase(uint256 indexed epoch, uint256 rebase, uint256 index); event LogStakingContractUpdated(address stakingContract); struct Rebase { uint epoch; uint rebase; // 18 decimals uint totalStakedBefore; uint totalStakedAfter; uint amountRebased; uint index; uint32 timeOccured; } Rebase[] public rebases; uint public INDEX; uint256 private constant MAX_UINT256 = ~uint256(0); uint256 private constant INITIAL_FRAGMENTS_SUPPLY = 5_000_000_000_000 * 10 ** 9; // TOTAL_GONS is a multiple of INITIAL_FRAGMENTS_SUPPLY so that _gonsPerFragment is an integer. // Use the highest value that fits in a uint256 for max granularity. uint256 private constant TOTAL_GONS = MAX_UINT256 - (MAX_UINT256 % INITIAL_FRAGMENTS_SUPPLY); // MAX_SUPPLY = maximum integer < (sqrt(4*TOTAL_GONS + 1) - 1) / 2 uint256 private constant MAX_SUPPLY = ~uint128(0); // (2^128) - 1 uint256 private _gonsPerFragment; mapping(address => uint256) private _gonBalances; mapping(address => mapping(address => uint256)) private _allowedValue; constructor() ERC20("Vote-escrowed SYNC", "veSYNC", 9) ERC20Permit() { initializer = msg.sender; _totalSupply = INITIAL_FRAGMENTS_SUPPLY; _gonsPerFragment = TOTAL_GONS.div(_totalSupply); } function initialize(address stakingContract_) external returns (bool) { require(msg.sender == initializer); require(stakingContract_ != address(0)); stakingContract = stakingContract_; _gonBalances[stakingContract] = TOTAL_GONS; emit Transfer(address(0x0), stakingContract, _totalSupply); emit LogStakingContractUpdated(stakingContract_); initializer = address(0); return true; } function setIndex(uint _INDEX) external onlyManager returns (bool) { require(INDEX == 0); INDEX = gonsForBalance(_INDEX); return true; } /** @notice increases veSYNC supply to increase staking balances relative to profit_ @param profit_ uint256 @return uint256 */ function rebase( uint256 profit_, uint epoch_ ) public onlyStakingContract returns (uint256) { uint256 rebaseAmount; uint256 circulatingSupply_ = circulatingSupply(); if (profit_ == 0) { emit LogSupply(epoch_, block.timestamp, _totalSupply); emit LogRebase(epoch_, 0, index()); return _totalSupply; } else if (circulatingSupply_ > 0) { rebaseAmount = profit_.mul(_totalSupply).div(circulatingSupply_); } else { rebaseAmount = profit_; } _totalSupply = _totalSupply.add(rebaseAmount); if (_totalSupply > MAX_SUPPLY) { _totalSupply = MAX_SUPPLY; } _gonsPerFragment = TOTAL_GONS.div(_totalSupply); _storeRebase(circulatingSupply_, profit_, epoch_); return _totalSupply; } /** @notice emits event with data about rebase @param previousCirculating_ uint @param profit_ uint @param epoch_ uint @return bool */ function _storeRebase( uint previousCirculating_, uint profit_, uint epoch_ ) internal returns (bool) { uint rebasePercent = profit_.mul(1e18).div(previousCirculating_); rebases.push( Rebase({ epoch: epoch_, rebase: rebasePercent, // 18 decimals totalStakedBefore: previousCirculating_, totalStakedAfter: circulatingSupply(), amountRebased: profit_, index: index(), timeOccured: uint32(block.timestamp) }) ); emit LogSupply(epoch_, block.timestamp, _totalSupply); emit LogRebase(epoch_, rebasePercent, index()); return true; } function balanceOf(address who) public view override returns (uint256) { return _gonBalances[who].div(_gonsPerFragment); } function gonsForBalance(uint amount) public view returns (uint) { return amount.mul(_gonsPerFragment); } function balanceForGons(uint gons) public view returns (uint) { return gons.div(_gonsPerFragment); } // Staking contract holds excess veSYNC function circulatingSupply() public view returns (uint) { return _totalSupply.sub(balanceOf(stakingContract)); } function index() public view returns (uint) { return balanceForGons(INDEX); } function transfer( address to, uint256 value ) public override returns (bool) { uint256 gonValue = value.mul(_gonsPerFragment); _gonBalances[msg.sender] = _gonBalances[msg.sender].sub(gonValue); _gonBalances[to] = _gonBalances[to].add(gonValue); emit Transfer(msg.sender, to, value); return true; } function allowance( address owner_, address spender ) public view override returns (uint256) { return _allowedValue[owner_][spender]; } function transferFrom( address from, address to, uint256 value ) public override returns (bool) { _allowedValue[from][msg.sender] = _allowedValue[from][msg.sender].sub( value ); emit Approval(from, msg.sender, _allowedValue[from][msg.sender]); uint256 gonValue = gonsForBalance(value); _gonBalances[from] = _gonBalances[from].sub(gonValue); _gonBalances[to] = _gonBalances[to].add(gonValue); emit Transfer(from, to, value); return true; } function approve( address spender, uint256 value ) public override returns (bool) { _allowedValue[msg.sender][spender] = value; emit Approval(msg.sender, spender, value); return true; } // What gets called in a permit function _approve( address owner, address spender, uint256 value ) internal virtual override { _allowedValue[owner][spender] = value; emit Approval(owner, spender, value); } function increaseAllowance( address spender, uint256 addedValue ) public override returns (bool) { _allowedValue[msg.sender][spender] = _allowedValue[msg.sender][spender] .add(addedValue); emit Approval(msg.sender, spender, _allowedValue[msg.sender][spender]); return true; } function decreaseAllowance( address spender, uint256 subtractedValue ) public override returns (bool) { uint256 oldValue = _allowedValue[msg.sender][spender]; if (subtractedValue >= oldValue) { _allowedValue[msg.sender][spender] = 0; } else { _allowedValue[msg.sender][spender] = oldValue.sub(subtractedValue); } emit Approval(msg.sender, spender, _allowedValue[msg.sender][spender]); return true; } } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; import "./lib/IERC20.sol"; import "./lib/IERC2612Permit.sol"; import "./lib/Counters.sol"; import "./ERC20.sol"; abstract contract ERC20Permit is ERC20, IERC2612Permit { using Counters for Counters.Counter; mapping(address => Counters.Counter) private _nonces; // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; bytes32 public DOMAIN_SEPARATOR; constructor() { uint256 chainID; assembly { chainID := chainid() } DOMAIN_SEPARATOR = keccak256( abi.encode( keccak256( "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" ), keccak256(bytes(name())), keccak256(bytes("1")), // Version chainID, address(this) ) ); } /** * @dev See {IERC2612Permit-permit}. * */ function permit( address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual override { require(block.timestamp <= deadline, "Permit: expired deadline"); bytes32 hashStruct = keccak256( abi.encode( PERMIT_TYPEHASH, owner, spender, amount, _nonces[owner].current(), deadline ) ); bytes32 _hash = keccak256( abi.encodePacked(uint16(0x1901), DOMAIN_SEPARATOR, hashStruct) ); address signer = ecrecover(_hash, v, r, s); require( signer != address(0) && signer == owner, "ZeroSwapPermit: Invalid signature" ); _nonces[owner].increment(); _approve(owner, spender, amount); } /** * @dev See {IERC2612Permit-nonces}. */ function nonces(address owner) public view override returns (uint256) { return _nonces[owner].current(); } } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; interface IOwnable { function owner() external view returns (address); function renounceOwnership() external; function transferOwnership(address newOwner_) external; } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; import "./lib/IOwnableManagement.sol"; contract OwnableManagement is IOwnableManagement { address internal _owner; address internal _newOwner; event OwnershipPushed(address indexed previousOwner, address indexed newOwner); event OwnershipPulled(address indexed previousOwner, address indexed newOwner); constructor () { _owner = msg.sender; emit OwnershipPushed( address(0), _owner ); } function manager() public view override returns (address) { return _owner; } modifier onlyManager() { require( _owner == msg.sender, "Ownable: caller is not the owner" ); _; } function renounceManagement() public virtual override onlyManager() { emit OwnershipPushed( _owner, address(0) ); _owner = address(0); } function pushManagement( address newOwner_ ) public virtual override onlyManager() { require( newOwner_ != address(0), "Ownable: new owner is the zero address"); emit OwnershipPushed( _owner, newOwner_ ); _newOwner = newOwner_; } function pullManagement() public virtual override { require( msg.sender == _newOwner, "Ownable: must be new owner to pull"); emit OwnershipPulled( _owner, _newOwner ); _owner = _newOwner; } }// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; interface IERC20 { function decimals() external view returns (uint8); /** * @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: AGPL-3.0-or-later pragma solidity 0.7.5; interface IERC2612Permit { function permit( address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; function nonces(address owner) external view returns (uint256); }// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; import "./SafeMath.sol"; library Counters { using SafeMath for uint256; struct Counter { uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { counter._value += 1; } function decrement(Counter storage counter) internal { counter._value = counter._value.sub(1); } } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; import "./lib/IERC20.sol"; import "./lib/SafeMath.sol"; abstract contract ERC20 is IERC20 { using SafeMath for uint256; // TODO comment actual hash value. bytes32 private constant ERC20TOKEN_ERC1820_INTERFACE_ID = keccak256("ERC20Token"); // Present in ERC777 mapping(address => uint256) internal _balances; // Present in ERC777 mapping(address => mapping(address => uint256)) internal _allowances; // Present in ERC777 uint256 internal _totalSupply; // Present in ERC777 string internal _name; // Present in ERC777 string internal _symbol; // Present in ERC777 uint8 internal _decimals; constructor(string memory name_, string memory symbol_, uint8 decimals_) { _name = name_; _symbol = symbol_; _decimals = decimals_; } function name() public view returns (string memory) { return _name; } function symbol() public view returns (string memory) { return _symbol; } function decimals() public view override returns (uint8) { return _decimals; } function totalSupply() public view override returns (uint256) { return _totalSupply; } function balanceOf( address account ) public view virtual override returns (uint256) { return _balances[account]; } function transfer( address recipient, uint256 amount ) public virtual override returns (bool) { _transfer(msg.sender, 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(msg.sender, spender, amount); return true; } function transferFrom( address sender, address recipient, uint256 amount ) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve( sender, msg.sender, _allowances[sender][msg.sender].sub( amount, "ERC20: transfer amount exceeds allowance" ) ); return true; } function increaseAllowance( address spender, uint256 addedValue ) public virtual returns (bool) { _approve( msg.sender, spender, _allowances[msg.sender][spender].add(addedValue) ); return true; } function decreaseAllowance( address spender, uint256 subtractedValue ) public virtual returns (bool) { _approve( msg.sender, spender, _allowances[msg.sender][spender].sub( subtractedValue, "ERC20: decreased allowance below zero" ) ); return true; } function _transfer( address sender, address recipient, uint256 amount ) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub( amount, "ERC20: transfer amount exceeds balance" ); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } function _mint(address account_, uint256 amount_) internal virtual { require(account_ != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(this), account_, amount_); _totalSupply = _totalSupply.add(amount_); _balances[account_] = _balances[account_].add(amount_); emit Transfer(address(this), account_, amount_); } function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub( amount, "ERC20: burn amount exceeds balance" ); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } function _beforeTokenTransfer( address from_, address to_, uint256 amount_ ) internal virtual {} } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; interface IOwnableManagement { function manager() external view returns (address); function renounceManagement() external; function pushManagement(address newOwner_) external; function pullManagement() external; } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; library SafeMath { function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } function add32(uint32 a, uint32 b) internal pure returns (uint32) { uint32 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } function sub( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } function sub32(uint32 a, uint32 b) internal pure returns (uint32) { return sub32(a, b, "SafeMath: subtraction overflow"); } function sub32( uint32 a, uint32 b, string memory errorMessage ) internal pure returns (uint32) { require(b <= a, errorMessage); uint32 c = a - b; return c; } function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } function mul32(uint32 a, uint32 b) internal pure returns (uint32) { if (a == 0) { return 0; } uint32 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } function div( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } function mod( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } function sqrrt(uint256 a) internal pure returns (uint c) { if (a > 3) { c = a; uint b = add(div(a, 2), 1); while (b < c) { c = b; b = div(add(div(a, b), b), 2); } } else if (a != 0) { c = 1; } } function percentageAmount( uint256 total_, uint8 percentage_ ) internal pure returns (uint256 percentAmount_) { return div(mul(total_, percentage_), 1000); } function substractPercentage( uint256 total_, uint8 percentageToSub_ ) internal pure returns (uint256 result_) { return sub(total_, div(mul(total_, percentageToSub_), 1000)); } function percentageOfTotal( uint256 part_, uint256 total_ ) internal pure returns (uint256 percent_) { return div(mul(part_, 100), total_); } function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow, so we distribute return (a / 2) + (b / 2) + (((a % 2) + (b % 2)) / 2); } function quadraticPricing( uint256 payment_, uint256 multiplier_ ) internal pure returns (uint256) { return sqrrt(mul(multiplier_, payment_)); } function bondingCurve( uint256 supply_, uint256 multiplier_ ) internal pure returns (uint256) { return mul(multiplier_, supply_); } }
File 3 of 4: Syncus
// SPDX-License-Identifier: AGPL-3.0-or-later pragma abicoder v2; pragma solidity 0.7.5; import "./lib/EnumerableSet.sol"; import "./lib/IERC2612Permit.sol"; import "./lib/IERC20.sol"; import "./ERC20Permit.sol"; import "./VaultOwned.sol"; import "./lib/IWETH.sol"; import "./lib/IUniswapV2Router.sol"; import "./lib/IUniswapV2Factory.sol"; contract Syncus is ERC20Permit, VaultOwned { using SafeMath for uint256; IUniswapV2Router public router = IUniswapV2Router(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D); address public uniswapV2Pair; address private treasury; uint256 public buyTax = 5; uint256 public sellTax = 15; mapping(address => bool) private _isExcludedFromTaxes; mapping(address => bool) public automatedMarketMakerPairs; receive() external payable {} constructor() ERC20("Syncus", "SYNC", 9) { _mint(msg.sender, 4_000_000_000 * 1e9); uniswapV2Pair = IUniswapV2Factory(router.factory()).createPair( address(this), router.WETH() ); _setAutomatedMarketMakerPair(address(uniswapV2Pair), true); treasury = msg.sender; excludeFromTaxes(owner(), true); excludeFromTaxes(address(this), true); excludeFromTaxes(address(0xdead), true); } function mint(address account_, uint256 amount_) external onlyVault { _mint(account_, amount_); } function burn(uint256 amount) public virtual { _burn(msg.sender, amount); } function burnFrom(address account_, uint256 amount_) public virtual { _burnFrom(account_, amount_); } function _burnFrom(address account_, uint256 amount_) public virtual { uint256 decreasedAllowance_ = allowance(account_, msg.sender).sub( amount_, "ERC20: burn amount exceeds allowance" ); _approve(account_, msg.sender, decreasedAllowance_); _burn(account_, amount_); } function excludeFromTaxes(address account, bool excluded) public onlyOwner { _isExcludedFromTaxes[account] = excluded; } function setAutomatedMarketMakerPair( address pair, bool value ) public onlyOwner { _setAutomatedMarketMakerPair(pair, value); } function _setAutomatedMarketMakerPair(address pair, bool value) private { automatedMarketMakerPairs[pair] = value; } function updateBuyTax(uint256 _buyTax) external onlyOwner { require(_buyTax <= 100, "Cannot set tax higher than 100%"); buyTax = _buyTax; } function updateSellTax(uint256 _sellTax) external onlyOwner { require(_sellTax <= 100, "Cannot set tax higher than 100%"); sellTax = _sellTax; } function updateTaxes(uint256 _buyTax, uint256 _sellTax) external onlyOwner { require( _sellTax <= 100 && _buyTax <= 100, "Cannot set taxes higher than 100%" ); buyTax = _buyTax; sellTax = _sellTax; } function _transfer( address from, address to, uint256 amount ) internal override { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); if (amount == 0) { super._transfer(from, to, 0); return; } bool takeTax = true; if (_isExcludedFromTaxes[from] || _isExcludedFromTaxes[to]) { takeTax = false; } uint256 taxes = 0; if (takeTax) { if (automatedMarketMakerPairs[to] && sellTax > 0) { taxes = amount.mul(sellTax).div(100); } else if (automatedMarketMakerPairs[from] && buyTax > 0) { taxes = amount.mul(buyTax).div(100); } if (taxes > 0) { super._transfer(from, treasury, taxes); } amount -= taxes; } super._transfer(from, to, amount); } function setTreasury(address _treasury) external onlyOwner { treasury = _treasury; } } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. bytes32 lastvalue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastvalue; // Update the index for the moved value set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains( Set storage set, bytes32 value ) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at( Set storage set, uint256 index ) private view returns (bytes32) { require( set._values.length > index, "EnumerableSet: index out of bounds" ); return set._values[index]; } function _getValues( Set storage set_ ) private view returns (bytes32[] storage) { return set_._values; } // TODO needs insert function that maintains order. // TODO needs NatSpec documentation comment. /** * Inserts new value by moving existing value at provided index to end * of array and setting provided value at provided index */ function _insert( Set storage set_, uint256 index_, bytes32 valueToInsert_ ) private returns (bool) { require(set_._values.length > index_); require( !_contains(set_, valueToInsert_), "Remove value you wish to insert if you wish to reorder array." ); bytes32 existingValue_ = _at(set_, index_); set_._values[index_] = valueToInsert_; return _add(set_, existingValue_); } struct Bytes4Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes4Set storage set, bytes4 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove( Bytes4Set storage set, bytes4 value ) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains( Bytes4Set storage set, bytes4 value ) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values on the set. O(1). */ function length(Bytes4Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at( Bytes4Set storage set, uint256 index ) internal view returns (bytes4) { return bytes4(_at(set._inner, index)); } function getValues( Bytes4Set storage set_ ) internal view returns (bytes4[] memory) { bytes4[] memory bytes4Array_; for ( uint256 iteration_ = 0; _length(set_._inner) > iteration_; iteration_++ ) { bytes4Array_[iteration_] = bytes4(_at(set_._inner, iteration_)); } return bytes4Array_; } function insert( Bytes4Set storage set_, uint256 index_, bytes4 valueToInsert_ ) internal returns (bool) { return _insert(set_._inner, index_, valueToInsert_); } struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add( Bytes32Set storage set, bytes32 value ) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove( Bytes32Set storage set, bytes32 value ) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains( Bytes32Set storage set, bytes32 value ) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values on the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at( Bytes32Set storage set, uint256 index ) internal view returns (bytes32) { return _at(set._inner, index); } function getValues( Bytes32Set storage set_ ) internal view returns (bytes4[] memory) { bytes4[] memory bytes4Array_; for ( uint256 iteration_ = 0; _length(set_._inner) >= iteration_; iteration_++ ) { bytes4Array_[iteration_] = bytes4(at(set_, iteration_)); } return bytes4Array_; } function insert( Bytes32Set storage set_, uint256 index_, bytes32 valueToInsert_ ) internal returns (bool) { return _insert(set_._inner, index_, valueToInsert_); } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add( AddressSet storage set, address value ) internal returns (bool) { return _add(set._inner, bytes32(uint256(value))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove( AddressSet storage set, address value ) internal returns (bool) { return _remove(set._inner, bytes32(uint256(value))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains( AddressSet storage set, address value ) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(value))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at( AddressSet storage set, uint256 index ) internal view returns (address) { return address(uint256(_at(set._inner, index))); } /** * TODO Might require explicit conversion of bytes32[] to address[]. * Might require iteration. */ function getValues( AddressSet storage set_ ) internal view returns (address[] memory) { address[] memory addressArray; for ( uint256 iteration_ = 0; _length(set_._inner) >= iteration_; iteration_++ ) { addressArray[iteration_] = at(set_, iteration_); } return addressArray; } function insert( AddressSet storage set_, uint256 index_, address valueToInsert_ ) internal returns (bool) { return _insert(set_._inner, index_, bytes32(uint256(valueToInsert_))); } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove( UintSet storage set, uint256 value ) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains( UintSet storage set, uint256 value ) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at( UintSet storage set, uint256 index ) internal view returns (uint256) { return uint256(_at(set._inner, index)); } struct UInt256Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add( UInt256Set storage set, uint256 value ) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove( UInt256Set storage set, uint256 value ) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains( UInt256Set storage set, uint256 value ) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UInt256Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at( UInt256Set storage set, uint256 index ) internal view returns (uint256) { return uint256(_at(set._inner, index)); } } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; interface IERC2612Permit { function permit( address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; function nonces(address owner) external view returns (uint256); }// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; interface IERC20 { function decimals() external view returns (uint8); /** * @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: AGPL-3.0-or-later pragma solidity 0.7.5; import "./lib/IERC20.sol"; import "./lib/IERC2612Permit.sol"; import "./lib/Counters.sol"; import "./ERC20.sol"; abstract contract ERC20Permit is ERC20, IERC2612Permit { using Counters for Counters.Counter; mapping(address => Counters.Counter) private _nonces; // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; bytes32 public DOMAIN_SEPARATOR; constructor() { uint256 chainID; assembly { chainID := chainid() } DOMAIN_SEPARATOR = keccak256( abi.encode( keccak256( "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" ), keccak256(bytes(name())), keccak256(bytes("1")), // Version chainID, address(this) ) ); } /** * @dev See {IERC2612Permit-permit}. * */ function permit( address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual override { require(block.timestamp <= deadline, "Permit: expired deadline"); bytes32 hashStruct = keccak256( abi.encode( PERMIT_TYPEHASH, owner, spender, amount, _nonces[owner].current(), deadline ) ); bytes32 _hash = keccak256( abi.encodePacked(uint16(0x1901), DOMAIN_SEPARATOR, hashStruct) ); address signer = ecrecover(_hash, v, r, s); require( signer != address(0) && signer == owner, "ZeroSwapPermit: Invalid signature" ); _nonces[owner].increment(); _approve(owner, spender, amount); } /** * @dev See {IERC2612Permit-nonces}. */ function nonces(address owner) public view override returns (uint256) { return _nonces[owner].current(); } } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; import "./Ownable.sol"; contract VaultOwned is Ownable { address internal _vault; function setVault(address vault_) external onlyOwner returns (bool) { _vault = vault_; return true; } function vault() public view returns (address) { return _vault; } modifier onlyVault() { require(_vault == msg.sender, "VaultOwned: caller is not the Vault"); _; } } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; interface IWETH { /** * @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 ); /** * @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 `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, 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 `from` to `to` 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 from, address to, uint256 amount ) external returns (bool); /// @notice Deposit ether to get wrapped ether function deposit() external payable; /// @notice Withdraw wrapped ether to get ether function withdraw(uint256) external; } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; interface IUniswapV2Router { function factory() external pure returns (address); function WETH() external pure returns (address); function addLiquidity( address tokenA, address tokenB, uint amountADesired, uint amountBDesired, uint amountAMin, uint amountBMin, address to, uint deadline ) external returns (uint amountA, uint amountB, uint liquidity); function addLiquidityETH( address token, uint amountTokenDesired, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external payable returns (uint amountToken, uint amountETH, uint liquidity); function removeLiquidity( address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline ) external returns (uint amountA, uint amountB); function removeLiquidityETH( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external returns (uint amountToken, uint amountETH); function removeLiquidityWithPermit( address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountA, uint amountB); function removeLiquidityETHWithPermit( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountToken, uint amountETH); function swapExactTokensForTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function swapTokensForExactTokens( uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function swapExactETHForTokens( uint amountOutMin, address[] calldata path, address to, uint deadline ) external payable returns (uint[] memory amounts); function swapTokensForExactETH( uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function swapExactTokensForETH( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function swapETHForExactTokens( uint amountOut, address[] calldata path, address to, uint deadline ) external payable returns (uint[] memory amounts); function quote( uint amountA, uint reserveA, uint reserveB ) external pure returns (uint amountB); function getAmountOut( uint amountIn, uint reserveIn, uint reserveOut ) external pure returns (uint amountOut); function getAmountIn( uint amountOut, uint reserveIn, uint reserveOut ) external pure returns (uint amountIn); function getAmountsOut( uint amountIn, address[] calldata path ) external view returns (uint[] memory amounts); function getAmountsIn( uint amountOut, address[] calldata path ) external view returns (uint[] memory amounts); function removeLiquidityETHSupportingFeeOnTransferTokens( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external returns (uint amountETH); function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountETH); function swapExactTokensForTokensSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external; function swapExactETHForTokensSupportingFeeOnTransferTokens( uint amountOutMin, address[] calldata path, address to, uint deadline ) external payable; function swapExactTokensForETHSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external; } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; interface IUniswapV2Factory { event PairCreated( address indexed token0, address indexed token1, address pair, uint ); 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 feeTo() external view returns (address); function feeToSetter() external view returns (address); function createPair( address tokenA, address tokenB ) external returns (address pair); } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; import "./SafeMath.sol"; library Counters { using SafeMath for uint256; struct Counter { uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { counter._value += 1; } function decrement(Counter storage counter) internal { counter._value = counter._value.sub(1); } } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; import "./lib/IERC20.sol"; import "./lib/SafeMath.sol"; abstract contract ERC20 is IERC20 { using SafeMath for uint256; // TODO comment actual hash value. bytes32 private constant ERC20TOKEN_ERC1820_INTERFACE_ID = keccak256("ERC20Token"); // Present in ERC777 mapping(address => uint256) internal _balances; // Present in ERC777 mapping(address => mapping(address => uint256)) internal _allowances; // Present in ERC777 uint256 internal _totalSupply; // Present in ERC777 string internal _name; // Present in ERC777 string internal _symbol; // Present in ERC777 uint8 internal _decimals; constructor(string memory name_, string memory symbol_, uint8 decimals_) { _name = name_; _symbol = symbol_; _decimals = decimals_; } function name() public view returns (string memory) { return _name; } function symbol() public view returns (string memory) { return _symbol; } function decimals() public view override returns (uint8) { return _decimals; } function totalSupply() public view override returns (uint256) { return _totalSupply; } function balanceOf( address account ) public view virtual override returns (uint256) { return _balances[account]; } function transfer( address recipient, uint256 amount ) public virtual override returns (bool) { _transfer(msg.sender, 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(msg.sender, spender, amount); return true; } function transferFrom( address sender, address recipient, uint256 amount ) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve( sender, msg.sender, _allowances[sender][msg.sender].sub( amount, "ERC20: transfer amount exceeds allowance" ) ); return true; } function increaseAllowance( address spender, uint256 addedValue ) public virtual returns (bool) { _approve( msg.sender, spender, _allowances[msg.sender][spender].add(addedValue) ); return true; } function decreaseAllowance( address spender, uint256 subtractedValue ) public virtual returns (bool) { _approve( msg.sender, spender, _allowances[msg.sender][spender].sub( subtractedValue, "ERC20: decreased allowance below zero" ) ); return true; } function _transfer( address sender, address recipient, uint256 amount ) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub( amount, "ERC20: transfer amount exceeds balance" ); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } function _mint(address account_, uint256 amount_) internal virtual { require(account_ != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(this), account_, amount_); _totalSupply = _totalSupply.add(amount_); _balances[account_] = _balances[account_].add(amount_); emit Transfer(address(this), account_, amount_); } function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub( amount, "ERC20: burn amount exceeds balance" ); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } function _beforeTokenTransfer( address from_, address to_, uint256 amount_ ) internal virtual {} } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; import "./lib/IOwnable.sol"; contract Ownable is IOwnable { address internal _owner; event OwnershipTransferred( address indexed previousOwner, address indexed newOwner ); constructor() { _owner = msg.sender; emit OwnershipTransferred(address(0), _owner); } function owner() public view override returns (address) { return _owner; } modifier onlyOwner() { require(_owner == msg.sender, "Ownable: caller is not the owner"); _; } function renounceOwnership() public virtual override onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } function transferOwnership( address newOwner_ ) public virtual override onlyOwner { require( newOwner_ != address(0), "Ownable: new owner is the zero address" ); emit OwnershipTransferred(_owner, newOwner_); _owner = newOwner_; } } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; library SafeMath { function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } function add32(uint32 a, uint32 b) internal pure returns (uint32) { uint32 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } function sub( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } function sub32(uint32 a, uint32 b) internal pure returns (uint32) { return sub32(a, b, "SafeMath: subtraction overflow"); } function sub32( uint32 a, uint32 b, string memory errorMessage ) internal pure returns (uint32) { require(b <= a, errorMessage); uint32 c = a - b; return c; } function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } function mul32(uint32 a, uint32 b) internal pure returns (uint32) { if (a == 0) { return 0; } uint32 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } function div( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } function mod( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } function sqrrt(uint256 a) internal pure returns (uint c) { if (a > 3) { c = a; uint b = add(div(a, 2), 1); while (b < c) { c = b; b = div(add(div(a, b), b), 2); } } else if (a != 0) { c = 1; } } function percentageAmount( uint256 total_, uint8 percentage_ ) internal pure returns (uint256 percentAmount_) { return div(mul(total_, percentage_), 1000); } function substractPercentage( uint256 total_, uint8 percentageToSub_ ) internal pure returns (uint256 result_) { return sub(total_, div(mul(total_, percentageToSub_), 1000)); } function percentageOfTotal( uint256 part_, uint256 total_ ) internal pure returns (uint256 percent_) { return div(mul(part_, 100), total_); } function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow, so we distribute return (a / 2) + (b / 2) + (((a % 2) + (b % 2)) / 2); } function quadraticPricing( uint256 payment_, uint256 multiplier_ ) internal pure returns (uint256) { return sqrrt(mul(multiplier_, payment_)); } function bondingCurve( uint256 supply_, uint256 multiplier_ ) internal pure returns (uint256) { return mul(multiplier_, supply_); } } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; interface IOwnable { function owner() external view returns (address); function renounceOwnership() external; function transferOwnership(address newOwner_) external; }
File 4 of 4: SyncusTreasury
// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; import "./lib/SafeMath.sol"; import "./lib/Address.sol"; import "./lib/IERC20.sol"; import "./lib/SafeERC20.sol"; import "./lib/ISyncus.sol"; import "./lib/IERC20Mintable.sol"; import "./lib/ISyncusCalculator.sol"; import "./lib/IOwnable.sol"; import "./OwnableManagement.sol"; contract SyncusTreasury is OwnableManagement { using SafeMath for uint; using SafeMath for uint32; using SafeERC20 for IERC20; event Deposit(address indexed token, uint amount, uint value); event Withdrawal(address indexed token, uint amount, uint value); event CreateDebt( address indexed debtor, address indexed token, uint amount, uint value ); event RepayDebt( address indexed debtor, address indexed token, uint amount, uint value ); event ReservesManaged(address indexed token, uint amount); event ReservesUpdated(uint indexed totalReserves); event ReservesAudited(uint indexed totalReserves); event RewardsMinted( address indexed caller, address indexed recipient, uint amount ); event ChangeQueued(MANAGING indexed managing, address queued); event ChangeActivated( MANAGING indexed managing, address activated, bool result ); enum MANAGING { RESERVEDEPOSITOR, RESERVESPENDER, RESERVETOKEN, RESERVEMANAGER, LIQUIDITYDEPOSITOR, LIQUIDITYTOKEN, LIQUIDITYMANAGER, DEBTOR, REWARDMANAGER, VESYNC } address public immutable Sync; uint32 public secondsNeededForQueue; address[] public reserveTokens; // Push only, beware false-positives. mapping(address => bool) public isReserveToken; mapping(address => uint32) public reserveTokenQueue; // Delays changes to mapping. address[] public reserveDepositors; // Push only, beware false-positives. Only for viewing. mapping(address => bool) public isReserveDepositor; mapping(address => uint32) public reserveDepositorQueue; // Delays changes to mapping. address[] public reserveSpenders; // Push only, beware false-positives. Only for viewing. mapping(address => bool) public isReserveSpender; mapping(address => uint32) public reserveSpenderQueue; // Delays changes to mapping. address[] public liquidityTokens; // Push only, beware false-positives. mapping(address => bool) public isLiquidityToken; mapping(address => uint32) public LiquidityTokenQueue; // Delays changes to mapping. address[] public liquidityDepositors; // Push only, beware false-positives. Only for viewing. mapping(address => bool) public isLiquidityDepositor; mapping(address => uint32) public LiquidityDepositorQueue; // Delays changes to mapping. mapping(address => address) public syncusCalculator; // calculator for liquidity token address[] public reserveManagers; // Push only, beware false-positives. Only for viewing. mapping(address => bool) public isReserveManager; mapping(address => uint32) public ReserveManagerQueue; // Delays changes to mapping. address[] public liquidityManagers; // Push only, beware false-positives. Only for viewing. mapping(address => bool) public isLiquidityManager; mapping(address => uint32) public LiquidityManagerQueue; // Delays changes to mapping. address[] public debtors; // Push only, beware false-positives. Only for viewing. mapping(address => bool) public isDebtor; mapping(address => uint32) public debtorQueue; // Delays changes to mapping. mapping(address => uint) public debtorBalance; address[] public rewardManagers; // Push only, beware false-positives. Only for viewing. mapping(address => bool) public isRewardManager; mapping(address => uint32) public rewardManagerQueue; // Delays changes to mapping. address public veSYNC; uint public veSYNCQueue; // Delays change to veSYNC address uint public totalReserves; // Risk-free value of all assets uint public totalDebt; bool isBackingEnabled = false; receive() external payable {} constructor(address _Sync, address _USDC, address _etherCalculator) { require(_Sync != address(0)); require(_USDC != address(0)); require(_etherCalculator != address(0)); Sync = _Sync; isReserveToken[_USDC] = true; reserveTokens.push(_USDC); syncusCalculator[address(0)] = _etherCalculator; } /** @notice allow approved address to deposit an asset for SYNC @param _amount uint @param _token address @param _profit uint @return send_ uint */ function deposit( uint _amount, address _token, uint _profit //profit in SYNC, 9 decimals needed ) external returns (uint send_) { require( isReserveToken[_token] || isLiquidityToken[_token], "Not accepted" ); IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount); if (isReserveToken[_token]) { require(isReserveDepositor[msg.sender], "Not approved"); } else { require(isLiquidityDepositor[msg.sender], "Not approved"); } uint value = valueOf(_token, _amount); // mint SYNC needed and store amount of rewards for distribution send_ = value.sub(_profit); IERC20Mintable(Sync).mint(msg.sender, send_); totalReserves = totalReserves.add(value); emit ReservesUpdated(totalReserves); emit Deposit(_token, _amount, value); } /** @notice allow approved address to burn SYNC for reserves @param _amount uint @param _token address */ function withdraw(uint _amount, address _token) external { require(isReserveToken[_token], "Not accepted"); // Only reserves can be used for redemptions require(isReserveSpender[msg.sender] == true, "Not approved"); uint value = valueOf(_token, _amount); ISyncus(Sync).burnFrom(msg.sender, value); totalReserves = totalReserves.sub(value); emit ReservesUpdated(totalReserves); IERC20(_token).safeTransfer(msg.sender, _amount); emit Withdrawal(_token, _amount, value); } /** @notice allow approved address to borrow reserves @param _amount uint @param _token address */ function incurDebt(uint _amount, address _token) external { require(isDebtor[msg.sender], "Not approved"); require(isReserveToken[_token], "Not accepted"); uint value = valueOf(_token, _amount); uint maximumDebt = IERC20(veSYNC).balanceOf(msg.sender); // Can only borrow against veSYNC held uint availableDebt = maximumDebt.sub(debtorBalance[msg.sender]); require(value <= availableDebt, "Exceeds debt limit"); debtorBalance[msg.sender] = debtorBalance[msg.sender].add(value); totalDebt = totalDebt.add(value); totalReserves = totalReserves.sub(value); emit ReservesUpdated(totalReserves); IERC20(_token).transfer(msg.sender, _amount); emit CreateDebt(msg.sender, _token, _amount, value); } /** @notice allow approved address to repay borrowed reserves with reserves @param _amount uint @param _token address */ function repayDebtWithReserve(uint _amount, address _token) external { require(isDebtor[msg.sender], "Not approved"); require(isReserveToken[_token], "Not accepted"); IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount); uint value = valueOf(_token, _amount); debtorBalance[msg.sender] = debtorBalance[msg.sender].sub(value); totalDebt = totalDebt.sub(value); totalReserves = totalReserves.add(value); emit ReservesUpdated(totalReserves); emit RepayDebt(msg.sender, _token, _amount, value); } /** @notice allow approved address to repay borrowed reserves with SYNC @param _amount uint */ function repayDebtWithSYNC(uint _amount) external { require(isDebtor[msg.sender], "Not approved"); ISyncus(Sync).burnFrom(msg.sender, _amount); debtorBalance[msg.sender] = debtorBalance[msg.sender].sub(_amount); totalDebt = totalDebt.sub(_amount); emit RepayDebt(msg.sender, Sync, _amount, _amount); } /** @notice allow approved address to withdraw assets @param _token address @param _amount uint */ function manage(address _token, uint _amount) external { if (isLiquidityToken[_token]) { require(isLiquidityManager[msg.sender], "Not approved"); } else { require(isReserveManager[msg.sender], "Not approved"); } uint value = valueOf(_token, _amount); if (isBackingEnabled) { require(value <= excessReserves(), "Insufficient reserves"); } totalReserves = totalReserves.sub(value); emit ReservesUpdated(totalReserves); IERC20(_token).safeTransfer(msg.sender, _amount); emit ReservesManaged(_token, _amount); } /** @notice send epoch reward to staking contract */ function mintRewards(address _recipient, uint _amount) external { require(isRewardManager[msg.sender], "Not approved"); if (isBackingEnabled) { require(_amount <= excessReserves(), "Insufficient reserves"); } IERC20Mintable(Sync).mint(_recipient, _amount); emit RewardsMinted(msg.sender, _recipient, _amount); } /** @notice returns excess reserves not backing tokens @return uint */ function excessReserves() public view returns (uint) { uint supply = IERC20(Sync).totalSupply().sub(totalDebt); if (supply > totalReserves) { return 0; } return totalReserves.sub(supply); } /** @notice takes inventory of all tracked assets @notice always consolidate to recognized reserves before audit */ function auditReserves() external onlyManager { uint reserves; for (uint i = 0; i < reserveTokens.length; i++) { reserves = reserves.add( valueOf( reserveTokens[i], IERC20(reserveTokens[i]).balanceOf(address(this)) ) ); } for (uint i = 0; i < liquidityTokens.length; i++) { reserves = reserves.add( valueOf( liquidityTokens[i], IERC20(liquidityTokens[i]).balanceOf(address(this)) ) ); } reserves = reserves.add(valueOf(address(0), address(this).balance)); totalReserves = reserves; emit ReservesUpdated(reserves); emit ReservesAudited(reserves); } /** @notice returns SYNC valuation of asset @param _token address @param _amount uint @return value_ uint */ function valueOf( address _token, uint _amount ) public view returns (uint value_) { if (_token == address(0)) { value_ = ISyncusCalculator(syncusCalculator[_token]).valuationEther( _amount ); } else if (isReserveToken[_token]) { // convert amount to match SYNC decimals value_ = _amount.mul(10 ** IERC20(Sync).decimals()).div( 10 ** IERC20(_token).decimals() ); } else if (isLiquidityToken[_token]) { value_ = ISyncusCalculator(syncusCalculator[_token]).valuation( _token, _amount ); } } /** @notice queue address to change boolean in mapping @param _managing MANAGING @param _address address @return bool */ function queue( MANAGING _managing, address _address ) external onlyManager returns (bool) { require(_address != address(0)); if (_managing == MANAGING.RESERVEDEPOSITOR) { // 0 reserveDepositorQueue[_address] = uint32(block.timestamp).add32( secondsNeededForQueue ); } else if (_managing == MANAGING.RESERVESPENDER) { // 1 reserveSpenderQueue[_address] = uint32(block.timestamp).add32( secondsNeededForQueue ); } else if (_managing == MANAGING.RESERVETOKEN) { // 2 reserveTokenQueue[_address] = uint32(block.timestamp).add32( secondsNeededForQueue ); } else if (_managing == MANAGING.RESERVEMANAGER) { // 3 ReserveManagerQueue[_address] = uint32(block.timestamp).add32( secondsNeededForQueue.mul32(2) ); } else if (_managing == MANAGING.LIQUIDITYDEPOSITOR) { // 4 LiquidityDepositorQueue[_address] = uint32(block.timestamp).add32( secondsNeededForQueue ); } else if (_managing == MANAGING.LIQUIDITYTOKEN) { // 5 LiquidityTokenQueue[_address] = uint32(block.timestamp).add32( secondsNeededForQueue ); } else if (_managing == MANAGING.LIQUIDITYMANAGER) { // 6 LiquidityManagerQueue[_address] = uint32(block.timestamp).add32( secondsNeededForQueue.mul32(2) ); } else if (_managing == MANAGING.DEBTOR) { // 7 debtorQueue[_address] = uint32(block.timestamp).add32( secondsNeededForQueue ); } else if (_managing == MANAGING.REWARDMANAGER) { // 8 rewardManagerQueue[_address] = uint32(block.timestamp).add32( secondsNeededForQueue ); } else if (_managing == MANAGING.VESYNC) { // 9 veSYNCQueue = uint32(block.timestamp).add32(secondsNeededForQueue); } else return false; emit ChangeQueued(_managing, _address); return true; } /** @notice verify queue then set boolean in mapping @param _managing MANAGING @param _address address @param _calculator address @return bool */ function toggle( MANAGING _managing, address _address, address _calculator ) external onlyManager returns (bool) { require(_address != address(0)); bool result; if (_managing == MANAGING.RESERVEDEPOSITOR) { // 0 if ( requirements( reserveDepositorQueue, isReserveDepositor, _address ) ) { reserveDepositorQueue[_address] = 0; if (!listContains(reserveDepositors, _address)) { reserveDepositors.push(_address); } } result = !isReserveDepositor[_address]; isReserveDepositor[_address] = result; } else if (_managing == MANAGING.RESERVESPENDER) { // 1 if (requirements(reserveSpenderQueue, isReserveSpender, _address)) { reserveSpenderQueue[_address] = 0; if (!listContains(reserveSpenders, _address)) { reserveSpenders.push(_address); } } result = !isReserveSpender[_address]; isReserveSpender[_address] = result; } else if (_managing == MANAGING.RESERVETOKEN) { // 2 if (requirements(reserveTokenQueue, isReserveToken, _address)) { reserveTokenQueue[_address] = 0; if (!listContains(reserveTokens, _address)) { reserveTokens.push(_address); } } result = !isReserveToken[_address]; isReserveToken[_address] = result; } else if (_managing == MANAGING.RESERVEMANAGER) { // 3 if (requirements(ReserveManagerQueue, isReserveManager, _address)) { reserveManagers.push(_address); ReserveManagerQueue[_address] = 0; if (!listContains(reserveManagers, _address)) { reserveManagers.push(_address); } } result = !isReserveManager[_address]; isReserveManager[_address] = result; } else if (_managing == MANAGING.LIQUIDITYDEPOSITOR) { // 4 if ( requirements( LiquidityDepositorQueue, isLiquidityDepositor, _address ) ) { liquidityDepositors.push(_address); LiquidityDepositorQueue[_address] = 0; if (!listContains(liquidityDepositors, _address)) { liquidityDepositors.push(_address); } } result = !isLiquidityDepositor[_address]; isLiquidityDepositor[_address] = result; } else if (_managing == MANAGING.LIQUIDITYTOKEN) { // 5 if (requirements(LiquidityTokenQueue, isLiquidityToken, _address)) { LiquidityTokenQueue[_address] = 0; if (!listContains(liquidityTokens, _address)) { liquidityTokens.push(_address); } } result = !isLiquidityToken[_address]; isLiquidityToken[_address] = result; syncusCalculator[_address] = _calculator; } else if (_managing == MANAGING.LIQUIDITYMANAGER) { // 6 if ( requirements( LiquidityManagerQueue, isLiquidityManager, _address ) ) { LiquidityManagerQueue[_address] = 0; if (!listContains(liquidityManagers, _address)) { liquidityManagers.push(_address); } } result = !isLiquidityManager[_address]; isLiquidityManager[_address] = result; } else if (_managing == MANAGING.DEBTOR) { // 7 if (requirements(debtorQueue, isDebtor, _address)) { debtorQueue[_address] = 0; if (!listContains(debtors, _address)) { debtors.push(_address); } } result = !isDebtor[_address]; isDebtor[_address] = result; } else if (_managing == MANAGING.REWARDMANAGER) { // 8 if (requirements(rewardManagerQueue, isRewardManager, _address)) { rewardManagerQueue[_address] = 0; if (!listContains(rewardManagers, _address)) { rewardManagers.push(_address); } } result = !isRewardManager[_address]; isRewardManager[_address] = result; } else if (_managing == MANAGING.VESYNC) { // 9 veSYNCQueue = 0; veSYNC = _address; result = true; } else return false; emit ChangeActivated(_managing, _address, result); return true; } /** @notice checks requirements and returns altered structs @param queue_ mapping( address => uint ) @param status_ mapping( address => bool ) @param _address address @return bool */ function requirements( mapping(address => uint32) storage queue_, mapping(address => bool) storage status_, address _address ) internal view returns (bool) { if (!status_[_address]) { require(queue_[_address] != 0, "Must queue"); require( queue_[_address] <= uint32(block.timestamp), "Queue not expired" ); return true; } return false; } /** @notice checks array to ensure against duplicate @param _list address[] @param _token address @return bool */ function listContains( address[] storage _list, address _token ) internal view returns (bool) { for (uint i = 0; i < _list.length; i++) { if (_list[i] == _token) { return true; } } return false; } function setEtherCalculator(address _calculator) external onlyManager { syncusCalculator[address(0)] = _calculator; } function setIsBackingEnabled(bool _isBackingEnabled) external onlyManager { isBackingEnabled = _isBackingEnabled; } function withdrawEther(uint _amount) external onlyManager { msg.sender.transfer(_amount); } // sync taxes and lost tokens function withdrawToken(address _token, uint _amount) external onlyManager { IERC20(_token).safeTransfer(msg.sender, _amount); } function emergencyWithdrawEther(address _recipient) external onlyManager { require(_recipient != address(0), "Invalid recipient address"); uint balance = address(this).balance; (bool success, ) = _recipient.call{value: balance}(""); require(success, "Transfer failed"); } } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; library SafeMath { function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } function add32(uint32 a, uint32 b) internal pure returns (uint32) { uint32 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } function sub( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } function sub32(uint32 a, uint32 b) internal pure returns (uint32) { return sub32(a, b, "SafeMath: subtraction overflow"); } function sub32( uint32 a, uint32 b, string memory errorMessage ) internal pure returns (uint32) { require(b <= a, errorMessage); uint32 c = a - b; return c; } function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } function mul32(uint32 a, uint32 b) internal pure returns (uint32) { if (a == 0) { return 0; } uint32 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } function div( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } function mod( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } function sqrrt(uint256 a) internal pure returns (uint c) { if (a > 3) { c = a; uint b = add(div(a, 2), 1); while (b < c) { c = b; b = div(add(div(a, b), b), 2); } } else if (a != 0) { c = 1; } } function percentageAmount( uint256 total_, uint8 percentage_ ) internal pure returns (uint256 percentAmount_) { return div(mul(total_, percentage_), 1000); } function substractPercentage( uint256 total_, uint8 percentageToSub_ ) internal pure returns (uint256 result_) { return sub(total_, div(mul(total_, percentageToSub_), 1000)); } function percentageOfTotal( uint256 part_, uint256 total_ ) internal pure returns (uint256 percent_) { return div(mul(part_, 100), total_); } function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow, so we distribute return (a / 2) + (b / 2) + (((a % 2) + (b % 2)) / 2); } function quadraticPricing( uint256 payment_, uint256 multiplier_ ) internal pure returns (uint256) { return sqrrt(mul(multiplier_, payment_)); } function bondingCurve( uint256 supply_, uint256 multiplier_ ) internal pure returns (uint256) { return mul(multiplier_, supply_); } } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; 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 in 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} */ 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). * * 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); } function _functionCallWithValue( address target, bytes memory data, uint256 weiValue, string memory errorMessage ) private returns (bytes memory) { require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{value: weiValue}( data ); 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); } } } /** * @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.3._ */ 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.3._ */ 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); } } } function addressToString( address _address ) internal pure returns (string memory) { bytes32 _bytes = bytes32(uint256(_address)); bytes memory HEX = "0123456789abcdef"; bytes memory _addr = new bytes(42); _addr[0] = "0"; _addr[1] = "x"; for (uint256 i = 0; i < 20; i++) { _addr[2 + i * 2] = HEX[uint8(_bytes[i + 12] >> 4)]; _addr[3 + i * 2] = HEX[uint8(_bytes[i + 12] & 0x0f)]; } return string(_addr); } } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; interface IERC20 { function decimals() external view returns (uint8); /** * @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: AGPL-3.0-or-later pragma solidity 0.7.5; import "./SafeMath.sol"; import "./Address.sol"; import "./IERC20.sol"; library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. // A Solidity high level call has three parts: // 1. The target address is checked to verify it contains contract code // 2. The call itself is made, and success asserted // 3. The return value is decoded, which in turn checks the size of the returned data. // solhint-disable-next-line max-line-length require(address(token).isContract(), "SafeERC20: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = address(token).call(data); require(success, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; interface ISyncus { function burn(uint256 amount) external; function burnFrom(address account_, uint256 amount_) external; } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; interface IERC20Mintable { function mint(uint256 amount_) external; function mint(address account_, uint256 ammount_) external; } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; interface ISyncusCalculator { function valuation( address pair_, uint amount_ ) external view returns (uint _value); function valuationEther(uint amount_) external view returns (uint _value); function markdown(address _pair) external view returns (uint); } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; interface IOwnable { function owner() external view returns (address); function renounceOwnership() external; function transferOwnership(address newOwner_) external; } // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; import "./lib/IOwnableManagement.sol"; contract OwnableManagement is IOwnableManagement { address internal _owner; address internal _newOwner; event OwnershipPushed(address indexed previousOwner, address indexed newOwner); event OwnershipPulled(address indexed previousOwner, address indexed newOwner); constructor () { _owner = msg.sender; emit OwnershipPushed( address(0), _owner ); } function manager() public view override returns (address) { return _owner; } modifier onlyManager() { require( _owner == msg.sender, "Ownable: caller is not the owner" ); _; } function renounceManagement() public virtual override onlyManager() { emit OwnershipPushed( _owner, address(0) ); _owner = address(0); } function pushManagement( address newOwner_ ) public virtual override onlyManager() { require( newOwner_ != address(0), "Ownable: new owner is the zero address"); emit OwnershipPushed( _owner, newOwner_ ); _newOwner = newOwner_; } function pullManagement() public virtual override { require( msg.sender == _newOwner, "Ownable: must be new owner to pull"); emit OwnershipPulled( _owner, _newOwner ); _owner = _newOwner; } }// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; interface IOwnableManagement { function manager() external view returns (address); function renounceManagement() external; function pushManagement(address newOwner_) external; function pullManagement() external; }