文件 1 的 7:AddressUpgradeable.sol
pragma solidity ^0.7.0;
library AddressUpgradeable {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly { size := extcodesize(account) }
return size > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 7:ContextUpgradeable.sol
pragma solidity >=0.6.0 <0.8.0;
import "../proxy/Initializable.sol";
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal initializer {
__Context_init_unchained();
}
function __Context_init_unchained() internal initializer {
}
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this;
return msg.data;
}
uint256[50] private __gap;
}
文件 3 的 7:IERC20.sol
pragma solidity >=0.6.0 <0.8.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 4 的 7:Initializable.sol
pragma solidity >=0.4.24 <0.8.0;
import "../utils/AddressUpgradeable.sol";
abstract contract Initializable {
bool private _initialized;
bool private _initializing;
modifier initializer() {
require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized");
bool isTopLevelCall = !_initializing;
if (isTopLevelCall) {
_initializing = true;
_initialized = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
}
}
function _isConstructor() private view returns (bool) {
return !AddressUpgradeable.isContract(address(this));
}
}
文件 5 的 7:OwnableUpgradeable.sol
pragma solidity ^0.7.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/Initializable.sol";
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
function __Ownable_init() internal initializer {
__Context_init_unchained();
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal initializer {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
uint256[49] private __gap;
}
文件 6 的 7:SafeMath.sol
pragma solidity >=0.6.0 <0.8.0;
library SafeMath {
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}
文件 7 的 7:SuperPad.sol
pragma solidity 0.7.6;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";
contract SuperPad is Initializable, ContextUpgradeable, OwnableUpgradeable {
using SafeMath for uint256;
struct Pool {
uint256 cap;
uint256 price;
uint256 maxCap;
address creator;
address token;
address swapToken;
bool isWhiteList;
bool onlyHolder;
bool enabled;
bool finished;
}
address public superToken;
uint256 private minSuper = 1e19;
uint256 private constant scaleFactor = 1e8;
uint256 private constant defaultSpan = 1e5;
Pool[] public pools;
mapping(uint256 => uint256) public poolsSold;
mapping(uint256 => mapping(address => uint256)) public lockedTokens;
mapping(uint256 => mapping(address => uint256)) public whiteList;
event NewPool(
uint256 id,
address creator,
address token,
address swapToken,
uint256 cap,
uint256 price,
bool isWhiteList,
bool onlyHolder,
uint256 maxCap
);
event Swap(
uint256 id,
uint256 roundID,
address sender,
uint256 amount,
uint256 amt
);
event Claim(uint256 id, address claimer, uint256 amount);
event PoolFinished(uint256 id);
event PoolStarted(uint256 id);
event WhiteList(uint256 id);
uint256[50] private __gap;
function initialize() public initializer {
__Ownable_init();
}
modifier onlyCreator(uint256 id) {
require(pools[id].creator == msg.sender, "Should be creator");
_;
}
function addWhiteList(uint256 id, address[] calldata _whiteList, uint256[] calldata _caps) external onlyOwner {
for (uint256 i = 0; i < _whiteList.length; ++i) {
whiteList[id][_whiteList[i]] = _caps[i];
}
emit WhiteList(id);
}
function setMinSuper(uint256 _minSuper) external onlyOwner {
minSuper = _minSuper;
}
function setSuperToken(address _superToken) external onlyOwner {
superToken = _superToken;
}
function poolsLength() external view returns (uint256) {
return pools.length;
}
function createPool(
address token,
address swapToken,
uint256 cap,
uint256 price,
bool isWhiteList,
bool onlyHolder,
uint256 maxCap
) external onlyOwner returns (uint256) {
require(cap <= IERC20(token).balanceOf(msg.sender) && cap > 0, "Cap check");
require(token != address(0), "Pool token cannot be zero address");
require(price > uint256(0), "Price must be greater than 0");
uint256 id = pools.length;
Pool memory newPool =
Pool(
cap,
price,
maxCap,
msg.sender,
token,
swapToken,
isWhiteList,
onlyHolder,
false,
false
);
pools.push(newPool);
IERC20(token).transferFrom(msg.sender, address(this), cap);
emit NewPool(
id,
msg.sender,
token,
swapToken,
cap,
price,
isWhiteList,
onlyHolder,
maxCap
);
return id;
}
function swap(uint256 id, uint256 amount) external payable {
require(amount != 0, "Amount should not be zero");
require(pools[id].enabled, "Pool must be enabled");
if (pools[id].onlyHolder) {
require(IERC20(superToken).balanceOf(msg.sender) >= minSuper, "Miniumum for the pool");
}
if (pools[id].isWhiteList) {
require(whiteList[id][msg.sender] > 0, "Should be white listed for the pool");
}
if (pools[id].swapToken == address(0)) {
require(amount == msg.value, "Amount is not equal msg.value");
}
_simpleSwap(id, amount);
}
function _simpleSwap(uint256 id, uint256 amount) internal {
Pool memory pool = pools[id];
uint256 left = pool.cap.sub(poolsSold[id]);
uint256 curLocked = lockedTokens[id][msg.sender];
if (left > pool.maxCap.sub(curLocked)) {
left = pool.maxCap.sub(curLocked);
}
if (pool.isWhiteList && left > whiteList[id][msg.sender].sub(curLocked)) {
left = whiteList[id][msg.sender].sub(curLocked);
}
require(left > 0, "Not enough tokens for swap");
uint256 amt = pool.price.mul(amount).div(scaleFactor);
uint256 back = 0;
if (left < amt) {
amt = left;
uint256 newAmount = amt.mul(scaleFactor).div(pool.price);
back = amount.sub(newAmount);
amount = newAmount;
}
lockedTokens[id][msg.sender] = curLocked.add(amt);
poolsSold[id] = poolsSold[id].add(amt);
if (pool.swapToken == address(0)) {
(bool success, ) = payable(pool.creator).call{value: amount}("");
require(success, "Should transfer ethers to the pool creator");
if (back > 0) {
(success, ) = payable(msg.sender).call{value: back}("");
require(success, "Should transfer left ethers back to the user");
}
} else {
IERC20(pool.swapToken).transferFrom(
msg.sender,
pool.creator,
amount
);
}
emit Swap(id, 0, msg.sender, amount, amt);
}
function startPool(uint256 id) external onlyCreator(id) {
require(!pools[id].enabled, "Pool is already enabled");
require(!pools[id].finished, "Pool is already completed");
pools[id].enabled = true;
emit PoolStarted(id);
}
function finishPool(uint256 id) external onlyCreator(id) {
require(pools[id].enabled, "Pool is not enabled");
require(!pools[id].finished, "Pool is already completed");
pools[id].enabled = false;
pools[id].finished = true;
emit PoolFinished(id);
}
function claim(uint256 id) external {
require(pools[id].finished, "Cannot claim until pool is finished");
require(lockedTokens[id][msg.sender] > 0, "Should have tokens to claim");
uint256 amount = lockedTokens[id][msg.sender];
lockedTokens[id][msg.sender] = 0;
IERC20(pools[id].token).transfer(msg.sender, amount);
emit Claim(id, msg.sender, amount);
}
}
{
"compilationTarget": {
"contracts/SuperPad.sol": "SuperPad"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"address","name":"claimer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"address","name":"creator","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"swapToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"cap","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isWhiteList","type":"bool"},{"indexed":false,"internalType":"bool","name":"onlyHolder","type":"bool"},{"indexed":false,"internalType":"uint256","name":"maxCap","type":"uint256"}],"name":"NewPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"}],"name":"PoolFinished","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"}],"name":"PoolStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"roundID","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amt","type":"uint256"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"}],"name":"WhiteList","type":"event"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address[]","name":"_whiteList","type":"address[]"},{"internalType":"uint256[]","name":"_caps","type":"uint256[]"}],"name":"addWhiteList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"swapToken","type":"address"},{"internalType":"uint256","name":"cap","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"bool","name":"isWhiteList","type":"bool"},{"internalType":"bool","name":"onlyHolder","type":"bool"},{"internalType":"uint256","name":"maxCap","type":"uint256"}],"name":"createPool","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"finishPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"lockedTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"pools","outputs":[{"internalType":"uint256","name":"cap","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"maxCap","type":"uint256"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"swapToken","type":"address"},{"internalType":"bool","name":"isWhiteList","type":"bool"},{"internalType":"bool","name":"onlyHolder","type":"bool"},{"internalType":"bool","name":"enabled","type":"bool"},{"internalType":"bool","name":"finished","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolsSold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minSuper","type":"uint256"}],"name":"setMinSuper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_superToken","type":"address"}],"name":"setSuperToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"startPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"superToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"swap","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"whiteList","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]