├── README.md ├── .mocharc.js ├── flatten ├── EclipseV2.sol ├── SolarPairFlatten.sol ├── SolarLockerFlatten.sol ├── SolarVaultFlatten.sol ├── ComplexRewarderPerSecV2.sol ├── ComplexRewarderPerSecV3.sol ├── ComplexRewarderPerSecV4.sol └── MulticallFlatten.sol ├── .gitignore ├── contracts ├── uniswapv2 │ ├── interfaces │ │ ├── ISolarCallee.sol │ │ ├── IWETH.sol │ │ ├── IERC20.sol │ │ ├── ISolarFactory.sol │ │ ├── ISolarERC20.sol │ │ ├── ISolarRouter02.sol │ │ ├── ISolarPair.sol │ │ └── ISolarRouter01.sol │ ├── libraries │ │ ├── UQ112x112.sol │ │ ├── SafeMath.sol │ │ ├── Math.sol │ │ ├── TransferHelper.sol │ │ └── SolarLibrary.sol │ ├── SolarFactory.sol │ ├── SolarERC20.sol │ └── SolarPair.sol ├── gasless │ ├── IToken.sol │ ├── MockRouter.sol │ ├── EIP712Base.sol │ ├── GasSwap.sol │ ├── EIP712MetaTransaction.sol │ └── ISolarRouter.sol ├── farm │ ├── v2 │ │ ├── ISolarPair.sol │ │ ├── ISolarDistributorV2.sol │ │ ├── rewarders │ │ │ ├── IRewarder.sol │ │ │ ├── RewarderBroken.sol │ │ │ ├── IComplexRewarder.sol │ │ │ ├── SimpleRewarderPerSec.sol │ │ │ └── ComplexRewarderPerSec.sol │ │ └── libraries │ │ │ ├── IBoringERC20.sol │ │ │ └── BoringERC20.sol │ └── ISolarERC20.sol ├── mock │ └── MockERC20.sol ├── eclipse │ ├── amaraV2 │ │ ├── ICommonEclipseAmaraV2.sol │ │ └── CommonEclipseAmaraV2.sol │ ├── ICommonEclipse.sol │ ├── v2 │ │ └── ICommonEclipseV2.sol │ └── amara │ │ ├── ICommonEclipseAmara.sol │ │ └── CommonEclipseAmara.sol ├── fee │ ├── interfaces │ │ ├── ISmartRouter.sol │ │ ├── ISolarFactory.sol │ │ ├── ISolarERC20.sol │ │ ├── ISolarRouter02.sol │ │ ├── ISolarPair.sol │ │ └── ISolarRouter01.sol │ └── SolarFeeColector.sol ├── burner │ ├── interfaces │ │ ├── ISolarFactory.sol │ │ ├── ISolarERC20.sol │ │ └── ISolarPair.sol │ └── SolarBurner.sol ├── libraries │ ├── IBoringERC20.sol │ └── BoringERC20.sol ├── nft │ └── NFTClaim.sol ├── forwarder │ ├── IForwarder.sol │ └── Forwarder.sol ├── helpers │ ├── Multicall2.sol │ └── Timelock.sol ├── locker │ └── SolarLocker.sol └── solar │ ├── SolarBeamToken.sol │ └── VestedSolarBeamToken.sol ├── package.json ├── test ├── utils │ ├── time.js │ └── index.js └── GasSwap.test.js └── hardhat.config.js /README.md: -------------------------------------------------------------------------------- 1 | # Solarbeam.io 2 | 3 | Solarbeam.io smart contracts -------------------------------------------------------------------------------- /.mocharc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | require: "hardhat/register", 3 | timeout: 200000, 4 | }; 5 | -------------------------------------------------------------------------------- /flatten/EclipseV2.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solarbeamio/contracts/HEAD/flatten/EclipseV2.sol -------------------------------------------------------------------------------- /flatten/SolarPairFlatten.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solarbeamio/contracts/HEAD/flatten/SolarPairFlatten.sol -------------------------------------------------------------------------------- /flatten/SolarLockerFlatten.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solarbeamio/contracts/HEAD/flatten/SolarLockerFlatten.sol -------------------------------------------------------------------------------- /flatten/SolarVaultFlatten.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solarbeamio/contracts/HEAD/flatten/SolarVaultFlatten.sol -------------------------------------------------------------------------------- /flatten/ComplexRewarderPerSecV2.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solarbeamio/contracts/HEAD/flatten/ComplexRewarderPerSecV2.sol -------------------------------------------------------------------------------- /flatten/ComplexRewarderPerSecV3.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solarbeamio/contracts/HEAD/flatten/ComplexRewarderPerSecV3.sol -------------------------------------------------------------------------------- /flatten/ComplexRewarderPerSecV4.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solarbeamio/contracts/HEAD/flatten/ComplexRewarderPerSecV4.sol -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | node_modules/ 3 | deployments/ 4 | tasks/ 5 | tasks/* 6 | deploy/ 7 | .secret 8 | .secret-testnet 9 | .env 10 | artifacts 11 | cache -------------------------------------------------------------------------------- /contracts/uniswapv2/interfaces/ISolarCallee.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity =0.6.12; 3 | 4 | interface ISolarCallee { 5 | function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external; 6 | } 7 | -------------------------------------------------------------------------------- /contracts/gasless/IToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.7; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 5 | import "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol"; 6 | 7 | interface IToken is IERC20, IERC20Permit {} 8 | -------------------------------------------------------------------------------- /contracts/uniswapv2/interfaces/IWETH.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity =0.6.12; 3 | 4 | interface IWETH { 5 | function deposit() external payable; 6 | 7 | function transfer(address to, uint256 value) external returns (bool); 8 | 9 | function withdraw(uint256) external; 10 | } 11 | -------------------------------------------------------------------------------- /contracts/farm/v2/ISolarPair.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.7; 3 | 4 | interface ISolarPair { 5 | function initialize(address, address) external; 6 | 7 | function permit( 8 | address owner, 9 | address spender, 10 | uint256 value, 11 | uint256 deadline, 12 | uint8 v, 13 | bytes32 r, 14 | bytes32 s 15 | ) external; 16 | } 17 | -------------------------------------------------------------------------------- /contracts/farm/v2/ISolarDistributorV2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.2; 3 | 4 | interface ISolarDistributorV2 { 5 | function totalAllocPoint() external view returns (uint256); 6 | 7 | function deposit(uint256 _pid, uint256 _amount) external; 8 | 9 | function poolLength() external view returns (uint256); 10 | 11 | function poolTotalLp(uint256 pid) external view returns (uint256); 12 | } 13 | -------------------------------------------------------------------------------- /contracts/farm/ISolarERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.2; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 5 | import "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol"; 6 | 7 | /** 8 | * @dev Interface of the ERC20 standard as defined in the EIP. 9 | */ 10 | interface ISolarERC20 is IERC20, IERC20Permit { 11 | function mint(address to, uint256 amount) external; 12 | } 13 | -------------------------------------------------------------------------------- /contracts/farm/v2/rewarders/IRewarder.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.2; 3 | 4 | import "../libraries/IBoringERC20.sol"; 5 | 6 | interface IRewarder { 7 | function onSolarReward(address user, uint256 newLpAmount) external; 8 | 9 | function pendingTokens(address user) 10 | external 11 | view 12 | returns (uint256 pending); 13 | 14 | function rewardToken() external view returns (IBoringERC20); 15 | } 16 | -------------------------------------------------------------------------------- /contracts/farm/v2/rewarders/RewarderBroken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.2; 3 | import "./IRewarder.sol"; 4 | import "../libraries/BoringERC20.sol"; 5 | 6 | contract RewarderBroken is IRewarder { 7 | IBoringERC20 public override rewardToken; 8 | 9 | function onSolarReward(address, uint256) external pure override { 10 | revert(); 11 | } 12 | 13 | function pendingTokens(address) external pure override returns (uint256) { 14 | revert(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /contracts/farm/v2/rewarders/IComplexRewarder.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.7; 3 | 4 | import "../libraries/IBoringERC20.sol"; 5 | 6 | interface IComplexRewarder { 7 | function onSolarReward( 8 | uint256 pid, 9 | address user, 10 | uint256 newLpAmount 11 | ) external; 12 | 13 | function pendingTokens(uint256 pid, address user) 14 | external 15 | view 16 | returns (uint256 pending); 17 | 18 | function rewardToken() external view returns (IBoringERC20); 19 | 20 | function poolRewardsPerSec(uint256 pid) external view returns (uint256); 21 | } 22 | -------------------------------------------------------------------------------- /contracts/gasless/MockRouter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.7; 3 | 4 | import "hardhat/console.sol"; 5 | 6 | import "@openzeppelin/contracts/access/Ownable.sol"; 7 | import "@openzeppelin/contracts/utils/Address.sol"; 8 | import "./EIP712MetaTransaction.sol"; 9 | import "./ISolarRouter.sol"; 10 | import "./IToken.sol"; 11 | 12 | contract MockRouter { 13 | function swapExactTokensForETH( 14 | uint256, 15 | uint256, 16 | address[] calldata, 17 | address, 18 | uint256 19 | ) external virtual returns (uint256[] memory amounts) { 20 | amounts = new uint256[](1); 21 | amounts[0] = 0; 22 | return amounts; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /contracts/uniswapv2/libraries/UQ112x112.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity =0.6.12; 3 | 4 | // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format)) 5 | 6 | // range: [0, 2**112 - 1] 7 | // resolution: 1 / 2**112 8 | 9 | library UQ112x112 { 10 | uint224 constant Q112 = 2**112; 11 | 12 | // encode a uint112 as a UQ112x112 13 | function encode(uint112 y) internal pure returns (uint224 z) { 14 | z = uint224(y) * Q112; // never overflows 15 | } 16 | 17 | // divide a UQ112x112 by a uint112, returning a UQ112x112 18 | function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) { 19 | z = x / uint224(y); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /contracts/mock/MockERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.2; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 5 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 6 | import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol"; 7 | 8 | contract MockERC20 is ERC20, ERC20Permit { 9 | using SafeERC20 for IERC20; 10 | 11 | constructor( 12 | string memory name, 13 | string memory symbol, 14 | uint256 totalSupply 15 | ) ERC20(name, symbol) ERC20Permit(name) { 16 | _mint(msg.sender, totalSupply); 17 | } 18 | 19 | function mint(address _who, uint256 _amount) public { 20 | _mint(_who, _amount); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /contracts/uniswapv2/libraries/SafeMath.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity =0.6.12; 3 | 4 | // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) 5 | 6 | library SafeMathSolar { 7 | function add(uint256 x, uint256 y) internal pure returns (uint256 z) { 8 | require((z = x + y) >= x, "ds-math-add-overflow"); 9 | } 10 | 11 | function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { 12 | require((z = x - y) <= x, "ds-math-sub-underflow"); 13 | } 14 | 15 | function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { 16 | require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /contracts/uniswapv2/libraries/Math.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity =0.6.12; 3 | 4 | // a library for performing various math operations 5 | 6 | library Math { 7 | function min(uint256 x, uint256 y) internal pure returns (uint256 z) { 8 | z = x < y ? x : y; 9 | } 10 | 11 | // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) 12 | function sqrt(uint256 y) internal pure returns (uint256 z) { 13 | if (y > 3) { 14 | z = y; 15 | uint256 x = y / 2 + 1; 16 | while (x < z) { 17 | z = x; 18 | x = (y / x + x) / 2; 19 | } 20 | } else if (y != 0) { 21 | z = 1; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /contracts/eclipse/amaraV2/ICommonEclipseAmaraV2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.7; 3 | 4 | /** @title ICommonEclipse 5 | * @notice It is an interface for CommonEclipse.sol 6 | */ 7 | abstract contract ICommonEclipseAmaraV2 { 8 | enum WITHDRAW_TYPE { 9 | RAISING, 10 | TAX 11 | } 12 | 13 | enum HARVEST_TYPE { 14 | TIMESTAMP, 15 | PERCENT 16 | } 17 | 18 | /** 19 | * @notice External view function to see user offering and refunding amounts for both pools 20 | * @param _user: user address 21 | * @param _pids: array of pids 22 | */ 23 | function viewUserOfferingAndRefundingAmountsForPools( 24 | address _user, 25 | uint8[] calldata _pids 26 | ) external view virtual returns (uint256[3][] memory); 27 | } 28 | -------------------------------------------------------------------------------- /contracts/fee/interfaces/ISmartRouter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.2; 3 | 4 | interface ISmartRouter { 5 | enum InputType { 6 | AMOUNT_IN, 7 | AMOUNT_OUT 8 | } 9 | 10 | struct FormattedOffer { 11 | uint256[] amounts; 12 | address[] adapters; 13 | address[] path; 14 | string[] tokens; 15 | } 16 | 17 | struct Trade { 18 | uint256[] amounts; 19 | address[] path; 20 | address[] adapters; 21 | } 22 | 23 | function findBestPath( 24 | uint256 _amount, 25 | address _tokenIn, 26 | address _tokenOut, 27 | uint256 _maxSteps, 28 | InputType _inputType 29 | ) external view returns (FormattedOffer memory); 30 | 31 | function swapNoSplit( 32 | Trade memory _trade, 33 | address _to, 34 | uint256 _fee 35 | ) external; 36 | } 37 | -------------------------------------------------------------------------------- /contracts/uniswapv2/interfaces/IERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity =0.6.12; 3 | 4 | interface IERC20Solar { 5 | event Approval(address indexed owner, address indexed spender, uint value); 6 | event Transfer(address indexed from, address indexed to, uint value); 7 | 8 | function name() external view returns (string memory); 9 | function symbol() external view returns (string memory); 10 | function decimals() external view returns (uint8); 11 | function totalSupply() external view returns (uint); 12 | function balanceOf(address owner) external view returns (uint); 13 | function allowance(address owner, address spender) external view returns (uint); 14 | 15 | function approve(address spender, uint value) external returns (bool); 16 | function transfer(address to, uint value) external returns (bool); 17 | function transferFrom(address from, address to, uint value) external returns (bool); 18 | } 19 | -------------------------------------------------------------------------------- /contracts/fee/interfaces/ISolarFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.2; 3 | 4 | interface ISolarFactory { 5 | event PairCreated(address indexed token0, address indexed token1, address pair, uint); 6 | 7 | function feeTo() external view returns (address); 8 | function feeToSetter() external view returns (address); 9 | function migrator() external view returns (address); 10 | function auro() external view returns (address); 11 | 12 | function getPair(address tokenA, address tokenB) external view returns (address pair); 13 | function allPairs(uint) external view returns (address pair); 14 | function allPairsLength() external view returns (uint); 15 | 16 | function createPair(address tokenA, address tokenB) external returns (address pair); 17 | 18 | function setFeeTo(address) external; 19 | function setFeeToSetter(address) external; 20 | function setMigrator(address) external; 21 | function setAuroAddress(address) external; 22 | } 23 | -------------------------------------------------------------------------------- /contracts/burner/interfaces/ISolarFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.2; 3 | 4 | interface ISolarFactory { 5 | event PairCreated(address indexed token0, address indexed token1, address pair, uint); 6 | 7 | function feeTo() external view returns (address); 8 | function feeToSetter() external view returns (address); 9 | function migrator() external view returns (address); 10 | function auro() external view returns (address); 11 | 12 | function getPair(address tokenA, address tokenB) external view returns (address pair); 13 | function allPairs(uint) external view returns (address pair); 14 | function allPairsLength() external view returns (uint); 15 | 16 | function createPair(address tokenA, address tokenB) external returns (address pair); 17 | 18 | function setFeeTo(address) external; 19 | function setFeeToSetter(address) external; 20 | function setMigrator(address) external; 21 | function setAuroAddress(address) external; 22 | } 23 | -------------------------------------------------------------------------------- /contracts/libraries/IBoringERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.7; 3 | 4 | interface IBoringERC20 { 5 | function mint(address to, uint256 amount) external; 6 | 7 | function totalSupply() external view returns (uint256); 8 | 9 | function balanceOf(address account) external view returns (uint256); 10 | 11 | function allowance(address owner, address spender) 12 | external 13 | view 14 | returns (uint256); 15 | 16 | function approve(address spender, uint256 amount) external returns (bool); 17 | 18 | event Transfer(address indexed from, address indexed to, uint256 value); 19 | event Approval( 20 | address indexed owner, 21 | address indexed spender, 22 | uint256 value 23 | ); 24 | 25 | /// @notice EIP 2612 26 | function permit( 27 | address owner, 28 | address spender, 29 | uint256 value, 30 | uint256 deadline, 31 | uint8 v, 32 | bytes32 r, 33 | bytes32 s 34 | ) external; 35 | } 36 | -------------------------------------------------------------------------------- /contracts/farm/v2/libraries/IBoringERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.7; 3 | 4 | interface IBoringERC20 { 5 | function mint(address to, uint256 amount) external; 6 | 7 | function totalSupply() external view returns (uint256); 8 | 9 | function balanceOf(address account) external view returns (uint256); 10 | 11 | function allowance(address owner, address spender) 12 | external 13 | view 14 | returns (uint256); 15 | 16 | function approve(address spender, uint256 amount) external returns (bool); 17 | 18 | event Transfer(address indexed from, address indexed to, uint256 value); 19 | event Approval( 20 | address indexed owner, 21 | address indexed spender, 22 | uint256 value 23 | ); 24 | 25 | /// @notice EIP 2612 26 | function permit( 27 | address owner, 28 | address spender, 29 | uint256 value, 30 | uint256 deadline, 31 | uint8 v, 32 | bytes32 r, 33 | bytes32 s 34 | ) external; 35 | } 36 | -------------------------------------------------------------------------------- /contracts/uniswapv2/interfaces/ISolarFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity =0.6.12; 3 | 4 | interface ISolarFactory { 5 | event PairCreated( 6 | address indexed token0, 7 | address indexed token1, 8 | address pair, 9 | uint256 10 | ); 11 | 12 | function feeTo() external view returns (address); 13 | 14 | function feeToSetter() external view returns (address); 15 | 16 | function migrator() external view returns (address); 17 | 18 | function getPair(address tokenA, address tokenB) 19 | external 20 | view 21 | returns (address pair); 22 | 23 | function allPairs(uint256) external view returns (address pair); 24 | 25 | function allPairsLength() external view returns (uint256); 26 | 27 | function createPair(address tokenA, address tokenB) 28 | external 29 | returns (address pair); 30 | 31 | function setFeeTo(address) external; 32 | 33 | function setFeeToSetter(address) external; 34 | 35 | function setMigrator(address) external; 36 | } 37 | -------------------------------------------------------------------------------- /contracts/burner/interfaces/ISolarERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.2; 3 | 4 | interface ISolarERC20 { 5 | event Approval(address indexed owner, address indexed spender, uint value); 6 | event Transfer(address indexed from, address indexed to, uint value); 7 | 8 | function name() external pure returns (string memory); 9 | function symbol() external pure returns (string memory); 10 | function decimals() external pure returns (uint8); 11 | function totalSupply() external view returns (uint); 12 | function balanceOf(address owner) external view returns (uint); 13 | function allowance(address owner, address spender) external view returns (uint); 14 | 15 | function approve(address spender, uint value) external returns (bool); 16 | function transfer(address to, uint value) external returns (bool); 17 | function transferFrom(address from, address to, uint value) external returns (bool); 18 | 19 | function DOMAIN_SEPARATOR() external view returns (bytes32); 20 | function PERMIT_TYPEHASH() external pure returns (bytes32); 21 | function nonces(address owner) external view returns (uint); 22 | 23 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; 24 | } -------------------------------------------------------------------------------- /contracts/fee/interfaces/ISolarERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.2; 3 | 4 | interface ISolarERC20 { 5 | event Approval(address indexed owner, address indexed spender, uint value); 6 | event Transfer(address indexed from, address indexed to, uint value); 7 | 8 | function name() external pure returns (string memory); 9 | function symbol() external pure returns (string memory); 10 | function decimals() external pure returns (uint8); 11 | function totalSupply() external view returns (uint); 12 | function balanceOf(address owner) external view returns (uint); 13 | function allowance(address owner, address spender) external view returns (uint); 14 | 15 | function approve(address spender, uint value) external returns (bool); 16 | function transfer(address to, uint value) external returns (bool); 17 | function transferFrom(address from, address to, uint value) external returns (bool); 18 | 19 | function DOMAIN_SEPARATOR() external view returns (bytes32); 20 | function PERMIT_TYPEHASH() external pure returns (bytes32); 21 | function nonces(address owner) external view returns (uint); 22 | 23 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; 24 | } -------------------------------------------------------------------------------- /contracts/uniswapv2/interfaces/ISolarERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity =0.6.12; 3 | 4 | interface ISolarERC20 { 5 | event Approval(address indexed owner, address indexed spender, uint value); 6 | event Transfer(address indexed from, address indexed to, uint value); 7 | 8 | function name() external pure returns (string memory); 9 | function symbol() external pure returns (string memory); 10 | function decimals() external pure returns (uint8); 11 | function totalSupply() external view returns (uint); 12 | function balanceOf(address owner) external view returns (uint); 13 | function allowance(address owner, address spender) external view returns (uint); 14 | 15 | function approve(address spender, uint value) external returns (bool); 16 | function transfer(address to, uint value) external returns (bool); 17 | function transferFrom(address from, address to, uint value) external returns (bool); 18 | 19 | function DOMAIN_SEPARATOR() external view returns (bytes32); 20 | function PERMIT_TYPEHASH() external pure returns (bytes32); 21 | function nonces(address owner) external view returns (uint); 22 | 23 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; 24 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "solarbeam-contracts", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "test": "hardhat test", 8 | "test:coverage": "cross-env NODE_OPTIONS=\"--max-old-space-size=2048\" hardhat coverage", 9 | "test:gas": "cross-env REPORT_GAS=true yarn test" 10 | }, 11 | "devDependencies": { 12 | "@boringcrypto/boring-solidity": "git+https://github.com/boringcrypto/BoringSolidity.git", 13 | "@nomiclabs/hardhat-ethers": "^2.0.2", 14 | "@nomiclabs/hardhat-etherscan": "^3.0.1", 15 | "@nomiclabs/hardhat-waffle": "^2.0.1", 16 | "@openzeppelin/contracts": "^4.2.0", 17 | "@types/mocha": "^8.2.1", 18 | "@types/node": "^14.14.31", 19 | "chai": "^4.3.4", 20 | "dotenv": "^10.0.0", 21 | "ethereum-waffle": "^3.4.0", 22 | "ethers": "^5.4.6", 23 | "hardhat": "^2.5.0", 24 | "hardhat-deploy": "^0.8.11", 25 | "hardhat-deploy-ethers": "^0.3.0-beta.10" 26 | }, 27 | "dependencies": { 28 | "@openzeppelin/contracts-upgradeable": "^4.4.2", 29 | "axios": "^0.24.0", 30 | "csv-writer": "^1.6.0", 31 | "ethereumjs-util": "^7.1.3", 32 | "lodash": "^4.17.21", 33 | "moment": "^2.29.1" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /contracts/fee/interfaces/ISolarRouter02.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.2; 3 | import "./ISolarRouter01.sol"; 4 | 5 | interface ISolarRouter02 is ISolarRouter01 { 6 | function removeLiquidityETHSupportingFeeOnTransferTokens( 7 | address token, 8 | uint256 liquidity, 9 | uint256 amountTokenMin, 10 | uint256 amountETHMin, 11 | address to, 12 | uint256 deadline 13 | ) external returns (uint256 amountETH); 14 | 15 | function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( 16 | address token, 17 | uint256 liquidity, 18 | uint256 amountTokenMin, 19 | uint256 amountETHMin, 20 | address to, 21 | uint256 deadline, 22 | bool approveMax, 23 | uint8 v, 24 | bytes32 r, 25 | bytes32 s 26 | ) external returns (uint256 amountETH); 27 | 28 | function swapExactTokensForTokensSupportingFeeOnTransferTokens( 29 | uint256 amountIn, 30 | uint256 amountOutMin, 31 | address[] calldata path, 32 | address to, 33 | uint256 deadline 34 | ) external; 35 | 36 | function swapExactETHForTokensSupportingFeeOnTransferTokens( 37 | uint256 amountOutMin, 38 | address[] calldata path, 39 | address to, 40 | uint256 deadline 41 | ) external payable; 42 | 43 | function swapExactTokensForETHSupportingFeeOnTransferTokens( 44 | uint256 amountIn, 45 | uint256 amountOutMin, 46 | address[] calldata path, 47 | address to, 48 | uint256 deadline 49 | ) external; 50 | } 51 | -------------------------------------------------------------------------------- /contracts/uniswapv2/interfaces/ISolarRouter02.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity =0.6.12; 3 | 4 | import "./ISolarRouter01.sol"; 5 | 6 | interface ISolarRouter02 is ISolarRouter01 { 7 | function removeLiquidityETHSupportingFeeOnTransferTokens( 8 | address token, 9 | uint256 liquidity, 10 | uint256 amountTokenMin, 11 | uint256 amountETHMin, 12 | address to, 13 | uint256 deadline 14 | ) external returns (uint256 amountETH); 15 | 16 | function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( 17 | address token, 18 | uint256 liquidity, 19 | uint256 amountTokenMin, 20 | uint256 amountETHMin, 21 | address to, 22 | uint256 deadline, 23 | bool approveMax, 24 | uint8 v, 25 | bytes32 r, 26 | bytes32 s 27 | ) external returns (uint256 amountETH); 28 | 29 | function swapExactTokensForTokensSupportingFeeOnTransferTokens( 30 | uint256 amountIn, 31 | uint256 amountOutMin, 32 | address[] calldata path, 33 | address to, 34 | uint256 deadline 35 | ) external; 36 | 37 | function swapExactETHForTokensSupportingFeeOnTransferTokens( 38 | uint256 amountOutMin, 39 | address[] calldata path, 40 | address to, 41 | uint256 deadline 42 | ) external payable; 43 | 44 | function swapExactTokensForETHSupportingFeeOnTransferTokens( 45 | uint256 amountIn, 46 | uint256 amountOutMin, 47 | address[] calldata path, 48 | address to, 49 | uint256 deadline 50 | ) external; 51 | } 52 | -------------------------------------------------------------------------------- /contracts/gasless/EIP712Base.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.7; 3 | 4 | contract EIP712Base { 5 | struct EIP712Domain { 6 | string name; 7 | string version; 8 | address verifyingContract; 9 | bytes32 salt; 10 | } 11 | 12 | bytes32 internal constant EIP712_DOMAIN_TYPEHASH = 13 | keccak256( 14 | bytes( 15 | "EIP712Domain(string name,string version,address verifyingContract,bytes32 salt)" 16 | ) 17 | ); 18 | 19 | bytes32 internal domainSeparator; 20 | 21 | constructor(string memory name, string memory version) { 22 | domainSeparator = keccak256( 23 | abi.encode( 24 | EIP712_DOMAIN_TYPEHASH, 25 | keccak256(bytes(name)), 26 | keccak256(bytes(version)), 27 | address(this), 28 | bytes32(getChainID()) 29 | ) 30 | ); 31 | } 32 | 33 | function getChainID() internal view returns (uint256 id) { 34 | assembly { 35 | id := chainid() 36 | } 37 | } 38 | 39 | function getDomainSeparator() private view returns (bytes32) { 40 | return domainSeparator; 41 | } 42 | 43 | /** 44 | * Accept message hash and returns hash message in EIP712 compatible form 45 | * So that it can be used to recover signer from signature signed using EIP712 formatted data 46 | * https://eips.ethereum.org/EIPS/eip-712 47 | * "\\x19" makes the encoding deterministic 48 | * "\\x01" is the version byte to make it compatible to EIP-191 49 | */ 50 | function toTypedMessageHash(bytes32 messageHash) 51 | internal 52 | view 53 | returns (bytes32) 54 | { 55 | return 56 | keccak256( 57 | abi.encodePacked("\x19\x01", getDomainSeparator(), messageHash) 58 | ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /test/utils/time.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require("hardhat"); 2 | const { BigNumber } = ethers; 3 | 4 | const disableAutomine = async function () { 5 | return ethers.provider.send("evm_setAutomine", [false]); 6 | }; 7 | 8 | const advanceBlock = async function () { 9 | return ethers.provider.send("evm_mine", []); 10 | }; 11 | 12 | const advanceBlockTo = async function (blockNumber) { 13 | for (let i = await ethers.provider.getBlockNumber(); i < blockNumber; i++) { 14 | await advanceBlock(); 15 | } 16 | }; 17 | 18 | const increase = async function (value) { 19 | await ethers.provider.send("evm_increaseTime", [value.toNumber()]); 20 | await advanceBlock(); 21 | }; 22 | 23 | const latest = async function () { 24 | const block = await ethers.provider.getBlock("latest"); 25 | return BigNumber.from(block.timestamp); 26 | }; 27 | 28 | const advanceTimeAndBlock = async function (time) { 29 | await advanceTime(time); 30 | await advanceBlock(); 31 | }; 32 | 33 | const advanceTime = async function (time) { 34 | await ethers.provider.send("evm_increaseTime", [time]); 35 | }; 36 | 37 | const duration = { 38 | seconds: function (val) { 39 | return BigNumber.from(val); 40 | }, 41 | minutes: function (val) { 42 | return BigNumber.from(val).mul(this.seconds("60")); 43 | }, 44 | hours: function (val) { 45 | return BigNumber.from(val).mul(this.minutes("60")); 46 | }, 47 | days: function (val) { 48 | return BigNumber.from(val).mul(this.hours("24")); 49 | }, 50 | weeks: function (val) { 51 | return BigNumber.from(val).mul(this.days("7")); 52 | }, 53 | years: function (val) { 54 | return BigNumber.from(val).mul(this.days("365")); 55 | }, 56 | }; 57 | 58 | module.exports = { 59 | advanceBlock, 60 | advanceBlockTo, 61 | increase, 62 | latest, 63 | advanceTimeAndBlock, 64 | advanceTime, 65 | disableAutomine, 66 | }; 67 | -------------------------------------------------------------------------------- /contracts/uniswapv2/libraries/TransferHelper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity =0.6.12; 3 | 4 | // helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false 5 | library TransferHelper { 6 | function safeApprove( 7 | address token, 8 | address to, 9 | uint256 value 10 | ) internal { 11 | // bytes4(keccak256(bytes('approve(address,uint256)'))); 12 | (bool success, bytes memory data) = token.call( 13 | abi.encodeWithSelector(0x095ea7b3, to, value) 14 | ); 15 | require( 16 | success && (data.length == 0 || abi.decode(data, (bool))), 17 | "TransferHelper: APPROVE_FAILED" 18 | ); 19 | } 20 | 21 | function safeTransfer( 22 | address token, 23 | address to, 24 | uint256 value 25 | ) internal { 26 | // bytes4(keccak256(bytes('transfer(address,uint256)'))); 27 | (bool success, bytes memory data) = token.call( 28 | abi.encodeWithSelector(0xa9059cbb, to, value) 29 | ); 30 | require( 31 | success && (data.length == 0 || abi.decode(data, (bool))), 32 | "TransferHelper: TRANSFER_FAILED" 33 | ); 34 | } 35 | 36 | function safeTransferFrom( 37 | address token, 38 | address from, 39 | address to, 40 | uint256 value 41 | ) internal { 42 | // bytes4(keccak256(bytes('transferFrom(address,address,uint256)'))); 43 | (bool success, bytes memory data) = token.call( 44 | abi.encodeWithSelector(0x23b872dd, from, to, value) 45 | ); 46 | require( 47 | success && (data.length == 0 || abi.decode(data, (bool))), 48 | "TransferHelper: TRANSFER_FROM_FAILED" 49 | ); 50 | } 51 | 52 | function safeTransferETH(address to, uint256 value) internal { 53 | (bool success, ) = to.call{value: value}(new bytes(0)); 54 | require(success, "TransferHelper: ETH_TRANSFER_FAILED"); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /contracts/nft/NFTClaim.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.2; 3 | 4 | import "@openzeppelin/contracts/access/Ownable.sol"; 5 | import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; 6 | import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; 7 | import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; 8 | 9 | library Errors { 10 | string constant C1 = 11 | "whitelist::whitelist length must be equal as amount length"; 12 | } 13 | 14 | contract NFTClaim is Ownable, ReentrancyGuard { 15 | // Info of each user for each pool. 16 | struct UserInfo { 17 | bool claimed; 18 | uint256 amount; 19 | } 20 | 21 | // Info of each pool. 22 | struct CampaignInfo { 23 | IERC721 nft; 24 | } 25 | 26 | // userInfo[_campaignId][_who] 27 | mapping(uint256 => mapping(address => UserInfo)) public userInfo; 28 | 29 | // mapping to keep track of nft rewards for sweep function 30 | mapping(address => bool) public nft; 31 | 32 | // CampainInfo[_campaignId]; 33 | CampaignInfo[] public campaignInfo; 34 | 35 | event AddCampaignInfo(uint256 indexed campaignID, IERC721 nft); 36 | event Whitelist( 37 | uint256 indexed campaignID, 38 | address indexed user, 39 | uint256 indexed amount 40 | ); 41 | event Claim(address indexed user, uint256 indexed campaignID); 42 | event AdminRecovery(address indexed nftAddress, uint256 amount); 43 | 44 | function addCampaignInfo(IERC721 _nft) external onlyOwner { 45 | campaignInfo.push(CampaignInfo({nft: _nft})); 46 | nft[address(_nft)] = true; 47 | emit AddCampaignInfo(campaignInfo.length - 1, _nft); 48 | } 49 | 50 | function campaignInfoLen() external view returns (uint256) { 51 | return campaignInfo.length; 52 | } 53 | 54 | function whitelist( 55 | uint256 _campaignID, 56 | address[] calldata _whitelist, 57 | uint256[] calldata _amount 58 | ) external onlyOwner { 59 | require(_whitelist.length == _amount.length, Errors.C1); 60 | 61 | for (uint256 i = 0; i < _whitelist.length; i++) { 62 | UserInfo storage user = userInfo[_campaignID][_whitelist[i]]; 63 | user.amount = _amount[i]; 64 | user.claimed = false; 65 | emit Whitelist(_campaignID, _whitelist[i], _amount[i]); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /test/utils/index.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require("hardhat"); 2 | const { BigNumber } = require("ethers"); 3 | 4 | const BASE_TEN = 10; 5 | const ADDRESS_ZERO = "0x0000000000000000000000000000000000000000"; 6 | 7 | const encodeParameters = function (types, values) { 8 | const abi = new ethers.utils.AbiCoder(); 9 | return abi.encode(types, values); 10 | }; 11 | 12 | const prepare = async function (thisObject, contracts) { 13 | for (let i in contracts) { 14 | let contract = contracts[i]; 15 | thisObject[contract] = await ethers.getContractFactory(contract); 16 | } 17 | thisObject.signers = await ethers.getSigners(); 18 | thisObject.alice = thisObject.signers[0]; 19 | thisObject.bob = thisObject.signers[1]; 20 | thisObject.carol = thisObject.signers[2]; 21 | thisObject.dev = thisObject.signers[3]; 22 | thisObject.alicePrivateKey = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"; 23 | thisObject.bobPrivateKey = "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"; 24 | thisObject.carolPrivateKey = "0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a"; 25 | }; 26 | const deploy = async function (thisObject, contracts) { 27 | for (let i in contracts) { 28 | let contract = contracts[i]; 29 | thisObject[contract[0]] = await contract[1].deploy(...(contract[2] || [])); 30 | await thisObject[contract[0]].deployed(); 31 | } 32 | }; 33 | const createSLP = async function (thisObject, name, tokenA, tokenB, amount) { 34 | const createPairTx = await thisObject.factory.createPair(tokenA.address, tokenB.address); 35 | 36 | const _pair = (await createPairTx.wait()).events[0].args.pair; 37 | 38 | thisObject[name] = await thisObject.JoePair.attach(_pair); 39 | 40 | await tokenA.transfer(thisObject[name].address, amount); 41 | await tokenB.transfer(thisObject[name].address, amount); 42 | 43 | await thisObject[name].mint(thisObject.alice.address); 44 | }; 45 | 46 | // Defaults to e18 using amount * 10^18 47 | const getBigNumber = function (amount, decimals = 18) { 48 | return BigNumber.from(amount).mul(BigNumber.from(BASE_TEN).pow(decimals)); 49 | }; 50 | 51 | const timeFunctions = require("./time"); 52 | 53 | module.exports = { 54 | ...timeFunctions, 55 | getBigNumber, 56 | createSLP, 57 | deploy, 58 | prepare, 59 | encodeParameters, 60 | BASE_TEN, 61 | ADDRESS_ZERO, 62 | }; 63 | -------------------------------------------------------------------------------- /contracts/uniswapv2/interfaces/ISolarPair.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity =0.6.12; 3 | 4 | interface ISolarPair { 5 | event Approval(address indexed owner, address indexed spender, uint value); 6 | event Transfer(address indexed from, address indexed to, uint value); 7 | 8 | function name() external pure returns (string memory); 9 | function symbol() external pure returns (string memory); 10 | function decimals() external pure returns (uint8); 11 | function totalSupply() external view returns (uint); 12 | function balanceOf(address owner) external view returns (uint); 13 | function allowance(address owner, address spender) external view returns (uint); 14 | 15 | function approve(address spender, uint value) external returns (bool); 16 | function transfer(address to, uint value) external returns (bool); 17 | function transferFrom(address from, address to, uint value) external returns (bool); 18 | 19 | function DOMAIN_SEPARATOR() external view returns (bytes32); 20 | function PERMIT_TYPEHASH() external pure returns (bytes32); 21 | function nonces(address owner) external view returns (uint); 22 | 23 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; 24 | 25 | event Mint(address indexed sender, uint amount0, uint amount1); 26 | event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); 27 | event Swap( 28 | address indexed sender, 29 | uint amount0In, 30 | uint amount1In, 31 | uint amount0Out, 32 | uint amount1Out, 33 | address indexed to 34 | ); 35 | event Sync(uint112 reserve0, uint112 reserve1); 36 | 37 | function MINIMUM_LIQUIDITY() external pure returns (uint); 38 | function factory() external view returns (address); 39 | function token0() external view returns (address); 40 | function token1() external view returns (address); 41 | function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); 42 | function price0CumulativeLast() external view returns (uint); 43 | function price1CumulativeLast() external view returns (uint); 44 | function kLast() external view returns (uint); 45 | 46 | function mint(address to) external returns (uint liquidity); 47 | function burn(address to) external returns (uint amount0, uint amount1); 48 | function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; 49 | function skim(address to) external; 50 | function sync() external; 51 | 52 | function initialize(address, address) external; 53 | } -------------------------------------------------------------------------------- /contracts/uniswapv2/SolarFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity =0.6.12; 3 | 4 | import "./interfaces/ISolarFactory.sol"; 5 | import "./SolarPair.sol"; 6 | 7 | contract SolarFactory is ISolarFactory { 8 | bytes32 public constant INIT_CODE_PAIR_HASH = 9 | keccak256(abi.encodePacked(type(SolarPair).creationCode)); 10 | 11 | address public override feeTo; 12 | address public override feeToSetter; 13 | address public override migrator; 14 | 15 | mapping(address => mapping(address => address)) public override getPair; 16 | address[] public override allPairs; 17 | 18 | event PairCreated( 19 | address indexed token0, 20 | address indexed token1, 21 | address pair, 22 | uint256 23 | ); 24 | 25 | constructor(address _feeToSetter) public { 26 | feeToSetter = _feeToSetter; 27 | } 28 | 29 | function allPairsLength() external view override returns (uint256) { 30 | return allPairs.length; 31 | } 32 | 33 | function createPair(address tokenA, address tokenB) 34 | external 35 | override 36 | returns (address pair) 37 | { 38 | require(tokenA != tokenB, "SolarBeam: IDENTICAL_ADDRESSES"); 39 | (address token0, address token1) = tokenA < tokenB 40 | ? (tokenA, tokenB) 41 | : (tokenB, tokenA); 42 | require(token0 != address(0), "SolarBeam: ZERO_ADDRESS"); 43 | require( 44 | getPair[token0][token1] == address(0), 45 | "SolarBeam: PAIR_EXISTS" 46 | ); // single check is sufficient 47 | bytes memory bytecode = type(SolarPair).creationCode; 48 | bytes32 salt = keccak256(abi.encodePacked(token0, token1)); 49 | assembly { 50 | pair := create2(0, add(bytecode, 32), mload(bytecode), salt) 51 | } 52 | SolarPair(pair).initialize(token0, token1); 53 | getPair[token0][token1] = pair; 54 | getPair[token1][token0] = pair; // populate mapping in the reverse direction 55 | allPairs.push(pair); 56 | emit PairCreated(token0, token1, pair, allPairs.length); 57 | } 58 | 59 | function setFeeTo(address _feeTo) external override { 60 | require(msg.sender == feeToSetter, "SolarBeam: FORBIDDEN"); 61 | feeTo = _feeTo; 62 | } 63 | 64 | function setMigrator(address _migrator) external override { 65 | require(msg.sender == feeToSetter, "SolarBeam: FORBIDDEN"); 66 | migrator = _migrator; 67 | } 68 | 69 | function setFeeToSetter(address _feeToSetter) external override { 70 | require(msg.sender == feeToSetter, "SolarBeam: FORBIDDEN"); 71 | feeToSetter = _feeToSetter; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /contracts/forwarder/IForwarder.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity ^0.8.2; 3 | pragma abicoder v2; 4 | 5 | interface IForwarder { 6 | 7 | struct ForwardRequest { 8 | address from; 9 | address to; 10 | uint256 value; 11 | uint256 gas; 12 | uint256 nonce; 13 | bytes data; 14 | uint256 validUntil; 15 | } 16 | 17 | event DomainRegistered(bytes32 indexed domainSeparator, bytes domainValue); 18 | 19 | event RequestTypeRegistered(bytes32 indexed typeHash, string typeStr); 20 | 21 | function getNonce(address from) 22 | external view 23 | returns(uint256); 24 | 25 | /** 26 | * verify the transaction would execute. 27 | * validate the signature and the nonce of the request. 28 | * revert if either signature or nonce are incorrect. 29 | * also revert if domainSeparator or requestTypeHash are not registered. 30 | */ 31 | function verify( 32 | ForwardRequest calldata forwardRequest, 33 | bytes32 domainSeparator, 34 | bytes32 requestTypeHash, 35 | bytes calldata suffixData, 36 | bytes calldata signature 37 | ) external view; 38 | 39 | /** 40 | * execute a transaction 41 | * @param forwardRequest - all transaction parameters 42 | * @param domainSeparator - domain used when signing this request 43 | * @param requestTypeHash - request type used when signing this request. 44 | * @param suffixData - the extension data used when signing this request. 45 | * @param signature - signature to validate. 46 | * 47 | * the transaction is verified, and then executed. 48 | * the success and ret of "call" are returned. 49 | * This method would revert only verification errors. target errors 50 | * are reported using the returned "success" and ret string 51 | */ 52 | function execute( 53 | ForwardRequest calldata forwardRequest, 54 | bytes32 domainSeparator, 55 | bytes32 requestTypeHash, 56 | bytes calldata suffixData, 57 | bytes calldata signature 58 | ) 59 | external payable 60 | returns (bool success, bytes memory ret); 61 | 62 | /** 63 | * Register a new Request typehash. 64 | * @param typeName - the name of the request type. 65 | * @param typeSuffix - any extra data after the generic params. 66 | * (must add at least one param. The generic ForwardRequest type is always registered by the constructor) 67 | */ 68 | function registerRequestType(string calldata typeName, string calldata typeSuffix) external; 69 | 70 | /** 71 | * Register a new domain separator. 72 | * The domain separator must have the following fields: name,version,chainId, verifyingContract. 73 | * the chainId is the current network's chainId, and the verifyingContract is this forwarder. 74 | * This method is given the domain name and version to create and register the domain separator value. 75 | * @param name the domain's display name 76 | * @param version the domain/protocol version 77 | */ 78 | function registerDomainSeparator(string calldata name, string calldata version) external; 79 | } -------------------------------------------------------------------------------- /contracts/helpers/Multicall2.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: UNLICENSED 2 | pragma solidity >=0.5.0; 3 | pragma experimental ABIEncoderV2; 4 | 5 | /// @title Multicall2 - Aggregate results from multiple read-only function calls 6 | /// @author Michael Elliot 7 | /// @author Joshua Levine 8 | /// @author Nick Johnson 9 | 10 | contract Multicall2 { 11 | struct Call { 12 | address target; 13 | bytes callData; 14 | } 15 | struct Result { 16 | bool success; 17 | bytes returnData; 18 | } 19 | 20 | function aggregate(Call[] memory calls) public returns (uint256 blockNumber, bytes[] memory returnData) { 21 | blockNumber = block.number; 22 | returnData = new bytes[](calls.length); 23 | for(uint256 i = 0; i < calls.length; i++) { 24 | (bool success, bytes memory ret) = calls[i].target.call(calls[i].callData); 25 | require(success, "Multicall aggregate: call failed"); 26 | returnData[i] = ret; 27 | } 28 | } 29 | function blockAndAggregate(Call[] memory calls) public returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData) { 30 | (blockNumber, blockHash, returnData) = tryBlockAndAggregate(true, calls); 31 | } 32 | function getBlockHash(uint256 blockNumber) public view returns (bytes32 blockHash) { 33 | blockHash = blockhash(blockNumber); 34 | } 35 | function getBlockNumber() public view returns (uint256 blockNumber) { 36 | blockNumber = block.number; 37 | } 38 | function getCurrentBlockCoinbase() public view returns (address coinbase) { 39 | coinbase = block.coinbase; 40 | } 41 | function getCurrentBlockDifficulty() public view returns (uint256 difficulty) { 42 | difficulty = block.difficulty; 43 | } 44 | function getCurrentBlockGasLimit() public view returns (uint256 gaslimit) { 45 | gaslimit = block.gaslimit; 46 | } 47 | function getCurrentBlockTimestamp() public view returns (uint256 timestamp) { 48 | timestamp = block.timestamp; 49 | } 50 | function getEthBalance(address addr) public view returns (uint256 balance) { 51 | balance = addr.balance; 52 | } 53 | function getLastBlockHash() public view returns (bytes32 blockHash) { 54 | blockHash = blockhash(block.number - 1); 55 | } 56 | function tryAggregate(bool requireSuccess, Call[] memory calls) public returns (Result[] memory returnData) { 57 | returnData = new Result[](calls.length); 58 | for(uint256 i = 0; i < calls.length; i++) { 59 | (bool success, bytes memory ret) = calls[i].target.call(calls[i].callData); 60 | 61 | if (requireSuccess) { 62 | require(success, "Multicall2 aggregate: call failed"); 63 | } 64 | 65 | returnData[i] = Result(success, ret); 66 | } 67 | } 68 | function tryBlockAndAggregate(bool requireSuccess, Call[] memory calls) public returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData) { 69 | blockNumber = block.number; 70 | blockHash = blockhash(block.number); 71 | returnData = tryAggregate(requireSuccess, calls); 72 | } 73 | } -------------------------------------------------------------------------------- /flatten/MulticallFlatten.sol: -------------------------------------------------------------------------------- 1 | 2 | // File contracts/helpers/Multicall2.sol 3 | 4 | pragma solidity >=0.5.0; 5 | pragma experimental ABIEncoderV2; 6 | 7 | /// @title Multicall2 - Aggregate results from multiple read-only function calls 8 | /// @author Michael Elliot 9 | /// @author Joshua Levine 10 | /// @author Nick Johnson 11 | 12 | contract Multicall2 { 13 | struct Call { 14 | address target; 15 | bytes callData; 16 | } 17 | struct Result { 18 | bool success; 19 | bytes returnData; 20 | } 21 | 22 | function aggregate(Call[] memory calls) public returns (uint256 blockNumber, bytes[] memory returnData) { 23 | blockNumber = block.number; 24 | returnData = new bytes[](calls.length); 25 | for(uint256 i = 0; i < calls.length; i++) { 26 | (bool success, bytes memory ret) = calls[i].target.call(calls[i].callData); 27 | require(success, "Multicall aggregate: call failed"); 28 | returnData[i] = ret; 29 | } 30 | } 31 | function blockAndAggregate(Call[] memory calls) public returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData) { 32 | (blockNumber, blockHash, returnData) = tryBlockAndAggregate(true, calls); 33 | } 34 | function getBlockHash(uint256 blockNumber) public view returns (bytes32 blockHash) { 35 | blockHash = blockhash(blockNumber); 36 | } 37 | function getBlockNumber() public view returns (uint256 blockNumber) { 38 | blockNumber = block.number; 39 | } 40 | function getCurrentBlockCoinbase() public view returns (address coinbase) { 41 | coinbase = block.coinbase; 42 | } 43 | function getCurrentBlockDifficulty() public view returns (uint256 difficulty) { 44 | difficulty = block.difficulty; 45 | } 46 | function getCurrentBlockGasLimit() public view returns (uint256 gaslimit) { 47 | gaslimit = block.gaslimit; 48 | } 49 | function getCurrentBlockTimestamp() public view returns (uint256 timestamp) { 50 | timestamp = block.timestamp; 51 | } 52 | function getEthBalance(address addr) public view returns (uint256 balance) { 53 | balance = addr.balance; 54 | } 55 | function getLastBlockHash() public view returns (bytes32 blockHash) { 56 | blockHash = blockhash(block.number - 1); 57 | } 58 | function tryAggregate(bool requireSuccess, Call[] memory calls) public returns (Result[] memory returnData) { 59 | returnData = new Result[](calls.length); 60 | for(uint256 i = 0; i < calls.length; i++) { 61 | (bool success, bytes memory ret) = calls[i].target.call(calls[i].callData); 62 | 63 | if (requireSuccess) { 64 | require(success, "Multicall2 aggregate: call failed"); 65 | } 66 | 67 | returnData[i] = Result(success, ret); 68 | } 69 | } 70 | function tryBlockAndAggregate(bool requireSuccess, Call[] memory calls) public returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData) { 71 | blockNumber = block.number; 72 | blockHash = blockhash(block.number); 73 | returnData = tryAggregate(requireSuccess, calls); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /contracts/burner/interfaces/ISolarPair.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.2; 3 | 4 | interface ISolarPair { 5 | event Approval( 6 | address indexed owner, 7 | address indexed spender, 8 | uint256 value 9 | ); 10 | event Transfer(address indexed from, address indexed to, uint256 value); 11 | 12 | function name() external pure returns (string memory); 13 | 14 | function symbol() external pure returns (string memory); 15 | 16 | function decimals() external pure returns (uint8); 17 | 18 | function totalSupply() external view returns (uint256); 19 | 20 | function balanceOf(address owner) external view returns (uint256); 21 | 22 | function allowance(address owner, address spender) 23 | external 24 | view 25 | returns (uint256); 26 | 27 | function approve(address spender, uint256 value) external returns (bool); 28 | 29 | function transfer(address to, uint256 value) external returns (bool); 30 | 31 | function transferFrom( 32 | address from, 33 | address to, 34 | uint256 value 35 | ) external returns (bool); 36 | 37 | function DOMAIN_SEPARATOR() external view returns (bytes32); 38 | 39 | function PERMIT_TYPEHASH() external pure returns (bytes32); 40 | 41 | function nonces(address owner) external view returns (uint256); 42 | 43 | function permit( 44 | address owner, 45 | address spender, 46 | uint256 value, 47 | uint256 deadline, 48 | uint8 v, 49 | bytes32 r, 50 | bytes32 s 51 | ) external; 52 | 53 | event Mint(address indexed sender, uint256 amount0, uint256 amount1); 54 | event Burn( 55 | address indexed sender, 56 | uint256 amount0, 57 | uint256 amount1, 58 | address indexed to 59 | ); 60 | event Swap( 61 | address indexed sender, 62 | uint256 amount0In, 63 | uint256 amount1In, 64 | uint256 amount0Out, 65 | uint256 amount1Out, 66 | address indexed to 67 | ); 68 | event Sync(uint112 reserve0, uint112 reserve1); 69 | 70 | function MINIMUM_LIQUIDITY() external pure returns (uint256); 71 | 72 | function factory() external view returns (address); 73 | 74 | function token0() external view returns (address); 75 | 76 | function token1() external view returns (address); 77 | 78 | function getReserves() 79 | external 80 | view 81 | returns ( 82 | uint112 reserve0, 83 | uint112 reserve1, 84 | uint32 blockTimestampLast 85 | ); 86 | 87 | function price0CumulativeLast() external view returns (uint256); 88 | 89 | function price1CumulativeLast() external view returns (uint256); 90 | 91 | function kLast() external view returns (uint256); 92 | 93 | function mint(address to) external returns (uint256 liquidity); 94 | 95 | function burn(address to) 96 | external 97 | returns (uint256 amount0, uint256 amount1); 98 | 99 | function swap( 100 | uint256 amount0Out, 101 | uint256 amount1Out, 102 | address to, 103 | bytes calldata data 104 | ) external; 105 | 106 | function skim(address to) external; 107 | 108 | function sync() external; 109 | 110 | function initialize(address, address) external; 111 | } 112 | -------------------------------------------------------------------------------- /contracts/fee/interfaces/ISolarPair.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.2; 3 | 4 | interface ISolarPair { 5 | event Approval( 6 | address indexed owner, 7 | address indexed spender, 8 | uint256 value 9 | ); 10 | event Transfer(address indexed from, address indexed to, uint256 value); 11 | 12 | function name() external pure returns (string memory); 13 | 14 | function symbol() external pure returns (string memory); 15 | 16 | function decimals() external pure returns (uint8); 17 | 18 | function totalSupply() external view returns (uint256); 19 | 20 | function balanceOf(address owner) external view returns (uint256); 21 | 22 | function allowance(address owner, address spender) 23 | external 24 | view 25 | returns (uint256); 26 | 27 | function approve(address spender, uint256 value) external returns (bool); 28 | 29 | function transfer(address to, uint256 value) external returns (bool); 30 | 31 | function transferFrom( 32 | address from, 33 | address to, 34 | uint256 value 35 | ) external returns (bool); 36 | 37 | function DOMAIN_SEPARATOR() external view returns (bytes32); 38 | 39 | function PERMIT_TYPEHASH() external pure returns (bytes32); 40 | 41 | function nonces(address owner) external view returns (uint256); 42 | 43 | function permit( 44 | address owner, 45 | address spender, 46 | uint256 value, 47 | uint256 deadline, 48 | uint8 v, 49 | bytes32 r, 50 | bytes32 s 51 | ) external; 52 | 53 | event Mint(address indexed sender, uint256 amount0, uint256 amount1); 54 | event Burn( 55 | address indexed sender, 56 | uint256 amount0, 57 | uint256 amount1, 58 | address indexed to 59 | ); 60 | event Swap( 61 | address indexed sender, 62 | uint256 amount0In, 63 | uint256 amount1In, 64 | uint256 amount0Out, 65 | uint256 amount1Out, 66 | address indexed to 67 | ); 68 | event Sync(uint112 reserve0, uint112 reserve1); 69 | 70 | function MINIMUM_LIQUIDITY() external pure returns (uint256); 71 | 72 | function factory() external view returns (address); 73 | 74 | function token0() external view returns (address); 75 | 76 | function token1() external view returns (address); 77 | 78 | function getReserves() 79 | external 80 | view 81 | returns ( 82 | uint112 reserve0, 83 | uint112 reserve1, 84 | uint32 blockTimestampLast 85 | ); 86 | 87 | function price0CumulativeLast() external view returns (uint256); 88 | 89 | function price1CumulativeLast() external view returns (uint256); 90 | 91 | function kLast() external view returns (uint256); 92 | 93 | function mint(address to) external returns (uint256 liquidity); 94 | 95 | function burn(address to) 96 | external 97 | returns (uint256 amount0, uint256 amount1); 98 | 99 | function swap( 100 | uint256 amount0Out, 101 | uint256 amount1Out, 102 | address to, 103 | bytes calldata data 104 | ) external; 105 | 106 | function skim(address to) external; 107 | 108 | function sync() external; 109 | 110 | function initialize(address, address) external; 111 | } 112 | -------------------------------------------------------------------------------- /hardhat.config.js: -------------------------------------------------------------------------------- 1 | require("dotenv/config"); 2 | require("@nomiclabs/hardhat-waffle"); 3 | require("@nomiclabs/hardhat-etherscan"); 4 | require("@nomiclabs/hardhat-ethers"); 5 | require("hardhat-deploy"); 6 | require("hardhat-deploy-ethers"); 7 | require("./tasks"); 8 | 9 | let accounts; 10 | 11 | if (process.env.PRIVATE_KEY) { 12 | accounts = [process.env.PRIVATE_KEY]; 13 | } else { 14 | accounts = { 15 | mnemonic: process.env.MNEMONIC || "test test test test test test test test test test test junk", 16 | }; 17 | } 18 | 19 | /** 20 | * @type import('hardhat/config').HardhatUserConfig 21 | */ 22 | module.exports = { 23 | defaultNetwork: "hardhat", 24 | namedAccounts: { 25 | deployer: { 26 | default: 0, 27 | }, 28 | dev: { 29 | default: 1, 30 | }, 31 | treasury: { 32 | default: 1, 33 | }, 34 | investor: { 35 | default: 2, 36 | }, 37 | }, 38 | etherscan: { 39 | apiKey: process.env.ETHERSCAN_API_KEY, 40 | }, 41 | mocha: { 42 | timeout: 200000, 43 | }, 44 | networks: { 45 | hardhat: { 46 | forking: { 47 | enabled: false, 48 | url: "https://ropsten.infura.io/v3/249b95cec9c541bf94a4333cc77e9b71", 49 | }, 50 | live: false, 51 | saveDeployments: true, 52 | tags: ["test", "local"], 53 | }, 54 | mainnet: { 55 | url: `https://mainnet.infura.io/v3/249b95cec9c541bf94a4333cc77e9b71`, 56 | chainId: 1, 57 | accounts, 58 | live: true, 59 | saveDeployments: false, 60 | tags: ["mainnet"], 61 | gasPrice: 5000000000, 62 | gas: 8000000, 63 | }, 64 | rinkeby: { 65 | url: `https://rinkeby.infura.io/v3/249b95cec9c541bf94a4333cc77e9b71`, 66 | chainId: 4, 67 | accounts, 68 | live: true, 69 | saveDeployments: false, 70 | tags: ["rinkeby"], 71 | gasPrice: 5000000000, 72 | gas: 8000000, 73 | }, 74 | moonriver: { 75 | url: `https://rpc.api.moonriver.moonbeam.network`, 76 | chainId: 1285, 77 | accounts, 78 | live: true, 79 | saveDeployments: true, 80 | tags: ["moonriver"], 81 | gasPrice: 10000000000, 82 | gas: 8000000, 83 | }, 84 | moonbase: { 85 | url: `https://rpc.api.moonbase.moonbeam.network`, 86 | chainId: 1287, 87 | accounts, 88 | live: true, 89 | saveDeployments: true, 90 | tags: ["moonbase"], 91 | gasPrice: 1000000000, 92 | gas: 8000000, 93 | }, 94 | }, 95 | solidity: { 96 | compilers: [{ 97 | version: "0.6.12", 98 | settings: { 99 | optimizer: { 100 | enabled: true, 101 | runs: 999999, 102 | }, 103 | }, 104 | }, 105 | { 106 | version: "0.8.2", 107 | settings: { 108 | optimizer: { 109 | enabled: true, 110 | runs: 999999, 111 | }, 112 | }, 113 | }, 114 | { 115 | version: "0.8.7", 116 | settings: { 117 | optimizer: { 118 | enabled: true, 119 | runs: 999999, 120 | }, 121 | }, 122 | }, 123 | ], 124 | }, 125 | }; -------------------------------------------------------------------------------- /contracts/fee/interfaces/ISolarRouter01.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.2; 3 | 4 | interface ISolarRouter01 { 5 | function factory() external pure returns (address); 6 | function WETH() external pure returns (address); 7 | 8 | function addLiquidity( 9 | address tokenA, 10 | address tokenB, 11 | uint amountADesired, 12 | uint amountBDesired, 13 | uint amountAMin, 14 | uint amountBMin, 15 | address to, 16 | uint deadline 17 | ) external returns (uint amountA, uint amountB, uint liquidity); 18 | function addLiquidityETH( 19 | address token, 20 | uint amountTokenDesired, 21 | uint amountTokenMin, 22 | uint amountETHMin, 23 | address to, 24 | uint deadline 25 | ) external payable returns (uint amountToken, uint amountETH, uint liquidity); 26 | function removeLiquidity( 27 | address tokenA, 28 | address tokenB, 29 | uint liquidity, 30 | uint amountAMin, 31 | uint amountBMin, 32 | address to, 33 | uint deadline 34 | ) external returns (uint amountA, uint amountB); 35 | function removeLiquidityETH( 36 | address token, 37 | uint liquidity, 38 | uint amountTokenMin, 39 | uint amountETHMin, 40 | address to, 41 | uint deadline 42 | ) external returns (uint amountToken, uint amountETH); 43 | function removeLiquidityWithPermit( 44 | address tokenA, 45 | address tokenB, 46 | uint liquidity, 47 | uint amountAMin, 48 | uint amountBMin, 49 | address to, 50 | uint deadline, 51 | bool approveMax, uint8 v, bytes32 r, bytes32 s 52 | ) external returns (uint amountA, uint amountB); 53 | function removeLiquidityETHWithPermit( 54 | address token, 55 | uint liquidity, 56 | uint amountTokenMin, 57 | uint amountETHMin, 58 | address to, 59 | uint deadline, 60 | bool approveMax, uint8 v, bytes32 r, bytes32 s 61 | ) external returns (uint amountToken, uint amountETH); 62 | function swapExactTokensForTokens( 63 | uint amountIn, 64 | uint amountOutMin, 65 | address[] calldata path, 66 | address to, 67 | uint deadline 68 | ) external returns (uint[] memory amounts); 69 | function swapTokensForExactTokens( 70 | uint amountOut, 71 | uint amountInMax, 72 | address[] calldata path, 73 | address to, 74 | uint deadline 75 | ) external returns (uint[] memory amounts); 76 | function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) 77 | external 78 | payable 79 | returns (uint[] memory amounts); 80 | function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) 81 | external 82 | returns (uint[] memory amounts); 83 | function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) 84 | external 85 | returns (uint[] memory amounts); 86 | function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) 87 | external 88 | payable 89 | returns (uint[] memory amounts); 90 | 91 | function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB); 92 | function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut); 93 | function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn); 94 | function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); 95 | function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts); 96 | } -------------------------------------------------------------------------------- /contracts/uniswapv2/interfaces/ISolarRouter01.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity =0.6.12; 3 | 4 | interface ISolarRouter01 { 5 | function factory() external pure returns (address); 6 | function WETH() external pure returns (address); 7 | 8 | function addLiquidity( 9 | address tokenA, 10 | address tokenB, 11 | uint amountADesired, 12 | uint amountBDesired, 13 | uint amountAMin, 14 | uint amountBMin, 15 | address to, 16 | uint deadline 17 | ) external returns (uint amountA, uint amountB, uint liquidity); 18 | function addLiquidityETH( 19 | address token, 20 | uint amountTokenDesired, 21 | uint amountTokenMin, 22 | uint amountETHMin, 23 | address to, 24 | uint deadline 25 | ) external payable returns (uint amountToken, uint amountETH, uint liquidity); 26 | function removeLiquidity( 27 | address tokenA, 28 | address tokenB, 29 | uint liquidity, 30 | uint amountAMin, 31 | uint amountBMin, 32 | address to, 33 | uint deadline 34 | ) external returns (uint amountA, uint amountB); 35 | function removeLiquidityETH( 36 | address token, 37 | uint liquidity, 38 | uint amountTokenMin, 39 | uint amountETHMin, 40 | address to, 41 | uint deadline 42 | ) external returns (uint amountToken, uint amountETH); 43 | function removeLiquidityWithPermit( 44 | address tokenA, 45 | address tokenB, 46 | uint liquidity, 47 | uint amountAMin, 48 | uint amountBMin, 49 | address to, 50 | uint deadline, 51 | bool approveMax, uint8 v, bytes32 r, bytes32 s 52 | ) external returns (uint amountA, uint amountB); 53 | function removeLiquidityETHWithPermit( 54 | address token, 55 | uint liquidity, 56 | uint amountTokenMin, 57 | uint amountETHMin, 58 | address to, 59 | uint deadline, 60 | bool approveMax, uint8 v, bytes32 r, bytes32 s 61 | ) external returns (uint amountToken, uint amountETH); 62 | function swapExactTokensForTokens( 63 | uint amountIn, 64 | uint amountOutMin, 65 | address[] calldata path, 66 | address to, 67 | uint deadline 68 | ) external returns (uint[] memory amounts); 69 | function swapTokensForExactTokens( 70 | uint amountOut, 71 | uint amountInMax, 72 | address[] calldata path, 73 | address to, 74 | uint deadline 75 | ) external returns (uint[] memory amounts); 76 | function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) 77 | external 78 | payable 79 | returns (uint[] memory amounts); 80 | function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) 81 | external 82 | returns (uint[] memory amounts); 83 | function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) 84 | external 85 | returns (uint[] memory amounts); 86 | function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) 87 | external 88 | payable 89 | returns (uint[] memory amounts); 90 | 91 | function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB); 92 | function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut); 93 | function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn); 94 | function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); 95 | function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts); 96 | } -------------------------------------------------------------------------------- /contracts/gasless/GasSwap.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.7; 3 | 4 | import "@openzeppelin/contracts/access/Ownable.sol"; 5 | import "@openzeppelin/contracts/utils/Address.sol"; 6 | import "./EIP712MetaTransaction.sol"; 7 | import "./ISolarRouter.sol"; 8 | import "./IToken.sol"; 9 | 10 | contract GasSwap is Ownable, EIP712MetaTransaction("GasSwap", "2") { 11 | address public immutable WMOVR = 0x98878B06940aE243284CA214f92Bb71a2b032B8A; 12 | 13 | struct Transformation { 14 | uint32 _uint32; 15 | bytes _bytes; 16 | } 17 | 18 | ISolarRouter public solarRouter; 19 | address public feeAddress; 20 | uint256 public feePercent = 100; //1% 21 | 22 | mapping(address => bool) public tokenWhitelist; 23 | 24 | constructor(address router) { 25 | solarRouter = ISolarRouter(router); 26 | } 27 | 28 | receive() external payable { 29 | require(Address.isContract(msgSender()), "REVERT_EOA_DEPOSIT"); 30 | } 31 | 32 | function whitelistToken(address tokenAddress, bool whitelisted) 33 | external 34 | onlyOwner 35 | { 36 | require(Address.isContract(tokenAddress), "NO_CONTRACT_AT_ADDRESS"); 37 | tokenWhitelist[tokenAddress] = whitelisted; 38 | } 39 | 40 | function changeFeePercent(uint256 newFeePercent) external onlyOwner { 41 | require(feePercent >= 0 && feePercent < 10000, "INVALID_FEE_PERCENT"); 42 | feePercent = newFeePercent; 43 | } 44 | 45 | function changeFeeAddress(address newFeeAddress) external onlyOwner { 46 | feeAddress = newFeeAddress; 47 | } 48 | 49 | function changeRouter(address newTarget) external onlyOwner { 50 | require(Address.isContract(newTarget), "NO_CONTRACT_AT_ADDRESS"); 51 | solarRouter = ISolarRouter(newTarget); 52 | } 53 | 54 | function withdrawToken(IToken token, uint256 amount) external onlyOwner { 55 | token.transfer(msg.sender, amount); 56 | } 57 | 58 | // Transfer ETH held by this contract to the sender/owner. 59 | function withdrawETH(uint256 amount) external onlyOwner { 60 | payable(msg.sender).transfer(amount); 61 | } 62 | 63 | // Swaps ERC20->MOVR tokens 64 | function swap(bytes calldata swapCallData) external returns (uint256) { 65 | ( 66 | uint256 amountIn, 67 | uint256 amountOutMin, 68 | address[] memory path, 69 | , 70 | uint256 deadline, 71 | uint8 v, 72 | bytes32 r, 73 | bytes32 s 74 | ) = abi.decode( 75 | swapCallData, 76 | ( 77 | uint256, 78 | uint256, 79 | address[], 80 | address, 81 | uint256, 82 | uint8, 83 | bytes32, 84 | bytes32 85 | ) 86 | ); 87 | 88 | require(path[path.length - 1] == WMOVR, "INVALID_OUTPUT_TOKEN"); 89 | 90 | require(tokenWhitelist[path[0]] == true, "INVALID_INPUT_TOKEN"); 91 | 92 | IToken sellToken = IToken(path[0]); 93 | 94 | sellToken.permit( 95 | msgSender(), 96 | address(this), 97 | amountIn, 98 | deadline, 99 | v, 100 | r, 101 | s 102 | ); 103 | 104 | sellToken.transferFrom(msgSender(), address(this), amountIn); 105 | 106 | uint256 beforeSwapBalance = address(this).balance; 107 | 108 | sellToken.approve(address(solarRouter), amountIn); 109 | 110 | solarRouter.swapExactTokensForETH( 111 | amountIn, 112 | amountOutMin, 113 | path, 114 | address(this), 115 | deadline 116 | ); 117 | 118 | uint256 tradeBalance = address(this).balance - beforeSwapBalance; 119 | uint256 amount = ((tradeBalance * 10000) - 120 | (tradeBalance * feePercent)) / 10000; 121 | uint256 fee = tradeBalance - amount; 122 | 123 | if (feeAddress != address(0)) { 124 | payable(feeAddress).transfer(fee); 125 | } 126 | payable(msgSender()).transfer(amount); 127 | return amount; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /contracts/locker/SolarLocker.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.2; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 5 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import "@openzeppelin/contracts/utils/math/SafeMath.sol"; 7 | import "@openzeppelin/contracts/access/Ownable.sol"; 8 | 9 | contract SolarLocker is Ownable{ 10 | using SafeMath for uint256; 11 | using SafeERC20 for IERC20; 12 | 13 | struct Items { 14 | IERC20 token; 15 | address withdrawer; 16 | uint256 amount; 17 | uint256 unlockTimestamp; 18 | bool withdrawn; 19 | } 20 | 21 | uint256 public depositsCount; 22 | mapping (address => uint256[]) private depositsByTokenAddress; 23 | mapping (address => uint256[]) public depositsByWithdrawer; 24 | mapping (uint256 => Items) public lockedToken; 25 | mapping (address => mapping(address => uint256)) public walletTokenBalance; 26 | 27 | uint256 public lockFee = 0.1 ether; 28 | address public marketingAddress; 29 | 30 | event Withdraw(address withdrawer, uint256 amount); 31 | event Lock(address token, uint256 amount, uint256 id); 32 | 33 | constructor() { 34 | marketingAddress = msg.sender; 35 | } 36 | 37 | function lockTokens(IERC20 _token, address _withdrawer, uint256 _amount, uint256 _unlockTimestamp) payable external returns (uint256 _id) { 38 | require(_amount > 0, 'Token amount too low!'); 39 | require(_unlockTimestamp < 10000000000, 'Unlock timestamp is not in seconds!'); 40 | require(_unlockTimestamp > block.timestamp, 'Unlock timestamp is not in the future!'); 41 | require(_token.allowance(msg.sender, address(this)) >= _amount, 'Approve tokens first!'); 42 | require(msg.value >= lockFee, 'Need to pay lock fee!'); 43 | 44 | uint256 beforeDeposit = _token.balanceOf(address(this)); 45 | _token.safeTransferFrom(msg.sender, address(this), _amount); 46 | uint256 afterDeposit = _token.balanceOf(address(this)); 47 | 48 | _amount = afterDeposit.sub(beforeDeposit); 49 | 50 | payable(marketingAddress).transfer(msg.value); 51 | 52 | walletTokenBalance[address(_token)][msg.sender] = walletTokenBalance[address(_token)][msg.sender].add(_amount); 53 | 54 | _id = ++depositsCount; 55 | lockedToken[_id].token = _token; 56 | lockedToken[_id].withdrawer = _withdrawer; 57 | lockedToken[_id].amount = _amount; 58 | lockedToken[_id].unlockTimestamp = _unlockTimestamp; 59 | lockedToken[_id].withdrawn = false; 60 | 61 | depositsByTokenAddress[address(_token)].push(_id); 62 | depositsByWithdrawer[_withdrawer].push(_id); 63 | 64 | emit Lock(address(_token), _amount, _id); 65 | 66 | return _id; 67 | } 68 | 69 | function withdrawTokens(uint256 _id) external { 70 | require(block.timestamp >= lockedToken[_id].unlockTimestamp, 'Tokens are still locked!'); 71 | require(msg.sender == lockedToken[_id].withdrawer, 'You are not the withdrawer!'); 72 | require(!lockedToken[_id].withdrawn, 'Tokens are already withdrawn!'); 73 | 74 | lockedToken[_id].withdrawn = true; 75 | 76 | walletTokenBalance[address(lockedToken[_id].token)][msg.sender] = walletTokenBalance[address(lockedToken[_id].token)][msg.sender].sub(lockedToken[_id].amount); 77 | 78 | emit Withdraw(msg.sender, lockedToken[_id].amount); 79 | lockedToken[_id].token.safeTransfer(msg.sender, lockedToken[_id].amount); 80 | } 81 | 82 | function setMarketingAddress(address _marketingAddress) external onlyOwner { 83 | marketingAddress = _marketingAddress; 84 | } 85 | 86 | function setLockFee(uint256 _lockFee) external onlyOwner { 87 | lockFee = _lockFee; 88 | } 89 | 90 | function getDepositsByTokenAddress(address _token) view external returns (uint256[] memory) { 91 | return depositsByTokenAddress[_token]; 92 | } 93 | 94 | function getDepositsByWithdrawer(address _withdrawer) view external returns (uint256[] memory) { 95 | return depositsByWithdrawer[_withdrawer]; 96 | } 97 | 98 | 99 | function getTokenTotalLockedBalance(address _token) view external returns (uint256) { 100 | return IERC20(_token).balanceOf(address(this)); 101 | } 102 | } -------------------------------------------------------------------------------- /contracts/eclipse/ICommonEclipse.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.7; 3 | 4 | /** @title ICommonEclipse 5 | * @notice It is an interface for CommonEclipse.sol 6 | */ 7 | abstract contract ICommonEclipse { 8 | /** 9 | * @notice It sets parameters for pool 10 | * @param _offeringAmountPool: offering amount (in tokens) 11 | * @param _raisingAmountPool: raising amount (in LP tokens) 12 | * @param _baseLimitInLP: base limit per user (in LP tokens) 13 | * @param _hasTax: if the pool has a tax 14 | * @param _pid: poolId 15 | * @dev This function is only callable by owner. 16 | */ 17 | function setPool( 18 | uint256 _offeringAmountPool, 19 | uint256 _raisingAmountPool, 20 | uint256 _baseLimitInLP, 21 | bool _hasTax, 22 | uint8 _pid 23 | ) external virtual; 24 | 25 | /** 26 | * @notice It allows users to deposit LP tokens to pool 27 | * @param _amount: the number of LP token used (18 decimals) 28 | * @param _pid: pool id 29 | */ 30 | function depositPool(uint256 _amount, uint8 _pid) external virtual; 31 | 32 | /** 33 | * @notice It allows users to harvest from pool 34 | * @param _pid: pool id 35 | * @param _harvestPeriod: chosen harvest period to claim 36 | */ 37 | function harvestPool(uint8 _pid, uint8 _harvestPeriod) external virtual; 38 | 39 | /** 40 | * @notice It allows owner to update start and end blocks of the sale 41 | * @param _startBlock: block number sale starts 42 | * @param _endBlock: block number sale ends 43 | */ 44 | function updateStartAndEndBlocks(uint256 _startBlock, uint256 _endBlock) 45 | external 46 | virtual; 47 | 48 | /** 49 | * @notice It allows owner to set the multiplier information 50 | * @param _multipliers: encoded multipliers for zero, seven and thirty day vaults 51 | * @dev encoded args are (uint8,uint8,uint8,uint8[2][3],uint8[2][3],uint8[2][3]) 52 | * (0 decimals) 53 | */ 54 | function setMultipliers(bytes memory _multipliers) public virtual; 55 | 56 | /** 57 | * @notice It allows owner to set the threshold for eligibility 58 | * @param _eligibilityThreshold: amount of solar staked in vaults to be eligibile 59 | */ 60 | function setEligibilityThreshold(uint256 _eligibilityThreshold) 61 | public 62 | virtual; 63 | 64 | /** 65 | * @notice It allows the admin to withdraw funds 66 | * @param _lpAmount: the number of LP token to withdraw (18 decimals) 67 | * @param _offerAmount: the number of offering amount to withdraw 68 | * @dev This function is only callable by owner. 69 | */ 70 | function finalWithdraw(uint256 _lpAmount, uint256 _offerAmount) 71 | external 72 | virtual; 73 | 74 | /** 75 | * @notice It returns the tax overflow rate calculated for a pool 76 | * @dev 100,000,000,000 means 0.1 (10%) / 1 means 0.0000000000001 (0.0000001%) / 1,000,000,000,000 means 1 (100%) 77 | * @param _pid: poolId 78 | * @return It returns the tax percentage 79 | */ 80 | function viewPoolTaxRateOverflow(uint256 _pid) 81 | external 82 | virtual 83 | returns (uint256); 84 | 85 | /** 86 | * @notice External view function to see user allocations for both pools 87 | * @param _user: user address 88 | * @param _pids[]: array of pids 89 | */ 90 | function viewUserAllocationPools(address _user, uint8[] calldata _pids) 91 | external 92 | virtual 93 | returns (uint256[] memory); 94 | 95 | /** 96 | * @notice External view function to see user offering and refunding amounts for both pools 97 | * @param _user: user address 98 | * @param _pids: array of pids 99 | */ 100 | function viewUserOfferingAndRefundingAmountsForPools( 101 | address _user, 102 | uint8[] calldata _pids 103 | ) external virtual returns (uint256[3][] memory); 104 | 105 | /** 106 | * @notice It allows users to withdraw LP tokens to pool 107 | * @param _amount: the number of LP token used (18 decimals) 108 | * @param _pid: pool id 109 | */ 110 | function withdrawPool(uint256 _amount, uint8 _pid) external virtual; 111 | 112 | /** 113 | * @notice It allows the admin to end sale and start claim 114 | * @dev This function is only callable by owner. 115 | */ 116 | function enableClaim() external virtual; 117 | } 118 | -------------------------------------------------------------------------------- /contracts/libraries/BoringERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.7; 3 | 4 | // solhint-disable avoid-low-level-calls 5 | import "./IBoringERC20.sol"; 6 | 7 | library BoringERC20 { 8 | bytes4 private constant SIG_SYMBOL = 0x95d89b41; // symbol() 9 | bytes4 private constant SIG_NAME = 0x06fdde03; // name() 10 | bytes4 private constant SIG_DECIMALS = 0x313ce567; // decimals() 11 | bytes4 private constant SIG_TRANSFER = 0xa9059cbb; // transfer(address,uint256) 12 | bytes4 private constant SIG_TRANSFER_FROM = 0x23b872dd; // transferFrom(address,address,uint256) 13 | 14 | function returnDataToString(bytes memory data) 15 | internal 16 | pure 17 | returns (string memory) 18 | { 19 | if (data.length >= 64) { 20 | return abi.decode(data, (string)); 21 | } else if (data.length == 32) { 22 | uint8 i = 0; 23 | while (i < 32 && data[i] != 0) { 24 | i++; 25 | } 26 | bytes memory bytesArray = new bytes(i); 27 | for (i = 0; i < 32 && data[i] != 0; i++) { 28 | bytesArray[i] = data[i]; 29 | } 30 | return string(bytesArray); 31 | } else { 32 | return "???"; 33 | } 34 | } 35 | 36 | /// @notice Provides a safe ERC20.symbol version which returns '???' as fallback string. 37 | /// @param token The address of the ERC-20 token contract. 38 | /// @return (string) Token symbol. 39 | function safeSymbol(IBoringERC20 token) 40 | internal 41 | view 42 | returns (string memory) 43 | { 44 | (bool success, bytes memory data) = address(token).staticcall( 45 | abi.encodeWithSelector(SIG_SYMBOL) 46 | ); 47 | return success ? returnDataToString(data) : "???"; 48 | } 49 | 50 | /// @notice Provides a safe ERC20.name version which returns '???' as fallback string. 51 | /// @param token The address of the ERC-20 token contract. 52 | /// @return (string) Token name. 53 | function safeName(IBoringERC20 token) 54 | internal 55 | view 56 | returns (string memory) 57 | { 58 | (bool success, bytes memory data) = address(token).staticcall( 59 | abi.encodeWithSelector(SIG_NAME) 60 | ); 61 | return success ? returnDataToString(data) : "???"; 62 | } 63 | 64 | /// @notice Provides a safe ERC20.decimals version which returns '18' as fallback value. 65 | /// @param token The address of the ERC-20 token contract. 66 | /// @return (uint8) Token decimals. 67 | function safeDecimals(IBoringERC20 token) internal view returns (uint8) { 68 | (bool success, bytes memory data) = address(token).staticcall( 69 | abi.encodeWithSelector(SIG_DECIMALS) 70 | ); 71 | return success && data.length == 32 ? abi.decode(data, (uint8)) : 18; 72 | } 73 | 74 | /// @notice Provides a safe ERC20.transfer version for different ERC-20 implementations. 75 | /// Reverts on a failed transfer. 76 | /// @param token The address of the ERC-20 token. 77 | /// @param to Transfer tokens to. 78 | /// @param amount The token amount. 79 | function safeTransfer( 80 | IBoringERC20 token, 81 | address to, 82 | uint256 amount 83 | ) internal { 84 | (bool success, bytes memory data) = address(token).call( 85 | abi.encodeWithSelector(SIG_TRANSFER, to, amount) 86 | ); 87 | require( 88 | success && (data.length == 0 || abi.decode(data, (bool))), 89 | "BoringERC20: Transfer failed" 90 | ); 91 | } 92 | 93 | /// @notice Provides a safe ERC20.transferFrom version for different ERC-20 implementations. 94 | /// Reverts on a failed transfer. 95 | /// @param token The address of the ERC-20 token. 96 | /// @param from Transfer tokens from. 97 | /// @param to Transfer tokens to. 98 | /// @param amount The token amount. 99 | function safeTransferFrom( 100 | IBoringERC20 token, 101 | address from, 102 | address to, 103 | uint256 amount 104 | ) internal { 105 | (bool success, bytes memory data) = address(token).call( 106 | abi.encodeWithSelector(SIG_TRANSFER_FROM, from, to, amount) 107 | ); 108 | require( 109 | success && (data.length == 0 || abi.decode(data, (bool))), 110 | "BoringERC20: TransferFrom failed" 111 | ); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /contracts/farm/v2/libraries/BoringERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.7; 3 | 4 | // solhint-disable avoid-low-level-calls 5 | import "./IBoringERC20.sol"; 6 | 7 | library BoringERC20 { 8 | bytes4 private constant SIG_SYMBOL = 0x95d89b41; // symbol() 9 | bytes4 private constant SIG_NAME = 0x06fdde03; // name() 10 | bytes4 private constant SIG_DECIMALS = 0x313ce567; // decimals() 11 | bytes4 private constant SIG_TRANSFER = 0xa9059cbb; // transfer(address,uint256) 12 | bytes4 private constant SIG_TRANSFER_FROM = 0x23b872dd; // transferFrom(address,address,uint256) 13 | 14 | function returnDataToString(bytes memory data) 15 | internal 16 | pure 17 | returns (string memory) 18 | { 19 | if (data.length >= 64) { 20 | return abi.decode(data, (string)); 21 | } else if (data.length == 32) { 22 | uint8 i = 0; 23 | while (i < 32 && data[i] != 0) { 24 | i++; 25 | } 26 | bytes memory bytesArray = new bytes(i); 27 | for (i = 0; i < 32 && data[i] != 0; i++) { 28 | bytesArray[i] = data[i]; 29 | } 30 | return string(bytesArray); 31 | } else { 32 | return "???"; 33 | } 34 | } 35 | 36 | /// @notice Provides a safe ERC20.symbol version which returns '???' as fallback string. 37 | /// @param token The address of the ERC-20 token contract. 38 | /// @return (string) Token symbol. 39 | function safeSymbol(IBoringERC20 token) 40 | internal 41 | view 42 | returns (string memory) 43 | { 44 | (bool success, bytes memory data) = address(token).staticcall( 45 | abi.encodeWithSelector(SIG_SYMBOL) 46 | ); 47 | return success ? returnDataToString(data) : "???"; 48 | } 49 | 50 | /// @notice Provides a safe ERC20.name version which returns '???' as fallback string. 51 | /// @param token The address of the ERC-20 token contract. 52 | /// @return (string) Token name. 53 | function safeName(IBoringERC20 token) 54 | internal 55 | view 56 | returns (string memory) 57 | { 58 | (bool success, bytes memory data) = address(token).staticcall( 59 | abi.encodeWithSelector(SIG_NAME) 60 | ); 61 | return success ? returnDataToString(data) : "???"; 62 | } 63 | 64 | /// @notice Provides a safe ERC20.decimals version which returns '18' as fallback value. 65 | /// @param token The address of the ERC-20 token contract. 66 | /// @return (uint8) Token decimals. 67 | function safeDecimals(IBoringERC20 token) internal view returns (uint8) { 68 | (bool success, bytes memory data) = address(token).staticcall( 69 | abi.encodeWithSelector(SIG_DECIMALS) 70 | ); 71 | return success && data.length == 32 ? abi.decode(data, (uint8)) : 18; 72 | } 73 | 74 | /// @notice Provides a safe ERC20.transfer version for different ERC-20 implementations. 75 | /// Reverts on a failed transfer. 76 | /// @param token The address of the ERC-20 token. 77 | /// @param to Transfer tokens to. 78 | /// @param amount The token amount. 79 | function safeTransfer( 80 | IBoringERC20 token, 81 | address to, 82 | uint256 amount 83 | ) internal { 84 | (bool success, bytes memory data) = address(token).call( 85 | abi.encodeWithSelector(SIG_TRANSFER, to, amount) 86 | ); 87 | require( 88 | success && (data.length == 0 || abi.decode(data, (bool))), 89 | "BoringERC20: Transfer failed" 90 | ); 91 | } 92 | 93 | /// @notice Provides a safe ERC20.transferFrom version for different ERC-20 implementations. 94 | /// Reverts on a failed transfer. 95 | /// @param token The address of the ERC-20 token. 96 | /// @param from Transfer tokens from. 97 | /// @param to Transfer tokens to. 98 | /// @param amount The token amount. 99 | function safeTransferFrom( 100 | IBoringERC20 token, 101 | address from, 102 | address to, 103 | uint256 amount 104 | ) internal { 105 | (bool success, bytes memory data) = address(token).call( 106 | abi.encodeWithSelector(SIG_TRANSFER_FROM, from, to, amount) 107 | ); 108 | require( 109 | success && (data.length == 0 || abi.decode(data, (bool))), 110 | "BoringERC20: TransferFrom failed" 111 | ); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /contracts/eclipse/v2/ICommonEclipseV2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.7; 3 | 4 | /** @title ICommonEclipse 5 | * @notice It is an interface for CommonEclipse.sol 6 | */ 7 | abstract contract ICommonEclipseV2 { 8 | enum WITHDRAW_TYPE { 9 | RAISING, 10 | TAX 11 | } 12 | 13 | enum HARVEST_TYPE { 14 | TIMESTAMP, 15 | PERCENT 16 | } 17 | 18 | /** 19 | * @notice It sets parameters for pool 20 | * @param _offeringAmountPool: offering amount (in tokens) 21 | * @param _raisingAmountPool: raising amount (in LP tokens) 22 | * @param _baseLimitInLP: base limit per user (in LP tokens) 23 | * @param _hasTax: if the pool has a tax 24 | * @param _pid: poolId 25 | * @dev This function is only callable by owner. 26 | */ 27 | function setPool( 28 | uint256 _offeringAmountPool, 29 | uint256 _raisingAmountPool, 30 | uint256 _baseLimitInLP, 31 | bool _hasTax, 32 | uint8 _pid 33 | ) external virtual; 34 | 35 | /** 36 | * @notice It allows users to deposit LP tokens to pool 37 | * @param _amount: the number of LP token used (18 decimals) 38 | * @param _pid: pool id 39 | */ 40 | function depositPool(uint256 _amount, uint8 _pid) external virtual; 41 | 42 | /** 43 | * @notice It allows users to harvest from pool 44 | * @param _pid: pool id 45 | * @param _harvestPeriod: chosen harvest period to claim 46 | */ 47 | function harvestPool(uint8 _pid, uint8 _harvestPeriod) external virtual; 48 | 49 | /** 50 | * @notice It allows owner to update start and end blocks of the sale 51 | * @param _startBlock: block number sale starts 52 | * @param _endBlock: block number sale ends 53 | */ 54 | function updateStartAndEndBlocks(uint256 _startBlock, uint256 _endBlock) 55 | external 56 | virtual; 57 | 58 | /** 59 | * @notice It allows owner to set the multiplier information 60 | * @param _multipliers: encoded multipliers for zero, seven and thirty day vaults 61 | * @dev encoded args are (uint8,uint8,uint8,uint8[2][3],uint8[2][3],uint8[2][3]) 62 | * (0 decimals) 63 | */ 64 | function setMultipliers(bytes memory _multipliers) public virtual; 65 | 66 | /** 67 | * @notice It allows owner to set the threshold for eligibility 68 | * @param _eligibilityThreshold: amount of solar staked in vaults to be eligibile 69 | */ 70 | function setEligibilityThreshold(uint256 _eligibilityThreshold) 71 | public 72 | virtual; 73 | 74 | /** 75 | * @notice It withdraws raisingAmount + taxes for a pool 76 | * @dev can only withdraw after the sale is finished 77 | * @param _type: withdraw type 78 | * @param _pid: pool id 79 | */ 80 | function finalWithdraw(WITHDRAW_TYPE _type, uint8 _pid) external virtual; 81 | 82 | /** 83 | * @notice It returns the tax overflow rate calculated for a pool 84 | * @dev 100,000,000,000 means 0.1 (10%) / 1 means 0.0000000000001 (0.0000001%) / 1,000,000,000,000 means 1 (100%) 85 | * @param _pid: poolId 86 | * @return It returns the tax percentage 87 | */ 88 | function viewPoolTaxRateOverflow(uint256 _pid) 89 | external 90 | virtual 91 | returns (uint256); 92 | 93 | /** 94 | * @notice External view function to see user allocations for both pools 95 | * @param _user: user address 96 | * @param _pids[]: array of pids 97 | */ 98 | function viewUserAllocationPools(address _user, uint8[] calldata _pids) 99 | external 100 | virtual 101 | returns (uint256[] memory); 102 | 103 | /** 104 | * @notice External view function to see user offering and refunding amounts for both pools 105 | * @param _user: user address 106 | * @param _pids: array of pids 107 | */ 108 | function viewUserOfferingAndRefundingAmountsForPools( 109 | address _user, 110 | uint8[] calldata _pids 111 | ) external virtual returns (uint256[3][] memory); 112 | 113 | /** 114 | * @notice It allows users to withdraw LP tokens to pool 115 | * @param _amount: the number of LP token used (18 decimals) 116 | * @param _pid: pool id 117 | */ 118 | function withdrawPool(uint256 _amount, uint8 _pid) external virtual; 119 | 120 | /** 121 | * @notice It allows the admin to end sale and start claim 122 | * @dev This function is only callable by owner. 123 | */ 124 | function enableClaim() external virtual; 125 | } 126 | -------------------------------------------------------------------------------- /contracts/gasless/EIP712MetaTransaction.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.7; 3 | 4 | import "./EIP712Base.sol"; 5 | 6 | contract EIP712MetaTransaction is EIP712Base { 7 | bytes32 private constant META_TRANSACTION_TYPEHASH = 8 | keccak256( 9 | bytes( 10 | "MetaTransaction(uint256 nonce,address from,bytes functionSignature)" 11 | ) 12 | ); 13 | 14 | event MetaTransactionExecuted( 15 | address userAddress, 16 | address payable relayerAddress, 17 | bytes functionSignature 18 | ); 19 | mapping(address => uint256) private nonces; 20 | 21 | /* 22 | * Meta transaction structure. 23 | * No point of including value field here as if user is doing value transfer then he has the funds to pay for gas 24 | * He should call the desired function directly in that case. 25 | */ 26 | struct MetaTransaction { 27 | uint256 nonce; 28 | address from; 29 | bytes functionSignature; 30 | } 31 | 32 | constructor(string memory name, string memory version) 33 | EIP712Base(name, version) 34 | {} 35 | 36 | function convertBytesToBytes4(bytes memory inBytes) 37 | internal 38 | pure 39 | returns (bytes4 outBytes4) 40 | { 41 | if (inBytes.length == 0) { 42 | return 0x0; 43 | } 44 | 45 | assembly { 46 | outBytes4 := mload(add(inBytes, 32)) 47 | } 48 | } 49 | 50 | function executeMetaTransaction( 51 | address userAddress, 52 | bytes memory functionSignature, 53 | bytes32 sigR, 54 | bytes32 sigS, 55 | uint8 sigV 56 | ) public payable returns (bytes memory) { 57 | bytes4 destinationFunctionSig = convertBytesToBytes4(functionSignature); 58 | require( 59 | destinationFunctionSig != msg.sig, 60 | "functionSignature can not be of executeMetaTransaction method" 61 | ); 62 | MetaTransaction memory metaTx = MetaTransaction({ 63 | nonce: nonces[userAddress], 64 | from: userAddress, 65 | functionSignature: functionSignature 66 | }); 67 | require( 68 | verify(userAddress, metaTx, sigR, sigS, sigV), 69 | "Signer and signature do not match" 70 | ); 71 | nonces[userAddress] += 1; 72 | // Append userAddress at the end to extract it from calling context 73 | (bool success, bytes memory returnData) = address(this).call( 74 | abi.encodePacked(functionSignature, userAddress) 75 | ); 76 | 77 | require(success, "Function call not successful"); 78 | emit MetaTransactionExecuted( 79 | userAddress, 80 | payable(msg.sender), 81 | functionSignature 82 | ); 83 | return returnData; 84 | } 85 | 86 | function hashMetaTransaction(MetaTransaction memory metaTx) 87 | internal 88 | pure 89 | returns (bytes32) 90 | { 91 | return 92 | keccak256( 93 | abi.encode( 94 | META_TRANSACTION_TYPEHASH, 95 | metaTx.nonce, 96 | metaTx.from, 97 | keccak256(metaTx.functionSignature) 98 | ) 99 | ); 100 | } 101 | 102 | function getNonce(address user) external view returns (uint256 nonce) { 103 | nonce = nonces[user]; 104 | } 105 | 106 | function verify( 107 | address user, 108 | MetaTransaction memory metaTx, 109 | bytes32 sigR, 110 | bytes32 sigS, 111 | uint8 sigV 112 | ) internal view returns (bool) { 113 | address signer = ecrecover( 114 | toTypedMessageHash(hashMetaTransaction(metaTx)), 115 | sigV, 116 | sigR, 117 | sigS 118 | ); 119 | require(signer != address(0), "Invalid signature"); 120 | return signer == user; 121 | } 122 | 123 | function msgSender() internal view returns (address sender) { 124 | if (msg.sender == address(this)) { 125 | bytes memory array = msg.data; 126 | uint256 index = msg.data.length; 127 | assembly { 128 | // Load the 32 bytes word from memory with the address on the lower 20 bytes, and mask those. 129 | sender := and( 130 | mload(add(array, index)), 131 | 0xffffffffffffffffffffffffffffffffffffffff 132 | ) 133 | } 134 | } else { 135 | sender = msg.sender; 136 | } 137 | return sender; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /contracts/solar/SolarBeamToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.2; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 5 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 7 | import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol"; 8 | import "@openzeppelin/contracts/security/Pausable.sol"; 9 | import "@openzeppelin/contracts/access/AccessControl.sol"; 10 | import "@openzeppelin/contracts/utils/math/SafeMath.sol"; 11 | import "@openzeppelin/contracts/metatx/ERC2771Context.sol"; 12 | 13 | contract SolarBeamToken is ERC20, ERC20Permit, Pausable, AccessControl { 14 | using SafeERC20 for IERC20; 15 | using SafeMath for uint256; 16 | 17 | bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); 18 | bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); 19 | bytes32 public constant RESCUER_ROLE = keccak256("RESCUER_ROLE"); 20 | bytes32 public constant TAKE_FEE_ROLE = keccak256("TAKE_FEE_ROLE"); 21 | bytes32 public constant ROUTER_ROLE = keccak256("ROUTER_ROLE"); 22 | 23 | uint256 private _maxSupply = 1000000000 * 10**decimals(); // 1 billion tokens is maximum supply 24 | uint256 private _initialSupply = 100000 * 10**decimals(); // 100,000 tokens is the initial supply 25 | 26 | address private _trustedForwarder; 27 | 28 | // Control support for EIP-2771 Meta Transactions 29 | bool public metaTxnsEnabled = false; 30 | 31 | event TokensRescued(address indexed sender, address indexed token, uint256 value); 32 | event MetaTxnsEnabled(address indexed caller); 33 | event MetaTxnsDisabled(address indexed caller); 34 | 35 | constructor(address trustedForwarder) ERC20("SolarBeam Token", "SOLAR") ERC20Permit("SolarBeam Token") { 36 | _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); 37 | _setupRole(PAUSER_ROLE, _msgSender()); 38 | _setupRole(MINTER_ROLE, _msgSender()); 39 | _setupRole(RESCUER_ROLE, _msgSender()); 40 | 41 | _trustedForwarder = trustedForwarder; 42 | 43 | _mint(_msgSender(), _initialSupply); 44 | } 45 | 46 | function isTrustedForwarder(address forwarder) public view virtual returns (bool) { 47 | return forwarder == _trustedForwarder; 48 | } 49 | 50 | function _msgSender() internal view override returns (address sender) { 51 | if (isTrustedForwarder(msg.sender)) { 52 | // The assembly code is more direct than the Solidity version using `abi.decode`. 53 | assembly { 54 | sender := shr(96, calldataload(sub(calldatasize(), 20))) 55 | } 56 | } else { 57 | return super._msgSender(); 58 | } 59 | } 60 | 61 | function _msgData() internal view override returns (bytes calldata) { 62 | if (isTrustedForwarder(msg.sender)) { 63 | return msg.data[:msg.data.length - 20]; 64 | } else { 65 | return super._msgData(); 66 | } 67 | } 68 | 69 | /** 70 | * @dev Returns the maximum amount of tokens that can be minted. 71 | */ 72 | function maxSupply() public view returns (uint256) { 73 | return _maxSupply; 74 | } 75 | 76 | function pause() public onlyRole(PAUSER_ROLE) { 77 | _pause(); 78 | } 79 | 80 | function unpause() public onlyRole(PAUSER_ROLE) { 81 | _unpause(); 82 | } 83 | 84 | function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) { 85 | require(totalSupply() + amount <= _maxSupply, "ERC20: cannot mint more tokens, cap exceeded"); 86 | _mint(to, amount); 87 | } 88 | 89 | function _beforeTokenTransfer( 90 | address from, 91 | address to, 92 | uint256 amount 93 | ) internal override whenNotPaused { 94 | super._beforeTokenTransfer(from, to, amount); 95 | } 96 | 97 | function rescueTokens(IERC20 token, uint256 value) external onlyRole(RESCUER_ROLE) { 98 | token.transfer(_msgSender(), value); 99 | 100 | emit TokensRescued(_msgSender(), address(token), value); 101 | } 102 | 103 | // Enable support for meta transactions 104 | function enableMetaTxns() public onlyRole(DEFAULT_ADMIN_ROLE) { 105 | require(!metaTxnsEnabled, "Meta transactions are already enabled"); 106 | 107 | metaTxnsEnabled = true; 108 | emit MetaTxnsEnabled(_msgSender()); 109 | } 110 | 111 | // Disable support for meta transactions 112 | function disableMetaTxns() public onlyRole(DEFAULT_ADMIN_ROLE) { 113 | require(metaTxnsEnabled, "Meta transactions are already disabled"); 114 | 115 | metaTxnsEnabled = false; 116 | emit MetaTxnsDisabled(_msgSender()); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /contracts/uniswapv2/SolarERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity =0.6.12; 3 | 4 | import "./libraries/SafeMath.sol"; 5 | 6 | contract SolarERC20 { 7 | using SafeMathSolar for uint256; 8 | 9 | string public constant name = "SolarBeam LP Token"; 10 | string public constant symbol = "SLP"; 11 | uint8 public constant decimals = 18; 12 | uint256 public totalSupply; 13 | mapping(address => uint256) public balanceOf; 14 | mapping(address => mapping(address => uint256)) public allowance; 15 | 16 | bytes32 public DOMAIN_SEPARATOR; 17 | // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); 18 | bytes32 public constant PERMIT_TYPEHASH = 19 | 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; 20 | mapping(address => uint256) public nonces; 21 | 22 | event Approval( 23 | address indexed owner, 24 | address indexed spender, 25 | uint256 value 26 | ); 27 | event Transfer(address indexed from, address indexed to, uint256 value); 28 | 29 | constructor() public { 30 | uint256 chainId; 31 | assembly { 32 | chainId := chainid() 33 | } 34 | DOMAIN_SEPARATOR = keccak256( 35 | abi.encode( 36 | keccak256( 37 | "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" 38 | ), 39 | keccak256(bytes(name)), 40 | keccak256(bytes("1")), 41 | chainId, 42 | address(this) 43 | ) 44 | ); 45 | } 46 | 47 | function _msgSender() internal view virtual returns (address) { 48 | return msg.sender; 49 | } 50 | 51 | function _msgData() internal pure virtual returns (bytes calldata) { 52 | return msg.data; 53 | } 54 | 55 | function _mint(address to, uint256 value) internal { 56 | totalSupply = totalSupply.add(value); 57 | balanceOf[to] = balanceOf[to].add(value); 58 | emit Transfer(address(0), to, value); 59 | } 60 | 61 | function _burn(address from, uint256 value) internal { 62 | balanceOf[from] = balanceOf[from].sub(value); 63 | totalSupply = totalSupply.sub(value); 64 | emit Transfer(from, address(0), value); 65 | } 66 | 67 | function _approve( 68 | address owner, 69 | address spender, 70 | uint256 value 71 | ) private { 72 | allowance[owner][spender] = value; 73 | emit Approval(owner, spender, value); 74 | } 75 | 76 | function _transfer( 77 | address from, 78 | address to, 79 | uint256 value 80 | ) private { 81 | balanceOf[from] = balanceOf[from].sub(value); 82 | balanceOf[to] = balanceOf[to].add(value); 83 | emit Transfer(from, to, value); 84 | } 85 | 86 | function approve(address spender, uint256 value) external returns (bool) { 87 | _approve(_msgSender(), spender, value); 88 | return true; 89 | } 90 | 91 | function transfer(address to, uint256 value) external returns (bool) { 92 | _transfer(_msgSender(), to, value); 93 | return true; 94 | } 95 | 96 | function transferFrom( 97 | address from, 98 | address to, 99 | uint256 value 100 | ) external returns (bool) { 101 | if (allowance[from][_msgSender()] != uint256(-1)) { 102 | allowance[from][_msgSender()] = allowance[from][_msgSender()].sub( 103 | value 104 | ); 105 | } 106 | _transfer(from, to, value); 107 | return true; 108 | } 109 | 110 | function permit( 111 | address owner, 112 | address spender, 113 | uint256 value, 114 | uint256 deadline, 115 | uint8 v, 116 | bytes32 r, 117 | bytes32 s 118 | ) external { 119 | require(deadline >= block.timestamp, "SolarBeam: EXPIRED"); 120 | bytes32 digest = keccak256( 121 | abi.encodePacked( 122 | "\x19\x01", 123 | DOMAIN_SEPARATOR, 124 | keccak256( 125 | abi.encode( 126 | PERMIT_TYPEHASH, 127 | owner, 128 | spender, 129 | value, 130 | nonces[owner]++, 131 | deadline 132 | ) 133 | ) 134 | ) 135 | ); 136 | address recoveredAddress = ecrecover(digest, v, r, s); 137 | require( 138 | recoveredAddress != address(0) && recoveredAddress == owner, 139 | "SolarBeam: INVALID_SIGNATURE" 140 | ); 141 | _approve(owner, spender, value); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /contracts/eclipse/amara/ICommonEclipseAmara.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.7; 3 | 4 | /** @title ICommonEclipse 5 | * @notice It is an interface for CommonEclipse.sol 6 | */ 7 | abstract contract ICommonEclipseAmara { 8 | enum WITHDRAW_TYPE { 9 | RAISING, 10 | TAX 11 | } 12 | 13 | enum HARVEST_TYPE { 14 | TIMESTAMP, 15 | PERCENT 16 | } 17 | 18 | /** 19 | * @notice It sets parameters for pool 20 | * @param _offeringAmountPool: offering amount (in tokens) 21 | * @param _raisingAmountPool: raising amount (in LP tokens) 22 | * @param _baseLimitInLP: base limit per user (in LP tokens) 23 | * @param _hasTax: if the pool has a tax 24 | * @param _pid: poolId 25 | * @dev This function is only callable by owner. 26 | */ 27 | function setPool( 28 | uint256 _offeringAmountPool, 29 | uint256 _raisingAmountPool, 30 | uint256 _baseLimitInLP, 31 | bool _hasTax, 32 | uint8 _pid 33 | ) external virtual; 34 | 35 | /** 36 | * @notice It allows users to deposit LP tokens to pool 37 | * @param _amount: the number of LP token used (18 decimals) 38 | * @param _pid: pool id 39 | */ 40 | function depositPool(uint256 _amount, uint8 _pid) external virtual; 41 | 42 | /** 43 | * @notice It allows users to harvest from pool 44 | * @param _pid: pool id 45 | * @param _harvestPeriod: chosen harvest period to claim 46 | */ 47 | function harvestPool(uint8 _pid, uint8 _harvestPeriod) external virtual; 48 | 49 | /** 50 | * @notice It allows owner to update start and end blocks of the sale 51 | * @param _startBlock: block number sale starts 52 | * @param _endBlock: block number sale ends 53 | */ 54 | function updateStartAndEndBlocks(uint256 _startBlock, uint256 _endBlock) 55 | external 56 | virtual; 57 | 58 | /** 59 | * @notice It allows owner to set the multiplier information 60 | * @param _multipliers: encoded multipliers for zero, seven and thirty day vaults 61 | * @dev encoded args are (uint8,uint8,uint8,uint8[2][3],uint8[2][3],uint8[2][3]) 62 | * (0 decimals) 63 | */ 64 | function setMultipliers(bytes memory _multipliers) public virtual; 65 | 66 | /** 67 | * @notice It allows owner to set the threshold for eligibility 68 | * @param _eligibilityThreshold: amount of solar staked in vaults to be eligibile 69 | */ 70 | function setEligibilityThreshold(uint256 _eligibilityThreshold) 71 | public 72 | virtual; 73 | 74 | /** 75 | * @notice It withdraws raisingAmount + taxes for a pool 76 | * @dev can only withdraw after the sale is finished 77 | * @param _type: withdraw type 78 | * @param _pid: pool id 79 | */ 80 | function finalWithdraw(WITHDRAW_TYPE _type, uint8 _pid) external virtual; 81 | 82 | /** 83 | * @notice It returns the tax overflow rate calculated for a pool 84 | * @dev 100,000,000,000 means 0.1 (10%) / 1 means 0.0000000000001 (0.0000001%) / 1,000,000,000,000 means 1 (100%) 85 | * @param _pid: poolId 86 | * @return It returns the tax percentage 87 | */ 88 | function viewPoolTaxRateOverflow(uint256 _pid) 89 | external 90 | virtual 91 | returns (uint256); 92 | 93 | /** 94 | * @notice External view function to see user allocations for both pools 95 | * @param _user: user address 96 | * @param _pids[]: array of pids 97 | */ 98 | function viewUserAllocationPools(address _user, uint8[] calldata _pids) 99 | external 100 | virtual 101 | returns (uint256[] memory); 102 | 103 | /** 104 | * @notice External view function to see user offering and refunding amounts for both pools 105 | * @param _user: user address 106 | * @param _pids: array of pids 107 | */ 108 | function viewUserOfferingAndRefundingAmountsForPools( 109 | address _user, 110 | uint8[] calldata _pids 111 | ) external view virtual returns (uint256[3][] memory); 112 | 113 | /** 114 | * @notice It allows users to withdraw LP tokens to pool 115 | * @param _amount: the number of LP token used (18 decimals) 116 | * @param _pid: pool id 117 | */ 118 | function withdrawPool(uint256 _amount, uint8 _pid) external virtual; 119 | 120 | /** 121 | * @notice It allows the admin to end sale and start claim 122 | * @dev This function is only callable by owner. 123 | */ 124 | function enableClaim() external virtual; 125 | 126 | function harvestReleasePercent(uint256) 127 | external 128 | view 129 | virtual 130 | returns (uint256); 131 | 132 | function harvestReleaseTimestamps(uint256) 133 | external 134 | view 135 | virtual 136 | returns (uint256); 137 | 138 | function harvestReleaseBlocks(uint256) 139 | external 140 | view 141 | virtual 142 | returns (uint256); 143 | } 144 | -------------------------------------------------------------------------------- /contracts/eclipse/amara/CommonEclipseAmara.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma experimental ABIEncoderV2; 3 | pragma solidity ^0.8.7; 4 | 5 | import "@openzeppelin/contracts/access/Ownable.sol"; 6 | import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 7 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 8 | import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; 9 | import "./ICommonEclipseAmara.sol"; 10 | 11 | contract CommonEclipseAmara is ReentrancyGuard, Ownable { 12 | using SafeERC20 for IERC20; 13 | 14 | /*/////////////////////////////////////////////////////////////// 15 | STORAGE 16 | //////////////////////////////////////////////////////////////*/ 17 | 18 | ICommonEclipseAmara eclipseV2; 19 | IERC20 offeringToken; 20 | uint256 public exchangeRate; 21 | 22 | uint8 public constant HARVEST_PERIODS = 6; // number of periods to split offering token to vest. 23 | 24 | struct UserInfo { 25 | uint256 amount; // How many tokens the user has provided for pool 26 | uint256 allocPoints; // Used to weight user allocation based on amount locked in solar vaults 27 | bool[HARVEST_PERIODS] claimed; // Whether the user has claimed (default: false) for pool 28 | bool isRefunded; // Wheter the user has been refunded or not. 29 | } 30 | 31 | mapping(address => mapping(uint8 => UserInfo)) public userInfo; 32 | 33 | event Harvest( 34 | address indexed user, 35 | uint256 offeringAmount, 36 | uint8 indexed pid 37 | ); 38 | 39 | constructor( 40 | ICommonEclipseAmara _eclipseV2, 41 | IERC20 _offeringToken, 42 | uint256 _exchangeRate 43 | ) { 44 | require(_offeringToken.totalSupply() > 0); 45 | require( 46 | _isContract(address(_offeringToken)), 47 | "_offeringToken is not a contract address" 48 | ); 49 | require( 50 | _isContract(address(_eclipseV2)), 51 | "_eclipseV2 is not a contract address" 52 | ); 53 | 54 | eclipseV2 = _eclipseV2; 55 | offeringToken = _offeringToken; 56 | exchangeRate = _exchangeRate; 57 | } 58 | 59 | /** 60 | * This method relies on extcodesize, which returns 0 for contracts in construction, 61 | * since the code is only stored at the end of the constructor execution. 62 | */ 63 | function _isContract(address account) internal view returns (bool) { 64 | uint256 size; 65 | assembly { 66 | size := extcodesize(account) 67 | } // solhint-disable-next-line no-inline-assembly 68 | return size > 0; 69 | } 70 | 71 | /*/////////////////////////////////////////////////////////////// 72 | HARVEST LOGIC 73 | //////////////////////////////////////////////////////////////*/ 74 | function harvestPool(uint8 _pid, uint8 _harvestPeriod) 75 | external 76 | nonReentrant 77 | { 78 | require(_pid < 2, "invalid pid"); 79 | require( 80 | _harvestPeriod < HARVEST_PERIODS, 81 | "harvest period out of range" 82 | ); 83 | 84 | require( 85 | block.timestamp > 86 | eclipseV2.harvestReleaseTimestamps(_harvestPeriod), 87 | "not harvest time" 88 | ); 89 | 90 | require( 91 | !userInfo[msg.sender][_pid].claimed[_harvestPeriod], 92 | "harvest for period already claimed" 93 | ); 94 | 95 | // uint256 offeringTokenAmount; 96 | uint8[] memory _pids = new uint8[](1); 97 | _pids[0] = _pid; 98 | 99 | uint256[3][] memory amountPools = eclipseV2 100 | .viewUserOfferingAndRefundingAmountsForPools(msg.sender, _pids); 101 | 102 | uint256 offeringTokenAmount = amountPools[0][0]; 103 | 104 | uint256 offeringTokenAmountPerPeriod; 105 | 106 | require(offeringTokenAmount > 0, "did not participate"); 107 | 108 | userInfo[msg.sender][_pid].claimed[_harvestPeriod] = true; 109 | 110 | if (offeringTokenAmount > 0) { 111 | offeringTokenAmountPerPeriod = 112 | (offeringTokenAmount * 113 | eclipseV2.harvestReleasePercent(_harvestPeriod)) / 114 | 1e4; 115 | 116 | offeringTokenAmountPerPeriod = 117 | offeringTokenAmountPerPeriod * 118 | exchangeRate; 119 | 120 | offeringToken.safeTransfer( 121 | address(msg.sender), 122 | offeringTokenAmountPerPeriod 123 | ); 124 | } 125 | 126 | userInfo[msg.sender][_pid].claimed[_harvestPeriod] = true; 127 | 128 | emit Harvest(msg.sender, offeringTokenAmountPerPeriod, _pid); 129 | } 130 | 131 | function hasHarvested( 132 | address _user, 133 | uint8 _pid, 134 | uint8 _harvestPeriod 135 | ) public view returns (bool) { 136 | return userInfo[_user][_pid].claimed[_harvestPeriod]; 137 | } 138 | 139 | function emergencyWithdraw(uint256 _offerAmount) external onlyOwner { 140 | require( 141 | _offerAmount <= offeringToken.balanceOf(address(this)), 142 | "Not enough offering tokens" 143 | ); 144 | 145 | if (_offerAmount > 0) { 146 | offeringToken.safeTransfer(address(msg.sender), _offerAmount); 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /contracts/uniswapv2/libraries/SolarLibrary.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity =0.6.12; 3 | 4 | import "../interfaces/ISolarPair.sol"; 5 | import "./SafeMath.sol"; 6 | 7 | library SolarLibrary { 8 | using SafeMathSolar for uint256; 9 | 10 | // returns sorted token addresses, used to handle return values from pairs sorted in this order 11 | function sortTokens(address tokenA, address tokenB) 12 | internal 13 | pure 14 | returns (address token0, address token1) 15 | { 16 | require(tokenA != tokenB, "SolarLibrary: IDENTICAL_ADDRESSES"); 17 | (token0, token1) = tokenA < tokenB 18 | ? (tokenA, tokenB) 19 | : (tokenB, tokenA); 20 | require(token0 != address(0), "SolarLibrary: ZERO_ADDRESS"); 21 | } 22 | 23 | // calculates the CREATE2 address for a pair without making any external calls 24 | function pairFor( 25 | address factory, 26 | address tokenA, 27 | address tokenB 28 | ) internal pure returns (address pair) { 29 | (address token0, address token1) = sortTokens(tokenA, tokenB); 30 | pair = address( 31 | uint256( 32 | keccak256( 33 | abi.encodePacked( 34 | hex"ff", 35 | factory, 36 | keccak256(abi.encodePacked(token0, token1)), 37 | hex"0f53772a0b91c61dc3aaaa6aa3f0c898f1dbd2c53070a959c4254207038e064d" // init code hash 38 | ) 39 | ) 40 | ) 41 | ); 42 | } 43 | 44 | // fetches and sorts the reserves for a pair 45 | function getReserves( 46 | address factory, 47 | address tokenA, 48 | address tokenB 49 | ) internal view returns (uint256 reserveA, uint256 reserveB) { 50 | (address token0, ) = sortTokens(tokenA, tokenB); 51 | (uint256 reserve0, uint256 reserve1, ) = ISolarPair( 52 | pairFor(factory, tokenA, tokenB) 53 | ).getReserves(); 54 | (reserveA, reserveB) = tokenA == token0 55 | ? (reserve0, reserve1) 56 | : (reserve1, reserve0); 57 | } 58 | 59 | // given some amount of an asset and pair reserves, returns an equivalent amount of the other asset 60 | function quote( 61 | uint256 amountA, 62 | uint256 reserveA, 63 | uint256 reserveB 64 | ) internal pure returns (uint256 amountB) { 65 | require(amountA > 0, "SolarLibrary: INSUFFICIENT_AMOUNT"); 66 | require( 67 | reserveA > 0 && reserveB > 0, 68 | "SolarLibrary: INSUFFICIENT_LIQUIDITY" 69 | ); 70 | amountB = amountA.mul(reserveB) / reserveA; 71 | } 72 | 73 | // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset 74 | function getAmountOut( 75 | uint256 amountIn, 76 | uint256 reserveIn, 77 | uint256 reserveOut 78 | ) internal pure returns (uint256 amountOut) { 79 | require(amountIn > 0, "SolarLibrary: INSUFFICIENT_INPUT_AMOUNT"); 80 | require( 81 | reserveIn > 0 && reserveOut > 0, 82 | "SolarLibrary: INSUFFICIENT_LIQUIDITY" 83 | ); 84 | uint256 feeMul = uint256(10000).sub(25); 85 | uint256 amountInWithFee = amountIn.mul(feeMul); 86 | uint256 numerator = amountInWithFee.mul(reserveOut); 87 | uint256 denominator = reserveIn.mul(10000).add(amountInWithFee); 88 | amountOut = numerator / denominator; 89 | } 90 | 91 | // given an output amount of an asset and pair reserves, returns a required input amount of the other asset 92 | function getAmountIn( 93 | uint256 amountOut, 94 | uint256 reserveIn, 95 | uint256 reserveOut 96 | ) internal pure returns (uint256 amountIn) { 97 | require(amountOut > 0, "SolarLibrary: INSUFFICIENT_OUTPUT_AMOUNT"); 98 | require( 99 | reserveIn > 0 && reserveOut > 0, 100 | "SolarLibrary: INSUFFICIENT_LIQUIDITY" 101 | ); 102 | uint256 feeMul = uint256(10000).sub(25); 103 | uint256 numerator = reserveIn.mul(amountOut).mul(10000); 104 | uint256 denominator = reserveOut.sub(amountOut).mul(feeMul); 105 | amountIn = (numerator / denominator).add(1); 106 | } 107 | 108 | // performs chained getAmountOut calculations on any number of pairs 109 | function getAmountsOut( 110 | address factory, 111 | uint256 amountIn, 112 | address[] memory path 113 | ) internal view returns (uint256[] memory amounts) { 114 | require(path.length >= 2, "SolarLibrary: INVALID_PATH"); 115 | amounts = new uint256[](path.length); 116 | amounts[0] = amountIn; 117 | for (uint256 i; i < path.length - 1; i++) { 118 | (uint256 reserveIn, uint256 reserveOut) = getReserves( 119 | factory, 120 | path[i], 121 | path[i + 1] 122 | ); 123 | amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut); 124 | } 125 | } 126 | 127 | // performs chained getAmountIn calculations on any number of pairs 128 | function getAmountsIn( 129 | address factory, 130 | uint256 amountOut, 131 | address[] memory path 132 | ) internal view returns (uint256[] memory amounts) { 133 | require(path.length >= 2, "SolarLibrary: INVALID_PATH"); 134 | amounts = new uint256[](path.length); 135 | amounts[amounts.length - 1] = amountOut; 136 | for (uint256 i = path.length - 1; i > 0; i--) { 137 | (uint256 reserveIn, uint256 reserveOut) = getReserves( 138 | factory, 139 | path[i - 1], 140 | path[i] 141 | ); 142 | amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut); 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /contracts/fee/SolarFeeColector.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.2; 3 | 4 | import "@openzeppelin/contracts/access/Ownable.sol"; 5 | import "@openzeppelin/contracts/utils/math/SafeMath.sol"; 6 | import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 7 | 8 | import "./interfaces/ISolarERC20.sol"; 9 | import "./interfaces/ISolarPair.sol"; 10 | import "./interfaces/ISolarFactory.sol"; 11 | import "./interfaces/ISolarRouter02.sol"; 12 | import "./interfaces/ISmartRouter.sol"; 13 | 14 | contract SolarFeeColector is Ownable { 15 | using SafeMath for uint256; 16 | using SafeERC20 for IERC20; 17 | uint256 internal constant UINT_MAX = type(uint256).max; 18 | 19 | ISmartRouter public smartRouter; 20 | ISolarRouter02 public router; 21 | address private immutable wmovr; 22 | 23 | constructor( 24 | address _smartRouter, 25 | address _router, 26 | address _wmovr 27 | ) { 28 | smartRouter = ISmartRouter(_smartRouter); 29 | router = ISolarRouter02(_router); 30 | wmovr = _wmovr; 31 | } 32 | 33 | function removeLiquidityAndSwap(address[] memory lpTokens, address toToken) 34 | external 35 | onlyOwner 36 | { 37 | uint256 len = lpTokens.length; 38 | for (uint256 i = 0; i < len; i++) { 39 | ISolarPair pair = ISolarPair(lpTokens[i]); 40 | address token0 = ISolarPair(pair).token0(); 41 | address token1 = ISolarPair(pair).token1(); 42 | 43 | _removeLiquidity(address(pair), address(this)); 44 | _swap(token0, toToken, address(this)); 45 | _swap(token1, toToken, address(this)); 46 | } 47 | } 48 | 49 | function removeLiquidity(address[] memory lpTokens) external onlyOwner { 50 | uint256 len = lpTokens.length; 51 | for (uint256 i = 0; i < len; i++) { 52 | _removeLiquidity(lpTokens[i], address(this)); 53 | } 54 | } 55 | 56 | function removeLiquidityFrom(address[] memory lpTokens) external onlyOwner { 57 | uint256 len = lpTokens.length; 58 | for (uint256 i = 0; i < len; i++) { 59 | _removeLiquidity(lpTokens[i], msg.sender); 60 | } 61 | } 62 | 63 | function _removeLiquidity(address lpToken, address from) internal { 64 | ISolarPair pair = ISolarPair(lpToken); 65 | address token0 = ISolarPair(lpToken).token0(); 66 | address token1 = ISolarPair(lpToken).token1(); 67 | require(address(pair) != address(0), "SolarFeeColector: Invalid pair"); 68 | 69 | uint256 amount = IERC20(address(pair)).balanceOf(from); 70 | 71 | if (amount > 0) { 72 | if (from != address(this)) { 73 | IERC20(address(pair)).safeTransferFrom( 74 | from, 75 | address(this), 76 | amount 77 | ); 78 | } 79 | 80 | if ( 81 | IERC20(lpToken).allowance(address(this), address(router)) < 82 | amount 83 | ) { 84 | IERC20(lpToken).safeApprove(address(router), UINT_MAX); 85 | } 86 | 87 | router.removeLiquidity( 88 | token0, 89 | token1, 90 | amount, 91 | 0, 92 | 0, 93 | msg.sender, 94 | block.timestamp 95 | ); 96 | } 97 | } 98 | 99 | function swapTokens(address[] memory tokens, address toToken) 100 | external 101 | onlyOwner 102 | { 103 | uint256 len = tokens.length; 104 | for (uint256 i = 0; i < len; i++) { 105 | _swap(tokens[i], toToken, address(this)); 106 | } 107 | } 108 | 109 | function swapTokensFrom(address[] memory tokens, address toToken) 110 | external 111 | onlyOwner 112 | { 113 | uint256 len = tokens.length; 114 | for (uint256 i = 0; i < len; i++) { 115 | _swap(tokens[i], toToken, msg.sender); 116 | } 117 | } 118 | 119 | function _swap( 120 | address fromToken, 121 | address toToken, 122 | address from 123 | ) internal { 124 | uint256 amount = IERC20(address(fromToken)).balanceOf(from); 125 | 126 | if (amount > 0) { 127 | if (from != address(this)) { 128 | IERC20(address(fromToken)).safeTransferFrom( 129 | from, 130 | address(this), 131 | amount 132 | ); 133 | } 134 | 135 | if ( 136 | IERC20(fromToken).allowance( 137 | address(this), 138 | address(smartRouter) 139 | ) < amount 140 | ) { 141 | IERC20(fromToken).safeApprove(address(smartRouter), UINT_MAX); 142 | } 143 | 144 | ISmartRouter.FormattedOffer memory offer = smartRouter.findBestPath( 145 | amount, 146 | fromToken, 147 | toToken, 148 | 3, 149 | ISmartRouter.InputType.AMOUNT_IN 150 | ); 151 | 152 | ISmartRouter.Trade memory trade = ISmartRouter.Trade( 153 | offer.amounts, 154 | offer.path, 155 | offer.adapters 156 | ); 157 | 158 | smartRouter.swapNoSplit(trade, msg.sender, 0); 159 | } 160 | } 161 | 162 | receive() external payable {} 163 | 164 | function recoverERC20(address _tokenAddress, uint256 _tokenAmount) 165 | external 166 | onlyOwner 167 | { 168 | require(_tokenAmount > 0, "Nothing to recover"); 169 | IERC20(_tokenAddress).safeTransfer(msg.sender, _tokenAmount); 170 | } 171 | 172 | function recoverNATIVE(uint256 _amount) external onlyOwner { 173 | require(_amount > 0, "Nothing to recover"); 174 | payable(msg.sender).transfer(_amount); 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /contracts/forwarder/Forwarder.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity ^0.8.2; 3 | pragma abicoder v2; 4 | 5 | import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; 6 | import "./IForwarder.sol"; 7 | 8 | contract Forwarder is IForwarder { 9 | using ECDSA for bytes32; 10 | 11 | string public constant GENERIC_PARAMS = "address from,address to,uint256 value,uint256 gas,uint256 nonce,bytes data,uint256 validUntil"; 12 | 13 | string public constant EIP712_DOMAIN_TYPE = "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"; 14 | 15 | mapping(bytes32 => bool) public typeHashes; 16 | mapping(bytes32 => bool) public domains; 17 | 18 | // Nonces of senders, used to prevent replay attacks 19 | mapping(address => uint256) private nonces; 20 | 21 | // solhint-disable-next-line no-empty-blocks 22 | receive() external payable {} 23 | 24 | function getNonce(address from) 25 | public view override 26 | returns (uint256) { 27 | return nonces[from]; 28 | } 29 | 30 | constructor() { 31 | string memory requestType = string(abi.encodePacked("ForwardRequest(", GENERIC_PARAMS, ")")); 32 | registerRequestTypeInternal(requestType); 33 | } 34 | 35 | function verify( 36 | ForwardRequest calldata req, 37 | bytes32 domainSeparator, 38 | bytes32 requestTypeHash, 39 | bytes calldata suffixData, 40 | bytes calldata sig) 41 | external override view { 42 | 43 | _verifyNonce(req); 44 | _verifySig(req, domainSeparator, requestTypeHash, suffixData, sig); 45 | } 46 | 47 | function execute( 48 | ForwardRequest calldata req, 49 | bytes32 domainSeparator, 50 | bytes32 requestTypeHash, 51 | bytes calldata suffixData, 52 | bytes calldata sig 53 | ) 54 | external payable 55 | override 56 | returns (bool success, bytes memory ret) { 57 | _verifySig(req, domainSeparator, requestTypeHash, suffixData, sig); 58 | _verifyAndUpdateNonce(req); 59 | 60 | require(req.validUntil == 0 || req.validUntil > block.number, "FWD: request expired"); 61 | 62 | uint gasForTransfer = 0; 63 | if ( req.value != 0 ) { 64 | gasForTransfer = 40000; //buffer in case we need to move eth after the transaction. 65 | } 66 | bytes memory callData = abi.encodePacked(req.data, req.from); 67 | require(gasleft()*63/64 >= req.gas + gasForTransfer, "FWD: insufficient gas"); 68 | // solhint-disable-next-line avoid-low-level-calls 69 | (success,ret) = req.to.call{gas : req.gas, value : req.value}(callData); 70 | if ( req.value != 0 && address(this).balance>0 ) { 71 | // can't fail: req.from signed (off-chain) the request, so it must be an EOA... 72 | payable(req.from).transfer(address(this).balance); 73 | } 74 | 75 | return (success,ret); 76 | } 77 | 78 | 79 | function _verifyNonce(ForwardRequest calldata req) internal view { 80 | require(nonces[req.from] == req.nonce, "FWD: nonce mismatch"); 81 | } 82 | 83 | function _verifyAndUpdateNonce(ForwardRequest calldata req) internal { 84 | require(nonces[req.from]++ == req.nonce, "FWD: nonce mismatch"); 85 | } 86 | 87 | function registerRequestType(string calldata typeName, string calldata typeSuffix) external override { 88 | 89 | for (uint i = 0; i < bytes(typeName).length; i++) { 90 | bytes1 c = bytes(typeName)[i]; 91 | require(c != "(" && c != ")", "FWD: invalid typename"); 92 | } 93 | 94 | string memory requestType = string(abi.encodePacked(typeName, "(", GENERIC_PARAMS, ",", typeSuffix)); 95 | registerRequestTypeInternal(requestType); 96 | } 97 | 98 | function registerDomainSeparator(string calldata name, string calldata version) external override { 99 | uint256 chainId; 100 | /* solhint-disable-next-line no-inline-assembly */ 101 | assembly { chainId := chainid() } 102 | 103 | bytes memory domainValue = abi.encode( 104 | keccak256(bytes(EIP712_DOMAIN_TYPE)), 105 | keccak256(bytes(name)), 106 | keccak256(bytes(version)), 107 | chainId, 108 | address(this)); 109 | 110 | bytes32 domainHash = keccak256(domainValue); 111 | 112 | domains[domainHash] = true; 113 | emit DomainRegistered(domainHash, domainValue); 114 | } 115 | 116 | function registerRequestTypeInternal(string memory requestType) internal { 117 | 118 | bytes32 requestTypehash = keccak256(bytes(requestType)); 119 | typeHashes[requestTypehash] = true; 120 | emit RequestTypeRegistered(requestTypehash, requestType); 121 | } 122 | 123 | function _verifySig( 124 | ForwardRequest calldata req, 125 | bytes32 domainSeparator, 126 | bytes32 requestTypeHash, 127 | bytes calldata suffixData, 128 | bytes calldata sig) 129 | internal 130 | view 131 | { 132 | require(domains[domainSeparator], "FWD: unregistered domain sep."); 133 | require(typeHashes[requestTypeHash], "FWD: unregistered typehash"); 134 | bytes32 digest = keccak256(abi.encodePacked( 135 | "\x19\x01", domainSeparator, 136 | keccak256(_getEncoded(req, requestTypeHash, suffixData)) 137 | )); 138 | require(digest.recover(sig) == req.from, "FWD: signature mismatch"); 139 | } 140 | 141 | function _getEncoded( 142 | ForwardRequest calldata req, 143 | bytes32 requestTypeHash, 144 | bytes calldata suffixData 145 | ) 146 | public 147 | pure 148 | returns ( 149 | bytes memory 150 | ) { 151 | // we use encodePacked since we append suffixData as-is, not as dynamic param. 152 | // still, we must make sure all first params are encoded as abi.encode() 153 | // would encode them - as 256-bit-wide params. 154 | return abi.encodePacked( 155 | requestTypeHash, 156 | uint256(uint160(req.from)), 157 | uint256(uint160(req.to)), 158 | req.value, 159 | req.gas, 160 | req.nonce, 161 | keccak256(req.data), 162 | req.validUntil, 163 | suffixData 164 | ); 165 | } 166 | } -------------------------------------------------------------------------------- /contracts/gasless/ISolarRouter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.7; 3 | 4 | interface ISolarRouter { 5 | function factory() external pure returns (address); 6 | 7 | function WETH() external pure returns (address); 8 | 9 | function addLiquidity( 10 | address tokenA, 11 | address tokenB, 12 | uint256 amountADesired, 13 | uint256 amountBDesired, 14 | uint256 amountAMin, 15 | uint256 amountBMin, 16 | address to, 17 | uint256 deadline 18 | ) 19 | external 20 | returns ( 21 | uint256 amountA, 22 | uint256 amountB, 23 | uint256 liquidity 24 | ); 25 | 26 | function addLiquidityETH( 27 | address token, 28 | uint256 amountTokenDesired, 29 | uint256 amountTokenMin, 30 | uint256 amountETHMin, 31 | address to, 32 | uint256 deadline 33 | ) 34 | external 35 | payable 36 | returns ( 37 | uint256 amountToken, 38 | uint256 amountETH, 39 | uint256 liquidity 40 | ); 41 | 42 | function removeLiquidity( 43 | address tokenA, 44 | address tokenB, 45 | uint256 liquidity, 46 | uint256 amountAMin, 47 | uint256 amountBMin, 48 | address to, 49 | uint256 deadline 50 | ) external returns (uint256 amountA, uint256 amountB); 51 | 52 | function removeLiquidityETH( 53 | address token, 54 | uint256 liquidity, 55 | uint256 amountTokenMin, 56 | uint256 amountETHMin, 57 | address to, 58 | uint256 deadline 59 | ) external returns (uint256 amountToken, uint256 amountETH); 60 | 61 | function removeLiquidityWithPermit( 62 | address tokenA, 63 | address tokenB, 64 | uint256 liquidity, 65 | uint256 amountAMin, 66 | uint256 amountBMin, 67 | address to, 68 | uint256 deadline, 69 | bool approveMax, 70 | uint8 v, 71 | bytes32 r, 72 | bytes32 s 73 | ) external returns (uint256 amountA, uint256 amountB); 74 | 75 | function removeLiquidityETHWithPermit( 76 | address token, 77 | uint256 liquidity, 78 | uint256 amountTokenMin, 79 | uint256 amountETHMin, 80 | address to, 81 | uint256 deadline, 82 | bool approveMax, 83 | uint8 v, 84 | bytes32 r, 85 | bytes32 s 86 | ) external returns (uint256 amountToken, uint256 amountETH); 87 | 88 | function swapExactTokensForTokens( 89 | uint256 amountIn, 90 | uint256 amountOutMin, 91 | address[] calldata path, 92 | address to, 93 | uint256 deadline 94 | ) external returns (uint256[] memory amounts); 95 | 96 | function swapTokensForExactTokens( 97 | uint256 amountOut, 98 | uint256 amountInMax, 99 | address[] calldata path, 100 | address to, 101 | uint256 deadline 102 | ) external returns (uint256[] memory amounts); 103 | 104 | function swapExactETHForTokens( 105 | uint256 amountOutMin, 106 | address[] calldata path, 107 | address to, 108 | uint256 deadline 109 | ) external payable returns (uint256[] memory amounts); 110 | 111 | function swapTokensForExactETH( 112 | uint256 amountOut, 113 | uint256 amountInMax, 114 | address[] calldata path, 115 | address to, 116 | uint256 deadline 117 | ) external returns (uint256[] memory amounts); 118 | 119 | function swapExactTokensForETH( 120 | uint256 amountIn, 121 | uint256 amountOutMin, 122 | address[] calldata path, 123 | address to, 124 | uint256 deadline 125 | ) external returns (uint256[] memory amounts); 126 | 127 | function swapETHForExactTokens( 128 | uint256 amountOut, 129 | address[] calldata path, 130 | address to, 131 | uint256 deadline 132 | ) external payable returns (uint256[] memory amounts); 133 | 134 | function quote( 135 | uint256 amountA, 136 | uint256 reserveA, 137 | uint256 reserveB 138 | ) external pure returns (uint256 amountB); 139 | 140 | function getAmountOut( 141 | uint256 amountIn, 142 | uint256 reserveIn, 143 | uint256 reserveOut, 144 | uint256 fee 145 | ) external pure returns (uint256 amountOut); 146 | 147 | function getAmountIn( 148 | uint256 amountOut, 149 | uint256 reserveIn, 150 | uint256 reserveOut, 151 | uint256 fee 152 | ) external pure returns (uint256 amountIn); 153 | 154 | function getAmountsOut( 155 | uint256 amountIn, 156 | address[] calldata path, 157 | uint256 fee 158 | ) external view returns (uint256[] memory amounts); 159 | 160 | function getAmountsIn( 161 | uint256 amountOut, 162 | address[] calldata path, 163 | uint256 fee 164 | ) external view returns (uint256[] memory amounts); 165 | 166 | function removeLiquidityETHSupportingFeeOnTransferTokens( 167 | address token, 168 | uint256 liquidity, 169 | uint256 amountTokenMin, 170 | uint256 amountETHMin, 171 | address to, 172 | uint256 deadline 173 | ) external returns (uint256 amountETH); 174 | 175 | function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( 176 | address token, 177 | uint256 liquidity, 178 | uint256 amountTokenMin, 179 | uint256 amountETHMin, 180 | address to, 181 | uint256 deadline, 182 | bool approveMax, 183 | uint8 v, 184 | bytes32 r, 185 | bytes32 s 186 | ) external returns (uint256 amountETH); 187 | 188 | function swapExactTokensForTokensSupportingFeeOnTransferTokens( 189 | uint256 amountIn, 190 | uint256 amountOutMin, 191 | address[] calldata path, 192 | address to, 193 | uint256 deadline 194 | ) external; 195 | 196 | function swapExactETHForTokensSupportingFeeOnTransferTokens( 197 | uint256 amountOutMin, 198 | address[] calldata path, 199 | address to, 200 | uint256 deadline 201 | ) external payable; 202 | 203 | function swapExactTokensForETHSupportingFeeOnTransferTokens( 204 | uint256 amountIn, 205 | uint256 amountOutMin, 206 | address[] calldata path, 207 | address to, 208 | uint256 deadline 209 | ) external; 210 | } 211 | -------------------------------------------------------------------------------- /contracts/helpers/Timelock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity =0.8.2; 3 | 4 | import "@openzeppelin/contracts/utils/math/SafeMath.sol"; 5 | 6 | contract Timelock { 7 | using SafeMath for uint256; 8 | 9 | event NewAdmin(address indexed newAdmin); 10 | event NewPendingAdmin(address indexed newPendingAdmin); 11 | event NewDelay(uint256 indexed newDelay); 12 | event CancelTransaction( 13 | bytes32 indexed txHash, 14 | address indexed target, 15 | uint256 value, 16 | string signature, 17 | bytes data, 18 | uint256 eta 19 | ); 20 | event ExecuteTransaction( 21 | bytes32 indexed txHash, 22 | address indexed target, 23 | uint256 value, 24 | string signature, 25 | bytes data, 26 | uint256 eta 27 | ); 28 | event QueueTransaction( 29 | bytes32 indexed txHash, 30 | address indexed target, 31 | uint256 value, 32 | string signature, 33 | bytes data, 34 | uint256 eta 35 | ); 36 | 37 | uint256 public constant GRACE_PERIOD = 14 days; 38 | uint256 public constant MINIMUM_DELAY = 6 hours; 39 | uint256 public constant MAXIMUM_DELAY = 30 days; 40 | 41 | address public admin; 42 | address public pendingAdmin; 43 | uint256 public delay; 44 | bool public admin_initialized; 45 | 46 | mapping(bytes32 => bool) public queuedTransactions; 47 | 48 | constructor(address admin_, uint256 delay_) { 49 | require( 50 | delay_ >= MINIMUM_DELAY, 51 | "Timelock::constructor: Delay must exceed minimum delay." 52 | ); 53 | require( 54 | delay_ <= MAXIMUM_DELAY, 55 | "Timelock::constructor: Delay must not exceed maximum delay." 56 | ); 57 | 58 | admin = admin_; 59 | delay = delay_; 60 | admin_initialized = false; 61 | } 62 | 63 | // XXX: function() external payable { } 64 | receive() external payable {} 65 | 66 | function setDelay(uint256 delay_) public { 67 | require( 68 | msg.sender == address(this), 69 | "Timelock::setDelay: Call must come from Timelock." 70 | ); 71 | require( 72 | delay_ >= MINIMUM_DELAY, 73 | "Timelock::setDelay: Delay must exceed minimum delay." 74 | ); 75 | require( 76 | delay_ <= MAXIMUM_DELAY, 77 | "Timelock::setDelay: Delay must not exceed maximum delay." 78 | ); 79 | delay = delay_; 80 | 81 | emit NewDelay(delay); 82 | } 83 | 84 | function acceptAdmin() public { 85 | require( 86 | msg.sender == pendingAdmin, 87 | "Timelock::acceptAdmin: Call must come from pendingAdmin." 88 | ); 89 | admin = msg.sender; 90 | pendingAdmin = address(0); 91 | 92 | emit NewAdmin(admin); 93 | } 94 | 95 | function setPendingAdmin(address pendingAdmin_) public { 96 | // allows one time setting of admin for deployment purposes 97 | if (admin_initialized) { 98 | require( 99 | msg.sender == address(this), 100 | "Timelock::setPendingAdmin: Call must come from Timelock." 101 | ); 102 | } else { 103 | require( 104 | msg.sender == admin, 105 | "Timelock::setPendingAdmin: First call must come from admin." 106 | ); 107 | admin_initialized = true; 108 | } 109 | pendingAdmin = pendingAdmin_; 110 | 111 | emit NewPendingAdmin(pendingAdmin); 112 | } 113 | 114 | function queueTransaction( 115 | address target, 116 | uint256 value, 117 | string memory signature, 118 | bytes memory data, 119 | uint256 eta 120 | ) public returns (bytes32) { 121 | require( 122 | msg.sender == admin, 123 | "Timelock::queueTransaction: Call must come from admin." 124 | ); 125 | require( 126 | eta >= getBlockTimestamp().add(delay), 127 | "Timelock::queueTransaction: Estimated execution block must satisfy delay." 128 | ); 129 | 130 | bytes32 txHash = keccak256( 131 | abi.encode(target, value, signature, data, eta) 132 | ); 133 | queuedTransactions[txHash] = true; 134 | 135 | emit QueueTransaction(txHash, target, value, signature, data, eta); 136 | return txHash; 137 | } 138 | 139 | function cancelTransaction( 140 | address target, 141 | uint256 value, 142 | string memory signature, 143 | bytes memory data, 144 | uint256 eta 145 | ) public { 146 | require( 147 | msg.sender == admin, 148 | "Timelock::cancelTransaction: Call must come from admin." 149 | ); 150 | 151 | bytes32 txHash = keccak256( 152 | abi.encode(target, value, signature, data, eta) 153 | ); 154 | queuedTransactions[txHash] = false; 155 | 156 | emit CancelTransaction(txHash, target, value, signature, data, eta); 157 | } 158 | 159 | function executeTransaction( 160 | address target, 161 | uint256 value, 162 | string memory signature, 163 | bytes memory data, 164 | uint256 eta 165 | ) public payable returns (bytes memory) { 166 | require( 167 | msg.sender == admin, 168 | "Timelock::executeTransaction: Call must come from admin." 169 | ); 170 | 171 | bytes32 txHash = keccak256( 172 | abi.encode(target, value, signature, data, eta) 173 | ); 174 | require( 175 | queuedTransactions[txHash], 176 | "Timelock::executeTransaction: Transaction hasn't been queued." 177 | ); 178 | require( 179 | getBlockTimestamp() >= eta, 180 | "Timelock::executeTransaction: Transaction hasn't surpassed time lock." 181 | ); 182 | require( 183 | getBlockTimestamp() <= eta.add(GRACE_PERIOD), 184 | "Timelock::executeTransaction: Transaction is stale." 185 | ); 186 | 187 | queuedTransactions[txHash] = false; 188 | 189 | bytes memory callData; 190 | 191 | if (bytes(signature).length == 0) { 192 | callData = data; 193 | } else { 194 | callData = abi.encodePacked( 195 | bytes4(keccak256(bytes(signature))), 196 | data 197 | ); 198 | } 199 | 200 | // solium-disable-next-line security/no-call-value 201 | (bool success, bytes memory returnData) = target.call{value: value}( 202 | callData 203 | ); 204 | require( 205 | success, 206 | "Timelock::executeTransaction: Transaction execution reverted." 207 | ); 208 | 209 | emit ExecuteTransaction(txHash, target, value, signature, data, eta); 210 | 211 | return returnData; 212 | } 213 | 214 | function getBlockTimestamp() internal view returns (uint256) { 215 | // solium-disable-next-line security/no-block-members 216 | return block.timestamp; 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /contracts/eclipse/amaraV2/CommonEclipseAmaraV2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma experimental ABIEncoderV2; 3 | pragma solidity ^0.8.7; 4 | 5 | import "@openzeppelin/contracts/access/Ownable.sol"; 6 | import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 7 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 8 | import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; 9 | import "./ICommonEclipseAmaraV2.sol"; 10 | import "../v2/CommonEclipseV2.sol"; 11 | 12 | contract CommonEclipseAmaraV2 is ReentrancyGuard, Ownable { 13 | using SafeERC20 for IERC20; 14 | 15 | /*/////////////////////////////////////////////////////////////// 16 | STORAGE 17 | //////////////////////////////////////////////////////////////*/ 18 | 19 | CommonEclipseV2 eclipseV2; 20 | CommonEclipseV2 amaraV2; 21 | IERC20 offeringToken; 22 | uint256 public exchangeRate; 23 | 24 | uint8 public constant HARVEST_PERIODS = 6; // number of periods to split offering token to vest. 25 | 26 | struct UserInfo { 27 | uint256 amount; // How many tokens the user has provided for pool 28 | uint256 allocPoints; // Used to weight user allocation based on amount locked in solar vaults 29 | bool[HARVEST_PERIODS] claimed; // Whether the user has claimed (default: false) for pool 30 | bool isRefunded; // Wheter the user has been refunded or not. 31 | } 32 | 33 | mapping(address => mapping(uint8 => UserInfo)) public _userInfo; 34 | 35 | event Harvest( 36 | address indexed user, 37 | uint256 offeringAmount, 38 | uint8 indexed pid 39 | ); 40 | 41 | constructor( 42 | CommonEclipseV2 _eclipseV2, 43 | CommonEclipseV2 _amaraV2, 44 | IERC20 _offeringToken, 45 | uint256 _exchangeRate 46 | ) { 47 | require(_offeringToken.totalSupply() > 0); 48 | require( 49 | _isContract(address(_offeringToken)), 50 | "_offeringToken is not a contract address" 51 | ); 52 | require( 53 | _isContract(address(_eclipseV2)), 54 | "_eclipseV2 is not a contract address" 55 | ); 56 | require( 57 | _isContract(address(_amaraV2)), 58 | "_amaraV2 is not a contract address" 59 | ); 60 | amaraV2 = _amaraV2; 61 | eclipseV2 = _eclipseV2; 62 | offeringToken = _offeringToken; 63 | exchangeRate = _exchangeRate; 64 | } 65 | 66 | /** 67 | * This method relies on extcodesize, which returns 0 for contracts in construction, 68 | * since the code is only stored at the end of the constructor execution. 69 | */ 70 | function _isContract(address account) internal view returns (bool) { 71 | uint256 size; 72 | assembly { 73 | size := extcodesize(account) 74 | } // solhint-disable-next-line no-inline-assembly 75 | return size > 0; 76 | } 77 | 78 | function calculateAmountToClaim( 79 | address _user, 80 | uint8 _pid, 81 | uint8 _harvestPeriod 82 | ) public view returns (uint256 result) { 83 | uint8[] memory _pids = new uint8[](1); 84 | _pids[0] = _pid; 85 | 86 | uint256[3][] memory amountPools = eclipseV2 87 | .viewUserOfferingAndRefundingAmountsForPools(_user, _pids); 88 | 89 | uint256 offeringTokenAmount = amountPools[0][0]; 90 | 91 | uint256 offeringTokenAmountPerPeriod = 0; 92 | result = 0; 93 | 94 | if (offeringTokenAmount > 0) { 95 | if (_pid == 0) { 96 | //BASIC 97 | if (!amaraV2.hasHarvested(_user, _pid, _harvestPeriod)) { 98 | result = 99 | ((offeringTokenAmount * 100 | eclipseV2.harvestReleasePercent(_harvestPeriod)) / 101 | 1e4) * 102 | exchangeRate; 103 | } 104 | } else { 105 | (uint256 amount, , ) = eclipseV2.userInfo(_user, _pid); 106 | 107 | ( 108 | uint256 raisingAmount, 109 | uint256 offeringAmount, 110 | , 111 | , 112 | , 113 | , 114 | 115 | ) = eclipseV2.poolInfo(_pid); 116 | 117 | uint256 refundAmount = amountPools[0][1]; 118 | 119 | /* TOTAL TOKENS */ 120 | uint256 correctOfferingAmount = ((amount - refundAmount) * 121 | offeringAmount) / raisingAmount; 122 | 123 | uint256 correctOfferingAmountPerPeriod = ((correctOfferingAmount * 124 | eclipseV2.harvestReleasePercent(_harvestPeriod)) / 125 | 1e4) * exchangeRate; 126 | 127 | if (amaraV2.hasHarvested(_user, _pid, _harvestPeriod)) { 128 | /* AMOUNT ALREADY PAID */ 129 | offeringTokenAmountPerPeriod = 130 | ((offeringTokenAmount * 131 | eclipseV2.harvestReleasePercent(_harvestPeriod)) / 132 | 1e4) * 133 | exchangeRate; 134 | } 135 | 136 | if ( 137 | offeringTokenAmountPerPeriod > 138 | correctOfferingAmountPerPeriod 139 | ) { 140 | result = 0; 141 | } else { 142 | result = 143 | correctOfferingAmountPerPeriod - 144 | offeringTokenAmountPerPeriod; 145 | } 146 | } 147 | } 148 | } 149 | 150 | /*/////////////////////////////////////////////////////////////// 151 | HARVEST LOGIC 152 | //////////////////////////////////////////////////////////////*/ 153 | function harvestPool(uint8 _pid, uint8 _harvestPeriod) 154 | external 155 | nonReentrant 156 | { 157 | require( 158 | _harvestPeriod < HARVEST_PERIODS, 159 | "harvest period out of range" 160 | ); 161 | 162 | require( 163 | block.timestamp > 164 | eclipseV2.harvestReleaseTimestamps(_harvestPeriod), 165 | "not harvest time" 166 | ); 167 | 168 | require( 169 | !_userInfo[msg.sender][_pid].claimed[_harvestPeriod], 170 | "harvest for period already claimed" 171 | ); 172 | 173 | uint256 userAmount = calculateAmountToClaim( 174 | msg.sender, 175 | _pid, 176 | _harvestPeriod 177 | ); 178 | 179 | require(userAmount > 0, "no tokens to claim"); 180 | 181 | _userInfo[msg.sender][_pid].claimed[_harvestPeriod] = true; 182 | 183 | offeringToken.safeTransfer(address(msg.sender), userAmount); 184 | 185 | _userInfo[msg.sender][_pid].claimed[_harvestPeriod] = true; 186 | 187 | emit Harvest(msg.sender, userAmount, _pid); 188 | } 189 | 190 | function hasHarvested( 191 | address _user, 192 | uint8 _pid, 193 | uint8 _harvestPeriod 194 | ) public view returns (bool) { 195 | uint256 userAmount = calculateAmountToClaim( 196 | _user, 197 | _pid, 198 | _harvestPeriod 199 | ); 200 | 201 | return 202 | _userInfo[_user][_pid].claimed[_harvestPeriod] || userAmount == 0; 203 | } 204 | 205 | function emergencyWithdraw(uint256 _offerAmount) external onlyOwner { 206 | require( 207 | _offerAmount <= offeringToken.balanceOf(address(this)), 208 | "Not enough offering tokens" 209 | ); 210 | 211 | if (_offerAmount > 0) { 212 | offeringToken.safeTransfer(address(msg.sender), _offerAmount); 213 | } 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /contracts/burner/SolarBurner.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.2; 3 | 4 | import "@openzeppelin/contracts/access/Ownable.sol"; 5 | import "@openzeppelin/contracts/utils/math/SafeMath.sol"; 6 | import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 7 | 8 | import "./interfaces/ISolarERC20.sol"; 9 | import "./interfaces/ISolarPair.sol"; 10 | import "./interfaces/ISolarFactory.sol"; 11 | 12 | contract SolarBurner is Ownable { 13 | using SafeMath for uint256; 14 | using SafeERC20 for IERC20; 15 | 16 | ISolarFactory public immutable factory; 17 | address public immutable burner; 18 | address private immutable solar; 19 | address private immutable wmovr; 20 | 21 | mapping(address => address) internal _bridges; 22 | 23 | event LogBridgeSet(address indexed token, address indexed bridge); 24 | 25 | event LogConvert( 26 | address indexed server, 27 | address indexed token0, 28 | address indexed token1, 29 | uint256 amount0, 30 | uint256 amount1, 31 | uint256 amountSOLAR 32 | ); 33 | 34 | constructor( 35 | address _factory, 36 | address _burner, 37 | address _solar, 38 | address _wmovr 39 | ) { 40 | factory = ISolarFactory(_factory); 41 | burner = _burner; 42 | solar = _solar; 43 | wmovr = _wmovr; 44 | } 45 | 46 | function bridgeFor(address token) public view returns (address bridge) { 47 | bridge = _bridges[token]; 48 | if (bridge == address(0)) { 49 | bridge = wmovr; 50 | } 51 | } 52 | 53 | function setBridge(address token, address bridge) external onlyOwner { 54 | // Checks 55 | require( 56 | token != solar && token != wmovr && token != bridge, 57 | "SolarBurner: Invalid bridge" 58 | ); 59 | 60 | // Effects 61 | _bridges[token] = bridge; 62 | emit LogBridgeSet(token, bridge); 63 | } 64 | 65 | // It's not a fool proof solution, but it prevents flash loans, so here it's ok to use tx.origin 66 | modifier onlyEOA() { 67 | // Try to make flash-loan exploit harder to do by only allowing externally owned addresses. 68 | require(msg.sender == tx.origin, "SolarBurner: must use EOA"); 69 | _; 70 | } 71 | 72 | // _convert is separate to save gas by only checking the 'onlyEOA' modifier once in case of convertMultiple 73 | function convert(address token0, address token1) external onlyEOA { 74 | _convert(token0, token1); 75 | } 76 | 77 | function convertMultiple( 78 | address[] calldata token0, 79 | address[] calldata token1 80 | ) external onlyEOA { 81 | uint256 len = token0.length; 82 | for (uint256 i = 0; i < len; i++) { 83 | _convert(token0[i], token1[i]); 84 | } 85 | } 86 | 87 | function _convert(address token0, address token1) internal { 88 | ISolarPair pair = ISolarPair(factory.getPair(token0, token1)); 89 | require(address(pair) != address(0), "SolarBurner: Invalid pair"); 90 | IERC20(address(pair)).safeTransfer( 91 | address(pair), 92 | pair.balanceOf(address(this)) 93 | ); 94 | (uint256 amount0, uint256 amount1) = pair.burn(address(this)); 95 | if (token0 != pair.token0()) { 96 | (amount0, amount1) = (amount1, amount0); 97 | } 98 | emit LogConvert( 99 | msg.sender, 100 | token0, 101 | token1, 102 | amount0, 103 | amount1, 104 | _convertStep(token0, token1, amount0, amount1) 105 | ); 106 | } 107 | 108 | // All safeTransfer, _swap, _toSOLAR, _convertStep: X1 - X5: OK 109 | function _convertStep( 110 | address token0, 111 | address token1, 112 | uint256 amount0, 113 | uint256 amount1 114 | ) internal returns (uint256 solarOut) { 115 | if (token0 == token1) { 116 | uint256 amount = amount0.add(amount1); 117 | if (token0 == solar) { 118 | IERC20(solar).safeTransfer(burner, amount); 119 | solarOut = amount; 120 | } else if (token0 == wmovr) { 121 | solarOut = _toSOLAR(wmovr, amount); 122 | } else { 123 | address bridge = bridgeFor(token0); 124 | amount = _swap(token0, bridge, amount, address(this)); 125 | solarOut = _convertStep(bridge, bridge, amount, 0); 126 | } 127 | } else if (token0 == solar) { 128 | IERC20(solar).safeTransfer(burner, amount0); 129 | solarOut = _toSOLAR(token1, amount1).add(amount0); 130 | } else if (token1 == solar) { 131 | // eg. USDC - SOLAR 132 | IERC20(solar).safeTransfer(burner, amount1); 133 | solarOut = _toSOLAR(token0, amount0).add(amount1); 134 | } else if (token0 == wmovr) { 135 | // eg. ETH - USDC 136 | solarOut = _toSOLAR( 137 | wmovr, 138 | _swap(token1, wmovr, amount1, address(this)).add(amount0) 139 | ); 140 | } else if (token1 == wmovr) { 141 | // eg. USDC - MOVR 142 | solarOut = _toSOLAR( 143 | wmovr, 144 | _swap(token0, wmovr, amount0, address(this)).add(amount1) 145 | ); 146 | } else { 147 | // eg. MIM - USDC 148 | address bridge0 = bridgeFor(token0); 149 | address bridge1 = bridgeFor(token1); 150 | if (bridge0 == token1) { 151 | // eg. MIM - USDC - and bridgeFor(MIM) = USDC 152 | solarOut = _convertStep( 153 | bridge0, 154 | token1, 155 | _swap(token0, bridge0, amount0, address(this)), 156 | amount1 157 | ); 158 | } else if (bridge1 == token0) { 159 | // eg. WBTC - WETH - and bridgeFor(WETH) = WBTC 160 | solarOut = _convertStep( 161 | token0, 162 | bridge1, 163 | amount0, 164 | _swap(token1, bridge1, amount1, address(this)) 165 | ); 166 | } else { 167 | solarOut = _convertStep( 168 | bridge0, 169 | bridge1, // eg. USDC - WETH - and bridgeFor(WETH) = WBTC 170 | _swap(token0, bridge0, amount0, address(this)), 171 | _swap(token1, bridge1, amount1, address(this)) 172 | ); 173 | } 174 | } 175 | } 176 | 177 | function _swap( 178 | address fromToken, 179 | address toToken, 180 | uint256 amountIn, 181 | address to 182 | ) internal returns (uint256 amountOut) { 183 | ISolarPair pair = ISolarPair(factory.getPair(fromToken, toToken)); 184 | require(address(pair) != address(0), "SolarBurner: Cannot convert"); 185 | 186 | (uint256 reserve0, uint256 reserve1, ) = pair.getReserves(); 187 | uint256 amountInWithFee = amountIn.mul(997); 188 | if (fromToken == pair.token0()) { 189 | amountOut = 190 | amountInWithFee.mul(reserve1) / 191 | reserve0.mul(1000).add(amountInWithFee); 192 | IERC20(fromToken).safeTransfer(address(pair), amountIn); 193 | pair.swap(0, amountOut, to, new bytes(0)); 194 | } else { 195 | amountOut = 196 | amountInWithFee.mul(reserve0) / 197 | reserve1.mul(1000).add(amountInWithFee); 198 | IERC20(fromToken).safeTransfer(address(pair), amountIn); 199 | pair.swap(amountOut, 0, to, new bytes(0)); 200 | } 201 | } 202 | 203 | function _toSOLAR(address token, uint256 amountIn) 204 | internal 205 | returns (uint256 amountOut) 206 | { 207 | amountOut = _swap(token, solar, amountIn, burner); 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /contracts/farm/v2/rewarders/SimpleRewarderPerSec.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.2; 3 | pragma experimental ABIEncoderV2; 4 | 5 | import "@openzeppelin/contracts/utils/Address.sol"; 6 | import "@openzeppelin/contracts/access/Ownable.sol"; 7 | import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; 8 | import "./IRewarder.sol"; 9 | import "../ISolarDistributorV2.sol"; 10 | import "../libraries/BoringERC20.sol"; 11 | 12 | /** 13 | * This is a sample contract to be used in the SolarDistributorV2 contract for partners to reward 14 | * stakers with their native token alongside SOLAR. 15 | * 16 | * It assumes no minting rights, so requires a set amount of YOUR_TOKEN to be transferred to this contract prior. 17 | * E.g. say you've allocated 100,000 XYZ to the SOLAR-XYZ farm over 30 days. Then you would need to transfer 18 | * 100,000 XYZ and set the block reward accordingly so it's fully distributed after 30 days. 19 | */ 20 | contract SimpleRewarderPerSec is IRewarder, Ownable, ReentrancyGuard { 21 | using BoringERC20 for IBoringERC20; 22 | 23 | IBoringERC20 public immutable override rewardToken; 24 | uint256 public immutable pid; 25 | bool public immutable isNative; 26 | ISolarDistributorV2 public immutable distributorV2; 27 | 28 | /// @notice Info of each distributorV2 user. 29 | /// `amount` LP token amount the user has provided. 30 | /// `rewardDebt` The amount of YOUR_TOKEN entitled to the user. 31 | struct UserInfo { 32 | uint256 amount; 33 | uint256 rewardDebt; 34 | } 35 | 36 | /// @notice Info of each distributorV2 poolInfo. 37 | /// `accTokenPerShare` Amount of YOUR_TOKEN each LP token is worth. 38 | /// `lastRewardTimestamp` The last timestamp YOUR_TOKEN was rewarded to the poolInfo. 39 | struct PoolInfo { 40 | uint256 accTokenPerShare; 41 | uint256 lastRewardTimestamp; 42 | } 43 | 44 | /// @notice Info of the poolInfo. 45 | PoolInfo public poolInfo; 46 | /// @notice Info of each user that stakes LP tokens. 47 | mapping(address => UserInfo) public userInfo; 48 | 49 | uint256 public tokenPerSec; 50 | uint256 private constant ACC_TOKEN_PRECISION = 1e12; 51 | 52 | event OnReward(address indexed user, uint256 amount); 53 | event RewardRateUpdated(uint256 oldRate, uint256 newRate); 54 | 55 | modifier onlyDistributorV2() { 56 | require( 57 | msg.sender == address(distributorV2), 58 | "onlyDistributorV2: only SolarDistributorV2 can call this function" 59 | ); 60 | _; 61 | } 62 | 63 | constructor( 64 | IBoringERC20 _rewardToken, 65 | uint256 _tokenPerSec, 66 | ISolarDistributorV2 _distributorV2, 67 | uint256 _pid, 68 | bool _isNative 69 | ) { 70 | require( 71 | Address.isContract(address(_rewardToken)), 72 | "constructor: reward token must be a valid contract" 73 | ); 74 | require( 75 | Address.isContract(address(_distributorV2)), 76 | "constructor: SolarDistributorV2 must be a valid contract" 77 | ); 78 | rewardToken = _rewardToken; 79 | pid = _pid; 80 | tokenPerSec = _tokenPerSec; 81 | distributorV2 = _distributorV2; 82 | isNative = _isNative; 83 | poolInfo = PoolInfo({ 84 | lastRewardTimestamp: block.timestamp, 85 | accTokenPerShare: 0 86 | }); 87 | } 88 | 89 | /// @notice Update reward variables of the given poolInfo. 90 | /// @return pool Returns the pool that was updated. 91 | function updatePool() public returns (PoolInfo memory pool) { 92 | pool = poolInfo; 93 | 94 | if (block.timestamp > pool.lastRewardTimestamp) { 95 | uint256 lpSupply = distributorV2.poolTotalLp(pid); 96 | 97 | if (lpSupply > 0) { 98 | uint256 timeElapsed = block.timestamp - 99 | pool.lastRewardTimestamp; 100 | uint256 tokenReward = timeElapsed * tokenPerSec; 101 | pool.accTokenPerShare += ((tokenReward * ACC_TOKEN_PRECISION) / 102 | lpSupply); 103 | } 104 | 105 | pool.lastRewardTimestamp = block.timestamp; 106 | poolInfo = pool; 107 | } 108 | } 109 | 110 | /// @notice Sets the distribution reward rate. This will also update the poolInfo. 111 | /// @param _tokenPerSec The number of tokens to distribute per second 112 | function setRewardRate(uint256 _tokenPerSec) external onlyOwner { 113 | updatePool(); 114 | 115 | emit RewardRateUpdated(tokenPerSec, _tokenPerSec); 116 | 117 | tokenPerSec = _tokenPerSec; 118 | } 119 | 120 | /// @notice internal function to see balance of reward token. 121 | function _balance() internal view returns (uint256) { 122 | if (isNative) { 123 | return address(this).balance; 124 | } else { 125 | return rewardToken.balanceOf(address(this)); 126 | } 127 | } 128 | 129 | /// @notice Function called by SolarDistributorV2 whenever staker claims SOLAR harvest. Allows staker to also receive a 2nd reward token. 130 | /// @param _user Address of user 131 | /// @param _lpAmount Number of LP tokens the user has 132 | function onSolarReward(address _user, uint256 _lpAmount) 133 | external 134 | override 135 | onlyDistributorV2 136 | nonReentrant 137 | { 138 | updatePool(); 139 | PoolInfo memory pool = poolInfo; 140 | UserInfo storage user = userInfo[_user]; 141 | uint256 pending; 142 | uint256 rewardBalance = _balance(); 143 | if (user.amount > 0) { 144 | pending = (((user.amount * pool.accTokenPerShare) / 145 | ACC_TOKEN_PRECISION) - user.rewardDebt); 146 | 147 | if (isNative) { 148 | if (pending > rewardBalance) { 149 | (bool success, ) = _user.call{value: rewardBalance}(""); 150 | require(success, "Transfer failed"); 151 | } else { 152 | (bool success, ) = _user.call{value: pending}(""); 153 | require(success, "Transfer failed"); 154 | } 155 | } else { 156 | if (pending > rewardBalance) { 157 | rewardToken.safeTransfer(_user, rewardBalance); 158 | } else { 159 | rewardToken.safeTransfer(_user, pending); 160 | } 161 | } 162 | } 163 | user.amount = _lpAmount; 164 | user.rewardDebt = 165 | (user.amount * pool.accTokenPerShare) / 166 | ACC_TOKEN_PRECISION; 167 | 168 | emit OnReward(_user, pending); 169 | } 170 | 171 | /// @notice View function to see pending tokens 172 | /// @param _user Address of user. 173 | /// @return pending reward for a given user. 174 | function pendingTokens(address _user) 175 | external 176 | view 177 | override 178 | returns (uint256 pending) 179 | { 180 | PoolInfo memory pool = poolInfo; 181 | UserInfo storage user = userInfo[_user]; 182 | 183 | uint256 accTokenPerShare = pool.accTokenPerShare; 184 | uint256 lpSupply = distributorV2.poolTotalLp(pid); 185 | 186 | if (block.timestamp > pool.lastRewardTimestamp && lpSupply != 0) { 187 | uint256 timeElapsed = block.timestamp - pool.lastRewardTimestamp; 188 | uint256 tokenReward = timeElapsed * tokenPerSec; 189 | accTokenPerShare += (tokenReward * ACC_TOKEN_PRECISION) / lpSupply; 190 | } 191 | 192 | pending = (((user.amount * accTokenPerShare) / ACC_TOKEN_PRECISION) - 193 | user.rewardDebt); 194 | } 195 | 196 | /// @notice In case rewarder is stopped before emissions finished, this function allows 197 | /// withdrawal of remaining tokens. 198 | function emergencyWithdraw() public onlyOwner { 199 | if (isNative) { 200 | (bool success, ) = msg.sender.call{value: address(this).balance}( 201 | "" 202 | ); 203 | require(success, "Transfer failed"); 204 | } else { 205 | rewardToken.safeTransfer( 206 | address(msg.sender), 207 | rewardToken.balanceOf(address(this)) 208 | ); 209 | } 210 | } 211 | 212 | /// @notice View function to see balance of reward token. 213 | function balance() external view returns (uint256) { 214 | return _balance(); 215 | } 216 | 217 | /// @notice payable function needed to receive MOVR 218 | receive() external payable {} 219 | } 220 | -------------------------------------------------------------------------------- /test/GasSwap.test.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require("hardhat"); 2 | const { expect } = require("chai"); 3 | const { latest } = require("./utils"); 4 | 5 | const splitSignatureToRSV = (signature) => { 6 | const r = "0x" + signature.substring(2).substring(0, 64); 7 | const s = "0x" + signature.substring(2).substring(64, 128); 8 | const v = parseInt(signature.substring(2).substring(128, 130), 16); 9 | return { r, s, v }; 10 | }; 11 | 12 | const signWithEthers = async (signer, fromAddress, typeData) => { 13 | const signerAddress = await signer.getAddress(); 14 | if (signerAddress.toLowerCase() !== fromAddress.toLowerCase()) { 15 | throw new Error("Signer address does not match requested signing address"); 16 | } 17 | 18 | const { EIP712Domain: _unused, ...types } = typeData.types; 19 | const rawSignature = await (signer.signTypedData ? signer.signTypedData(typeData.domain, types, typeData.message) : signer._signTypedData(typeData.domain, types, typeData.message)); 20 | 21 | return splitSignatureToRSV(rawSignature); 22 | }; 23 | 24 | describe("GasSwap", function () { 25 | before(async function () { 26 | const [owner] = await ethers.getSigners(); 27 | this.owner = owner; 28 | this.signers = await ethers.getSigners(); 29 | this.deployer = this.signers[0]; 30 | this.bob = this.signers[1]; 31 | this.carol = this.signers[2]; 32 | this.dev = this.signers[3]; 33 | this.treasury = this.signers[4]; 34 | this.investor = this.signers[5]; 35 | this.minter = this.signers[6]; 36 | this.alice = this.signers[7]; 37 | 38 | this.GasSwap = await ethers.getContractFactory("GasSwap"); 39 | this.Router = await ethers.getContractFactory("MockRouter"); 40 | this.ERC20 = await ethers.getContractFactory("MockERC20"); 41 | }); 42 | 43 | beforeEach(async function () { 44 | this.router = await this.Router.deploy(); 45 | await this.router.deployed(); 46 | 47 | this.gasSwap = await this.GasSwap.deploy(this.router.address); 48 | await this.gasSwap.deployed(); 49 | 50 | this.erc20 = await this.ERC20.deploy("MockERC20", "MOCK", BigInt(10 * 1e18).toString()); 51 | await this.erc20.deployed(); 52 | }); 53 | 54 | it("execute swap", async function () { 55 | const { chainId } = await ethers.provider.getNetwork(); 56 | const erc20nounce = await this.erc20.nonces(this.deployer.address); 57 | const lastTimestamp = await latest(); 58 | 59 | const balance = await this.erc20.balanceOf(this.deployer.address); 60 | 61 | const permitInfo = { 62 | version: "1", 63 | name: "MockERC20", 64 | }; 65 | 66 | const domain = { 67 | name: permitInfo.name, 68 | version: permitInfo.version, 69 | verifyingContract: this.erc20.address, 70 | chainId, 71 | }; 72 | 73 | const EIP2612_TYPE = [ 74 | { name: "owner", type: "address" }, 75 | { name: "spender", type: "address" }, 76 | { name: "value", type: "uint256" }, 77 | { name: "nonce", type: "uint256" }, 78 | { name: "deadline", type: "uint256" }, 79 | ]; 80 | 81 | const EIP712_DOMAIN_TYPE = [ 82 | { name: "name", type: "string" }, 83 | { name: "version", type: "string" }, 84 | { name: "chainId", type: "uint256" }, 85 | { name: "verifyingContract", type: "address" }, 86 | ]; 87 | 88 | const deadline = lastTimestamp.add(60 * 30); 89 | 90 | const message = { 91 | owner: this.deployer.address, 92 | spender: this.gasSwap.address, 93 | value: balance, 94 | nonce: erc20nounce, 95 | deadline: deadline, 96 | }; 97 | 98 | const data = { 99 | types: { 100 | EIP712Domain: EIP712_DOMAIN_TYPE, 101 | Permit: EIP2612_TYPE, 102 | }, 103 | domain, 104 | primaryType: "Permit", 105 | message, 106 | }; 107 | 108 | const { r, s, v } = await signWithEthers(this.deployer, this.deployer.address, data); 109 | 110 | const swapCallData = ethers.utils.defaultAbiCoder.encode(["uint256", "uint256", "address[]", "address", "uint256", "uint8", "bytes32", "bytes32"], [balance, 0, [this.erc20.address, "0x98878B06940aE243284CA214f92Bb71a2b032B8A"], this.deployer.address, deadline, v, r, s]); 111 | 112 | await this.gasSwap.whitelistToken(this.erc20.address, true); 113 | 114 | await this.gasSwap.swap(swapCallData); 115 | 116 | const balanceAfterSwap = await this.erc20.balanceOf(this.deployer.address); 117 | 118 | expect(balanceAfterSwap).to.equal(0); 119 | }); 120 | 121 | it("execute meta tx", async function () { 122 | const { chainId } = await ethers.provider.getNetwork(); 123 | const erc20nounce = await this.erc20.nonces(this.deployer.address); 124 | const lastTimestamp = await latest(); 125 | 126 | const permitInfo = { 127 | version: "1", 128 | name: "MockERC20", 129 | }; 130 | 131 | const domain = { 132 | name: permitInfo.name, 133 | version: permitInfo.version, 134 | verifyingContract: this.erc20.address, 135 | chainId, 136 | }; 137 | 138 | const EIP2612_TYPE = [ 139 | { name: "owner", type: "address" }, 140 | { name: "spender", type: "address" }, 141 | { name: "value", type: "uint256" }, 142 | { name: "nonce", type: "uint256" }, 143 | { name: "deadline", type: "uint256" }, 144 | ]; 145 | 146 | const EIP712_DOMAIN_TYPE = [ 147 | { name: "name", type: "string" }, 148 | { name: "version", type: "string" }, 149 | { name: "chainId", type: "uint256" }, 150 | { name: "verifyingContract", type: "address" }, 151 | ]; 152 | 153 | const deadline = lastTimestamp.add(60 * 30); 154 | 155 | const message = { 156 | owner: this.deployer.address, 157 | spender: this.gasSwap.address, 158 | value: BigInt(10 * 1e18).toString(), 159 | nonce: erc20nounce, 160 | deadline: deadline, 161 | }; 162 | 163 | const data = { 164 | types: { 165 | EIP712Domain: EIP712_DOMAIN_TYPE, 166 | Permit: EIP2612_TYPE, 167 | }, 168 | domain, 169 | primaryType: "Permit", 170 | message, 171 | }; 172 | 173 | const { r, s, v } = await signWithEthers(this.deployer, this.deployer.address, data); 174 | 175 | const swapCallData = ethers.utils.defaultAbiCoder.encode(["uint256", "uint256", "address[]", "address", "uint256", "uint8", "bytes32", "bytes32"], [BigInt(10 * 1e18).toString(), 0, [this.erc20.address, "0x98878B06940aE243284CA214f92Bb71a2b032B8A"], this.deployer.address, deadline, v, r, s]); 176 | 177 | //// META DATA 178 | 179 | // Initialize Constants 180 | const domainType = [ 181 | { name: "name", type: "string" }, 182 | { name: "version", type: "string" }, 183 | { name: "verifyingContract", type: "address" }, 184 | { name: "salt", type: "bytes32" }, 185 | ]; 186 | 187 | const metaTransactionType = [ 188 | { name: "nonce", type: "uint256" }, 189 | { name: "from", type: "address" }, 190 | { name: "functionSignature", type: "bytes" }, 191 | ]; 192 | 193 | const domainData = { 194 | name: "GasSwap", 195 | version: "2", 196 | verifyingContract: this.gasSwap.address, 197 | salt: ethers.utils.hexZeroPad(ethers.BigNumber.from(chainId).toHexString(), 32), 198 | }; 199 | 200 | const nonce = await this.gasSwap.getNonce(this.deployer.address); 201 | 202 | const functionSignature = this.gasSwap.interface.encodeFunctionData("swap", [swapCallData]); 203 | 204 | const metaMessage = { 205 | nonce: parseInt(nonce), 206 | from: this.deployer.address, 207 | functionSignature: functionSignature, 208 | }; 209 | 210 | const metaDataToSign = { 211 | types: { 212 | EIP712Domain: domainType, 213 | MetaTransaction: metaTransactionType, 214 | }, 215 | domain: domainData, 216 | primaryType: "MetaTransaction", 217 | message: metaMessage, 218 | }; 219 | 220 | const { r: metaR, s: metaS, v: metaV } = await signWithEthers(this.deployer, this.deployer.address, metaDataToSign); 221 | 222 | await this.gasSwap.whitelistToken(this.erc20.address, true); 223 | 224 | await this.gasSwap.executeMetaTransaction(this.deployer.address, functionSignature, metaR, metaS, metaV); 225 | 226 | const balanceAfterSwap = await this.erc20.balanceOf(this.deployer.address); 227 | 228 | expect(balanceAfterSwap).to.equal(0); 229 | }); 230 | }); 231 | -------------------------------------------------------------------------------- /contracts/farm/v2/rewarders/ComplexRewarderPerSec.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.2; 3 | pragma experimental ABIEncoderV2; 4 | 5 | import "@openzeppelin/contracts/utils/Address.sol"; 6 | import "@openzeppelin/contracts/access/Ownable.sol"; 7 | import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; 8 | import "./IComplexRewarder.sol"; 9 | import "../ISolarDistributorV2.sol"; 10 | import "../libraries/BoringERC20.sol"; 11 | 12 | /** 13 | * This is a sample contract to be used in the SolarDistributorV2 contract for partners to reward 14 | * stakers with their native token alongside SOLAR. 15 | * 16 | * It assumes no minting rights, so requires a set amount of YOUR_TOKEN to be transferred to this contract prior. 17 | * E.g. say you've allocated 100,000 XYZ to the SOLAR-XYZ farm over 30 days. Then you would need to transfer 18 | * 100,000 XYZ and set the block reward accordingly so it's fully distributed after 30 days. 19 | */ 20 | contract ComplexRewarderPerSec is IComplexRewarder, Ownable, ReentrancyGuard { 21 | using BoringERC20 for IBoringERC20; 22 | 23 | IBoringERC20 public immutable override rewardToken; 24 | ISolarDistributorV2 public immutable distributorV2; 25 | bool public immutable isNative; 26 | 27 | /// @notice Info of each distributorV2 user. 28 | /// `amount` LP token amount the user has provided. 29 | /// `rewardDebt` The amount of YOUR_TOKEN entitled to the user. 30 | struct UserInfo { 31 | uint256 amount; 32 | uint256 rewardDebt; 33 | } 34 | 35 | /// @notice Info of each distributorV2 poolInfo. 36 | /// `accTokenPerShare` Amount of YOUR_TOKEN each LP token is worth. 37 | /// `lastRewardTimestamp` The last timestamp YOUR_TOKEN was rewarded to the poolInfo. 38 | /// `allocPoint` The amount of allocation points assigned to the pool. 39 | struct PoolInfo { 40 | uint256 accTokenPerShare; 41 | uint256 lastRewardTimestamp; 42 | uint256 allocPoint; 43 | } 44 | 45 | /// @notice Info of each pool. 46 | mapping(uint256 => PoolInfo) public poolInfo; 47 | 48 | uint256[] public poolIds; 49 | 50 | /// @notice Info of each user that stakes LP tokens. 51 | mapping(uint256 => mapping(address => UserInfo)) public userInfo; 52 | 53 | /// @dev Total allocation points. Must be the sum of all allocation points in all pools. 54 | uint256 public totalAllocPoint = 0; 55 | 56 | uint256 public tokenPerSec; 57 | uint256 private constant ACC_TOKEN_PRECISION = 1e12; 58 | 59 | event OnReward(address indexed user, uint256 amount); 60 | event RewardRateUpdated(uint256 oldRate, uint256 newRate); 61 | event AddPool(uint256 indexed pid, uint256 allocPoint); 62 | event SetPool(uint256 indexed pid, uint256 allocPoint); 63 | event UpdatePool( 64 | uint256 indexed pid, 65 | uint256 lastRewardTimestamp, 66 | uint256 lpSupply, 67 | uint256 accTokenPerShare 68 | ); 69 | 70 | modifier onlyDistributorV2() { 71 | require( 72 | msg.sender == address(distributorV2), 73 | "onlyDistributorV2: only SolarDistributorV2 can call this function" 74 | ); 75 | _; 76 | } 77 | 78 | constructor( 79 | IBoringERC20 _rewardToken, 80 | uint256 _tokenPerSec, 81 | ISolarDistributorV2 _distributorV2, 82 | bool _isNative 83 | ) { 84 | require( 85 | Address.isContract(address(_rewardToken)), 86 | "constructor: reward token must be a valid contract" 87 | ); 88 | require( 89 | Address.isContract(address(_distributorV2)), 90 | "constructor: SolarDistributorV2 must be a valid contract" 91 | ); 92 | rewardToken = _rewardToken; 93 | tokenPerSec = _tokenPerSec; 94 | distributorV2 = _distributorV2; 95 | isNative = _isNative; 96 | } 97 | 98 | /// @notice Add a new pool. Can only be called by the owner. 99 | /// @param _pid pool id on DistributorV2 100 | /// @param _allocPoint allocation of the new pool. 101 | function add(uint256 _pid, uint256 _allocPoint) public onlyOwner { 102 | require(poolInfo[_pid].lastRewardTimestamp == 0, "pool already exists"); 103 | totalAllocPoint += _allocPoint; 104 | 105 | poolInfo[_pid] = PoolInfo({ 106 | allocPoint: _allocPoint, 107 | lastRewardTimestamp: block.timestamp, 108 | accTokenPerShare: 0 109 | }); 110 | poolIds.push(_pid); 111 | emit AddPool(_pid, _allocPoint); 112 | } 113 | 114 | /// @notice Update the given pool's allocation point and `IRewarder` contract. Can only be called by the owner. 115 | /// @param _pid The index of the pool. See `poolInfo`. 116 | /// @param _allocPoint New AP of the pool. 117 | function set(uint256 _pid, uint256 _allocPoint) public onlyOwner { 118 | totalAllocPoint = 119 | totalAllocPoint - 120 | poolInfo[_pid].allocPoint + 121 | _allocPoint; 122 | poolInfo[_pid].allocPoint = _allocPoint; 123 | emit SetPool(_pid, _allocPoint); 124 | } 125 | 126 | /// @notice Sets the distribution reward rate. This will also update the poolInfo. 127 | /// @param _tokenPerSec The number of tokens to distribute per second 128 | function setRewardRate(uint256 _tokenPerSec) external onlyOwner { 129 | massUpdatePools(); 130 | emit RewardRateUpdated(tokenPerSec, _tokenPerSec); 131 | tokenPerSec = _tokenPerSec; 132 | } 133 | 134 | /// @notice Update reward variables of the given pool. 135 | /// @param pid The index of the pool. See `poolInfo`. 136 | /// @return pool Returns the pool that was updated. 137 | function updatePool(uint256 pid) public returns (PoolInfo memory pool) { 138 | pool = poolInfo[pid]; 139 | 140 | if (block.timestamp > pool.lastRewardTimestamp) { 141 | uint256 lpSupply = distributorV2.poolTotalLp(pid); 142 | 143 | if (lpSupply > 0) { 144 | uint256 timeElapsed = block.timestamp - 145 | pool.lastRewardTimestamp; 146 | uint256 tokenReward = (timeElapsed * 147 | tokenPerSec * 148 | pool.allocPoint) / totalAllocPoint; 149 | pool.accTokenPerShare += ((tokenReward * ACC_TOKEN_PRECISION) / 150 | lpSupply); 151 | } 152 | 153 | pool.lastRewardTimestamp = block.timestamp; 154 | poolInfo[pid] = pool; 155 | emit UpdatePool( 156 | pid, 157 | pool.lastRewardTimestamp, 158 | lpSupply, 159 | pool.accTokenPerShare 160 | ); 161 | } 162 | } 163 | 164 | // Update reward vairables for all pools. Be careful of gas spending! 165 | function massUpdatePools() public { 166 | uint256 length = poolIds.length; 167 | for (uint256 pid = 0; pid < length; ++pid) { 168 | updatePool(poolIds[pid]); 169 | } 170 | } 171 | 172 | /// @notice internal function to see balance of reward token. 173 | function _balance() internal view returns (uint256) { 174 | if (isNative) { 175 | return address(this).balance; 176 | } else { 177 | return rewardToken.balanceOf(address(this)); 178 | } 179 | } 180 | 181 | /// @notice Function called by SolarDistributorV2 whenever staker claims SOLAR harvest. Allows staker to also receive a 2nd reward token. 182 | /// @param _user Address of user 183 | /// @param _lpAmount Number of LP tokens the user has 184 | function onSolarReward( 185 | uint256 _pid, 186 | address _user, 187 | uint256 _lpAmount 188 | ) external override onlyDistributorV2 nonReentrant { 189 | PoolInfo memory pool = updatePool(_pid); 190 | UserInfo storage user = userInfo[_pid][_user]; 191 | uint256 pending; 192 | uint256 rewardBalance = _balance(); 193 | if (user.amount > 0) { 194 | pending = (((user.amount * pool.accTokenPerShare) / 195 | ACC_TOKEN_PRECISION) - user.rewardDebt); 196 | 197 | if (isNative) { 198 | if (pending > rewardBalance) { 199 | (bool success, ) = _user.call{value: rewardBalance}(""); 200 | require(success, "Transfer failed"); 201 | } else { 202 | (bool success, ) = _user.call{value: pending}(""); 203 | require(success, "Transfer failed"); 204 | } 205 | } else { 206 | if (pending > rewardBalance) { 207 | rewardToken.safeTransfer(_user, rewardBalance); 208 | } else { 209 | rewardToken.safeTransfer(_user, pending); 210 | } 211 | } 212 | } 213 | user.amount = _lpAmount; 214 | user.rewardDebt = 215 | (user.amount * pool.accTokenPerShare) / 216 | ACC_TOKEN_PRECISION; 217 | 218 | emit OnReward(_user, pending); 219 | } 220 | 221 | /// @notice View function to see pending tokens 222 | /// @param _pid pool id. 223 | /// @param _user Address of user. 224 | /// @return pending reward for a given user. 225 | function pendingTokens(uint256 _pid, address _user) 226 | external 227 | view 228 | override 229 | returns (uint256 pending) 230 | { 231 | PoolInfo memory pool = poolInfo[_pid]; 232 | UserInfo storage user = userInfo[_pid][_user]; 233 | 234 | uint256 accTokenPerShare = pool.accTokenPerShare; 235 | uint256 lpSupply = distributorV2.poolTotalLp(_pid); 236 | 237 | if (block.timestamp > pool.lastRewardTimestamp && lpSupply != 0) { 238 | uint256 timeElapsed = block.timestamp - pool.lastRewardTimestamp; 239 | uint256 tokenReward = (timeElapsed * 240 | tokenPerSec * 241 | pool.allocPoint) / totalAllocPoint; 242 | accTokenPerShare += (tokenReward * ACC_TOKEN_PRECISION) / lpSupply; 243 | } 244 | 245 | pending = (((user.amount * accTokenPerShare) / ACC_TOKEN_PRECISION) - 246 | user.rewardDebt); 247 | } 248 | 249 | /// @notice In case rewarder is stopped before emissions finished, this function allows 250 | /// withdrawal of remaining tokens. 251 | function emergencyWithdraw() public onlyOwner { 252 | if (isNative) { 253 | (bool success, ) = msg.sender.call{value: address(this).balance}( 254 | "" 255 | ); 256 | require(success, "Transfer failed"); 257 | } else { 258 | rewardToken.safeTransfer( 259 | address(msg.sender), 260 | rewardToken.balanceOf(address(this)) 261 | ); 262 | } 263 | } 264 | 265 | /// @notice View function to see pool rewards per sec 266 | function poolRewardsPerSec(uint256 _pid) 267 | external 268 | view 269 | override 270 | returns (uint256) 271 | { 272 | PoolInfo storage pool = poolInfo[_pid]; 273 | return (pool.allocPoint * tokenPerSec) / totalAllocPoint; 274 | } 275 | 276 | /// @notice View function to see balance of reward token. 277 | function balance() external view returns (uint256) { 278 | return _balance(); 279 | } 280 | 281 | /// @notice payable function needed to receive MOVR 282 | receive() external payable {} 283 | } 284 | -------------------------------------------------------------------------------- /contracts/solar/VestedSolarBeamToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.7; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; 5 | import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol"; 6 | import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; 7 | import "@openzeppelin/contracts/access/Ownable.sol"; 8 | import "../libraries/IBoringERC20.sol"; 9 | import "../libraries/BoringERC20.sol"; 10 | 11 | interface IVestedSolarBeamToken { 12 | function userLockedAmount(address _addr) external view returns (uint256); 13 | 14 | function userLockedUntil(address _addr) external view returns (uint256); 15 | 16 | function votingPowerUnlockTime(uint256 _value, uint256 _unlock_time) 17 | external 18 | view 19 | returns (uint256); 20 | 21 | function votingPowerLockedDays(uint256 _value, uint256 _days) 22 | external 23 | view 24 | returns (uint256); 25 | 26 | function deposit(address _addr, uint256 _value) external; 27 | 28 | function create(uint256 _value, uint256 _days) external; 29 | 30 | function increaseAmount(uint256 _value) external; 31 | 32 | function increaseLock(uint256 _days) external; 33 | 34 | function withdraw() external; 35 | } 36 | 37 | contract VestedSolarBeamToken is 38 | ERC20Burnable, 39 | ERC20Permit, 40 | IVestedSolarBeamToken, 41 | Ownable, 42 | ReentrancyGuard 43 | { 44 | using BoringERC20 for IBoringERC20; 45 | 46 | uint256 public constant MINDAYS = 7; 47 | uint256 public constant MAXDAYS = 4 * 365; 48 | 49 | uint256 public constant MAXTIME = MAXDAYS * 1 days; // 4 years 50 | uint256 public constant MAX_WITHDRAWAL_PENALTY = 90000; // 90% 51 | uint256 public constant PRECISION = 1e5; // 5 decimals 52 | 53 | address public immutable lockedToken; 54 | address public penaltyCollector; 55 | uint256 public minLockedAmount; 56 | uint256 public earlyWithdrawPenaltyRate; 57 | 58 | // flags 59 | uint256 private _unlocked; 60 | 61 | struct LockedBalance { 62 | uint256 amount; 63 | uint256 end; 64 | } 65 | 66 | mapping(address => LockedBalance) public locked; 67 | mapping(address => uint256) public mintedForLock; 68 | 69 | /* ========== MODIFIERS ========== */ 70 | 71 | modifier lock() { 72 | require(_unlocked == 1, "LOCKED"); 73 | _unlocked = 0; 74 | _; 75 | _unlocked = 1; 76 | } 77 | 78 | /* =============== EVENTS ==================== */ 79 | event Deposit(address indexed provider, uint256 value, uint256 locktime); 80 | event Withdraw(address indexed provider, uint256 value); 81 | event PenaltyCollectorSet(address indexed addr); 82 | event EarlyWithdrawPenaltySet(uint256 indexed penalty); 83 | event MinLockedAmountSet(uint256 indexed amount); 84 | 85 | constructor( 86 | string memory _tokenName, 87 | string memory _tokenSymbol, 88 | address _lockedToken, 89 | uint256 _minLockedAmount 90 | ) ERC20(_tokenName, _tokenSymbol) ERC20Permit(_tokenName) { 91 | lockedToken = _lockedToken; 92 | minLockedAmount = _minLockedAmount; 93 | earlyWithdrawPenaltyRate = 75000; // 75% 94 | penaltyCollector = 0x000000000000000000000000000000000000dEaD; 95 | _unlocked = 1; 96 | } 97 | 98 | /* ========== PUBLIC FUNCTIONS ========== */ 99 | function userLockedAmount(address _addr) 100 | external 101 | view 102 | override 103 | returns (uint256) 104 | { 105 | return locked[_addr].amount; 106 | } 107 | 108 | function userLockedUntil(address _addr) 109 | external 110 | view 111 | override 112 | returns (uint256) 113 | { 114 | return locked[_addr].end; 115 | } 116 | 117 | function votingPowerUnlockTime(uint256 _value, uint256 _unlockTime) 118 | public 119 | view 120 | override 121 | returns (uint256) 122 | { 123 | uint256 _now = block.timestamp; 124 | if (_unlockTime <= _now) return 0; 125 | uint256 _lockedSeconds = _unlockTime - _now; 126 | if (_lockedSeconds >= MAXTIME) { 127 | return _value; 128 | } 129 | return (_value * _lockedSeconds) / MAXTIME; 130 | } 131 | 132 | function votingPowerLockedDays(uint256 _value, uint256 _days) 133 | public 134 | pure 135 | override 136 | returns (uint256) 137 | { 138 | if (_days >= MAXDAYS) { 139 | return _value; 140 | } 141 | return (_value * _days) / MAXDAYS; 142 | } 143 | 144 | function deposit(address _addr, uint256 _value) 145 | external 146 | override 147 | nonReentrant 148 | { 149 | require(_value > 0, "deposit: invalid amount"); 150 | require(locked[_addr].amount > 0, "deposit: no lock for this address"); 151 | _deposit(_addr, _value, 0); 152 | } 153 | 154 | function createWithPermit( 155 | uint256 _value, 156 | uint256 _days, 157 | uint256 deadline, 158 | uint8 v, 159 | bytes32 r, 160 | bytes32 s 161 | ) external nonReentrant { 162 | require(_value >= minLockedAmount, "create: less than min amount"); 163 | require( 164 | locked[_msgSender()].amount == 0, 165 | "create: withdraw old tokens first" 166 | ); 167 | require(_days >= MINDAYS, "create: less than min amount of 7 days"); 168 | require(_days <= MAXDAYS, "create: voting lock can be 4 years max"); 169 | 170 | IBoringERC20(lockedToken).permit( 171 | _msgSender(), 172 | address(this), 173 | _value, 174 | deadline, 175 | v, 176 | r, 177 | s 178 | ); 179 | 180 | _deposit(_msgSender(), _value, _days); 181 | } 182 | 183 | function create(uint256 _value, uint256 _days) 184 | external 185 | override 186 | nonReentrant 187 | { 188 | require(_value >= minLockedAmount, "create: less than min amount"); 189 | require( 190 | locked[_msgSender()].amount == 0, 191 | "create: withdraw old tokens first" 192 | ); 193 | require(_days >= MINDAYS, "create: less than min amount of 7 days"); 194 | require(_days <= MAXDAYS, "create: voting lock can be 4 years max"); 195 | _deposit(_msgSender(), _value, _days); 196 | } 197 | 198 | function increaseAmountWithPermit( 199 | uint256 _value, 200 | uint256 deadline, 201 | uint8 v, 202 | bytes32 r, 203 | bytes32 s 204 | ) external nonReentrant { 205 | require(_value > 0, "increaseAmount: invalid amount"); 206 | 207 | IBoringERC20(lockedToken).permit( 208 | _msgSender(), 209 | address(this), 210 | _value, 211 | deadline, 212 | v, 213 | r, 214 | s 215 | ); 216 | 217 | _deposit(_msgSender(), _value, 0); 218 | } 219 | 220 | function increaseAmount(uint256 _value) external override nonReentrant { 221 | require(_value > 0, "increaseAmount: invalid amount"); 222 | _deposit(_msgSender(), _value, 0); 223 | } 224 | 225 | function increaseLock(uint256 _days) external override nonReentrant { 226 | require(_days > 0, "increaseLock: invalid amount"); 227 | require( 228 | _days <= MAXDAYS, 229 | "increaseLock: voting lock can be 4 years max" 230 | ); 231 | _deposit(_msgSender(), 0, _days); 232 | } 233 | 234 | function withdraw() external override lock { 235 | LockedBalance storage _locked = locked[_msgSender()]; 236 | uint256 _now = block.timestamp; 237 | require(_locked.amount > 0, "withdraw: nothing to withdraw"); 238 | require(_now >= _locked.end, "withdraw: user still locked"); 239 | uint256 _amount = _locked.amount; 240 | _locked.end = 0; 241 | _locked.amount = 0; 242 | _burn(_msgSender(), mintedForLock[_msgSender()]); 243 | mintedForLock[_msgSender()] = 0; 244 | IBoringERC20(lockedToken).safeTransfer(_msgSender(), _amount); 245 | 246 | emit Withdraw(_msgSender(), _amount); 247 | } 248 | 249 | // This will charge PENALTY if lock is not expired yet 250 | function emergencyWithdraw() external lock { 251 | LockedBalance storage _locked = locked[_msgSender()]; 252 | uint256 _now = block.timestamp; 253 | require(_locked.amount > 0, "emergencyWithdraw: nothing to withdraw"); 254 | uint256 _amount = _locked.amount; 255 | if (_now < _locked.end) { 256 | uint256 _fee = (_amount * earlyWithdrawPenaltyRate) / PRECISION; 257 | _penalize(_fee); 258 | _amount = _amount - _fee; 259 | } 260 | _locked.end = 0; 261 | _locked.amount = 0; 262 | _burn(_msgSender(), mintedForLock[_msgSender()]); 263 | mintedForLock[_msgSender()] = 0; 264 | 265 | IBoringERC20(lockedToken).safeTransfer(_msgSender(), _amount); 266 | 267 | emit Withdraw(_msgSender(), _amount); 268 | } 269 | 270 | /* ========== INTERNAL FUNCTIONS ========== */ 271 | function _deposit( 272 | address _addr, 273 | uint256 _value, 274 | uint256 _days 275 | ) internal lock { 276 | LockedBalance storage _locked = locked[_addr]; 277 | uint256 _now = block.timestamp; 278 | uint256 _amount = _locked.amount; 279 | uint256 _end = _locked.end; 280 | uint256 _vp; 281 | if (_amount == 0) { 282 | _vp = votingPowerLockedDays(_value, _days); 283 | _locked.amount = _value; 284 | _locked.end = _now + _days * 1 days; 285 | } else if (_days == 0) { 286 | _vp = votingPowerUnlockTime(_value, _end); 287 | _locked.amount = _amount + _value; 288 | } else { 289 | require( 290 | _value == 0, 291 | "_deposit: cannot increase amount and extend lock in the same time" 292 | ); 293 | _vp = votingPowerLockedDays(_amount, _days); 294 | _locked.end = _end + _days * 1 days; 295 | require( 296 | _locked.end - _now <= MAXTIME, 297 | "_deposit: cannot extend lock to more than 4 years" 298 | ); 299 | } 300 | require(_vp > 0, "No benefit to lock"); 301 | if (_value > 0) { 302 | IBoringERC20(lockedToken).safeTransferFrom( 303 | _msgSender(), 304 | address(this), 305 | _value 306 | ); 307 | } 308 | _mint(_addr, _vp); 309 | mintedForLock[_addr] += _vp; 310 | 311 | emit Deposit(_addr, _locked.amount, _locked.end); 312 | } 313 | 314 | function _penalize(uint256 _amount) internal { 315 | IBoringERC20(lockedToken).safeTransfer(penaltyCollector, _amount); 316 | } 317 | 318 | /* ========== RESTRICTED FUNCTIONS ========== */ 319 | function setMinLockedAmount(uint256 _minLockedAmount) external onlyOwner { 320 | minLockedAmount = _minLockedAmount; 321 | emit MinLockedAmountSet(_minLockedAmount); 322 | } 323 | 324 | function setEarlyWithdrawPenaltyRate(uint256 _earlyWithdrawPenaltyRate) 325 | external 326 | onlyOwner 327 | { 328 | require( 329 | _earlyWithdrawPenaltyRate <= MAX_WITHDRAWAL_PENALTY, 330 | "setEarlyWithdrawPenaltyRate: withdrawal penalty is too high" 331 | ); // <= 90% 332 | earlyWithdrawPenaltyRate = _earlyWithdrawPenaltyRate; 333 | emit EarlyWithdrawPenaltySet(_earlyWithdrawPenaltyRate); 334 | } 335 | 336 | function setPenaltyCollector(address _addr) external onlyOwner { 337 | require( 338 | penaltyCollector != address(0), 339 | "setPenaltyCollector: set a valid address" 340 | ); 341 | penaltyCollector = _addr; 342 | emit PenaltyCollectorSet(_addr); 343 | } 344 | } 345 | -------------------------------------------------------------------------------- /contracts/uniswapv2/SolarPair.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity =0.6.12; 3 | 4 | import "./SolarERC20.sol"; 5 | import "./libraries/Math.sol"; 6 | import "./libraries/UQ112x112.sol"; 7 | import "./interfaces/IERC20.sol"; 8 | import "./interfaces/ISolarFactory.sol"; 9 | import "./interfaces/ISolarCallee.sol"; 10 | 11 | interface IMigrator { 12 | // Return the desired amount of liquidity token that the migrator wants. 13 | function desiredLiquidity() external view returns (uint256); 14 | } 15 | 16 | contract SolarPair is SolarERC20 { 17 | using SafeMathSolar for uint256; 18 | using UQ112x112 for uint224; 19 | 20 | uint256 public constant MINIMUM_LIQUIDITY = 10**3; 21 | bytes4 private constant SELECTOR = 22 | bytes4(keccak256(bytes("transfer(address,uint256)"))); 23 | 24 | address public factory; 25 | address public token0; 26 | address public token1; 27 | 28 | uint112 private reserve0; // uses single storage slot, accessible via getReserves 29 | uint112 private reserve1; // uses single storage slot, accessible via getReserves 30 | uint32 private blockTimestampLast; // uses single storage slot, accessible via getReserves 31 | 32 | uint256 public price0CumulativeLast; 33 | uint256 public price1CumulativeLast; 34 | uint256 public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event 35 | 36 | struct SwapVariables { 37 | uint112 _reserve0; 38 | uint112 _reserve1; 39 | uint256 balance0; 40 | uint256 balance1; 41 | uint256 amount0In; 42 | uint256 amount1In; 43 | } 44 | 45 | uint256 private unlocked = 1; 46 | modifier lock() { 47 | require(unlocked == 1, "SolarBeam: LOCKED"); 48 | unlocked = 0; 49 | _; 50 | unlocked = 1; 51 | } 52 | 53 | function getReserves() 54 | public 55 | view 56 | returns ( 57 | uint112 _reserve0, 58 | uint112 _reserve1, 59 | uint32 _blockTimestampLast 60 | ) 61 | { 62 | _reserve0 = reserve0; 63 | _reserve1 = reserve1; 64 | _blockTimestampLast = blockTimestampLast; 65 | } 66 | 67 | function _safeTransfer( 68 | address token, 69 | address to, 70 | uint256 value 71 | ) private { 72 | (bool success, bytes memory data) = token.call( 73 | abi.encodeWithSelector(SELECTOR, to, value) 74 | ); 75 | require( 76 | success && (data.length == 0 || abi.decode(data, (bool))), 77 | "SolarBeam: TRANSFER_FAILED" 78 | ); 79 | } 80 | 81 | event Mint(address indexed sender, uint256 amount0, uint256 amount1); 82 | event Burn( 83 | address indexed sender, 84 | uint256 amount0, 85 | uint256 amount1, 86 | address indexed to 87 | ); 88 | event Swap( 89 | address indexed sender, 90 | uint256 amount0In, 91 | uint256 amount1In, 92 | uint256 amount0Out, 93 | uint256 amount1Out, 94 | address indexed to 95 | ); 96 | event Sync(uint112 reserve0, uint112 reserve1); 97 | 98 | constructor() public { 99 | factory = msg.sender; 100 | } 101 | 102 | // called once by the factory at time of deployment 103 | function initialize(address _token0, address _token1) external { 104 | require(msg.sender == factory, "SolarBeam: FORBIDDEN"); // sufficient check 105 | token0 = _token0; 106 | token1 = _token1; 107 | } 108 | 109 | // update reserves and, on the first call per block, price accumulators 110 | function _update( 111 | uint256 balance0, 112 | uint256 balance1, 113 | uint112 _reserve0, 114 | uint112 _reserve1 115 | ) private { 116 | require( 117 | balance0 <= uint112(-1) && balance1 <= uint112(-1), 118 | "SolarBeam: OVERFLOW" 119 | ); 120 | uint32 blockTimestamp = uint32(block.timestamp % 2**32); 121 | uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired 122 | if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) { 123 | // * never overflows, and + overflow is desired 124 | price0CumulativeLast += 125 | uint256(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * 126 | timeElapsed; 127 | price1CumulativeLast += 128 | uint256(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * 129 | timeElapsed; 130 | } 131 | reserve0 = uint112(balance0); 132 | reserve1 = uint112(balance1); 133 | blockTimestampLast = blockTimestamp; 134 | emit Sync(reserve0, reserve1); 135 | } 136 | 137 | // if fee is on, mint liquidity equivalent to 1/6th of the growth in sqrt(k) 138 | function _mintFee(uint112 _reserve0, uint112 _reserve1) 139 | private 140 | returns (bool feeOn) 141 | { 142 | address feeTo = ISolarFactory(factory).feeTo(); 143 | feeOn = feeTo != address(0); 144 | uint256 _kLast = kLast; // gas savings 145 | if (feeOn) { 146 | if (_kLast != 0) { 147 | uint256 rootK = Math.sqrt(uint256(_reserve0).mul(_reserve1)); 148 | uint256 rootKLast = Math.sqrt(_kLast); 149 | if (rootK > rootKLast) { 150 | uint256 numerator = totalSupply.mul(rootK.sub(rootKLast)); 151 | uint256 denominator = rootK.mul(5).add(rootKLast); 152 | uint256 liquidity = numerator / denominator; 153 | if (liquidity > 0) _mint(feeTo, liquidity); 154 | } 155 | } 156 | } else if (_kLast != 0) { 157 | kLast = 0; 158 | } 159 | } 160 | 161 | // this low-level function should be called from a contract which performs important safety checks 162 | function mint(address to) external lock returns (uint256 liquidity) { 163 | (uint112 _reserve0, uint112 _reserve1, ) = getReserves(); // gas savings 164 | uint256 balance0 = IERC20Solar(token0).balanceOf(address(this)); 165 | uint256 balance1 = IERC20Solar(token1).balanceOf(address(this)); 166 | uint256 amount0 = balance0.sub(_reserve0); 167 | uint256 amount1 = balance1.sub(_reserve1); 168 | 169 | bool feeOn = _mintFee(_reserve0, _reserve1); 170 | uint256 _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee 171 | if (_totalSupply == 0) { 172 | address migrator = ISolarFactory(factory).migrator(); 173 | if (_msgSender() == migrator) { 174 | liquidity = IMigrator(migrator).desiredLiquidity(); 175 | require( 176 | liquidity > 0 && liquidity != uint256(-1), 177 | "Bad desired liquidity" 178 | ); 179 | } else { 180 | require(migrator == address(0), "Must not have migrator"); 181 | liquidity = Math.sqrt(amount0.mul(amount1)).sub( 182 | MINIMUM_LIQUIDITY 183 | ); 184 | _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens 185 | } 186 | } else { 187 | liquidity = Math.min( 188 | amount0.mul(_totalSupply) / _reserve0, 189 | amount1.mul(_totalSupply) / _reserve1 190 | ); 191 | } 192 | require(liquidity > 0, "SolarBeam: INSUFFICIENT_LIQUIDITY_MINTED"); 193 | _mint(to, liquidity); 194 | 195 | _update(balance0, balance1, _reserve0, _reserve1); 196 | if (feeOn) kLast = uint256(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date 197 | emit Mint(_msgSender(), amount0, amount1); 198 | } 199 | 200 | // this low-level function should be called from a contract which performs important safety checks 201 | function burn(address to) 202 | external 203 | lock 204 | returns (uint256 amount0, uint256 amount1) 205 | { 206 | (uint112 _reserve0, uint112 _reserve1, ) = getReserves(); // gas savings 207 | address _token0 = token0; // gas savings 208 | address _token1 = token1; // gas savings 209 | uint256 balance0 = IERC20Solar(_token0).balanceOf(address(this)); 210 | uint256 balance1 = IERC20Solar(_token1).balanceOf(address(this)); 211 | uint256 liquidity = balanceOf[address(this)]; 212 | 213 | bool feeOn = _mintFee(_reserve0, _reserve1); 214 | uint256 _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee 215 | amount0 = liquidity.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution 216 | amount1 = liquidity.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution 217 | require( 218 | amount0 > 0 && amount1 > 0, 219 | "SolarBeam: INSUFFICIENT_LIQUIDITY_BURNED" 220 | ); 221 | _burn(address(this), liquidity); 222 | _safeTransfer(_token0, to, amount0); 223 | _safeTransfer(_token1, to, amount1); 224 | balance0 = IERC20Solar(_token0).balanceOf(address(this)); 225 | balance1 = IERC20Solar(_token1).balanceOf(address(this)); 226 | 227 | _update(balance0, balance1, _reserve0, _reserve1); 228 | if (feeOn) kLast = uint256(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date 229 | emit Burn(_msgSender(), amount0, amount1, to); 230 | } 231 | 232 | // this low-level function should be called from a contract which performs important safety checks 233 | function swap( 234 | uint256 amount0Out, 235 | uint256 amount1Out, 236 | address to, 237 | bytes calldata data 238 | ) external lock { 239 | require( 240 | amount0Out > 0 || amount1Out > 0, 241 | "SolarBeam: INSUFFICIENT_OUTPUT_AMOUNT" 242 | ); 243 | SwapVariables memory vars = SwapVariables(0, 0, 0, 0, 0, 0); 244 | (vars._reserve0, vars._reserve1, ) = getReserves(); // gas savings 245 | require( 246 | amount0Out < vars._reserve0 && amount1Out < vars._reserve1, 247 | "SolarBeam: INSUFFICIENT_LIQUIDITY" 248 | ); 249 | 250 | { 251 | // scope for _token{0,1}, avoids stack too deep errors 252 | address _token0 = token0; 253 | address _token1 = token1; 254 | require(to != _token0 && to != _token1, "SolarBeam: INVALID_TO"); 255 | if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens 256 | if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens 257 | if (data.length > 0) 258 | ISolarCallee(to).uniswapV2Call( 259 | _msgSender(), 260 | amount0Out, 261 | amount1Out, 262 | data 263 | ); 264 | vars.balance0 = IERC20Solar(_token0).balanceOf(address(this)); 265 | vars.balance1 = IERC20Solar(_token1).balanceOf(address(this)); 266 | } 267 | vars.amount0In = vars.balance0 > vars._reserve0 - amount0Out 268 | ? vars.balance0 - (vars._reserve0 - amount0Out) 269 | : 0; 270 | vars.amount1In = vars.balance1 > vars._reserve1 - amount1Out 271 | ? vars.balance1 - (vars._reserve1 - amount1Out) 272 | : 0; 273 | require( 274 | vars.amount0In > 0 || vars.amount1In > 0, 275 | "SolarBeam: INSUFFICIENT_INPUT_AMOUNT" 276 | ); 277 | { 278 | // scope for reserve{0,1} - Adjusted, avoids stack too deep errors 279 | uint256 balance0Adjusted = vars.balance0.mul(10000).sub( 280 | vars.amount0In.mul(25) 281 | ); 282 | uint256 balance1Adjusted = vars.balance1.mul(10000).sub( 283 | vars.amount1In.mul(25) 284 | ); 285 | require( 286 | balance0Adjusted.mul(balance1Adjusted) >= 287 | uint256(vars._reserve0).mul(vars._reserve1).mul(10000**2), 288 | "SolarBeam: K" 289 | ); 290 | } 291 | 292 | _update(vars.balance0, vars.balance1, vars._reserve0, vars._reserve1); 293 | emit Swap( 294 | _msgSender(), 295 | vars.amount0In, 296 | vars.amount1In, 297 | amount0Out, 298 | amount1Out, 299 | to 300 | ); 301 | } 302 | 303 | // force balances to match reserves 304 | function skim(address to) external lock { 305 | address _token0 = token0; // gas savings 306 | address _token1 = token1; // gas savings 307 | _safeTransfer( 308 | _token0, 309 | to, 310 | IERC20Solar(_token0).balanceOf(address(this)).sub(reserve0) 311 | ); 312 | _safeTransfer( 313 | _token1, 314 | to, 315 | IERC20Solar(_token1).balanceOf(address(this)).sub(reserve1) 316 | ); 317 | } 318 | 319 | // force reserves to match balances 320 | function sync() external lock { 321 | _update( 322 | IERC20Solar(token0).balanceOf(address(this)), 323 | IERC20Solar(token1).balanceOf(address(this)), 324 | reserve0, 325 | reserve1 326 | ); 327 | } 328 | } 329 | --------------------------------------------------------------------------------