// Verified using https://dapp.tools
// hevm: flattened sources of src/simple.sol
pragma solidity >0.4.13 >=0.4.23 >=0.6.0 >=0.6.7 <0.7.0;
////// lib/ds-auth/src/auth.sol
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/* pragma solidity >=0.4.23; */
interface DSAuthority {
function canCall(
address src, address dst, bytes4 sig
) external view returns (bool);
}
contract DSAuthEvents {
event LogSetAuthority (address indexed authority);
event LogSetOwner (address indexed owner);
}
contract DSAuth is DSAuthEvents {
DSAuthority public authority;
address public owner;
constructor() public {
owner = msg.sender;
emit LogSetOwner(msg.sender);
}
function setOwner(address owner_)
public
auth
{
owner = owner_;
emit LogSetOwner(owner);
}
function setAuthority(DSAuthority authority_)
public
auth
{
authority = authority_;
emit LogSetAuthority(address(authority));
}
modifier auth {
require(isAuthorized(msg.sender, msg.sig), "ds-auth-unauthorized");
_;
}
function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
if (src == address(this)) {
return true;
} else if (src == owner) {
return true;
} else if (authority == DSAuthority(0)) {
return false;
} else {
return authority.canCall(src, address(this), sig);
}
}
}
////// lib/ds-math/src/math.sol
/// math.sol -- mixin for inline numerical wizardry
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/* pragma solidity >0.4.13; */
contract DSMath {
function add(uint x, uint y) internal pure returns (uint z) {
require((z = x + y) >= x, "ds-math-add-overflow");
}
function sub(uint x, uint y) internal pure returns (uint z) {
require((z = x - y) <= x, "ds-math-sub-underflow");
}
function mul(uint x, uint y) internal pure returns (uint z) {
require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow");
}
function min(uint x, uint y) internal pure returns (uint z) {
return x <= y ? x : y;
}
function max(uint x, uint y) internal pure returns (uint z) {
return x >= y ? x : y;
}
function imin(int x, int y) internal pure returns (int z) {
return x <= y ? x : y;
}
function imax(int x, int y) internal pure returns (int z) {
return x >= y ? x : y;
}
uint constant WAD = 10 ** 18;
uint constant RAY = 10 ** 27;
//rounds to zero if x*y < WAD / 2
function wmul(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, y), WAD / 2) / WAD;
}
//rounds to zero if x*y < WAD / 2
function rmul(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, y), RAY / 2) / RAY;
}
//rounds to zero if x*y < WAD / 2
function wdiv(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, WAD), y / 2) / y;
}
//rounds to zero if x*y < RAY / 2
function rdiv(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, RAY), y / 2) / y;
}
// This famous algorithm is called "exponentiation by squaring"
// and calculates x^n with x as fixed-point and n as regular unsigned.
//
// It's O(log n), instead of O(n) for naive repeated multiplication.
//
// These facts are why it works:
//
// If n is even, then x^n = (x^2)^(n/2).
// If n is odd, then x^n = x * x^(n-1),
// and applying the equation for even x gives
// x^n = x * (x^2)^((n-1) / 2).
//
// Also, EVM division is flooring and
// floor[(n-1) / 2] = floor[n / 2].
//
function rpow(uint x, uint n) internal pure returns (uint z) {
z = n % 2 != 0 ? x : RAY;
for (n /= 2; n != 0; n /= 2) {
x = rmul(x, x);
if (n % 2 != 0) {
z = rmul(z, x);
}
}
}
}
////// lib/ds-token/src/token.sol
/// token.sol -- ERC20 implementation with minting and burning
// Copyright (C) 2015, 2016, 2017 DappHub, LLC
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/* pragma solidity >=0.4.23; */
/* import "ds-math/math.sol"; */
/* import "ds-auth/auth.sol"; */
contract DSToken is DSMath, DSAuth {
bool public stopped;
uint256 public totalSupply;
mapping (address => uint256) public balanceOf;
mapping (address => mapping (address => uint256)) public allowance;
bytes32 public symbol;
uint256 public decimals = 18; // standard token precision. override to customize
bytes32 public name = ""; // Optional token name
constructor(bytes32 symbol_) public {
symbol = symbol_;
}
event Approval(address indexed src, address indexed guy, uint wad);
event Transfer(address indexed src, address indexed dst, uint wad);
event Mint(address indexed guy, uint wad);
event Burn(address indexed guy, uint wad);
event Stop();
event Start();
modifier stoppable {
require(!stopped, "ds-stop-is-stopped");
_;
}
function approve(address guy) external returns (bool) {
return approve(guy, uint(-1));
}
function approve(address guy, uint wad) public stoppable returns (bool) {
allowance[msg.sender][guy] = wad;
emit Approval(msg.sender, guy, wad);
return true;
}
function transfer(address dst, uint wad) external returns (bool) {
return transferFrom(msg.sender, dst, wad);
}
function transferFrom(address src, address dst, uint wad)
public
stoppable
returns (bool)
{
if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) {
require(allowance[src][msg.sender] >= wad, "ds-token-insufficient-approval");
allowance[src][msg.sender] = sub(allowance[src][msg.sender], wad);
}
require(balanceOf[src] >= wad, "ds-token-insufficient-balance");
balanceOf[src] = sub(balanceOf[src], wad);
balanceOf[dst] = add(balanceOf[dst], wad);
emit Transfer(src, dst, wad);
return true;
}
function push(address dst, uint wad) external {
transferFrom(msg.sender, dst, wad);
}
function pull(address src, uint wad) external {
transferFrom(src, msg.sender, wad);
}
function move(address src, address dst, uint wad) external {
transferFrom(src, dst, wad);
}
function mint(uint wad) external {
mint(msg.sender, wad);
}
function burn(uint wad) external {
burn(msg.sender, wad);
}
function mint(address guy, uint wad) public auth stoppable {
balanceOf[guy] = add(balanceOf[guy], wad);
totalSupply = add(totalSupply, wad);
emit Mint(guy, wad);
}
function burn(address guy, uint wad) public auth stoppable {
if (guy != msg.sender && allowance[guy][msg.sender] != uint(-1)) {
require(allowance[guy][msg.sender] >= wad, "ds-token-insufficient-approval");
allowance[guy][msg.sender] = sub(allowance[guy][msg.sender], wad);
}
require(balanceOf[guy] >= wad, "ds-token-insufficient-balance");
balanceOf[guy] = sub(balanceOf[guy], wad);
totalSupply = sub(totalSupply, wad);
emit Burn(guy, wad);
}
function stop() public auth {
stopped = true;
emit Stop();
}
function start() public auth {
stopped = false;
emit Start();
}
function setName(bytes32 name_) external auth {
name = name_;
}
}
////// src/transferhelper.sol
/* pragma solidity >=0.6.0; */
// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library TransferHelper {
function safeApprove(address token, address to, uint value) internal {
// bytes4(keccak256(bytes('approve(address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED');
}
function safeTransfer(address token, address to, uint value) internal {
// bytes4(keccak256(bytes('transfer(address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED');
}
function safeTransferFrom(address token, address from, address to, uint value) internal {
// bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED');
}
function safeTransferETH(address to, uint value) internal {
(bool success,) = to.call{value:value}(new bytes(0));
require(success, 'TransferHelper: ETH_TRANSFER_FAILED');
}
}
////// src/simple.sol
/* pragma solidity ^0.6.7; */
/* import "ds-token/token.sol"; */
/* import "ds-auth/auth.sol"; */
/* import "./transferhelper.sol"; */
contract SimpleSale is DSAuth, DSMath
{
mapping(address => uint) internal _tkn_sale_quantity;
address public _default;
// uint[2]{price, total_quantity}
mapping(address => uint[2]) internal _tkn_sale_params;
mapping(address => address) internal _tkn_owners;
mapping(address => bool) public _tkn_open;
mapping(address => uint) public balances;
event SetSaleParams(address indexed token, address owner, uint price, uint quantity);
event CrowdSell(address indexed token, uint price, uint volume, address user);
event SetTokenOpen(address indexed token, bool open);
event Claim(address indexed receiver, uint amount);
modifier tokenExists(address token)
{
require(_tkn_owners[token] != address(0x00), "the token not exists!");
_;
}
modifier tokenOpen(address token)
{
require(_tkn_open[token], "the token is not open for sale!");
_;
}
constructor() DSAuth() payable public
{
}
receive() payable external
{
crowdsell(_default);
}
function claim(uint amount) public
{
require(balances[msg.sender] > 0 && balances[msg.sender] >= amount, "The balance is insufficient.");
balances[msg.sender] = sub(balances[msg.sender], amount);
TransferHelper.safeTransferETH(msg.sender,amount);
emit Claim(msg.sender, amount);
}
function crowdsell(address token) public payable tokenExists(token) tokenOpen(token)
{
sell(token, msg.value, msg.sender);
emit CrowdSell(token, _tkn_sale_params[token][0], msg.value, msg.sender);
}
function sell(address token, uint msgValue, address msgSender) private
{
require(_tkn_owners[token] != address(0x00) && _tkn_sale_params[token][0] > 0, "Not yet started, stay tuned.");
address tokenOwner = _tkn_owners[token];
uint price = _tkn_sale_params[token][0];
uint total_quantity = _tkn_sale_params[token][1];
uint amount = wmul(msgValue, price);
require(add(_tkn_sale_quantity[token],amount) <= total_quantity, "sold out!");
require(DSToken(token).allowance(tokenOwner, address(this)) >= amount, "reach to uplimit of allowance.");
TransferHelper.safeTransferFrom(token,tokenOwner, msgSender, amount);
_tkn_sale_quantity[token] = add(_tkn_sale_quantity[token], amount);
balances[tokenOwner] = add(balances[tokenOwner], msgValue);
}
function setSaleParams(address token, address owner, uint[2] memory price_uplimit, bool isDefault) public auth{
require(token != address(0x00), "incorrect token address.");
require(owner != address(0x00), "incorrect token owner.");
if(_tkn_owners[token] == address(0x00))
{
_tkn_owners[token] = owner;
}
if(isDefault)
{
_default = token;
}
require(price_uplimit.length == 2 && price_uplimit[0] > 0 && price_uplimit[1] > 0, "They must be correct(price, sale quantity).");
require(DSToken(token).allowance(owner, address(this)) >= price_uplimit[1], "makesure allowance enough!");
_tkn_sale_params[token] = price_uplimit;
emit SetSaleParams(token, owner, price_uplimit[0], price_uplimit[1]);
}
function setTokenOpen(address token, bool isOpen) public auth tokenExists(token)
{
_tkn_open[token] = isOpen;
emit SetTokenOpen(token, isOpen);
}
function getSaleParams(address token) public view returns (uint[2] memory)
{
return _tkn_sale_params[token];
}
function getTokenOwner(address token) public view returns (address)
{
return _tkn_owners[token];
}
function getSaleQuantity(address token) public view returns (uint)
{
return _tkn_sale_quantity[token];
}
}
{
"compilationTarget": {
"SimpleSale.sol": "SimpleSale"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[],"stateMutability":"payable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"volume","type":"uint256"},{"indexed":false,"internalType":"address","name":"user","type":"address"}],"name":"CrowdSell","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"authority","type":"address"}],"name":"LogSetAuthority","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"LogSetOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"SetSaleParams","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"bool","name":"open","type":"bool"}],"name":"SetTokenOpen","type":"event"},{"inputs":[],"name":"_default","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_tkn_open","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"authority","outputs":[{"internalType":"contract DSAuthority","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"crowdsell","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getSaleParams","outputs":[{"internalType":"uint256[2]","name":"","type":"uint256[2]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getSaleQuantity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getTokenOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract DSAuthority","name":"authority_","type":"address"}],"name":"setAuthority","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256[2]","name":"price_uplimit","type":"uint256[2]"},{"internalType":"bool","name":"isDefault","type":"bool"}],"name":"setSaleParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"isOpen","type":"bool"}],"name":"setTokenOpen","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]