文件 1 的 9:Address.sol
pragma solidity >=0.6.2 <0.8.0;
library Address {
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 functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 9:Context.sol
pragma solidity >=0.6.0 <0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this;
return msg.data;
}
}
文件 3 的 9: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 的 9:ILaunchpadPool.sol
pragma solidity 0.7.6;
pragma abicoder v2;
interface ILaunchpadPool {
struct VestingPhase {
uint256 fromTimestamp;
uint256 toTimestamp;
uint256 percentage;
}
struct VestingPlan {
uint256 length;
mapping(uint256 => VestingPhase) phases;
}
struct PurchasePhase {
uint256 fromTimestamp;
uint256 toTimestamp;
}
struct PurchasePlan {
uint256 length;
mapping(uint256 => PurchasePhase) phases;
}
struct PoolDetail {
string poolId;
string poolType;
address tokenAddress;
uint256[] tokenSupply;
uint256[] tokenSold;
uint256[] openAllocation;
address supportedPayment;
uint256[] supportedRates;
PurchasePhase[] purchasePlan;
VestingPhase[] vestingPlan;
uint256 bps;
}
struct UserDetail {
string poolId;
address userAddress;
uint256[] orderedAmount;
uint256[] vestedAmount;
uint256[] accumulatedAmount;
}
event SetVerifier(address verifier);
event NewMerkleRoot(
bytes32 root,
string ipfsCID,
address submitter
);
event TokenWithdraw(address token, uint256 amount, address sendTo);
event EtherWithdraw(uint256 amount, address sendTo);
event NewPoolPlans(
PurchasePhase[] purchasePlan,
VestingPhase[] vestingPlan
);
event NewPaymentTypes(
address _paymentToken,
uint256[] _paymentRates
);
event NewOrder(
string indexed poolId,
address recipient,
address paymentToken,
uint256 paymentAmount,
uint256[] purchaseAmount
);
function submitMerkleRoot(bytes32 _merkleRoot, string calldata _ipfsCID) external;
function purchase(
address buyer,
address paymentToken,
uint256 paymentAmount,
uint256[] calldata purchaseAmount,
uint256[] calldata purchaseCap,
bytes32[] calldata merkleProof,
bytes calldata signature
) external payable;
function vest(address buyer, uint256[] calldata vestAmount) external;
function getPoolDetail() external view returns (PoolDetail memory);
function getUserDetails(address[] calldata userAddresses) external view returns (UserDetail[] memory);
function updatePool(uint256[] calldata _openAllocation) external;
function updatePlans(
PurchasePhase[] calldata _purchasePlan,
VestingPhase[] calldata _vestingPlan
) external;
function updateTokenAddress(
address _tokenAddress
) external;
function updatePayments(address _paymentToken, uint256[] calldata _paymentRates)
external;
function getMerkleRoot() external view returns(bytes32);
function getIpfsCID() external view returns(string memory);
}
文件 5 的 9:ILaunchpadRouter.sol
pragma solidity 0.7.6;
pragma abicoder v2;
import "./ILaunchpadPool.sol";
interface ILaunchpadRouter {
function getPools(string[] calldata poolIds) external view returns (address[] memory);
function getPoolDetails(string[] calldata poolIds) external view returns (ILaunchpadPool.PoolDetail[] memory);
function getUserDetails(string calldata poolId, address[] calldata userAddresses) external view returns (ILaunchpadPool.UserDetail[] memory);
function purchase(
string calldata poolId,
address paymentToken,
uint256 paymentAmount,
uint256[] calldata purchaseAmount,
uint256[] calldata purchaseCap,
bytes32[] calldata merkleProof,
bytes calldata signature
) external payable;
function vest(string calldata poolId, uint256[] calldata vestAmount) external;
}
文件 6 的 9:LaunchpadRouter.sol
pragma solidity 0.7.6;
pragma abicoder v2;
import "../interfaces/launchpad/ILaunchpadRouter.sol";
import "../interfaces/launchpad/ILaunchpadPool.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract LaunchpadRouter is Ownable, ILaunchpadRouter {
using SafeERC20 for IERC20;
uint256 internal constant MAX_AMOUNT = uint256(-1);
address internal constant NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
mapping(string => address) public pools;
constructor(address _owner) Ownable() {
if (_owner != msg.sender) {
transferOwnership(_owner);
}
}
receive() external payable {}
function withdrawToken(
address token,
uint256 amount,
address sendTo
) external onlyOwner {
IERC20(token).safeTransfer(sendTo, amount);
}
function withdrawEther(uint256 amount, address payable sendTo) external onlyOwner {
(bool success, ) = sendTo.call{value: amount}("");
require(success, "withdraw failed");
}
function updatePools(string[] calldata poolIds, address[] calldata poolAddresses)
external
onlyOwner
{
require(poolIds.length == poolAddresses.length, "mismatch length");
for (uint256 i = 0; i < poolIds.length; i++) {
pools[poolIds[i]] = poolAddresses[i];
}
}
function getPools(string[] calldata poolIds)
external
view
override
returns (address[] memory poolAddresses)
{
poolAddresses = new address[](poolIds.length);
for (uint256 i = 0; i < poolIds.length; i++) {
poolAddresses[i] = pools[poolIds[i]];
}
}
function getPoolDetails(string[] calldata poolIds)
external
view
override
returns (ILaunchpadPool.PoolDetail[] memory poolDetails)
{
poolDetails = new ILaunchpadPool.PoolDetail[](poolIds.length);
for (uint256 i = 0; i < poolIds.length; i++) {
ILaunchpadPool pool = ILaunchpadPool(pools[poolIds[i]]);
if (pool != ILaunchpadPool(0)) {
poolDetails[i] = pool.getPoolDetail();
}
}
}
function getUserDetails(string calldata poolId, address[] calldata userAddresses)
external
view
override
returns (ILaunchpadPool.UserDetail[] memory)
{
return _pool(poolId).getUserDetails(userAddresses);
}
function purchase(
string calldata poolId,
address paymentToken,
uint256 paymentAmount,
uint256[] calldata purchaseAmount,
uint256[] calldata purchaseCap,
bytes32[] calldata merkleProof,
bytes calldata signature
) external payable override {
_processPayment(paymentToken, paymentAmount);
ILaunchpadPool pool = _pool(poolId);
if (paymentToken == NATIVE_TOKEN_ADDRESS) {
pool.purchase{value: paymentAmount}(
msg.sender,
paymentToken,
paymentAmount,
purchaseAmount,
purchaseCap,
merkleProof,
signature
);
} else {
_safeApproveAllowance(address(pool), paymentToken);
pool.purchase(
msg.sender,
paymentToken,
paymentAmount,
purchaseAmount,
purchaseCap,
merkleProof,
signature
);
}
}
function vest(string calldata poolId, uint256[] calldata vestAmount) external override {
_pool(poolId).vest(msg.sender, vestAmount);
}
function _processPayment(address paymentToken, uint256 paymentAmount) private {
if (paymentToken == NATIVE_TOKEN_ADDRESS) {
require(msg.value == paymentAmount, "payment: wrong received amount");
} else {
require(msg.value == 0, "payment: extra received amount");
IERC20(paymentToken).safeTransferFrom(msg.sender, address(this), paymentAmount);
}
}
function _pool(string calldata poolId) private view returns (ILaunchpadPool pool) {
pool = ILaunchpadPool(pools[poolId]);
require(pool != ILaunchpadPool(0), "pool not exist");
}
function _safeApproveAllowance(address spender, address token) private {
if (IERC20(token).allowance(address(this), spender) == 0) {
IERC20(token).safeApprove(spender, MAX_AMOUNT);
}
}
}
文件 7 的 9:Ownable.sol
pragma solidity >=0.6.0 <0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor () internal {
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;
}
}
文件 8 的 9:SafeERC20.sol
pragma solidity >=0.6.0 <0.8.0;
import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
require((value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 9 的 9: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;
}
}
{
"compilationTarget": {
"contracts/launchpad/LaunchpadRouter.sol": "LaunchpadRouter"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "none"
},
"optimizer": {
"enabled": true,
"runs": 780
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"string[]","name":"poolIds","type":"string[]"}],"name":"getPoolDetails","outputs":[{"components":[{"internalType":"string","name":"poolId","type":"string"},{"internalType":"string","name":"poolType","type":"string"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256[]","name":"tokenSupply","type":"uint256[]"},{"internalType":"uint256[]","name":"tokenSold","type":"uint256[]"},{"internalType":"uint256[]","name":"openAllocation","type":"uint256[]"},{"internalType":"address","name":"supportedPayment","type":"address"},{"internalType":"uint256[]","name":"supportedRates","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"}],"internalType":"struct ILaunchpadPool.PurchasePhase[]","name":"purchasePlan","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"toTimestamp","type":"uint256"},{"internalType":"uint256","name":"percentage","type":"uint256"}],"internalType":"struct ILaunchpadPool.VestingPhase[]","name":"vestingPlan","type":"tuple[]"},{"internalType":"uint256","name":"bps","type":"uint256"}],"internalType":"struct ILaunchpadPool.PoolDetail[]","name":"poolDetails","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string[]","name":"poolIds","type":"string[]"}],"name":"getPools","outputs":[{"internalType":"address[]","name":"poolAddresses","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"poolId","type":"string"},{"internalType":"address[]","name":"userAddresses","type":"address[]"}],"name":"getUserDetails","outputs":[{"components":[{"internalType":"string","name":"poolId","type":"string"},{"internalType":"address","name":"userAddress","type":"address"},{"internalType":"uint256[]","name":"orderedAmount","type":"uint256[]"},{"internalType":"uint256[]","name":"vestedAmount","type":"uint256[]"},{"internalType":"uint256[]","name":"accumulatedAmount","type":"uint256[]"}],"internalType":"struct ILaunchpadPool.UserDetail[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"pools","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"poolId","type":"string"},{"internalType":"address","name":"paymentToken","type":"address"},{"internalType":"uint256","name":"paymentAmount","type":"uint256"},{"internalType":"uint256[]","name":"purchaseAmount","type":"uint256[]"},{"internalType":"uint256[]","name":"purchaseCap","type":"uint256[]"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"purchase","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string[]","name":"poolIds","type":"string[]"},{"internalType":"address[]","name":"poolAddresses","type":"address[]"}],"name":"updatePools","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"poolId","type":"string"},{"internalType":"uint256[]","name":"vestAmount","type":"uint256[]"}],"name":"vest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address payable","name":"sendTo","type":"address"}],"name":"withdrawEther","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"sendTo","type":"address"}],"name":"withdrawToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]