Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions contracts/IQLF.sol
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
// SPDX-License-Identifier: MIT

/**
* @author Yisi Liu
* @contact yisiliu@gmail.com
* @author_time 01/06/2021
**/

pragma solidity >= 0.6.0;
pragma solidity ^0.8.0;

interface IQLF {
/**
* @dev Returns if the given address is qualified, implemented on demand.
* @dev View only
*/
function ifQualified (address testee) external view returns (bool);

/**
* @dev Logs if the given address is qualified, implemented on demand.
*/
function logQualified (address testee) external;
function logQualified (address testee) external returns (bool);

/**
* @dev Emit when `ifQualified` is called to decide if the given `address`
* is `qualified` according to the preset rule by the contract creator and
* the current block `number` and the current block `timestamp`.
*/
event Qualification(bool qualified, uint256 number, uint256 timestamp);
event Qualification(address testee, bool qualified, uint256 number, uint256 timestamp);
}
60 changes: 24 additions & 36 deletions contracts/ito.sol
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
// SPDX-License-Identifier: MIT

/**
* @author Yisi Liu
* @contact yisiliu@gmail.com
* @author_time 01/06/2021
* @modification 03/31/2021
**/

pragma solidity >= 0.6.0;
import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
import "openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol";
import "openzeppelin-solidity/contracts/token/ERC721/IERC721.sol";
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "./IQLF.sol";
import "hardhat/console.sol";

Expand All @@ -31,6 +34,11 @@ contract HappyTokenPool {
mapping(address => uint256) swapped_map; // swapped amount of an address
}

struct Packed {
uint256 packed1;
uint256 packed2;
}

