Transaction Hash:
Block:
12979293 at Aug-07-2021 05:21:51 PM +UTC
Transaction Fee:
0.008458790591898296 ETH
$18.18
Gas Used:
168,428 Gas / 50.221997482 Gwei
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
|
0x3EcEf08D...8bFf2D5bB
Miner
| (MiningPoolHub) | 2,481.178211026196440318 Eth | 2,481.180764680564611666 Eth | 0.002553654368171348 | |
| 0xF6dc9b36...d8ED3B0BE |
0.013371250691358024 Eth
Nonce: 25
|
0.004912460099459728 Eth
Nonce: 26
| 0.008458790591898296 |
Execution Trace
MainchainGatewayProxy.993e1c42( )
MainchainGatewayManager.withdrawERC20For( _withdrawalId=515359, _user=0xF6dc9b366dd7a02Fa4Fc7BEEaDaa392d8ED3B0BE, _token=0xCC8Fa225D80b9c7D42F96e9570156c65D6cAAa25, _amount=2052, _signatures=0x01E2A2002323EA2F393DA1E4416A943794EEED51B0F472D70045D143ED7789FFED40DB5F5D34D8440B8C044A6EF710547873080E747C88BD67ED7DB69F189A29C81B01B15BAEBC51DFA87F4B262C5DFF4482DC7E8CC61BC5B9B950939FD61D2CC410FA1E929C18CB727AAE71FE18F79D7CE5AD50A5AEA464B36ECFD973A0BBE3C9C3581C0173F6B36457B3C92B99B3F4A60A5780D8BDD92EC709B3C731998725D6DE845A847AE536764D8FEC1B58FC7FC9A350DC1A9CD285C4EB392FC7B7E71298A1DFFB9A1C0161BEE3A3D2613EEEB1BB4E983A601899F91FEF6F9E9C87FC83F121584884A179435D691026B66C11300AE9527A60217ACCEBD0CB15C566B30FDDE95D2E29394A1C01FCE45A2B066C6449DD36D1483C238C56791FF4CB262642485F482FA2234E98822F7CCDAD557BE40A3296982C6C0DF507DFDC2F0D7E112F2666D8E0C08B1471CA1B )-
Registry.isTokenMapped( _token=0xCC8Fa225D80b9c7D42F96e9570156c65D6cAAa25, _standard=20, _isMainchain=True ) => ( True ) -
Registry.STATICCALL( ) -
Registry.getContract( _name=VALIDATOR ) => ( _address=0x42B19dca30fd612B1757682C074497847F2B57e0 ) -
Null: 0x000...001.a044e07e( ) -
MainchainValidator.isValidator( _addr=0x11360EaCDEDd59bC433aFad4fc8f0417d1fbEbab ) => ( True ) -
Null: 0x000...001.a044e07e( ) -
MainchainValidator.isValidator( _addr=0x70bB1FB41C8C42F6ddd53a708E2B82209495e455 ) => ( True ) -
Null: 0x000...001.a044e07e( ) -
MainchainValidator.isValidator( _addr=0xE70cbF18114822c0e32C6B35d2478f02a8Ac78A9 ) => ( True ) -
Null: 0x000...001.a044e07e( ) -
MainchainValidator.isValidator( _addr=0xEE11d2016e9f2faE606b2F12986811F4abbe6215 ) => ( True ) -
Null: 0x000...001.a044e07e( ) -
MainchainValidator.isValidator( _addr=0xf224beFf587362A88D859e899D0d80C080E1e812 ) => ( True ) -
MainchainValidator.checkThreshold( _voteCount=5 ) => ( True ) -
Registry.STATICCALL( ) -
Registry.getContract( _name=WETH_TOKEN ) => ( _address=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 ) -
SmoothLovePotion.balanceOf( 0x1A2a1c938CE3eC39b6D47113c7955bAa9DD454F2 ) => ( 7754 )
-
SmoothLovePotion.transfer( _to=0xF6dc9b366dd7a02Fa4Fc7BEEaDaa392d8ED3B0BE, _value=2052 ) => ( _success=True )
-
withdrawERC20For[MainchainGatewayManager (ln:1024)]
verifySignatures[MainchainGatewayManager (ln:1045)]div[MainchainGatewayManager (ln:1132)]getContract[MainchainGatewayManager (ln:1134)]VALIDATOR[MainchainGatewayManager (ln:1134)]recover[MainchainGatewayManager (ln:1139)]mul[MainchainGatewayManager (ln:1139)]isValidator[MainchainGatewayManager (ln:1140)]checkThreshold[MainchainGatewayManager (ln:1148)]
getContract[MainchainGatewayManager (ln:1047)]WETH_TOKEN[MainchainGatewayManager (ln:1047)]_withdrawETHFor[MainchainGatewayManager (ln:1048)]getContract[MainchainGatewayManager (ln:1211)]WETH_TOKEN[MainchainGatewayManager (ln:1211)]withdraw[MainchainGatewayManager (ln:1212)]transfer[MainchainGatewayManager (ln:1213)]toPayable[MainchainGatewayManager (ln:1213)]
balanceOf[MainchainGatewayManager (ln:1050)]mint[MainchainGatewayManager (ln:1054)]sub[MainchainGatewayManager (ln:1054)]transfer[MainchainGatewayManager (ln:1059)]_insertWithdrawalEntry[MainchainGatewayManager (ln:1062)]WithdrawalEntry[MainchainGatewayManager (ln:1194)]TokenWithdrew[MainchainGatewayManager (ln:1202)]
File 1 of 5: MainchainGatewayProxy
File 2 of 5: MainchainGatewayManager
File 3 of 5: Registry
File 4 of 5: MainchainValidator
File 5 of 5: SmoothLovePotion
// File: @axie/contract-library/contracts/access/HasAdmin.sol
pragma solidity ^0.5.2;
contract HasAdmin {
event AdminChanged(address indexed _oldAdmin, address indexed _newAdmin);
event AdminRemoved(address indexed _oldAdmin);
address public admin;
modifier onlyAdmin {
require(msg.sender == admin);
_;
}
constructor() internal {
admin = msg.sender;
emit AdminChanged(address(0), admin);
}
function changeAdmin(address _newAdmin) external onlyAdmin {
require(_newAdmin != address(0));
emit AdminChanged(admin, _newAdmin);
admin = _newAdmin;
}
function removeAdmin() external onlyAdmin {
emit AdminRemoved(admin);
admin = address(0);
}
}
// File: @axie/contract-library/contracts/proxy/ProxyStorage.sol
pragma solidity ^0.5.2;
/**
* @title ProxyStorage
* @dev Store the address of logic contact that the proxy should forward to.
*/
contract ProxyStorage is HasAdmin {
address internal _proxyTo;
}
// File: @axie/contract-library/contracts/proxy/Proxy.sol
pragma solidity ^0.5.2;
/**
* @title Proxy
* @dev Gives the possibility to delegate any call to a foreign implementation.
*/
contract Proxy is ProxyStorage {
event ProxyUpdated(address indexed _new, address indexed _old);
constructor(address _proxyTo) public {
updateProxyTo(_proxyTo);
}
/**
* @dev Tells the address of the implementation where every call will be delegated.
* @return address of the implementation to which it will be delegated
*/
function implementation() public view returns (address) {
return _proxyTo;
}
/**
* @dev See more at: https://eips.ethereum.org/EIPS/eip-897
* @return type of proxy - always upgradable
*/
function proxyType() external pure returns (uint256) {
// Upgradeable proxy
return 2;
}
/**
* @dev Fallback function allowing to perform a delegatecall to the given implementation.
* This function will return whatever the implementation call returns
*/
function () payable external {
address _impl = implementation();
require(_impl != address(0));
assembly {
let ptr := mload(0x40)
calldatacopy(ptr, 0, calldatasize)
let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0)
let size := returndatasize
returndatacopy(ptr, 0, size)
switch result
case 0 { revert(ptr, size) }
default { return(ptr, size) }
}
}
function updateProxyTo(address _newProxyTo) public onlyAdmin {
require(_newProxyTo != address(0x0));
_proxyTo = _newProxyTo;
emit ProxyUpdated(_newProxyTo, _proxyTo);
}
}
// File: @axie/contract-library/contracts/lifecycle/Pausable.sol
pragma solidity ^0.5.2;
contract Pausable is HasAdmin {
event Paused();
event Unpaused();
bool public paused;
modifier whenNotPaused() {
require(!paused);
_;
}
modifier whenPaused() {
require(paused);
_;
}
function pause() public onlyAdmin whenNotPaused {
paused = true;
emit Paused();
}
function unpause() public onlyAdmin whenPaused {
paused = false;
emit Unpaused();
}
}
// File: @axie/contract-library/contracts/math/SafeMath.sol
pragma solidity ^0.5.2;
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
c = a + b;
require(c >= a);
}
function sub(uint256 a, uint256 b) internal pure returns (uint256 c) {
require(b <= a);
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
if (a == 0) {
return 0;
}
c = a * b;
require(c / a == b);
}
function div(uint256 a, uint256 b) internal pure returns (uint256 c) {
// Since Solidity automatically asserts when dividing by 0,
// but we only need it to revert.
require(b > 0);
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256 c) {
// Same reason as `div`.
require(b > 0);
return a % b;
}
function ceilingDiv(uint256 a, uint256 b) internal pure returns (uint256 c) {
return add(div(a, b), mod(a, b) > 0 ? 1 : 0);
}
function subU64(uint64 a, uint64 b) internal pure returns (uint64 c) {
require(b <= a);
return a - b;
}
function addU8(uint8 a, uint8 b) internal pure returns (uint8 c) {
c = a + b;
require(c >= a);
}
}
// File: contracts/chain/common/IValidator.sol
pragma solidity ^0.5.17;
contract IValidator {
event ValidatorAdded(uint256 indexed _id, address indexed _validator);
event ValidatorRemoved(uint256 indexed _id, address indexed _validator);
event ThresholdUpdated(
uint256 indexed _id,
uint256 indexed _numerator,
uint256 indexed _denominator,
uint256 _previousNumerator,
uint256 _previousDenominator
);
function isValidator(address _addr) public view returns (bool);
function getValidators() public view returns (address[] memory _validators);
function checkThreshold(uint256 _voteCount) public view returns (bool);
}
// File: contracts/chain/common/Validator.sol
pragma solidity ^0.5.17;
contract Validator is IValidator {
using SafeMath for uint256;
mapping(address => bool) validatorMap;
address[] public validators;
uint256 public validatorCount;
uint256 public num;
uint256 public denom;
constructor(address[] memory _validators, uint256 _num, uint256 _denom)
public
{
validators = _validators;
validatorCount = _validators.length;
for (uint256 _i = 0; _i < validatorCount; _i++) {
address _validator = _validators[_i];
validatorMap[_validator] = true;
}
num = _num;
denom = _denom;
}
function isValidator(address _addr)
public
view
returns (bool)
{
return validatorMap[_addr];
}
function getValidators()
public
view
returns (address[] memory _validators)
{
_validators = validators;
}
function checkThreshold(uint256 _voteCount)
public
view
returns (bool)
{
return _voteCount.mul(denom) >= num.mul(validatorCount);
}
function _addValidator(uint256 _id, address _validator)
internal
{
require(!validatorMap[_validator]);
validators.push(_validator);
validatorMap[_validator] = true;
validatorCount++;
emit ValidatorAdded(_id, _validator);
}
function _removeValidator(uint256 _id, address _validator)
internal
{
require(isValidator(_validator));
uint256 _index;
for (uint256 _i = 0; _i < validatorCount; _i++) {
if (validators[_i] == _validator) {
_index = _i;
break;
}
}
validatorMap[_validator] = false;
validators[_index] = validators[validatorCount - 1];
validators.pop();
validatorCount--;
emit ValidatorRemoved(_id, _validator);
}
function _updateQuorum(uint256 _id, uint256 _numerator, uint256 _denominator)
internal
{
require(_numerator <= _denominator);
uint256 _previousNumerator = num;
uint256 _previousDenominator = denom;
num = _numerator;
denom = _denominator;
emit ThresholdUpdated(
_id,
_numerator,
_denominator,
_previousNumerator,
_previousDenominator
);
}
}
// File: contracts/chain/mainchain/MainchainValidator.sol
pragma solidity ^0.5.17;
/**
* @title Validator
* @dev Simple validator contract
*/
contract MainchainValidator is Validator, HasAdmin {
uint256 nonce;
constructor(
address[] memory _validators,
uint256 _num,
uint256 _denom
) Validator(_validators, _num, _denom) public {
}
function addValidators(address[] calldata _validators) external onlyAdmin {
for (uint256 _i; _i < _validators.length; ++_i) {
_addValidator(nonce++, _validators[_i]);
}
}
function removeValidator(address _validator) external onlyAdmin {
_removeValidator(nonce++, _validator);
}
function updateQuorum(uint256 _numerator, uint256 _denominator) external onlyAdmin {
_updateQuorum(nonce++, _numerator, _denominator);
}
}
// File: contracts/chain/common/Registry.sol
pragma solidity ^0.5.17;
contract Registry is HasAdmin {
event ContractAddressUpdated(
string indexed _name,
bytes32 indexed _code,
address indexed _newAddress
);
event TokenMapped(
address indexed _mainchainToken,
address indexed _sidechainToken,
uint32 _standard
);
string public constant GATEWAY = "GATEWAY";
string public constant WETH_TOKEN = "WETH_TOKEN";
string public constant VALIDATOR = "VALIDATOR";
string public constant ACKNOWLEDGEMENT = "ACKNOWLEDGEMENT";
struct TokenMapping {
address mainchainToken;
address sidechainToken;
uint32 standard; // 20, 721 or any other standards
}
mapping(bytes32 => address) public contractAddresses;
mapping(address => TokenMapping) public mainchainMap;
mapping(address => TokenMapping) public sidechainMap;
function getContract(string calldata _name)
external
view
returns (address _address)
{
bytes32 _code = getCode(_name);
_address = contractAddresses[_code];
require(_address != address(0));
}
function isTokenMapped(address _token, uint32 _standard, bool _isMainchain)
external
view
returns (bool)
{
TokenMapping memory _mapping = _getTokenMapping(_token, _isMainchain);
return _mapping.mainchainToken != address(0) &&
_mapping.sidechainToken != address(0) &&
_mapping.standard == _standard;
}
function updateContract(string calldata _name, address _newAddress)
external
onlyAdmin
{
bytes32 _code = getCode(_name);
contractAddresses[_code] = _newAddress;
emit ContractAddressUpdated(_name, _code, _newAddress);
}
function mapToken(address _mainchainToken, address _sidechainToken, uint32 _standard)
external
onlyAdmin
{
TokenMapping memory _map = TokenMapping(
_mainchainToken,
_sidechainToken,
_standard
);
mainchainMap[_mainchainToken] = _map;
sidechainMap[_sidechainToken] = _map;
emit TokenMapped(
_mainchainToken,
_sidechainToken,
_standard
);
}
function clearMapToken(address _mainchainToken, address _sidechainToken)
external
onlyAdmin
{
TokenMapping storage _mainchainMap = mainchainMap[_mainchainToken];
_clearMapEntry(_mainchainMap);
TokenMapping storage _sidechainMap = sidechainMap[_sidechainToken];
_clearMapEntry(_sidechainMap);
}
function getMappedToken(
address _token,
bool _isMainchain
)
external
view
returns (
address _mainchainToken,
address _sidechainToken,
uint32 _standard
)
{
TokenMapping memory _mapping = _getTokenMapping(_token, _isMainchain);
_mainchainToken = _mapping.mainchainToken;
_sidechainToken = _mapping.sidechainToken;
_standard = _mapping.standard;
}
function getCode(string memory _name)
public
pure
returns (bytes32)
{
return keccak256(abi.encodePacked(_name));
}
function _getTokenMapping(
address _token,
bool isMainchain
)
internal
view
returns (TokenMapping memory _mapping)
{
if (isMainchain) {
_mapping = mainchainMap[_token];
} else {
_mapping = sidechainMap[_token];
}
}
function _clearMapEntry(TokenMapping storage _entry)
internal
{
_entry.mainchainToken = address(0);
_entry.sidechainToken = address(0);
_entry.standard = 0;
}
}
// File: contracts/chain/mainchain/MainchainGatewayStorage.sol
pragma solidity ^0.5.17;
/**
* @title GatewayStorage
* @dev Storage of deposit and withdraw information.
*/
contract MainchainGatewayStorage is ProxyStorage, Pausable {
event TokenDeposited(
uint256 indexed _depositId,
address indexed _owner,
address indexed _tokenAddress,
address _sidechainAddress,
uint32 _standard,
uint256 _tokenNumber // ERC-20 amount or ERC721 tokenId
);
event TokenWithdrew(
uint256 indexed _withdrawId,
address indexed _owner,
address indexed _tokenAddress,
uint256 _tokenNumber
);
struct DepositEntry {
address owner;
address tokenAddress;
address sidechainAddress;
uint32 standard;
uint256 tokenNumber;
}
struct WithdrawalEntry {
address owner;
address tokenAddress;
uint256 tokenNumber;
}
Registry public registry;
uint256 public depositCount;
DepositEntry[] public deposits;
mapping(uint256 => WithdrawalEntry) public withdrawals;
function updateRegistry(address _registry) external onlyAdmin {
registry = Registry(_registry);
}
}
// File: contracts/chain/mainchain/MainchainGatewayProxy.sol
pragma solidity ^0.5.17;
contract MainchainGatewayProxy is Proxy, MainchainGatewayStorage {
constructor(address _proxyTo, address _registry)
public
Proxy(_proxyTo)
{
registry = Registry(_registry);
}
}File 2 of 5: MainchainGatewayManager
// File: @axie/contract-library/contracts/cryptography/ECVerify.sol
pragma solidity ^0.5.2;
library ECVerify {
enum SignatureMode {
EIP712,
GETH,
TREZOR
}
function recover(bytes32 _hash, bytes memory _signature) internal pure returns (address _signer) {
return recover(_hash, _signature, 0);
}
// solium-disable-next-line security/no-assign-params
function recover(bytes32 _hash, bytes memory _signature, uint256 _index) internal pure returns (address _signer) {
require(_signature.length >= _index + 66);
SignatureMode _mode = SignatureMode(uint8(_signature[_index]));
bytes32 _r;
bytes32 _s;
uint8 _v;
// solium-disable-next-line security/no-inline-assembly
assembly {
_r := mload(add(_signature, add(_index, 33)))
_s := mload(add(_signature, add(_index, 65)))
_v := and(255, mload(add(_signature, add(_index, 66))))
}
if (_v < 27) {
_v += 27;
}
require(_v == 27 || _v == 28);
if (_mode == SignatureMode.GETH) {
_hash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _hash));
} else if (_mode == SignatureMode.TREZOR) {
_hash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n\x20", _hash));
}
return ecrecover(_hash, _v, _r, _s);
}
function ecverify(bytes32 _hash, bytes memory _signature, address _signer) internal pure returns (bool _valid) {
return _signer == recover(_hash, _signature);
}
}
// File: @axie/contract-library/contracts/math/SafeMath.sol
pragma solidity ^0.5.2;
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
c = a + b;
require(c >= a);
}
function sub(uint256 a, uint256 b) internal pure returns (uint256 c) {
require(b <= a);
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
if (a == 0) {
return 0;
}
c = a * b;
require(c / a == b);
}
function div(uint256 a, uint256 b) internal pure returns (uint256 c) {
// Since Solidity automatically asserts when dividing by 0,
// but we only need it to revert.
require(b > 0);
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256 c) {
// Same reason as `div`.
require(b > 0);
return a % b;
}
function ceilingDiv(uint256 a, uint256 b) internal pure returns (uint256 c) {
return add(div(a, b), mod(a, b) > 0 ? 1 : 0);
}
function subU64(uint64 a, uint64 b) internal pure returns (uint64 c) {
require(b <= a);
return a - b;
}
function addU8(uint8 a, uint8 b) internal pure returns (uint8 c) {
c = a + b;
require(c >= a);
}
}
// File: @axie/contract-library/contracts/token/erc20/IERC20.sol
pragma solidity ^0.5.2;
interface IERC20 {
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
function totalSupply() external view returns (uint256 _supply);
function balanceOf(address _owner) external view returns (uint256 _balance);
function approve(address _spender, uint256 _value) external returns (bool _success);
function allowance(address _owner, address _spender) external view returns (uint256 _value);
function transfer(address _to, uint256 _value) external returns (bool _success);
function transferFrom(address _from, address _to, uint256 _value) external returns (bool _success);
}
// File: @axie/contract-library/contracts/token/erc20/IERC20Mintable.sol
pragma solidity ^0.5.2;
interface IERC20Mintable {
function mint(address _to, uint256 _value) external returns (bool _success);
}
// File: @axie/contract-library/contracts/token/erc721/IERC721.sol
pragma solidity ^0.5.2;
interface IERC721 {
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
function balanceOf(address _owner) external view returns (uint256 _balance);
function ownerOf(uint256 _tokenId) external view returns (address _owner);
function approve(address _to, uint256 _tokenId) external;
function getApproved(uint256 _tokenId) external view returns (address _operator);
function setApprovalForAll(address _operator, bool _approved) external;
function isApprovedForAll(address _owner, address _operator) external view returns (bool _approved);
function transferFrom(address _from, address _to, uint256 _tokenId) external;
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external;
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata _data) external;
}
// File: @axie/contract-library/contracts/token/erc721/IERC721Mintable.sol
pragma solidity ^0.5.2;
interface IERC721Mintable {
function mint(address _to, uint256 _tokenId) external returns (bool);
function mintNew(address _to) external returns (uint256 _tokenId);
}
// File: @axie/contract-library/contracts/util/AddressUtils.sol
pragma solidity ^0.5.2;
library AddressUtils {
function toPayable(address _address) internal pure returns (address payable _payable) {
return address(uint160(_address));
}
function isContract(address _address) internal view returns (bool _correct) {
uint256 _size;
// solium-disable-next-line security/no-inline-assembly
assembly { _size := extcodesize(_address) }
return _size > 0;
}
}
// File: @axie/contract-library/contracts/token/erc20/ERC20.sol
pragma solidity ^0.5.2;
contract ERC20 is IERC20 {
using SafeMath for uint256;
uint256 public totalSupply;
mapping (address => uint256) public balanceOf;
mapping (address => mapping (address => uint256)) public allowance;
function approve(address _spender, uint256 _value) public returns (bool _success) {
allowance[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
function transfer(address _to, uint256 _value) public returns (bool _success) {
require(_to != address(0));
balanceOf[msg.sender] = balanceOf[msg.sender].sub(_value);
balanceOf[_to] = balanceOf[_to].add(_value);
emit Transfer(msg.sender, _to, _value);
return true;
}
function transferFrom(address _from, address _to, uint256 _value) public returns (bool _success) {
require(_to != address(0));
balanceOf[_from] = balanceOf[_from].sub(_value);
balanceOf[_to] = balanceOf[_to].add(_value);
allowance[_from][msg.sender] = allowance[_from][msg.sender].sub(_value);
emit Transfer(_from, _to, _value);
return true;
}
}
// File: @axie/contract-library/contracts/token/erc20/IERC20Detailed.sol
pragma solidity ^0.5.2;
interface IERC20Detailed {
function name() external view returns (string memory _name);
function symbol() external view returns (string memory _symbol);
function decimals() external view returns (uint8 _decimals);
}
// File: @axie/contract-library/contracts/token/erc20/ERC20Detailed.sol
pragma solidity ^0.5.2;
contract ERC20Detailed is ERC20, IERC20Detailed {
string public name;
string public symbol;
uint8 public decimals;
constructor(string memory _name, string memory _symbol, uint8 _decimals) public {
name = _name;
symbol = _symbol;
decimals = _decimals;
}
}
// File: @axie/contract-library/contracts/access/HasAdmin.sol
pragma solidity ^0.5.2;
contract HasAdmin {
event AdminChanged(address indexed _oldAdmin, address indexed _newAdmin);
event AdminRemoved(address indexed _oldAdmin);
address public admin;
modifier onlyAdmin {
require(msg.sender == admin);
_;
}
constructor() internal {
admin = msg.sender;
emit AdminChanged(address(0), admin);
}
function changeAdmin(address _newAdmin) external onlyAdmin {
require(_newAdmin != address(0));
emit AdminChanged(admin, _newAdmin);
admin = _newAdmin;
}
function removeAdmin() external onlyAdmin {
emit AdminRemoved(admin);
admin = address(0);
}
}
// File: @axie/contract-library/contracts/access/HasMinters.sol
pragma solidity ^0.5.2;
contract HasMinters is HasAdmin {
event MinterAdded(address indexed _minter);
event MinterRemoved(address indexed _minter);
address[] public minters;
mapping (address => bool) public minter;
modifier onlyMinter {
require(minter[msg.sender]);
_;
}
function addMinters(address[] memory _addedMinters) public onlyAdmin {
address _minter;
for (uint256 i = 0; i < _addedMinters.length; i++) {
_minter = _addedMinters[i];
if (!minter[_minter]) {
minters.push(_minter);
minter[_minter] = true;
emit MinterAdded(_minter);
}
}
}
function removeMinters(address[] memory _removedMinters) public onlyAdmin {
address _minter;
for (uint256 i = 0; i < _removedMinters.length; i++) {
_minter = _removedMinters[i];
if (minter[_minter]) {
minter[_minter] = false;
emit MinterRemoved(_minter);
}
}
uint256 i = 0;
while (i < minters.length) {
_minter = minters[i];
if (!minter[_minter]) {
minters[i] = minters[minters.length - 1];
delete minters[minters.length - 1];
minters.length--;
} else {
i++;
}
}
}
function isMinter(address _addr) public view returns (bool) {
return minter[_addr];
}
}
// File: @axie/contract-library/contracts/token/erc20/ERC20Mintable.sol
pragma solidity ^0.5.2;
contract ERC20Mintable is HasMinters, ERC20 {
function mint(address _to, uint256 _value) public onlyMinter returns (bool _success) {
return _mint(_to, _value);
}
function _mint(address _to, uint256 _value) internal returns (bool success) {
totalSupply = totalSupply.add(_value);
balanceOf[_to] = balanceOf[_to].add(_value);
emit Transfer(address(0), _to, _value);
return true;
}
}
// File: contracts/chain/mainchain/WETH.sol
pragma solidity ^0.5.17;
contract WETH is ERC20Detailed {
event Deposit(
address _sender,
uint256 _value
);
event Withdrawal(
address _sender,
uint256 _value
);
constructor () ERC20Detailed("Wrapped Ether", "WETH", 18)
public
{}
function deposit()
external
payable
{
balanceOf[msg.sender] += msg.value;
emit Deposit(msg.sender, msg.value);
}
function withdraw(uint256 _wad)
external
{
require(balanceOf[msg.sender] >= _wad);
balanceOf[msg.sender] -= _wad;
msg.sender.transfer(_wad);
emit Withdrawal(msg.sender, _wad);
}
}
// File: @axie/contract-library/contracts/proxy/ProxyStorage.sol
pragma solidity ^0.5.2;
/**
* @title ProxyStorage
* @dev Store the address of logic contact that the proxy should forward to.
*/
contract ProxyStorage is HasAdmin {
address internal _proxyTo;
}
// File: @axie/contract-library/contracts/lifecycle/Pausable.sol
pragma solidity ^0.5.2;
contract Pausable is HasAdmin {
event Paused();
event Unpaused();
bool public paused;
modifier whenNotPaused() {
require(!paused);
_;
}
modifier whenPaused() {
require(paused);
_;
}
function pause() public onlyAdmin whenNotPaused {
paused = true;
emit Paused();
}
function unpause() public onlyAdmin whenPaused {
paused = false;
emit Unpaused();
}
}
// File: contracts/chain/common/IValidator.sol
pragma solidity ^0.5.17;
contract IValidator {
event ValidatorAdded(uint256 indexed _id, address indexed _validator);
event ValidatorRemoved(uint256 indexed _id, address indexed _validator);
event ThresholdUpdated(
uint256 indexed _id,
uint256 indexed _numerator,
uint256 indexed _denominator,
uint256 _previousNumerator,
uint256 _previousDenominator
);
function isValidator(address _addr) public view returns (bool);
function getValidators() public view returns (address[] memory _validators);
function checkThreshold(uint256 _voteCount) public view returns (bool);
}
// File: contracts/chain/common/Validator.sol
pragma solidity ^0.5.17;
contract Validator is IValidator {
using SafeMath for uint256;
mapping(address => bool) validatorMap;
address[] public validators;
uint256 public validatorCount;
uint256 public num;
uint256 public denom;
constructor(address[] memory _validators, uint256 _num, uint256 _denom)
public
{
validators = _validators;
validatorCount = _validators.length;
for (uint256 _i = 0; _i < validatorCount; _i++) {
address _validator = _validators[_i];
validatorMap[_validator] = true;
}
num = _num;
denom = _denom;
}
function isValidator(address _addr)
public
view
returns (bool)
{
return validatorMap[_addr];
}
function getValidators()
public
view
returns (address[] memory _validators)
{
_validators = validators;
}
function checkThreshold(uint256 _voteCount)
public
view
returns (bool)
{
return _voteCount.mul(denom) >= num.mul(validatorCount);
}
function _addValidator(uint256 _id, address _validator)
internal
{
require(!validatorMap[_validator]);
validators.push(_validator);
validatorMap[_validator] = true;
validatorCount++;
emit ValidatorAdded(_id, _validator);
}
function _removeValidator(uint256 _id, address _validator)
internal
{
require(isValidator(_validator));
uint256 _index;
for (uint256 _i = 0; _i < validatorCount; _i++) {
if (validators[_i] == _validator) {
_index = _i;
break;
}
}
validatorMap[_validator] = false;
validators[_index] = validators[validatorCount - 1];
validators.pop();
validatorCount--;
emit ValidatorRemoved(_id, _validator);
}
function _updateQuorum(uint256 _id, uint256 _numerator, uint256 _denominator)
internal
{
require(_numerator <= _denominator);
uint256 _previousNumerator = num;
uint256 _previousDenominator = denom;
num = _numerator;
denom = _denominator;
emit ThresholdUpdated(
_id,
_numerator,
_denominator,
_previousNumerator,
_previousDenominator
);
}
}
// File: contracts/chain/mainchain/MainchainValidator.sol
pragma solidity ^0.5.17;
/**
* @title Validator
* @dev Simple validator contract
*/
contract MainchainValidator is Validator, HasAdmin {
uint256 nonce;
constructor(
address[] memory _validators,
uint256 _num,
uint256 _denom
) Validator(_validators, _num, _denom) public {
}
function addValidators(address[] calldata _validators) external onlyAdmin {
for (uint256 _i; _i < _validators.length; ++_i) {
_addValidator(nonce++, _validators[_i]);
}
}
function removeValidator(address _validator) external onlyAdmin {
_removeValidator(nonce++, _validator);
}
function updateQuorum(uint256 _numerator, uint256 _denominator) external onlyAdmin {
_updateQuorum(nonce++, _numerator, _denominator);
}
}
// File: contracts/chain/common/Registry.sol
pragma solidity ^0.5.17;
contract Registry is HasAdmin {
event ContractAddressUpdated(
string indexed _name,
bytes32 indexed _code,
address indexed _newAddress
);
event TokenMapped(
address indexed _mainchainToken,
address indexed _sidechainToken,
uint32 _standard
);
string public constant GATEWAY = "GATEWAY";
string public constant WETH_TOKEN = "WETH_TOKEN";
string public constant VALIDATOR = "VALIDATOR";
string public constant ACKNOWLEDGEMENT = "ACKNOWLEDGEMENT";
struct TokenMapping {
address mainchainToken;
address sidechainToken;
uint32 standard; // 20, 721 or any other standards
}
mapping(bytes32 => address) public contractAddresses;
mapping(address => TokenMapping) public mainchainMap;
mapping(address => TokenMapping) public sidechainMap;
function getContract(string calldata _name)
external
view
returns (address _address)
{
bytes32 _code = getCode(_name);
_address = contractAddresses[_code];
require(_address != address(0));
}
function isTokenMapped(address _token, uint32 _standard, bool _isMainchain)
external
view
returns (bool)
{
TokenMapping memory _mapping = _getTokenMapping(_token, _isMainchain);
return _mapping.mainchainToken != address(0) &&
_mapping.sidechainToken != address(0) &&
_mapping.standard == _standard;
}
function updateContract(string calldata _name, address _newAddress)
external
onlyAdmin
{
bytes32 _code = getCode(_name);
contractAddresses[_code] = _newAddress;
emit ContractAddressUpdated(_name, _code, _newAddress);
}
function mapToken(address _mainchainToken, address _sidechainToken, uint32 _standard)
external
onlyAdmin
{
TokenMapping memory _map = TokenMapping(
_mainchainToken,
_sidechainToken,
_standard
);
mainchainMap[_mainchainToken] = _map;
sidechainMap[_sidechainToken] = _map;
emit TokenMapped(
_mainchainToken,
_sidechainToken,
_standard
);
}
function clearMapToken(address _mainchainToken, address _sidechainToken)
external
onlyAdmin
{
TokenMapping storage _mainchainMap = mainchainMap[_mainchainToken];
_clearMapEntry(_mainchainMap);
TokenMapping storage _sidechainMap = sidechainMap[_sidechainToken];
_clearMapEntry(_sidechainMap);
}
function getMappedToken(
address _token,
bool _isMainchain
)
external
view
returns (
address _mainchainToken,
address _sidechainToken,
uint32 _standard
)
{
TokenMapping memory _mapping = _getTokenMapping(_token, _isMainchain);
_mainchainToken = _mapping.mainchainToken;
_sidechainToken = _mapping.sidechainToken;
_standard = _mapping.standard;
}
function getCode(string memory _name)
public
pure
returns (bytes32)
{
return keccak256(abi.encodePacked(_name));
}
function _getTokenMapping(
address _token,
bool isMainchain
)
internal
view
returns (TokenMapping memory _mapping)
{
if (isMainchain) {
_mapping = mainchainMap[_token];
} else {
_mapping = sidechainMap[_token];
}
}
function _clearMapEntry(TokenMapping storage _entry)
internal
{
_entry.mainchainToken = address(0);
_entry.sidechainToken = address(0);
_entry.standard = 0;
}
}
// File: contracts/chain/mainchain/MainchainGatewayStorage.sol
pragma solidity ^0.5.17;
/**
* @title GatewayStorage
* @dev Storage of deposit and withdraw information.
*/
contract MainchainGatewayStorage is ProxyStorage, Pausable {
event TokenDeposited(
uint256 indexed _depositId,
address indexed _owner,
address indexed _tokenAddress,
address _sidechainAddress,
uint32 _standard,
uint256 _tokenNumber // ERC-20 amount or ERC721 tokenId
);
event TokenWithdrew(
uint256 indexed _withdrawId,
address indexed _owner,
address indexed _tokenAddress,
uint256 _tokenNumber
);
struct DepositEntry {
address owner;
address tokenAddress;
address sidechainAddress;
uint32 standard;
uint256 tokenNumber;
}
struct WithdrawalEntry {
address owner;
address tokenAddress;
uint256 tokenNumber;
}
Registry public registry;
uint256 public depositCount;
DepositEntry[] public deposits;
mapping(uint256 => WithdrawalEntry) public withdrawals;
function updateRegistry(address _registry) external onlyAdmin {
registry = Registry(_registry);
}
}
// File: contracts/chain/mainchain/MainchainGatewayManager.sol
pragma solidity ^0.5.17;
/**
* @title MainchainGatewayManager
* @dev Logic to handle deposits and withdrawl on Mainchain.
*/
contract MainchainGatewayManager is MainchainGatewayStorage {
using AddressUtils for address;
using SafeMath for uint256;
using ECVerify for bytes32;
modifier onlyMappedToken(address _token, uint32 _standard) {
require(
registry.isTokenMapped(_token, _standard, true),
"MainchainGatewayManager: Token is not mapped"
);
_;
}
modifier onlyNewWithdrawal(uint256 _withdrawalId) {
WithdrawalEntry storage _entry = withdrawals[_withdrawalId];
require(_entry.owner == address(0) && _entry.tokenAddress == address(0));
_;
}
// Should be able to withdraw from WETH
function()
external
payable
{}
function depositEth()
external
whenNotPaused
payable
returns (uint256)
{
return depositEthFor(msg.sender);
}
function depositERC20(address _token, uint256 _amount)
external
whenNotPaused
returns (uint256)
{
return depositERC20For(msg.sender, _token, _amount);
}
function depositERC721(address _token, uint256 _tokenId)
external
whenNotPaused
returns (uint256)
{
return depositERC721For(msg.sender, _token, _tokenId);
}
function depositEthFor(address _owner)
public
whenNotPaused
payable
returns (uint256)
{
address _weth = registry.getContract(registry.WETH_TOKEN());
WETH(_weth).deposit.value(msg.value)();
return _createDepositEntry(_owner, _weth, 20, msg.value);
}
function depositERC20For(address _user, address _token, uint256 _amount)
public
whenNotPaused
returns (uint256)
{
require(
IERC20(_token).transferFrom(msg.sender, address(this), _amount),
"MainchainGatewayManager: ERC-20 token transfer failed"
);
return _createDepositEntry(_user, _token, 20, _amount);
}
function depositERC721For(address _user, address _token, uint256 _tokenId)
public
whenNotPaused
returns (uint256)
{
IERC721(_token).transferFrom(msg.sender, address(this), _tokenId);
return _createDepositEntry(_user, _token, 721, _tokenId);
}
function depositBulkFor(
address _user,
address[] memory _tokens,
uint256[] memory _tokenNumbers
)
public
whenNotPaused
{
require(_tokens.length == _tokenNumbers.length);
for (uint256 _i = 0; _i < _tokens.length; _i++) {
address _token = _tokens[_i];
uint256 _tokenNumber = _tokenNumbers[_i];
(,, uint32 _standard) = registry.getMappedToken(_token, true);
if (_standard == 20) {
depositERC20For(_user, _token, _tokenNumber);
} else if (_standard == 721) {
depositERC721For(_user, _token, _tokenNumber);
} else {
revert("Token is not mapped or token type not supported");
}
}
}
function withdrawToken(
uint256 _withdrawalId,
address _token,
uint256 _amount,
bytes memory _signatures
)
public
whenNotPaused
{
withdrawTokenFor(
_withdrawalId,
msg.sender,
_token,
_amount,
_signatures
);
}
function withdrawTokenFor(
uint256 _withdrawalId,
address _user,
address _token,
uint256 _amount,
bytes memory _signatures
)
public
whenNotPaused
{
(,, uint32 _tokenType) = registry.getMappedToken(_token, true);
if (_tokenType == 20) {
withdrawERC20For(
_withdrawalId,
_user,
_token,
_amount,
_signatures
);
} else if (_tokenType == 721) {
withdrawERC721For(
_withdrawalId,
_user,
_token,
_amount,
_signatures
);
}
}
function withdrawERC20(
uint256 _withdrawalId,
address _token,
uint256 _amount,
bytes memory _signatures
)
public
whenNotPaused
{
withdrawERC20For(
_withdrawalId,
msg.sender,
_token,
_amount,
_signatures
);
}
function withdrawERC20For(
uint256 _withdrawalId,
address _user,
address _token,
uint256 _amount,
bytes memory _signatures
)
public
whenNotPaused
onlyMappedToken(_token, 20)
{
bytes32 _hash = keccak256(
abi.encodePacked(
"withdrawERC20",
_withdrawalId,
_user,
_token,
_amount
)
);
require(verifySignatures(_hash, _signatures));
if (_token == registry.getContract(registry.WETH_TOKEN())) {
_withdrawETHFor(_user, _amount);
} else {
uint256 _gatewayBalance = IERC20(_token).balanceOf(address(this));
if (_gatewayBalance < _amount) {
require(
IERC20Mintable(_token).mint(address(this), _amount.sub(_gatewayBalance)),
"MainchainGatewayManager: Minting ERC20 token to gateway failed"
);
}
require(IERC20(_token).transfer(_user, _amount), "Transfer failed");
}
_insertWithdrawalEntry(
_withdrawalId,
_user,
_token,
_amount
);
}
function withdrawERC721(
uint256 _withdrawalId,
address _token,
uint256 _tokenId,
bytes memory _signatures
)
public
whenNotPaused
{
withdrawERC721For(
_withdrawalId,
msg.sender,
_token,
_tokenId,
_signatures
);
}
function withdrawERC721For(
uint256 _withdrawalId,
address _user,
address _token,
uint256 _tokenId,
bytes memory _signatures
)
public
whenNotPaused
onlyMappedToken(_token, 721)
{
bytes32 _hash = keccak256(
abi.encodePacked(
"withdrawERC721",
_withdrawalId,
_user,
_token,
_tokenId
)
);
require(verifySignatures(_hash, _signatures));
if (!_tryERC721TransferFrom(_token, address(this), _user, _tokenId)) {
require(
IERC721Mintable(_token).mint(_user, _tokenId),
"MainchainGatewayManager: Minting ERC721 token to gateway failed"
);
}
_insertWithdrawalEntry(_withdrawalId, _user, _token, _tokenId);
}
/**
* @dev returns true if there is enough signatures from validators.
*/
function verifySignatures(
bytes32 _hash,
bytes memory _signatures
)
public
view
returns (bool)
{
uint256 _signatureCount = _signatures.length.div(66);
Validator _validator = Validator(registry.getContract(registry.VALIDATOR()));
uint256 _validatorCount = 0;
address _lastSigner = address(0);
for (uint256 i = 0; i < _signatureCount; i++) {
address _signer = _hash.recover(_signatures, i.mul(66));
if (_validator.isValidator(_signer)) {
_validatorCount++;
}
// Prevent duplication of signatures
require(_signer > _lastSigner);
_lastSigner = _signer;
}
return _validator.checkThreshold(_validatorCount);
}
function _createDepositEntry(
address _owner,
address _token,
uint32 _standard,
uint256 _number
)
internal
onlyMappedToken(_token, _standard)
returns (uint256 _depositId)
{
(,address _sidechainToken, uint32 _tokenStandard) = registry.getMappedToken(_token, true);
require(_standard == _tokenStandard);
DepositEntry memory _entry = DepositEntry(
_owner,
_token,
_sidechainToken,
_standard,
_number
);
deposits.push(_entry);
_depositId = depositCount++;
emit TokenDeposited(
_depositId,
_owner,
_token,
_sidechainToken,
_standard,
_number
);
}
function _insertWithdrawalEntry(
uint256 _withdrawalId,
address _owner,
address _token,
uint256 _number
)
internal
onlyNewWithdrawal(_withdrawalId)
{
WithdrawalEntry memory _entry = WithdrawalEntry(
_owner,
_token,
_number
);
withdrawals[_withdrawalId] = _entry;
emit TokenWithdrew(_withdrawalId, _owner, _token, _number);
}
function _withdrawETHFor(
address _user,
uint256 _amount
)
internal
{
address _weth = registry.getContract(registry.WETH_TOKEN());
WETH(_weth).withdraw(_amount);
_user.toPayable().transfer(_amount);
}
// See more here https://blog.polymath.network/try-catch-in-solidity-handling-the-revert-exception-f53718f76047
function _tryERC721TransferFrom(
address _token,
address _from,
address _to,
uint256 _tokenId
)
internal
returns (bool)
{
(bool success,) = _token.call(
abi.encodeWithSelector(
IERC721(_token).transferFrom.selector, _from, _to, _tokenId
)
);
return success;
}
}File 3 of 5: Registry
// File: @axie/contract-library/contracts/access/HasAdmin.sol
pragma solidity ^0.5.2;
contract HasAdmin {
event AdminChanged(address indexed _oldAdmin, address indexed _newAdmin);
event AdminRemoved(address indexed _oldAdmin);
address public admin;
modifier onlyAdmin {
require(msg.sender == admin);
_;
}
constructor() internal {
admin = msg.sender;
emit AdminChanged(address(0), admin);
}
function changeAdmin(address _newAdmin) external onlyAdmin {
require(_newAdmin != address(0));
emit AdminChanged(admin, _newAdmin);
admin = _newAdmin;
}
function removeAdmin() external onlyAdmin {
emit AdminRemoved(admin);
admin = address(0);
}
}
// File: contracts/chain/common/Registry.sol
pragma solidity ^0.5.17;
contract Registry is HasAdmin {
event ContractAddressUpdated(
string indexed _name,
bytes32 indexed _code,
address indexed _newAddress
);
event TokenMapped(
address indexed _mainchainToken,
address indexed _sidechainToken,
uint32 _standard
);
string public constant GATEWAY = "GATEWAY";
string public constant WETH_TOKEN = "WETH_TOKEN";
string public constant VALIDATOR = "VALIDATOR";
string public constant ACKNOWLEDGEMENT = "ACKNOWLEDGEMENT";
struct TokenMapping {
address mainchainToken;
address sidechainToken;
uint32 standard; // 20, 721 or any other standards
}
mapping(bytes32 => address) public contractAddresses;
mapping(address => TokenMapping) public mainchainMap;
mapping(address => TokenMapping) public sidechainMap;
function getContract(string calldata _name)
external
view
returns (address _address)
{
bytes32 _code = getCode(_name);
_address = contractAddresses[_code];
require(_address != address(0));
}
function isTokenMapped(address _token, uint32 _standard, bool _isMainchain)
external
view
returns (bool)
{
TokenMapping memory _mapping = _getTokenMapping(_token, _isMainchain);
return _mapping.mainchainToken != address(0) &&
_mapping.sidechainToken != address(0) &&
_mapping.standard == _standard;
}
function updateContract(string calldata _name, address _newAddress)
external
onlyAdmin
{
bytes32 _code = getCode(_name);
contractAddresses[_code] = _newAddress;
emit ContractAddressUpdated(_name, _code, _newAddress);
}
function mapToken(address _mainchainToken, address _sidechainToken, uint32 _standard)
external
onlyAdmin
{
TokenMapping memory _map = TokenMapping(
_mainchainToken,
_sidechainToken,
_standard
);
mainchainMap[_mainchainToken] = _map;
sidechainMap[_sidechainToken] = _map;
emit TokenMapped(
_mainchainToken,
_sidechainToken,
_standard
);
}
function clearMapToken(address _mainchainToken, address _sidechainToken)
external
onlyAdmin
{
TokenMapping storage _mainchainMap = mainchainMap[_mainchainToken];
_clearMapEntry(_mainchainMap);
TokenMapping storage _sidechainMap = sidechainMap[_sidechainToken];
_clearMapEntry(_sidechainMap);
}
function getMappedToken(
address _token,
bool _isMainchain
)
external
view
returns (
address _mainchainToken,
address _sidechainToken,
uint32 _standard
)
{
TokenMapping memory _mapping = _getTokenMapping(_token, _isMainchain);
_mainchainToken = _mapping.mainchainToken;
_sidechainToken = _mapping.sidechainToken;
_standard = _mapping.standard;
}
function getCode(string memory _name)
public
pure
returns (bytes32)
{
return keccak256(abi.encodePacked(_name));
}
function _getTokenMapping(
address _token,
bool isMainchain
)
internal
view
returns (TokenMapping memory _mapping)
{
if (isMainchain) {
_mapping = mainchainMap[_token];
} else {
_mapping = sidechainMap[_token];
}
}
function _clearMapEntry(TokenMapping storage _entry)
internal
{
_entry.mainchainToken = address(0);
_entry.sidechainToken = address(0);
_entry.standard = 0;
}
}File 4 of 5: MainchainValidator
// File: @axie/contract-library/contracts/math/SafeMath.sol
pragma solidity ^0.5.2;
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
c = a + b;
require(c >= a);
}
function sub(uint256 a, uint256 b) internal pure returns (uint256 c) {
require(b <= a);
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
if (a == 0) {
return 0;
}
c = a * b;
require(c / a == b);
}
function div(uint256 a, uint256 b) internal pure returns (uint256 c) {
// Since Solidity automatically asserts when dividing by 0,
// but we only need it to revert.
require(b > 0);
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256 c) {
// Same reason as `div`.
require(b > 0);
return a % b;
}
function ceilingDiv(uint256 a, uint256 b) internal pure returns (uint256 c) {
return add(div(a, b), mod(a, b) > 0 ? 1 : 0);
}
function subU64(uint64 a, uint64 b) internal pure returns (uint64 c) {
require(b <= a);
return a - b;
}
function addU8(uint8 a, uint8 b) internal pure returns (uint8 c) {
c = a + b;
require(c >= a);
}
}
// File: @axie/contract-library/contracts/access/HasAdmin.sol
pragma solidity ^0.5.2;
contract HasAdmin {
event AdminChanged(address indexed _oldAdmin, address indexed _newAdmin);
event AdminRemoved(address indexed _oldAdmin);
address public admin;
modifier onlyAdmin {
require(msg.sender == admin);
_;
}
constructor() internal {
admin = msg.sender;
emit AdminChanged(address(0), admin);
}
function changeAdmin(address _newAdmin) external onlyAdmin {
require(_newAdmin != address(0));
emit AdminChanged(admin, _newAdmin);
admin = _newAdmin;
}
function removeAdmin() external onlyAdmin {
emit AdminRemoved(admin);
admin = address(0);
}
}
// File: contracts/chain/common/IValidator.sol
pragma solidity ^0.5.17;
contract IValidator {
event ValidatorAdded(uint256 indexed _id, address indexed _validator);
event ValidatorRemoved(uint256 indexed _id, address indexed _validator);
event ThresholdUpdated(
uint256 indexed _id,
uint256 indexed _numerator,
uint256 indexed _denominator,
uint256 _previousNumerator,
uint256 _previousDenominator
);
function isValidator(address _addr) public view returns (bool);
function getValidators() public view returns (address[] memory _validators);
function checkThreshold(uint256 _voteCount) public view returns (bool);
}
// File: contracts/chain/common/Validator.sol
pragma solidity ^0.5.17;
contract Validator is IValidator {
using SafeMath for uint256;
mapping(address => bool) validatorMap;
address[] public validators;
uint256 public validatorCount;
uint256 public num;
uint256 public denom;
constructor(address[] memory _validators, uint256 _num, uint256 _denom)
public
{
validators = _validators;
validatorCount = _validators.length;
for (uint256 _i = 0; _i < validatorCount; _i++) {
address _validator = _validators[_i];
validatorMap[_validator] = true;
}
num = _num;
denom = _denom;
}
function isValidator(address _addr)
public
view
returns (bool)
{
return validatorMap[_addr];
}
function getValidators()
public
view
returns (address[] memory _validators)
{
_validators = validators;
}
function checkThreshold(uint256 _voteCount)
public
view
returns (bool)
{
return _voteCount.mul(denom) >= num.mul(validatorCount);
}
function _addValidator(uint256 _id, address _validator)
internal
{
require(!validatorMap[_validator]);
validators.push(_validator);
validatorMap[_validator] = true;
validatorCount++;
emit ValidatorAdded(_id, _validator);
}
function _removeValidator(uint256 _id, address _validator)
internal
{
require(isValidator(_validator));
uint256 _index;
for (uint256 _i = 0; _i < validatorCount; _i++) {
if (validators[_i] == _validator) {
_index = _i;
break;
}
}
validatorMap[_validator] = false;
validators[_index] = validators[validatorCount - 1];
validators.pop();
validatorCount--;
emit ValidatorRemoved(_id, _validator);
}
function _updateQuorum(uint256 _id, uint256 _numerator, uint256 _denominator)
internal
{
require(_numerator <= _denominator);
uint256 _previousNumerator = num;
uint256 _previousDenominator = denom;
num = _numerator;
denom = _denominator;
emit ThresholdUpdated(
_id,
_numerator,
_denominator,
_previousNumerator,
_previousDenominator
);
}
}
// File: contracts/chain/mainchain/MainchainValidator.sol
pragma solidity ^0.5.17;
/**
* @title Validator
* @dev Simple validator contract
*/
contract MainchainValidator is Validator, HasAdmin {
uint256 nonce;
constructor(
address[] memory _validators,
uint256 _num,
uint256 _denom
) Validator(_validators, _num, _denom) public {
}
function addValidators(address[] calldata _validators) external onlyAdmin {
for (uint256 _i; _i < _validators.length; ++_i) {
_addValidator(nonce++, _validators[_i]);
}
}
function removeValidator(address _validator) external onlyAdmin {
_removeValidator(nonce++, _validator);
}
function updateQuorum(uint256 _numerator, uint256 _denominator) external onlyAdmin {
_updateQuorum(nonce++, _numerator, _denominator);
}
}File 5 of 5: SmoothLovePotion
// File: math/SafeMath.sol
pragma solidity 0.5.17;
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
c = a + b;
require(c >= a, "SafeMath: addition overflow");
}
function sub(uint256 a, uint256 b) internal pure returns (uint256 c) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
if (a == 0) {
return 0;
}
c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
}
function div(uint256 a, uint256 b) internal pure returns (uint256 c) {
// Since Solidity automatically asserts when dividing by 0,
// but we only need it to revert.
require(b > 0, "SafeMath: division by zero");
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256 c) {
// Same reason as `div`.
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
}
// File: token/erc20/IERC20.sol
pragma solidity 0.5.17;
interface IERC20 {
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
function totalSupply() external view returns (uint256 _supply);
function balanceOf(address _owner) external view returns (uint256 _balance);
function approve(address _spender, uint256 _value) external returns (bool _success);
function allowance(address _owner, address _spender) external view returns (uint256 _value);
function transfer(address _to, uint256 _value) external returns (bool _success);
function transferFrom(address _from, address _to, uint256 _value) external returns (bool _success);
}
// File: token/erc20/ERC20.sol
pragma solidity 0.5.17;
contract ERC20 is IERC20 {
using SafeMath for uint256;
uint256 public totalSupply;
mapping (address => uint256) public balanceOf;
mapping (address => mapping (address => uint256)) internal _allowance;
function approve(address _spender, uint256 _value) public returns (bool) {
_approve(msg.sender, _spender, _value);
return true;
}
function allowance(address _owner, address _spender) public view returns (uint256) {
return _allowance[_owner][_spender];
}
function increaseAllowance(address _spender, uint256 _value) public returns (bool) {
_approve(msg.sender, _spender, _allowance[msg.sender][_spender].add(_value));
return true;
}
function decreaseAllowance(address _spender, uint256 _value) public returns (bool) {
_approve(msg.sender, _spender, _allowance[msg.sender][_spender].sub(_value));
return true;
}
function transfer(address _to, uint256 _value) public returns (bool _success) {
_transfer(msg.sender, _to, _value);
return true;
}
function transferFrom(address _from, address _to, uint256 _value) public returns (bool _success) {
_transfer(_from, _to, _value);
_approve(_from, msg.sender, _allowance[_from][msg.sender].sub(_value));
return true;
}
function _approve(address _owner, address _spender, uint256 _amount) internal {
require(_owner != address(0), "ERC20: approve from the zero address");
require(_spender != address(0), "ERC20: approve to the zero address");
_allowance[_owner][_spender] = _amount;
emit Approval(_owner, _spender, _amount);
}
function _transfer(address _from, address _to, uint256 _value) internal {
require(_from != address(0), "ERC20: transfer from the zero address");
require(_to != address(0), "ERC20: transfer to the zero address");
require(_to != address(this), "ERC20: transfer to this contract address");
balanceOf[_from] = balanceOf[_from].sub(_value);
balanceOf[_to] = balanceOf[_to].add(_value);
emit Transfer(_from, _to, _value);
}
}
// File: token/erc20/IERC20Detailed.sol
pragma solidity 0.5.17;
interface IERC20Detailed {
function name() external view returns (string memory _name);
function symbol() external view returns (string memory _symbol);
function decimals() external view returns (uint8 _decimals);
}
// File: token/erc20/ERC20Detailed.sol
pragma solidity 0.5.17;
contract ERC20Detailed is ERC20, IERC20Detailed {
string public name;
string public symbol;
uint8 public decimals;
constructor(string memory _name, string memory _symbol, uint8 _decimals) public {
name = _name;
symbol = _symbol;
decimals = _decimals;
}
}
// File: token/erc20/ERC20GatewayWhitelist.sol
pragma solidity 0.5.17;
contract ERC20GatewayWhitelist is ERC20 {
address public mainchainGateway;
function allowance(address _owner, address _spender)
public
view
returns (uint256 _value)
{
if (_spender == mainchainGateway) return uint256(-1);
return _allowance[_owner][_spender];
}
function transferFrom(
address _from,
address _to,
uint256 _value
)
public
returns (bool _success)
{
if (allowance(_from, msg.sender) != uint256(-1)) {
super._approve(_from, msg.sender, _allowance[_from][msg.sender].sub(_value));
}
_transfer(_from, _to, _value);
return true;
}
function _setGateway(address _mainchainGateway) internal {
require(
_mainchainGateway != address(0),
"ERC20GatewayWhitelist: setting gateway to the zero address"
);
mainchainGateway = _mainchainGateway;
}
}
// File: access/HasAdmin.sol
pragma solidity 0.5.17;
contract HasAdmin {
event AdminChanged(address indexed _oldAdmin, address indexed _newAdmin);
event AdminRemoved(address indexed _oldAdmin);
address public admin;
modifier onlyAdmin {
require(msg.sender == admin, "HasAdmin: not admin");
_;
}
constructor() internal {
admin = msg.sender;
emit AdminChanged(address(0), admin);
}
function changeAdmin(address _newAdmin) external onlyAdmin {
require(_newAdmin != address(0), "HasAdmin: new admin is the zero address");
emit AdminChanged(admin, _newAdmin);
admin = _newAdmin;
}
function removeAdmin() external onlyAdmin {
emit AdminRemoved(admin);
admin = address(0);
}
}
// File: access/HasMinters.sol
pragma solidity 0.5.17;
contract HasMinters is HasAdmin {
event MinterAdded(address indexed _minter);
event MinterRemoved(address indexed _minter);
address[] public minters;
mapping (address => bool) public minter;
modifier onlyMinter {
require(minter[msg.sender]);
_;
}
function addMinters(address[] memory _addedMinters) public onlyAdmin {
address _minter;
for (uint256 i = 0; i < _addedMinters.length; i++) {
_minter = _addedMinters[i];
if (!minter[_minter]) {
minters.push(_minter);
minter[_minter] = true;
emit MinterAdded(_minter);
}
}
}
function removeMinters(address[] memory _removedMinters) public onlyAdmin {
address _minter;
for (uint256 i = 0; i < _removedMinters.length; i++) {
_minter = _removedMinters[i];
if (minter[_minter]) {
minter[_minter] = false;
emit MinterRemoved(_minter);
}
}
uint256 i = 0;
while (i < minters.length) {
_minter = minters[i];
if (!minter[_minter]) {
minters[i] = minters[minters.length - 1];
delete minters[minters.length - 1];
minters.length--;
} else {
i++;
}
}
}
function isMinter(address _addr) public view returns (bool) {
return minter[_addr];
}
}
// File: token/erc20/ERC20Mintable.sol
pragma solidity 0.5.17;
contract ERC20Mintable is HasMinters, ERC20 {
function mint(address _to, uint256 _value) public onlyMinter returns (bool _success) {
return _mint(_to, _value);
}
function _mint(address _to, uint256 _value) internal returns (bool success) {
totalSupply = totalSupply.add(_value);
balanceOf[_to] = balanceOf[_to].add(_value);
emit Transfer(address(0), _to, _value);
return true;
}
}
// File: SmoothLovePotion.sol
pragma solidity 0.5.17;
contract SmoothLovePotion is ERC20Detailed, ERC20Mintable, ERC20GatewayWhitelist {
constructor(address _mainchainGateway)
public
ERC20Detailed("Smooth Love Potion", "SLP", 0)
{
_setGateway(_mainchainGateway);
address[] memory _minters = new address[](1);
_minters[0] = _mainchainGateway;
addMinters(_minters);
}
}