pragma solidity ^0.8.4;
//SPDX-License-Identifier: MIT
abstract contract ERC20 {
function balanceOf(address _owner) virtual public view returns (uint256 balance);
function transfer(address _to, uint256 _amount) virtual public returns (bool success);
function transferFrom(address _from, address _to, uint256 _amount) virtual public returns (bool success);
}
interface StoreInterface {
function getExtensionStake(uint _option) external view returns(uint256, address);
function getExtensionCollateral(uint _option) external view returns(uint256, address);
function updateCollateral(uint256 _amount, uint256 _option) external;
}
interface StoreExtension {
function processPayment(address _customer, uint256 _tokenID, uint256 _amount) external;
}
interface StoreHubInterface {
function initBalance(address _store) external;
function withdraw(address _to) external;
}
interface StoreProxy {
function init(address _owner, address usdtHub, address daiHub) external;
}
contract StoreHub {
event CollateralTransfer(address indexed store, address to, uint256 amount, uint256 rate, bool didTrade);
event CollateralReliefUpdated(address indexed store, uint256 amount, uint256 rate, bool didAdd);
event StoreCreated(address indexed store, address owner, uint256 creationDate);
event AtokenTransfer(address indexed store, address to, uint256 amount);
event ExtensionUpdated(address indexed store, address extension);
event OwnerUpdated(address indexed store, address newOwner);
event StakeUpdated(address indexed store, uint256 stake);
ERC20 public usdcContract;
address public usdtStoreHub;
address public daiStoreHub;
address public storeImplementation;
uint256 public totalSupply;
mapping(address => bool) public isValidStore;
mapping(address => uint256) public storeBalance;
function deployStore() external {
address newStore;
bytes20 targetBytes = bytes20(storeImplementation);
assembly {
let clone := mload(0x40)
mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(clone, 0x14), targetBytes)
mstore(add(clone, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
newStore := create(0, clone, 0x37)
}
StoreProxy(newStore).init(msg.sender, usdtStoreHub, daiStoreHub);
isValidStore[newStore] = true;
storeBalance[newStore] = 1;
StoreHubInterface(usdtStoreHub).initBalance(newStore);
StoreHubInterface(daiStoreHub).initBalance(newStore);
emit StoreCreated(newStore, msg.sender, block.timestamp);
}
function withdraw(uint256 _collateral) external {
require(isValidStore[msg.sender] == true);
uint256 balance = storeBalance[msg.sender] - 1;
storeBalance[msg.sender] = 1;
totalSupply += _collateral;
usdcContract.transfer(msg.sender, balance);
emit CollateralTransfer(address(0), msg.sender, _collateral, 0, false);
}
function callEvent(
address _value1,
uint256 _value2,
uint256 _value3,
bool _value4,
uint _option
) external {
require(isValidStore[msg.sender] == true);
if(_option == 0) {
emit StakeUpdated(msg.sender, _value2);
}
else if(_option == 1) {
emit CollateralReliefUpdated(msg.sender, _value2, _value3, _value4);
}
else if(_option == 2) {
emit CollateralTransfer(msg.sender, _value1, _value2, _value3, _value4);
}
else if(_option == 3) {
emit AtokenTransfer(msg.sender, _value1, _value2);
}
else if(_option == 4) {
emit ExtensionUpdated(msg.sender, _value1);
}
else {
emit OwnerUpdated(msg.sender, _value1);
}
}
}
contract mUSDC is StoreHub {
string public name = "Malus USDC Token";
string public symbol = "mUSDC";
uint public decimals = 6;
event Transfer(address indexed _from, address indexed _to, uint256 _amount);
event Approval(address indexed _owner, address indexed _spender, uint256 _amount);
mapping(address => uint256) balances;
mapping (address => mapping (address => uint256)) allowed;
constructor(address _usdcContract, address _usdtStoreHub, address _daiStoreHub, address _implementation) {
usdcContract = ERC20(_usdcContract);
usdtStoreHub = _usdtStoreHub;
daiStoreHub = _daiStoreHub;
storeImplementation = _implementation;
}
function balanceOf(address _owner) public view returns (uint256 balance) {
return balances[_owner];
}
function transfer(address _to, uint256 _amount) public returns (bool success) {
require(balances[msg.sender] >= _amount);
if(isValidStore[_to] == true) {
StoreInterface store = StoreInterface(_to);
burn(store, msg.sender, 0, _amount);
return true;
}
balances[_to] += _amount;
balances[msg.sender] -= _amount;
emit Transfer(msg.sender, _to, _amount);
return true;
}
function transferFrom(address _from, address _to, uint256 _amount) public returns (bool success) {
require(balances[_from] >= _amount);
if(isValidStore[_to] == true) {
StoreInterface store = StoreInterface(_to);
burn(store, _from, 0, _amount);
return true;
}
if (_from != msg.sender && allowed[_from][msg.sender] < (2**256 - 1)) {
require(allowed[_from][msg.sender] >= _amount);
allowed[_from][msg.sender] -= _amount;
}
balances[_to] += _amount;
balances[_from] -= _amount;
emit Transfer(_from, _to, _amount);
return true;
}
function approve(address _spender, uint256 _amount) public returns (bool success) {
allowed[msg.sender][_spender] = _amount;
emit Approval(msg.sender, _spender, _amount);
return true;
}
function allowance(address _owner, address _spender) public view returns (uint remaining) {
return allowed[_owner][_spender];
}
function mint(StoreInterface _store, uint256 _tokenID, uint256 _amount) external {
(uint256 stake, address extensionAddress) = _store.getExtensionStake(0);
uint256 cashbackAmount = ((_amount * 700) / 10000);
uint256 prevStoreBalance = (storeBalance[address(_store)] += _amount) - _amount;
require(cashbackAmount >= 1);
require((stake - (((prevStoreBalance - 1) * 700) / 10000)) >= cashbackAmount);
balances[msg.sender] += cashbackAmount;
usdcContract.transferFrom(msg.sender, address(this), _amount);
if(extensionAddress != address(0)) {
StoreExtension(extensionAddress).processPayment(msg.sender, _tokenID, _amount);
}
emit Transfer(address(_store), msg.sender, cashbackAmount);
}
function burn(StoreInterface _store, address _from, uint256 _tokenID, uint256 _amount) public {
(uint256 collateral, address extensionAddress) = _store.getExtensionCollateral(0);
require(isValidStore[address(_store)] == true);
require(collateral >= _amount);
require(balances[_from] >= _amount);
if (_from != msg.sender && allowed[_from][msg.sender] < (2**256 - 1)) {
require(allowed[_from][msg.sender] >= _amount);
allowed[_from][msg.sender] -= _amount;
}
_store.updateCollateral(_amount, 0);
balances[_from] -= _amount;
totalSupply -= _amount;
if(extensionAddress != address(0)) {
StoreExtension(extensionAddress).processPayment(msg.sender, _tokenID, _amount);
}
emit Transfer(msg.sender, address(_store), _amount);
}
}
{
"compilationTarget": {
"contracts/mUSDC.sol": "mUSDC"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_usdcContract","type":"address"},{"internalType":"address","name":"_usdtStoreHub","type":"address"},{"internalType":"address","name":"_daiStoreHub","type":"address"},{"internalType":"address","name":"_implementation","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_owner","type":"address"},{"indexed":true,"internalType":"address","name":"_spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"store","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AtokenTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"store","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"},{"indexed":false,"internalType":"bool","name":"didAdd","type":"bool"}],"name":"CollateralReliefUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"store","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"},{"indexed":false,"internalType":"bool","name":"didTrade","type":"bool"}],"name":"CollateralTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"store","type":"address"},{"indexed":false,"internalType":"address","name":"extension","type":"address"}],"name":"ExtensionUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"store","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"store","type":"address"},{"indexed":false,"internalType":"uint256","name":"stake","type":"uint256"}],"name":"StakeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"store","type":"address"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"creationDate","type":"uint256"}],"name":"StoreCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"remaining","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract StoreInterface","name":"_store","type":"address"},{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_tokenID","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_value1","type":"address"},{"internalType":"uint256","name":"_value2","type":"uint256"},{"internalType":"uint256","name":"_value3","type":"uint256"},{"internalType":"bool","name":"_value4","type":"bool"},{"internalType":"uint256","name":"_option","type":"uint256"}],"name":"callEvent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"daiStoreHub","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deployStore","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isValidStore","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract StoreInterface","name":"_store","type":"address"},{"internalType":"uint256","name":"_tokenID","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"storeBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"storeImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"usdcContract","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"usdtStoreHub","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_collateral","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]