// swap pool filling success event
event FillSuccess (
uint256 total,
Expand Down Expand Up @@ -78,16 +86,12 @@ contract HappyTokenPool {
bytes32 private seed;
address DEFAULT_ADDRESS = 0x0000000000000000000000000000000000000000; // a universal address

constructor() public {
constructor() {
contract_creator = msg.sender;
seed = keccak256(abi.encodePacked(magic, block.timestamp, contract_creator));
base_timestamp = 1616976000; // 00:00:00 03/30/2021 GMT(UTC+0)
}


function test_allowance (address _token_addr) public {
console.log('allowance', IERC20(_token_addr).allowance(msg.sender, address(this)));
}
/**
* @dev
* fill_pool() creates a swap pool with specific parameters from input
Expand Down Expand Up @@ -174,15 +178,16 @@ contract HappyTokenPool {
public payable returns (uint256 swapped) {

Pool storage pool = pool_by_id[id];
address payable recipient = address(uint160(_recipient));
require (IQLF(pool.qualification).ifQualified(msg.sender) == true, "Not Qualified");
if (pool.qualification != DEFAULT_ADDRESS) {
require (IQLF(pool.qualification).logQualified(msg.sender) == true, "Not Qualified");
}
require (unbox(pool.packed1, 208, 24) + base_timestamp < block.timestamp, "Not started.");
require (unbox(pool.packed1, 232, 24) + base_timestamp > block.timestamp, "Expired.");
// sha3(sha3(passowrd)[:48] + msg.sender) so that the raw password will never appear in the contract
require (verification == keccak256(abi.encodePacked(unbox(pool.packed1, 160, 48), msg.sender)),
'Wrong Password');
// sha3(msg.sender) to protect from front runs (but this is kinda naive since the contract is open sourced)
require (validation == keccak256(toBytes(msg.sender)), "Validation Failed");
require (validation == keccak256(abi.encodePacked(msg.sender)), "Validation Failed");

uint256 total_tokens = unbox(pool.packed2, 0, 128);
// revert if the pool is empty
Expand Down Expand Up @@ -231,10 +236,10 @@ contract HappyTokenPool {
IERC20(exchange_addr).safeTransferFrom(msg.sender, address(this), input_total);
}
// transfer the swapped tokens to the recipient address (could be different from the swapper address) - OUTPUT
transfer_token(address(unbox(pool.packed1, 0, 160)), address(this), recipient, swapped_tokens);
transfer_token(address(uint160(unbox(pool.packed1, 0, 160))), address(this), msg.sender, swapped_tokens);

// Swap success event
emit SwapSuccess(id, recipient, exchange_addr, address(unbox(pool.packed1, 0, 160)),
emit SwapSuccess(id, msg.sender, exchange_addr, address(uint160(unbox(pool.packed1, 0, 160))),
input_total, swapped_tokens);
return swapped_tokens;
}
Expand Down Expand Up @@ -278,7 +283,7 @@ contract HappyTokenPool {
Pool storage pool = pool_by_id[id];
require(msg.sender == pool.creator, "Only the pool creator can destruct.");

address token_address = address(unbox(pool.packed1, 0, 160));
address token_address = address(uint160(unbox(pool.packed1, 0, 160)));
uint256 expiration = unbox(pool.packed1, 232, 24) + base_timestamp;
uint256 remaining_tokens = unbox(pool.packed2, 0, 128);
// only after expiration or the pool is empty
Expand All @@ -298,7 +303,7 @@ contract HappyTokenPool {
transfer_token(pool.exchange_addrs[i], address(this), msg.sender, pool.exchanged_tokens[i]);
// ETH
else
msg.sender.transfer(pool.exchanged_tokens[i]);
payable(msg.sender).transfer(pool.exchanged_tokens[i]);
}
}
emit DestructSuccess(id, token_address, remaining_tokens, pool.exchanged_tokens);
Expand Down Expand Up @@ -340,7 +345,7 @@ contract HappyTokenPool {
transfer_token(token_address, address(this), msg.sender, withdraw_balance);
// ETH
else
msg.sender.transfer(withdraw_balance);
payable(msg.sender).transfer(withdraw_balance);
// clear the record
pool.exchanged_tokens[addr_i] = 0;
emit WithdrawSuccess(id, token_address, withdraw_balance);
Expand All @@ -359,7 +364,7 @@ contract HappyTokenPool {
function wrap1 (address _token_addr, bytes32 _hash, uint256 _start, uint256 _end) internal pure
returns (uint256 packed1) {
uint256 _packed1 = 0;
_packed1 |= box(0, 160, uint256(_token_addr)); // token_addr = 160 bits
_packed1 |= box(0, 160, uint256(uint160(_token_addr))); // token_addr = 160 bits
_packed1 |= box(160, 48, uint256(_hash) >> 208); // hash = 48 bits (safe?)
_packed1 |= box(208, 24, _start); // start_time = 24 bits
_packed1 |= box(232, 24, _end); // expiration_time = 24 bits
Expand Down Expand Up @@ -455,21 +460,4 @@ contract HappyTokenPool {
require(IERC20(token_address).balanceOf(sender_address) >= amount, "Balance not enough");
IERC20(token_address).safeTransfer(recipient_address, amount);
}

/**
* a address to be converted
* toBytes() converts an address into a byte
**/

// https://ethereum.stackexchange.com/questions/884/how-to-convert-an-address-to-bytes-in-solidity
// 695 gas consumed
function toBytes (address a) internal pure returns (bytes memory b) {
assembly {
let m := mload(0x40)
a := and(a, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
mstore(add(m, 20), xor(0x140000000000000000000000000000000000000000, a))
mstore(0x40, add(m, 52))
b := m
}
}
}
34 changes: 34 additions & 0 deletions contracts/ito_deployer.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: MIT

/**
* @author Yisi Liu
* @contact yisiliu@gmail.com
* @author_time 01/06/2021
* @modification 03/31/2021
**/

pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "./IQLF.sol";
import "hardhat/console.sol";

contract HappyTokenPoolDeployer {
uint32 nonce;
uint32 base_timestamp;
address public deployer_creator;
mapping(bytes32 => address) public pool_by_id;
bytes32 private seed;
address public ZERO_ADDRESS = 0x0000000000000000000000000000000000000000;

constructor() {
deployer_creator = msg.sender;
string memory magic = "Traffic has resumed in Egypt's Suez Canal after a stranded container ship blocking it for \
nearly a week was finally freed by salvage crews. Tug boats honked their horns in celebration as the 400m-long (1,300ft) \
Ever Given was dislodged on Monday March 29th";
seed = keccak256(abi.encodePacked(magic, block.timestamp, deployer_creator));
nonce = 0;
}
}
17 changes: 9 additions & 8 deletions contracts/qualification.sol
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
// SPDX-License-Identifier: MIT

/**
* @author Yisi Liu
* @contact yisiliu@gmail.com
* @author_time 01/06/2021
**/

pragma solidity >= 0.6.0;
pragma solidity ^0.8.0;

import "./IQLF.sol";

contract QLF is IQLF {
string private name;
uint256 private creation_time;

constructor (string memory _name) public {
constructor (string memory _name) {
name = _name;
creation_time = block.timestamp;
}
Expand All @@ -25,13 +27,12 @@ contract QLF is IQLF {
return creation_time;
}

function ifQualified(address testee) public view override returns (bool) {
bool qualified = true;
return qualified;
function ifQualified(address) public pure override returns (bool qualified) {
qualified = true;
}

function logQualified(address testee) public override {
bool qualified = true;
emit Qualification(qualified, block.number, block.timestamp);
function logQualified(address testee) public override returns (bool qualified) {
qualified = true;
emit Qualification(testee, qualified, block.number, block.timestamp);
}
}
4 changes: 3 additions & 1 deletion contracts/test_internal.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
pragma solidity >= 0.6.0;
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;
import './ito.sol';

contract InternalFunctions is HappyTokenPool {
Expand Down
8 changes: 5 additions & 3 deletions contracts/test_tokenA.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
pragma solidity >= 0.6.0;
// SPDX-License-Identifier: MIT

import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract TestTokenA is ERC20 {
constructor(uint initialSupply) ERC20("TestTokenA", "TESTA") public{
constructor(uint initialSupply) ERC20("TestTokenA", "TESTA") {
_mint(msg.sender, initialSupply);
}
}
8 changes: 5 additions & 3 deletions contracts/test_tokenB.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
pragma solidity >= 0.6.0;
// SPDX-License-Identifier: MIT

import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract TestTokenB is ERC20 {
constructor(uint initialSupply) ERC20("TestTokenB", "TESTB") public{
constructor(uint initialSupply) ERC20("TestTokenB", "TESTB") {
_mint(msg.sender, initialSupply);
}
}
8 changes: 5 additions & 3 deletions contracts/test_tokenC.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
pragma solidity >= 0.6.0;
// SPDX-License-Identifier: MIT

import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract TestTokenC is ERC20 {
constructor(uint initialSupply) ERC20("TestTokenC", "TESTC") public{
constructor(uint initialSupply) ERC20("TestTokenC", "TESTC") {
_mint(msg.sender, initialSupply);
}
}
54 changes: 54 additions & 0 deletions contracts/vault.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// SPDX-License-Identifier: MIT

/**
* @author Yisi Liu
* @contact yisiliu@gmail.com
* @author_time 04/01/2021
**/

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

contract HappyTokenVault {
using SafeERC20 for IERC20;

address immutable private _keeper;
address rescue_team;

modifier keepOnly {
require(msg.sender == _keeper, "You Shall Not Pass.");
_;
}

modifier recycling {
require(msg.sender == _keeper || msg.sender == rescue_team, "You Are Not Part of The Team.");
_;
}

constructor (address _rescue_team) {
if (rescue_team != 0x0000000000000000000000000000000000000000)
rescue_team = _rescue_team;
_keeper = msg.sender;
}

function send (address token_address, address to, uint256 value) public keepOnly {
IERC20(token_address).safeTransfer(to, value);
}

function retrieve (address[] memory token_addresses) public recycling {
uint256 _balance;
for(uint256 i = 0; i < token_addresses.length; i++) {
_balance = IERC20(token_addresses[i]).balanceOf(address(this));
if (_balance > 0) {
IERC20(token_addresses[i]).transfer(msg.sender, _balance);
}
}

_balance = address(this).balance;
if (_balance > 0)
payable(msg.sender).transfer(_balance);

selfdestruct(payable(msg.sender));
}
}
7 changes: 6 additions & 1 deletion hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import "hardhat-gas-reporter"
import "@nomiclabs/hardhat-waffle"
import "@nomiclabs/hardhat-ethers"

/**
* @type import('hardhat/config').HardhatUserConfig
*/
module.exports = {};

module.exports = {
solidity: {
version: "0.8.0"
}
};
Loading