Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 1 from a total of 1 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Launch | 21419869 | 451 days ago | IN | 0 ETH | 0.02444337 |
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x60c06040 | 21419869 | 451 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
UpgradeController
Compiler Version
v0.8.11+commit.d7f03943
Optimization Enabled:
Yes with 200 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
/* SPDX-License-Identifier: apache-2.0 */
pragma solidity 0.8.11;
import "../SmartController.sol";
import "../TokenFrontend.sol";
/**
* @title UpgradeController
* @notice Manages the upgrade process for the SmartController.
* Deploys new contracts, transfers ownerships, and sets privileges and allowances limit.
* @dev Can be deployed and operated by a development key, with the final ownership transferred as defined in function parameters.
* Contains functions to launch the upgrade process and a transfer ownership.
*/
contract UpgradeController {
address public controllerAddress;
address public oldControllerAddress;
address public frontendAddress;
address internal deployer;
constructor() {
deployer = msg.sender;
}
/**
* @notice Launches the upgrade process, deploying a new SmartController and transferring necessary ownerships and privileges.
* @dev This contract can be used and deployed through the use of a development key.
* The final ownership will be transferred to the address provided in the function parameters, not the development key used for deployment.
* @param old_ The address of the old SmartController contract. Must be provided.
* @param frontend_ The address of the TokenFrontend contract. Must be provided.
* @param storage_ The address of the storage contract where the state is kept. Must be provided.
* @param validator_ The address of the validator contract. Must be provided.
* @param ticker_ The bytes3 ticker symbol for the token. Must be provided.
* @param owner_ The final owner's address where ownership will be transferred to after the upgrade process. Must be provided.
* @param system_ Optional system account's address, can be provided if there is a system account to add, otherwise address(0).
* @param admin_ Optional admin account's address, can be provided if there is an admin account to add, otherwise address(0).
* @param maxMintAllowance_ Optional maximum mint allowance, can be set to control minting limit, otherwise 0.
*/
function launch(
address old_,
address frontend_,
address storage_,
address validator_,
bytes3 ticker_,
address owner_,
address system_,
address admin_,
uint256 maxMintAllowance_
) public {
require(
deployer == msg.sender,
"UpgradeController: Only deployer can launch"
);
oldControllerAddress = old_;
frontendAddress = frontend_;
SmartController oldController = SmartController(oldControllerAddress);
TokenFrontend frontend = TokenFrontend(frontendAddress);
// #1 Claiming ownership
oldController.claimOwnership();
frontend.claimOwnership();
// #2 Deploying new controller
SmartController controller = new SmartController(
storage_,
validator_,
ticker_,
frontendAddress
);
controllerAddress = address(controller);
// #3 Transfering storage ownership to new controller
oldController.transferStorageOwnership(controllerAddress);
controller.claimStorageOwnership();
// #4 Grant privileges
controller.addSystemAccount(system_);
controller.addAdminAccount(admin_);
// #5 Set MintAllowance limit
if (maxMintAllowance_ > 0) {
controller.setMaxMintAllowance(maxMintAllowance_);
}
// #6 Connect the new controller to frontend
frontend.setController(controllerAddress);
// #7 Transfer ownership to owner_
controller.transferOwnership(owner_);
frontend.transferOwnership(owner_);
oldController.transferOwnership(owner_);
}
function revertToLastController(
address _controller,
address _oldController,
address _frontend,
address _owner
) public {
require(
deployer == msg.sender,
"UpgradeController: Only deployer can revert to LastController"
);
SmartController controller = SmartController(_controller);
SmartController oldController = SmartController(_oldController);
TokenFrontend frontend = TokenFrontend(_frontend);
// #2 Transfering storage ownership to new controller
oldController.transferStorageOwnership(_controller);
controller.claimStorageOwnership();
// #3 Connect the new controller to frontend
frontend.setController(_controller);
// #4 Transfer ownership to owner_
controller.transferOwnership(_owner);
frontend.transferOwnership(_owner);
oldController.transferOwnership(_owner);
}
function transferOwnership(address newOwner) public {
require(
deployer == msg.sender,
"UpgradeController: Only deployer can transfer ownership"
);
SmartController(controllerAddress).transferOwnership(newOwner);
TokenFrontend(frontendAddress).transferOwnership(newOwner);
SmartController(oldControllerAddress).transferOwnership(newOwner);
}
}/* SPDX-License-Identifier: apache-2.0 */
/**
* Copyright 2022 Monerium ehf.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.11;
import "./SmartTokenLib.sol";
import "./MintableController.sol";
import "./IValidator.sol";
/**
* @title SmartController
* @dev This contract adds "smart" functionality which is required from a regulatory perspective.
*/
contract SmartController is MintableController {
using SmartTokenLib for SmartTokenLib.SmartStorage;
SmartTokenLib.SmartStorage internal smartToken;
bytes3 public ticker;
uint256 public constant INITIAL_SUPPLY = 0;
/**
* @dev Contract constructor.
* @param storage_ Address of the token storage for the controller.
* @param validator Address of validator.
* @param ticker_ 3 letter currency ticker.
* @param frontend_ Address of the authorized frontend.
*/
constructor(
address storage_,
address validator,
bytes3 ticker_,
address frontend_
) MintableController(storage_, INITIAL_SUPPLY, frontend_) {
require(
validator != address(0x0),
"validator cannot be the null address"
);
smartToken.setValidator(validator);
ticker = ticker_;
}
/**
* @dev Sets a new validator.
* @param validator Address of validator.
*/
function setValidator(address validator) external onlyOwner {
smartToken.setValidator(validator);
}
/**
* @dev Recovers tokens from an address and reissues them to another address.
* In case a user loses its private key the tokens can be recovered by burning
* the tokens from that address and reissuing to a new address.
* To recover tokens the contract owner needs to provide a signature
* proving that the token owner has authorized the owner to do so.
* @param caller Address of the caller passed through the frontend.
* @param from Address to burn tokens from.
* @param to Address to mint tokens to.
* @param h Hash which the token owner signed.
* @param v Signature component.
* @param r Signature component.
* @param s Sigature component.
* @return Amount recovered.
*/
function recover_withCaller(
address caller,
address from,
address to,
bytes32 h,
uint8 v,
bytes32 r,
bytes32 s
) external onlyFrontend onlySystemAccount(caller) whenNotPaused returns (uint) {
_avoidBlackholes(to);
return SmartTokenLib.recover(token, from, to, h, v, r, s);
}
/**
* @dev Transfers tokens [ERC20].
* The caller, to address and amount are validated before executing method.
* Prior to transfering tokens the validator needs to approve.
* @notice Overrides method in a parent.
* @param caller Address of the caller passed through the frontend.
* @param to Recipient address.
* @param amount Number of tokens to transfer.
*/
function transfer_withCaller(
address caller,
address to,
uint256 amount
) public whenNotPaused override returns (bool) {
require(
smartToken.validate(caller, to, amount),
"transfer request not valid"
);
return super.transfer_withCaller(caller, to, amount);
}
/**
* @dev Transfers tokens from a specific address [ERC20].
* The address owner has to approve the spender beforehand.
* The from address, to address and amount are validated before executing method.
* @notice Overrides method in a parent.
* Prior to transfering tokens the validator needs to approve.
* @param caller Address of the caller passed through the frontend.
* @param from Address to debet the tokens from.
* @param to Recipient address.
* @param amount Number of tokens to transfer.
*/
function transferFrom_withCaller(
address caller,
address from,
address to,
uint256 amount
) public whenNotPaused override returns (bool) {
require(
smartToken.validate(from, to, amount),
"transferFrom request not valid"
);
return super.transferFrom_withCaller(caller, from, to, amount);
}
/**
* @dev Transfers tokens and subsequently calls a method on the recipient [ERC677].
* If the recipient is a non-contract address this method behaves just like transfer.
* The caller, to address and amount are validated before executing method.
* @notice Overrides method in a parent.
* @param caller Address of the caller passed through the frontend.
* @param to Recipient address.
* @param amount Number of tokens to transfer.
* @param data Additional data passed to the recipient's tokenFallback method.
*/
function transferAndCall_withCaller(
address caller,
address to,
uint256 amount,
bytes calldata data
) public whenNotPaused override returns (bool) {
require(
smartToken.validate(caller, to, amount),
"transferAndCall request not valid"
);
return super.transferAndCall_withCaller(caller, to, amount, data);
}
/**
* @dev Gets the current validator.
* @return Address of validator.
*/
function getValidator() external view returns (address) {
return smartToken.getValidator();
}
}/* SPDX-License-Identifier: apache-2.0 */
/**
* Copyright 2022 Monerium ehf.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.11;
import "./ownership/Claimable.sol";
import "./ownership/CanReclaimToken.sol";
import "./ownership/NoOwner.sol";
import "./IERC20.sol";
import "./SmartController.sol";
import "./IPolygonPosRootToken.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
/**
* @title TokenFrontend
* @dev This contract implements a token forwarder.
* The token frontend is [ERC20 and ERC677] compliant and forwards
* standard methods to a controller. The primary function is to allow
* for a statically deployed contract for users to interact with while
* simultaneously allow the controllers to be upgraded when bugs are
* discovered or new functionality needs to be added.
*/
abstract contract TokenFrontend is
Claimable,
CanReclaimToken,
NoOwner,
IERC20,
IPolygonPosRootToken,
AccessControl
{
bytes32 public constant PREDICATE_ROLE = keccak256("PREDICATE_ROLE");
SmartController internal controller;
string public name;
string public symbol;
bytes3 public ticker;
/**
* @dev Emitted when tokens are transferred.
* @param from Sender address.
* @param to Recipient address.
* @param amount Number of tokens transferred.
* @param data Additional data passed to the recipient's tokenFallback method.
*/
event Transfer(
address indexed from,
address indexed to,
uint256 amount,
bytes data
);
/**
* @dev Emitted when updating the controller.
* @param ticker Three letter ticker representing the currency.
* @param old Address of the old controller.
* @param current Address of the new controller.
*/
event Controller(
bytes3 indexed ticker,
address indexed old,
address indexed current
);
/**
* @dev Contract constructor.
* @notice The contract is an abstract contract as a result of the internal modifier.
* @param name_ Token name.
* @param symbol_ Token symbol.
* @param ticker_ 3 letter currency ticker.
*/
constructor(string memory name_, string memory symbol_, bytes3 ticker_) {
name = name_;
symbol = symbol_;
ticker = ticker_;
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
}
/**
* @dev Sets a new controller.
* @param address_ Address of the controller.
*/
function setController(address address_) external onlyOwner {
require(
address_ != address(0x0),
"controller address cannot be the null address"
);
emit Controller(ticker, address(controller), address_);
controller = SmartController(address_);
require(
controller.isFrontend(address(this)),
"controller frontend does not point back"
);
require(
controller.ticker() == ticker,
"ticker does not match controller ticket"
);
}
/**
* @dev Transfers tokens [ERC20].
* @param to Recipient address.
* @param amount Number of tokens to transfer.
*/
function transfer(address to, uint256 amount) external returns (bool ok) {
ok = controller.transfer_withCaller(msg.sender, to, amount);
emit Transfer(msg.sender, to, amount);
}
/**
* @dev Transfers tokens from a specific address [ERC20].
* The address owner has to approve the spender beforehand.
* @param from Address to debet the tokens from.
* @param to Recipient address.
* @param amount Number of tokens to transfer.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool ok) {
ok = controller.transferFrom_withCaller(msg.sender, from, to, amount);
emit Transfer(from, to, amount);
}
/**
* @dev Approves a spender [ERC20].
* Note that using the approve/transferFrom presents a possible
* security vulnerability described in:
* https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/edit#heading=h.quou09mcbpzw
* Use transferAndCall to mitigate.
* @param spender The address of the future spender.
* @param amount The allowance of the spender.
*/
function approve(
address spender,
uint256 amount
) external returns (bool ok) {
ok = controller.approve_withCaller(msg.sender, spender, amount);
emit Approval(msg.sender, spender, amount);
}
/**
* @dev Transfers tokens and subsequently calls a method on the recipient [ERC677].
* If the recipient is a non-contract address this method behaves just like transfer.
* @param to Recipient address.
* @param amount Number of tokens to transfer.
* @param data Additional data passed to the recipient's tokenFallback method.
*/
function transferAndCall(
address to,
uint256 amount,
bytes calldata data
) external returns (bool ok) {
ok = controller.transferAndCall_withCaller(
msg.sender,
to,
amount,
data
);
emit Transfer(msg.sender, to, amount);
emit Transfer(msg.sender, to, amount, data);
}
/**
* @dev Mints new tokens.
* @param to Address to credit the tokens.
* @param amount Number of tokens to mint.
*/
function mintTo(address to, uint256 amount) external returns (bool ok) {
ok = controller.mintTo_withCaller(msg.sender, to, amount);
emit Transfer(address(0x0), to, amount);
}
/**
* @notice Polygon Bridge Mechanism. Called when token is withdrawn from child chain.
* @dev Should be callable only by Matic's Predicate contract.
* Should handle deposit by minting the required amount for user.
* @param to Address to credit the tokens.
* @param amount Number of tokens to mint.
*/
function mint(
address to,
uint256 amount
) external override returns (bool ok) {
require(hasRole(PREDICATE_ROLE, msg.sender), "caller is not PREDICATE");
ok = this.mintTo(to, amount);
}
/**
* @dev Burns tokens from token owner.
* This removes the burned tokens from circulation.
* @param from Address of the token owner.
* @param amount Number of tokens to burn.
* @param h Hash which the token owner signed.
* @param v Signature component.
* @param r Signature component.
* @param s Sigature component.
*/
function burnFrom(
address from,
uint256 amount,
bytes32 h,
uint8 v,
bytes32 r,
bytes32 s
) external returns (bool ok) {
ok = controller.burnFrom_withCaller(
msg.sender,
from,
amount,
h,
v,
r,
s
);
emit Transfer(from, address(0x0), amount);
}
/**
* @dev Recovers tokens from an address and reissues them to another address.
* In case a user loses its private key the tokens can be recovered by burning
* the tokens from that address and reissuing to a new address.
* To recover tokens the contract owner needs to provide a signature
* proving that the token owner has authorized the owner to do so.
* @param from Address to burn tokens from.
* @param to Address to mint tokens to.
* @param h Hash which the token owner signed.
* @param v Signature component.
* @param r Signature component.
* @param s Sigature component.
* @return amount Amount recovered.
*/
function recover(
address from,
address to,
bytes32 h,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amount) {
amount = controller.recover_withCaller(
msg.sender,
from,
to,
h,
v,
r,
s
);
emit Transfer(from, to, amount);
}
/**
* @dev Gets the current controller.
* @return Address of the controller.
*/
function getController() external view returns (address) {
return address(controller);
}
/**
* @dev Returns the total supply.
* @return Number of tokens.
*/
function totalSupply() external view returns (uint) {
return controller.totalSupply();
}
/**
* @dev Returns the number tokens associated with an address.
* @param who Address to lookup.
* @return Balance of address.
*/
function balanceOf(address who) external view returns (uint) {
return controller.balanceOf(who);
}
/**
* @dev Returns the allowance for a spender
* @param owner The address of the owner of the tokens.
* @param spender The address of the spender.
* @return Number of tokens the spender is allowed to spend.
*/
function allowance(
address owner,
address spender
) external view returns (uint) {
return controller.allowance(owner, spender);
}
/**
* @dev Returns the number of decimals in one token.
* @return Number of decimals.
*/
function decimals() external view returns (uint) {
return controller.decimals();
}
/**
* @dev Explicit override of transferOwnership from Claimable and Ownable
* @param newOwner Address to transfer ownership to.
*/
function transferOwnership(
address newOwner
) public override(Claimable, Ownable) {
Claimable.transferOwnership(newOwner);
}
}/* SPDX-License-Identifier: apache-2.0 */
/**
* Copyright 2022 Monerium ehf.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.11;
import "./ERC20Lib.sol";
import "./MintableTokenLib.sol";
import "./IValidator.sol";
import "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
/**
* @title SmartTokenLib
* @dev This library provides functionality which is required from a regulatory perspective.
*/
library SmartTokenLib {
using ERC20Lib for TokenStorage;
using MintableTokenLib for TokenStorage;
using SignatureChecker for address;
struct SmartStorage {
IValidator validator;
}
/**
* @dev Emitted when the contract owner recovers tokens.
* @param from Sender address.
* @param to Recipient address.
* @param amount Number of tokens.
*/
event Recovered(address indexed from, address indexed to, uint256 amount);
/**
* @dev Emitted when updating the validator.
* @param old Address of the old validator.
* @param current Address of the new validator.
*/
event Validator(address indexed old, address indexed current);
/**
* @dev Sets a new validator.
* @param self Smart storage to operate on.
* @param validator Address of validator.
*/
function setValidator(
SmartStorage storage self,
address validator
) external {
emit Validator(address(self.validator), validator);
self.validator = IValidator(validator);
}
/**
* @dev Approves or rejects a transfer request.
* The request is forwarded to a validator which implements
* the actual business logic.
* @param self Smart storage to operate on.
* @param from Sender address.
* @param to Recipient address.
* @param amount Number of tokens.
*/
function validate(
SmartStorage storage self,
address from,
address to,
uint256 amount
) external returns (bool valid) {
return self.validator.validate(from, to, amount);
}
/**
* @dev Recovers tokens from an address and reissues them to another address.
* In case a user loses its private key the tokens can be recovered by burning
* the tokens from that address and reissuing to a new address.
* To recover tokens the contract owner needs to provide a signature
* proving that the token owner has authorized the owner to do so.
* @param from Address to burn tokens from.
* @param to Address to mint tokens to.
* @param h Hash which the token owner signed.
* @param v Signature component.
* @param r Signature component.
* @param s Sigature component.
* @return Amount recovered.
*/
function recover(
TokenStorage token,
address from,
address to,
bytes32 h,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256) {
bytes memory signature;
if (r != bytes32(0) || s != bytes32(0)) {
signature = bytes(abi.encodePacked(r, s, v));
}
require(
from.isValidSignatureNow(h, signature),
"signature/hash does not recover from address"
);
uint256 amount = token.balanceOf(from);
require(token.burn(from, amount), "burn failed");
require(token.mint(to, amount), "mint failed");
emit Recovered(from, to, amount);
return amount;
}
/**
* @dev Gets the current validator.
* @param self Smart storage to operate on.
* @return Address of validator.
*/
function getValidator(
SmartStorage storage self
) external view returns (address) {
return address(self.validator);
}
}/* SPDX-License-Identifier: apache-2.0 */
/**
* Copyright 2022 Monerium ehf.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.11;
import "./StandardController.sol";
import "./MintableTokenLib.sol";
import "./ITokenFrontend.sol";
/**
* @title MintableController
* @dev This contracts implements functionality allowing for minting and burning of tokens.
*/
contract MintableController is StandardController {
using MintableTokenLib for TokenStorage;
mapping(address => uint256) internal mintAllowances;
uint256 internal maxMintAllowance;
/**
* @dev Contract constructor.
* @param storage_ Address of the token storage for the controller.
* @param initialSupply The amount of tokens to mint upon creation.
* @param frontend_ Address of the authorized frontend.
*/
constructor(
address storage_,
uint256 initialSupply,
address frontend_
) StandardController(storage_, initialSupply, frontend_) {
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
}
/**
* @dev Emitted when allowance is set.
* @param account The address of the account.
* @param amount The amount of allowance.
*/
event MintAllowance(address indexed account, uint256 amount);
/**
* @dev Emitted when max allowance is set.
* @param amount The amount of allowance.
*/
event MaxMintAllowance(uint256 amount);
/**
* @dev modifier to restrict access to system accounts with enough allowance
* @param account The address of the account.
* @param amount The amount of allowance.
*/
modifier onlyAllowedSystemAccount(address account, uint256 amount) {
require(
hasRole(SYSTEM_ROLE, account),
"MintableController: caller is not a system account"
);
require(
mintAllowances[account] >= amount,
"MintableController: caller is not allowed to perform this action"
);
_;
}
/**
* @dev Mints new tokens.
* @param caller Address of the caller passed through the frontend.
* @param to Address to credit the tokens.
* @param amount Number of tokens to mint.
*/
function mintTo_withCaller(
address caller,
address to,
uint256 amount
)
public
onlyFrontend
onlyAllowedSystemAccount(caller, amount)
whenNotPaused
returns (bool)
{
_avoidBlackholes(to);
mintAllowances[caller] = mintAllowances[caller] - amount;
require(token.mint(to, amount), "MintableController: mint failed");
return true;
}
/**
* @dev Burns tokens from token owner.
* This removes the burned tokens from circulation.
* @param caller Address of the caller passed through the frontend.
*/
function burnFrom_withCaller(
address caller,
address,
uint256,
bytes32,
uint8,
bytes32,
bytes32
) public view onlyFrontend returns (bool) {
require(
caller == address(this),
"only allow this contract to be the caller"
);
return true;
}
/**
* @dev Burns tokens from token owner.
* This removes the burned tokens from circulation.
* @param from Address of the token owner.
* @param amount Number of tokens to burn.
*/
function burnFrom(
address from,
uint256 amount,
bytes32 h,
bytes memory signature
) public onlySystemAccount(msg.sender) whenNotPaused returns (bool) {
require(
token.burn(from, amount, h, signature),
"MintableController: burn failed"
);
ITokenFrontend tokenFrontend = ITokenFrontend(frontend);
require(
tokenFrontend.burnFrom(from, amount, h, 0, 0, 0),
"MintableController: TokenFrontend burn call failed"
);
return true;
}
/**
* @dev set maximum allowance for system accounts.
* @param amount The amount of allowance.
*/
function setMaxMintAllowance(uint256 amount) public virtual onlyOwner {
emit MaxMintAllowance(amount);
maxMintAllowance = amount;
}
/**
* @dev get maximum allowance for system accounts.
* @return The amount of allowance.
*/
function getMaxMintAllowance() public view virtual returns (uint256) {
return maxMintAllowance;
}
/**
* @dev set allowance for an account.
* @param account The address of the account.
* @param amount The amount of allowance.
*/
function setMintAllowance(
address account,
uint256 amount
) public virtual onlyAdminAccounts {
require(
amount <= maxMintAllowance,
"MintableController: allowance exceeds maximum setted by owner"
);
mintAllowances[account] = amount;
emit MintAllowance(account, amount);
}
/**
* @dev get allowance for an account.
* @param account The address of the account.
* @return The amount of allowance.
*/
function getMintAllowance(
address account
) public view virtual returns (uint256) {
return mintAllowances[account];
}
}/* SPDX-License-Identifier: apache-2.0 */
/**
* Copyright 2022 Monerium ehf.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.11;
/**
* @title IValidator
* @dev Contracts implementing this interface validate token transfers.
*/
interface IValidator {
/**
* @dev Emitted when a validator makes a decision.
* @param from Sender address.
* @param to Recipient address.
* @param amount Number of tokens.
* @param valid True if transfer approved, false if rejected.
*/
event Decision(
address indexed from,
address indexed to,
uint256 amount,
bool valid
);
/**
* @dev Validates token transfer.
* If the sender is on the blacklist the transfer is denied.
* @param from Sender address.
* @param to Recipient address.
* @param amount Number of tokens.
*/
function validate(
address from,
address to,
uint256 amount
) external returns (bool valid);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;
import "./Ownable.sol";
/**
* @title Claimable
* @dev Extension for the Ownable contract, where the ownership needs to be claimed.
* This allows the new owner to accept the transfer.
*/
abstract contract Claimable is Ownable {
address public pendingOwner;
/**
* @dev emitted when the pendingOwner address is changed
* @param previousPendingOwner previous pendingOwner address
* @param newPendingOwner new pendingOwner address
*/
event OwnershipTransferPending(
address indexed previousPendingOwner,
address indexed newPendingOwner
);
/**
* @dev Modifier throws if called by any account other than the pendingOwner.
*/
modifier onlyPendingOwner() {
require(msg.sender == pendingOwner);
_;
}
/**
* @dev Allows the current owner to set the pendingOwner address.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(
address newOwner
) public virtual override onlyOwner {
emit OwnershipTransferPending(pendingOwner, newOwner);
pendingOwner = newOwner;
}
/**
* @dev Allows the pendingOwner address to finalize the transfer.
*/
function claimOwnership() public onlyPendingOwner {
emit OwnershipTransferred(owner, pendingOwner);
owner = pendingOwner;
pendingOwner = address(0);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;
import "./Ownable.sol";
import "../token/ERC20/ERC20Basic.sol";
import "../token/ERC20/SafeERC20.sol";
/**
* @title Contracts that should be able to recover tokens
* @author SylTi
* @dev This allow a contract to recover any ERC20 token received in a contract by transferring the balance to the contract owner.
* This will prevent any accidental loss of tokens.
*/
contract CanReclaimToken is Ownable {
using SafeERC20 for ERC20Basic;
/**
* @dev Reclaim all ERC20Basic compatible tokens
* @param _token ERC20Basic The address of the token contract
*/
function reclaimToken(ERC20Basic _token) external onlyOwner {
uint256 balance = _token.balanceOf(address(this));
_token.safeTransfer(owner, balance);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;
import "./HasNoEther.sol";
import "./HasNoContracts.sol";
/**
* @title Base contract for contracts that should not own things.
* @author Remco Bloemen <remco@2π.com>
* @dev Solves a class of errors where a contract accidentally becomes owner of Ether, Tokens or
* Owned contracts. See respective base contracts for details.
*/
contract NoOwner is HasNoEther, HasNoContracts {
}/* SPDX-License-Identifier: apache-2.0 */
/**
* Copyright 2022 Monerium ehf.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.11;
/**
* @dev Interface of the ERC20 standard as defined in the EIP. Does not include
* the optional functions; to access them see `ERC20Detailed`.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a `Transfer` event.
*/
function transfer(
address recipient,
uint256 amount
) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through `transferFrom`. This is
* zero by default.
*
* This value changes when `approve` or `transferFrom` are called.
*/
function allowance(
address owner,
address spender
) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* > Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an `Approval` event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a `Transfer` event.
*/
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to `approve`. `value` is the new allowance.
*/
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
}/* SPDX-License-Identifier: apache-2.0 */
pragma solidity 0.8.11;
/**
* @title IPolygonPosRootToken
* @dev This interface define the mandatory method enabling polygon bridging mechanism.
* @notice This interface should be inherited to deploy on ethereum.
*/
interface IPolygonPosRootToken {
function mint(address user, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/AccessControl.sol)
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role, _msgSender());
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view override returns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(uint160(account), 20),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}/* SPDX-License-Identifier: apache-2.0 */
/**
* Copyright 2022 Monerium ehf.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.11;
import "./TokenStorage.sol";
/**
* @title ERC20Lib
* @dev Standard ERC20 token functionality.
* https://github.com/ethereum/EIPs/issues/20
*/
library ERC20Lib {
/**
* @dev Transfers tokens [ERC20].
* @param db Token storage to operate on.
* @param caller Address of the caller passed through the frontend.
* @param to Recipient address.
* @param amount Number of tokens to transfer.
*/
function transfer(
TokenStorage db,
address caller,
address to,
uint256 amount
) external returns (bool success) {
db.subBalance(caller, amount);
db.addBalance(to, amount);
return true;
}
/**
* @dev Transfers tokens from a specific address [ERC20].
* The address owner has to approve the spender beforehand.
* @param db Token storage to operate on.
* @param caller Address of the caller passed through the frontend.
* @param from Address to debet the tokens from.
* @param to Recipient address.
* @param amount Number of tokens to transfer.
*/
function transferFrom(
TokenStorage db,
address caller,
address from,
address to,
uint256 amount
) external returns (bool success) {
uint256 allowance_ = db.getAllowed(from, caller);
db.subBalance(from, amount);
db.addBalance(to, amount);
db.setAllowed(from, caller, allowance_ - amount);
return true;
}
/**
* @dev Approves a spender [ERC20].
* Note that using the approve/transferFrom presents a possible
* security vulnerability described in:
* https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/edit#heading=h.quou09mcbpzw
* Use transferAndCall to mitigate.
* @param db Token storage to operate on.
* @param caller Address of the caller passed through the frontend.
* @param spender The address of the future spender.
* @param amount The allowance of the spender.
*/
function approve(
TokenStorage db,
address caller,
address spender,
uint256 amount
) public returns (bool success) {
db.setAllowed(caller, spender, amount);
return true;
}
/**
* @dev Returns the number tokens associated with an address.
* @param db Token storage to operate on.
* @param who Address to lookup.
* @return balance Balance of address.
*/
function balanceOf(
TokenStorage db,
address who
) external view returns (uint256 balance) {
return db.getBalance(who);
}
/**
* @dev Returns the allowance for a spender
* @param db Token storage to operate on.
* @param owner The address of the owner of the tokens.
* @param spender The address of the spender.
* @return remaining Number of tokens the spender is allowed to spend.
*/
function allowance(
TokenStorage db,
address owner,
address spender
) external view returns (uint256 remaining) {
return db.getAllowed(owner, spender);
}
}/* SPDX-License-Identifier: apache-2.0 */
/**
* Copyright 2022 Monerium ehf.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.11;
import "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
import "./ERC20Lib.sol";
import "./TokenStorage.sol";
/**
* @title Mintable token
* @dev Simple ERC20 Token example, with mintable token creation
* @dev Issue: * https://github.com/OpenZeppelin/openzeppelin-solidity/issues/120
* Based on code by TokenMarketNet: https://github.com/TokenMarketNet/ico/blob/master/contracts/MintableToken.sol
*/
library MintableTokenLib {
using SignatureChecker for address;
/**
* @dev Mints new tokens.
* @param db Token storage to operate on.
* @param to The address that will recieve the minted tokens.
* @param amount The amount of tokens to mint.
*/
function mint(
TokenStorage db,
address to,
uint256 amount
) external returns (bool) {
db.addBalance(to, amount);
return true;
}
/**
* @dev Burns tokens.
* @param db Token storage to operate on.
* @param from The address holding tokens.
* @param amount The amount of tokens to burn.
*/
function burn(
TokenStorage db,
address from,
uint256 amount
) public returns (bool) {
db.subBalance(from, amount);
return true;
}
/**
* @dev Burns tokens from a specific address.
* To burn the tokens the caller needs to provide a signature
* proving that the caller is authorized by the token owner to do so.
* @param db Token storage to operate on.
* @param from The address holding tokens.
* @param amount The amount of tokens to burn.
* @param h Hash which the token owner signed.
* @param signature Signature component.
*/
function burn(
TokenStorage db,
address from,
uint256 amount,
bytes32 h,
bytes memory signature
) external returns (bool) {
require(
from.isValidSignatureNow(h, signature),
"signature/hash does not match"
);
return burn(db, from, amount);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/cryptography/SignatureChecker.sol)
pragma solidity ^0.8.0;
import "./ECDSA.sol";
import "../Address.sol";
import "../../interfaces/IERC1271.sol";
/**
* @dev Signature verification helper: Provide a single mechanism to verify both private-key (EOA) ECDSA signature and
* ERC1271 contract signatures. Using this instead of ECDSA.recover in your contract will make them compatible with
* smart contract wallets such as Argent and Gnosis.
*
* Note: unlike ECDSA signatures, contract signature's are revocable, and the outcome of this function can thus change
* through time. It could return true at block N and false at block N+1 (or the opposite).
*
* _Available since v4.1._
*/
library SignatureChecker {
function isValidSignatureNow(
address signer,
bytes32 hash,
bytes memory signature
) internal view returns (bool) {
(address recovered, ECDSA.RecoverError error) = ECDSA.tryRecover(hash, signature);
if (error == ECDSA.RecoverError.NoError && recovered == signer) {
return true;
}
(bool success, bytes memory result) = signer.staticcall(
abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, signature)
);
return (success && result.length == 32 && abi.decode(result, (bytes4)) == IERC1271.isValidSignature.selector);
}
}/* SPDX-License-Identifier: apache-2.0 */
/**
* Copyright 2022 Monerium ehf.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.11;
import "./TokenStorage.sol";
import "./ERC20Lib.sol";
import "./ERC677Lib.sol";
import "./ClaimableSystemRole.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
/**
* @title StandardController
* @dev This is the base contract which delegates token methods [ERC20 and ERC677]
* to their respective library implementations.
* The controller is primarily intended to be interacted with via a token frontend.
*/
contract StandardController is ClaimableSystemRole, Pausable {
using ERC20Lib for TokenStorage;
using ERC677Lib for TokenStorage;
TokenStorage internal token;
address internal frontend;
mapping(address => bool) internal bridgeFrontends;
uint8 public decimals = 18;
bytes32 private constant PERMIT_TYPEHASH =
keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
/**
* @dev Emitted when updating the frontend.
* @param old Address of the old frontend.
* @param current Address of the new frontend.
*/
event Frontend(address indexed old, address indexed current);
/**
* @dev Emitted when updating the Bridge frontend.
* @param frontend Address of the new Bridge frontend.
* @param title String of the frontend name.
*/
event BridgeFrontend(address indexed frontend, string indexed title);
/**
* @dev Emitted when removing a Bridge frontend.
* @param frontend Address of the Bridge frontend.
*/
event BridgeFrontendRemoved(address indexed frontend);
/**
* @dev Emitted when updating the storage.
* @param old Address of the old storage.
* @param current Address of the new storage.
*/
event Storage(address indexed old, address indexed current);
/**
* @dev Modifier which prevents the function from being called by unauthorized parties.
* The caller must be the frontend otherwise the call is reverted.
*/
modifier onlyFrontend() {
require(isFrontend(msg.sender));
_;
}
/*//////////////////////////////////////////////////////////////
EIP-2612 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
/**
* @dev Contract constructor.
* @param storage_ Address of the token storage for the controller.
* @param initialSupply The amount of tokens to mint upon creation.
* @param frontend_ Address of the authorized frontend.
*/
constructor(address storage_, uint256 initialSupply, address frontend_) {
require(
storage_ == address(0x0) || initialSupply == 0,
"either a token storage must be initialized or no initial supply"
);
if (storage_ == address(0x0)) {
token = new TokenStorage();
token.addBalance(msg.sender, initialSupply);
} else {
token = TokenStorage(storage_);
}
frontend = frontend_;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
/**
* @dev Prevents tokens to be sent to well known blackholes by throwing on known blackholes.
* @param to The address of the intended recipient.
*/
function _avoidBlackholes(address to) internal view {
require(to != address(0x0), "must not send to 0x0");
require(to != address(this), "must not send to controller");
require(to != address(token), "must not send to token storage");
require(to != frontend, "must not send to frontend");
require(isFrontend(to) == false, "must not send to bridgeFrontends");
}
/**
* @dev Returns the current frontend.
* @return Address of the frontend.
*/
function getFrontend() external view returns (address) {
return frontend;
}
/**
* @dev Returns the current storage.
* @return Address of the storage.
*/
function getStorage() external view returns (address) {
return address(token);
}
/**
* @dev Sets a new frontend.
* @param frontend_ Address of the new frontend.
*/
function setFrontend(address frontend_) public onlyOwner {
emit Frontend(frontend, frontend_);
frontend = frontend_;
}
/**
* @dev Set a new bridge frontend.
* @param frontend_ Address of the new bridge frontend.
* @param title Keccack256 hash of the frontend title.
*/
function setBridgeFrontend(
address frontend_,
string calldata title
) public onlyOwner {
bridgeFrontends[frontend_] = true;
emit BridgeFrontend(frontend_, title);
}
/**
* @dev Removes a bridge frontend.
* @param frontend_ Address of the bridge frontend to remove.
*/
function removeBridgeFrontend(address frontend_) public onlyOwner {
bridgeFrontends[frontend_] = false;
emit BridgeFrontendRemoved(frontend_);
}
/**
* @dev Checks wether an address is a frontend.
* @param frontend_ Address of the frontend candidate.
*/
function isFrontend(address frontend_) public view returns (bool) {
return (frontend_ == frontend) || bridgeFrontends[frontend_];
}
/**
* @dev Sets a new storage.
* @param storage_ Address of the new storage.
*/
function setStorage(address storage_) external onlyOwner {
emit Storage(address(token), storage_);
token = TokenStorage(storage_);
}
/**
* @dev Transfers the ownership of the storage.
* @param newOwner Address of the new storage owner.
*/
function transferStorageOwnership(address newOwner) public onlyOwner {
token.transferOwnership(newOwner);
}
/**
* @dev Claims the ownership of the storage.
*/
function claimStorageOwnership() public onlyOwner {
token.claimOwnership();
}
/**
* @dev Transfers tokens [ERC20].
* @param caller Address of the caller passed through the frontend.
* @param to Recipient address.
* @param amount Number of tokens to transfer.
*/
function transfer_withCaller(
address caller,
address to,
uint256 amount
) public virtual onlyFrontend returns (bool ok) {
_avoidBlackholes(to);
return token.transfer(caller, to, amount);
}
/**
* @dev Transfers tokens from a specific address [ERC20].
* The address owner has to approve the spender beforehand.
* @param caller Address of the caller passed through the frontend.
* @param from Address to debet the tokens from.
* @param to Recipient address.
* @param amount Number of tokens to transfer.
*/
function transferFrom_withCaller(
address caller,
address from,
address to,
uint256 amount
) public virtual onlyFrontend returns (bool ok) {
_avoidBlackholes(to);
return token.transferFrom(caller, from, to, amount);
}
/**
* @dev Approves a spender [ERC20].
* Note that using the approve/transferFrom presents a possible
* security vulnerability described in:
* https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/edit#heading=h.quou09mcbpzw
* Use transferAndCall to mitigate.
* @param caller Address of the caller passed through the frontend.
* @param spender The address of the future spender.
* @param amount The allowance of the spender.
*/
function approve_withCaller(
address caller,
address spender,
uint256 amount
) public onlyFrontend returns (bool ok) {
return token.approve(caller, spender, amount);
}
function getPermitDigest(
address owner,
address spender,
uint256 value,
uint256 nonce,
uint256 deadline
) public view returns (bytes32) {
return keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
PERMIT_TYPEHASH,
owner,
spender,
value,
nonce,
deadline
)
)
)
);
}
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
// Unchecked because the only math done is incrementing
// the owner's nonce which cannot realistically overflow.
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
PERMIT_TYPEHASH,
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
}
token.approve(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes("standardController")),
keccak256("1"),
block.chainid,
address(this)
)
);
}
/**
* @dev Transfers tokens and subsequently calls a method on the recipient [ERC677].
* If the recipient is a non-contract address this method behaves just like transfer.
* @param caller Address of the caller passed through the frontend.
* @param to Recipient address.
* @param amount Number of tokens to transfer.
* @param data Additional data passed to the recipient's tokenFallback method.
*/
function transferAndCall_withCaller(
address caller,
address to,
uint256 amount,
bytes calldata data
) public virtual onlyFrontend returns (bool ok) {
_avoidBlackholes(to);
return token.transferAndCall(caller, to, amount, data);
}
/**
* @dev Returns the total supply.
* @return Number of tokens.
*/
function totalSupply() external view returns (uint) {
return token.getSupply();
}
/**
* @dev Returns the number tokens associated with an address.
* @param who Address to lookup.
* @return Balance of address.
*/
function balanceOf(address who) external view returns (uint) {
return token.getBalance(who);
}
/**
* @dev Returns the allowance for a spender
* @param owner The address of the owner of the tokens.
* @param spender The address of the spender.
* @return Number of tokens the spender is allowed to spend.
*/
function allowance(
address owner,
address spender
) external view returns (uint) {
return token.allowance(owner, spender);
}
/**
* @dev pausable function to pause the contract
*/
function pause() public onlyOwner {
_pause();
}
/**
* @dev pausable function to unpause the contract
*/
function unpause() public onlyOwner {
_unpause();
}
}/* SPDX-License-Identifier: apache-2.0 */
/**
* Copyright 2022 Monerium ehf.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.11;
interface ITokenFrontend {
function burnFrom(
address from,
uint256 amount,
bytes32 h,
uint8 v,
bytes32 r,
bytes32 s
) external returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
address public owner;
event OwnershipRenounced(address indexed previousOwner);
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
constructor() {
owner = msg.sender;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param _newOwner The address to transfer ownership to.
*/
function transferOwnership(address _newOwner) public virtual onlyOwner {
_transferOwnership(_newOwner);
}
/**
* @dev Transfers control of the contract to a newOwner.
* @param _newOwner The address to transfer ownership to.
*/
function _transferOwnership(address _newOwner) internal {
require(_newOwner != address(0));
emit OwnershipTransferred(owner, _newOwner);
owner = _newOwner;
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;
/**
* @title ERC20Basic
* @dev Simpler version of ERC20 interface
* See https://github.com/ethereum/EIPs/issues/179
*/
abstract contract ERC20Basic {
function totalSupply() public view virtual returns (uint256);
function balanceOf(address _who) public view virtual returns (uint256);
function transfer(
address _to,
uint256 _value
) public virtual returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;
import "./ERC20Basic.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure.
* To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
function safeTransfer(
ERC20Basic _token,
address _to,
uint256 _value
) internal {
require(_token.transfer(_to, _value));
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;
import "./Ownable.sol";
/**
* @title Contracts that should not own Ether
* @author Remco Bloemen <remco@2π.com>
* @dev This tries to block incoming ether to prevent accidental loss of Ether. Should Ether end up
* in the contract, it will allow the owner to reclaim this Ether.
* @notice Ether can still be sent to this contract by:
* calling functions labeled `payable`
* `selfdestruct(contract_address)`
* mining directly to the contract address
*/
contract HasNoEther is Ownable {
/**
* @dev Constructor that rejects incoming Ether
* The `payable` flag is added so we can access `msg.value` without compiler warning. If we
* leave out payable, then Solidity will allow inheriting contracts to implement a payable
* constructor. By doing it this way we prevent a payable constructor from working. Alternatively
* we could use assembly to access msg.value.
*/
constructor() payable {
require(msg.value == 0);
}
/**
* @dev Disallows direct send by setting a default function without the `payable` flag.
*/
fallback() external {}
/**
* @dev Transfer all Ether held by the contract to the owner.
*/
function reclaimEther() external onlyOwner {
payable(owner).transfer(address(this).balance);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;
import "./Ownable.sol";
/**
* @title Contracts that should not own Contracts
* @author Remco Bloemen <remco@2π.com>
* @dev Should contracts (anything Ownable) end up being owned by this contract, it allows the owner
* of this contract to reclaim ownership of the contracts.
*/
contract HasNoContracts is Ownable {
/**
* @dev Reclaim ownership of Ownable contracts
* @param _contractAddr The address of the Ownable to be reclaimed.
*/
function reclaimContract(address _contractAddr) external onlyOwner {
Ownable contractInst = Ownable(_contractAddr);
contractInst.transferOwnership(owner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)
pragma solidity ^0.8.0;
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}/* SPDX-License-Identifier: apache-2.0 */
/**
* Copyright 2022 Monerium ehf.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.11;
import "./ownership/Claimable.sol";
import "./ownership/CanReclaimToken.sol";
import "./ownership/NoOwner.sol";
import "./TokenStorageLib.sol";
/**
* @title TokenStorage
* @dev External storage for tokens.
* The storage is implemented in a separate contract to maintain state
* between token upgrades.
*/
contract TokenStorage is Claimable, CanReclaimToken, NoOwner {
using TokenStorageLib for TokenStorageLib.TokenStorage;
TokenStorageLib.TokenStorage internal tokenStorage;
/**
* @dev Increases balance of an address.
* @param to Address to increase.
* @param amount Number of units to add.
*/
function addBalance(address to, uint256 amount) external onlyOwner {
tokenStorage.addBalance(to, amount);
}
/**
* @dev Decreases balance of an address.
* @param from Address to decrease.
* @param amount Number of units to subtract.
*/
function subBalance(address from, uint256 amount) external onlyOwner {
tokenStorage.subBalance(from, amount);
}
/**
* @dev Sets the allowance for a spender.
* @param owner Address of the owner of the tokens to spend.
* @param spender Address of the spender.
* @param amount Quantity of allowance.
*/
function setAllowed(
address owner,
address spender,
uint256 amount
) external onlyOwner {
tokenStorage.setAllowed(owner, spender, amount);
}
/**
* @dev Returns the supply of tokens.
* @return Total supply.
*/
function getSupply() external view returns (uint256) {
return tokenStorage.getSupply();
}
/**
* @dev Returns the balance of an address.
* @param who Address to lookup.
* @return Number of units.
*/
function getBalance(address who) external view returns (uint256) {
return tokenStorage.getBalance(who);
}
/**
* @dev Returns the allowance for a spender.
* @param owner Address of the owner of the tokens to spend.
* @param spender Address of the spender.
* @return Number of units.
*/
function getAllowed(
address owner,
address spender
) external view returns (uint256) {
return tokenStorage.getAllowed(owner, spender);
}
/**
* @dev Explicit override of transferOwnership from Claimable and Ownable
* @param newOwner Address to transfer ownership to.
*/
function transferOwnership(
address newOwner
) public override(Claimable, Ownable) {
Claimable.transferOwnership(newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../Strings.sol";
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
} else if (error == RecoverError.InvalidSignatureV) {
revert("ECDSA: invalid signature 'v' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
// Check the signature length
// - case 65: r,s,v signature (standard)
// - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else if (signature.length == 64) {
bytes32 r;
bytes32 vs;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
assembly {
r := mload(add(signature, 0x20))
vs := mload(add(signature, 0x40))
}
return tryRecover(hash, r, vs);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address, RecoverError) {
bytes32 s;
uint8 v;
assembly {
s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
v := add(shr(255, vs), 27)
}
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/
function recover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
if (v != 27 && v != 28) {
return (address(0), RecoverError.InvalidSignatureV);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)
pragma solidity ^0.8.0;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC1271 standard signature validation method for
* contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
*
* _Available since v4.1._
*/
interface IERC1271 {
/**
* @dev Should return whether the signature provided is valid for the provided data
* @param hash Hash of the data to be signed
* @param signature Signature byte array associated with _data
*/
function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}/* SPDX-License-Identifier: apache-2.0 */
/**
* Copyright 2022 Monerium ehf.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.11;
import "@openzeppelin/contracts/utils/Address.sol";
import "./IERC677Recipient.sol";
import "./TokenStorage.sol";
import "./ERC20Lib.sol";
/**
* @title ERC677
* @dev ERC677 token functionality.
* https://github.com/ethereum/EIPs/issues/677
*/
library ERC677Lib {
using ERC20Lib for TokenStorage;
using Address for address;
/**
* @dev Transfers tokens and subsequently calls a method on the recipient [ERC677].
* If the recipient is a non-contract address this method behaves just like transfer.
* @notice db.transfer either returns true or reverts.
* @param db Token storage to operate on.
* @param caller Address of the caller passed through the frontend.
* @param to Recipient address.
* @param amount Number of tokens to transfer.
* @param data Additional data passed to the recipient's tokenFallback method.
*/
function transferAndCall(
TokenStorage db,
address caller,
address to,
uint256 amount,
bytes calldata data
) external returns (bool) {
require(db.transfer(caller, to, amount), "unable to transfer");
if (to.isContract()) {
IERC677Recipient recipient = IERC677Recipient(to);
require(
recipient.onTokenTransfer(caller, amount, data),
"token handler returns false"
);
}
return true;
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;
import "./SystemRole.sol";
/**
* @title ClaimableSystemRole
* @dev Extension for the SystemRole contract, where the ownership needs to be claimed.
* This allows the new owner to accept the transfer.
*/
abstract contract ClaimableSystemRole is SystemRole {
address public pendingOwner;
/**
* @dev emitted when the pendingOwner address is changed
* @param previousPendingOwner previous pendingOwner address
* @param newPendingOwner new pendingOwner address
*/
event OwnershipTransferPending(
address indexed previousPendingOwner,
address indexed newPendingOwner
);
/**
* @dev Modifier throws if called by any account other than the pendingOwner.
*/
modifier onlyPendingOwner() {
require(msg.sender == pendingOwner);
_;
}
/**
* @dev Allows the current owner to set the pendingOwner address.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(
address newOwner
) public virtual override onlyOwner {
emit OwnershipTransferPending(pendingOwner, newOwner);
pendingOwner = newOwner;
}
/**
* @dev Allows the pendingOwner address to finalize the transfer.
*/
function claimOwnership() public onlyPendingOwner {
emit OwnershipTransferred(owner, pendingOwner);
owner = pendingOwner;
_setupRole(DEFAULT_ADMIN_ROLE, owner);
pendingOwner = address(0);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
constructor() {
_paused = false;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
require(!paused(), "Pausable: paused");
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
require(paused(), "Pausable: not paused");
_;
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}/* SPDX-License-Identifier: apache-2.0 */
/**
* Copyright 2022 Monerium ehf.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.11;
/*
* @title TokenStorageLib
* @dev Implementation of an[external storage for tokens.
*/
library TokenStorageLib {
struct TokenStorage {
mapping(address => uint) balances;
mapping(address => mapping(address => uint)) allowed;
uint256 totalSupply;
}
/**
* @dev Increases balance of an address.
* @param self Token storage to operate on.
* @param to Address to increase.
* @param amount Number of units to add.
*/
function addBalance(
TokenStorage storage self,
address to,
uint256 amount
) external {
self.totalSupply = self.totalSupply + amount;
self.balances[to] = self.balances[to] + amount;
}
/**
* @dev Decreases balance of an address.
* @param self Token storage to operate on.
* @param from Address to decrease.
* @param amount Number of units to subtract.
*/
function subBalance(
TokenStorage storage self,
address from,
uint256 amount
) external {
self.totalSupply = self.totalSupply - amount;
self.balances[from] = self.balances[from] - amount;
}
/**
* @dev Sets the allowance for a spender.
* @param self Token storage to operate on.
* @param owner Address of the owner of the tokens to spend.
* @param spender Address of the spender.
* @param amount Qunatity of allowance.
*/
function setAllowed(
TokenStorage storage self,
address owner,
address spender,
uint256 amount
) external {
self.allowed[owner][spender] = amount;
}
/**
* @dev Returns the supply of tokens.
* @param self Token storage to operate on.
* @return Total supply.
*/
function getSupply(TokenStorage storage self) external view returns (uint) {
return self.totalSupply;
}
/**
* @dev Returns the balance of an address.
* @param self Token storage to operate on.
* @param who Address to lookup.
* @return Number of units.
*/
function getBalance(
TokenStorage storage self,
address who
) external view returns (uint) {
return self.balances[who];
}
/**
* @dev Returns the allowance for a spender.
* @param self Token storage to operate on.
* @param owner Address of the owner of the tokens to spend.
* @param spender Address of the spender.
* @return Number of units.
*/
function getAllowed(
TokenStorage storage self,
address owner,
address spender
) external view returns (uint) {
return self.allowed[owner][spender];
}
}/* SPDX-License-Identifier: apache-2.0 */
/**
* Copyright 2022 Monerium ehf.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.11;
/**
* @title IERC677Recipient
* @dev Contracts implementing this interface can participate in [ERC677].
*/
interface IERC677Recipient {
/**
* @dev Receives notification from [ERC677] transferAndCall.
* @param from Sender address.
* @param amount Number of tokens.
* @param data Additional data.
*/
function onTokenTransfer(
address from,
uint256 amount,
bytes calldata data
) external returns (bool);
}/* SPDX-License-Identifier: apache-2.0 */
/**
* Copyright 2022 Monerium ehf.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.11;
import "@openzeppelin/contracts/access/AccessControl.sol";
import "./ownership/Ownable.sol";
/**
* @title SystemRole
* @dev SystemRole accounts have been approved to perform operational actions (e.g. mint and burn).
* @dev AdminRole accounts have been approved to perform administrative actions (e.g. setting allowances).
* @notice The contract is an abstract contract.
*/
abstract contract SystemRole is AccessControl, Ownable {
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
bytes32 public constant SYSTEM_ROLE = keccak256("SYSTEM_ROLE");
/**
* @dev Emitted when system account is added.
* @param account The address of the account.
*/
event SystemAccountAdded(address indexed account);
/**
* @dev Emitted when system account is removed.
* @param account The address of the account.
*/
event SystemAccountRemoved(address indexed account);
/**
* @dev Emitted when admin account is added.
* @param account The address of the account.
*/
event AdminAccountAdded(address indexed account);
/**
* @dev Emitted when admin account is removed.
* @param account The address of the account.
*/
event AdminAccountRemoved(address indexed account);
/**
* @dev modifier to restrict access to system accounts.
*/
modifier onlySystemAccounts() {
require(
hasRole(SYSTEM_ROLE, msg.sender),
"SystemRole: caller is not a system account"
);
_;
}
/**
* @dev modifier to restrict access to system accounts.
* @param account The address of the account.
*/
modifier onlySystemAccount(address account) {
require(
hasRole(SYSTEM_ROLE, account),
"SystemRole: caller is not a system account"
);
_;
}
/**
* @dev modifier to restrict access to admin accounts.
*/
modifier onlyAdminAccounts() {
require(
hasRole(ADMIN_ROLE, msg.sender),
"SystemRole: caller is not an admin account"
);
_;
}
/**
* @dev modifier to restrict access to admin accounts.
* @param account The address of the account.
*/
modifier onlyAdminAccount(address account) {
require(
hasRole(ADMIN_ROLE, account),
"SystemRole: caller is not an admin account"
);
_;
}
/**
* @dev Checks wether an address is a system account.
* @param account The address of the account.
* @return true if system account.
*/
function isSystemAccount(address account) public view returns (bool) {
return hasRole(SYSTEM_ROLE, account);
}
/**
* @dev Checks wether an address is a admin account.
* @param account The address of the account.
* @return true if admin account.
*/
function isAdminAccount(address account) public view returns (bool) {
return hasRole(ADMIN_ROLE, account);
}
/**
* @dev add system account.
* @param account The address of the account.
*/
function addSystemAccount(address account) public virtual onlyOwner {
grantRole(SYSTEM_ROLE, account);
emit SystemAccountAdded(account);
}
/**
* @dev remove system account.
* @param account The address of the account.
*/
function removeSystemAccount(address account) public virtual onlyOwner {
revokeRole(SYSTEM_ROLE, account);
emit SystemAccountRemoved(account);
}
/**
* @dev add admin account.
* @param account The address of the account.
*/
function addAdminAccount(address account) public virtual onlyOwner {
grantRole(ADMIN_ROLE, account);
emit AdminAccountAdded(account);
}
/**
* @dev remove admin account.
* @param account The address of the account.
*/
function removeAdminAccount(address account) public virtual onlyOwner {
revokeRole(ADMIN_ROLE, account);
emit AdminAccountRemoved(account);
}
}{
"remappings": [
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "london",
"viaIR": false,
"libraries": {
"src/ERC20Lib.sol": {
"ERC20Lib": "0x0c06ccf38114ddfc35e07427b9424adcca9f44f8"
},
"src/ERC677Lib.sol": {
"ERC677Lib": "0x2d80dbf04d0802abd7a342dafa5d7cb42bfbb52f"
},
"src/MintableTokenLib.sol": {
"MintableTokenLib": "0x0fc041a4b6a3f634445804daafd03f202337c125"
},
"src/SmartTokenLib.sol": {
"SmartTokenLib": "0x6a2f117b2e35e59ee35022186ae6b365dcab84ad"
},
"src/TokenStorageLib.sol": {
"TokenStorageLib": "0xddfe2c5f94909420cf55827fffa09a7ff9b2ab77"
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"controllerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"frontendAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"old_","type":"address"},{"internalType":"address","name":"frontend_","type":"address"},{"internalType":"address","name":"storage_","type":"address"},{"internalType":"address","name":"validator_","type":"address"},{"internalType":"bytes3","name":"ticker_","type":"bytes3"},{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"system_","type":"address"},{"internalType":"address","name":"admin_","type":"address"},{"internalType":"uint256","name":"maxMintAllowance_","type":"uint256"}],"name":"launch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"oldControllerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_controller","type":"address"},{"internalType":"address","name":"_oldController","type":"address"},{"internalType":"address","name":"_frontend","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"revertToLastController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b50600380546001600160a01b03191633179055614c55806100326000396000f3fe60806040523480156200001157600080fd5b50600436106200006a5760003560e01c8063027798d8146200006f5780630bace4ce14620000885780633941456c146200009f5780634b24ea4714620000cf5780639c130c0514620000e3578063f2fde38b14620000f7575b600080fd5b620000866200008036600462000ad0565b6200010e565b005b620000866200009936600462000b90565b62000645565b600254620000b3906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b600054620000b3906001600160a01b031681565b600154620000b3906001600160a01b031681565b620000866200010836600462000bed565b620008fd565b6003546001600160a01b03163314620001825760405162461bcd60e51b815260206004820152602b60248201527f55706772616465436f6e74726f6c6c65723a204f6e6c79206465706c6f79657260448201526a040c6c2dc40d8c2eadcc6d60ab1b60648201526084015b60405180910390fd5b600180546001600160a01b03808c166001600160a01b0319928316811790935560028054918c16919092168117909155604080516309ce3c1960e31b815290518391634e71e0c891600480830192600092919082900301818387803b158015620001eb57600080fd5b505af115801562000200573d6000803e3d6000fd5b50505050806001600160a01b0316634e71e0c86040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156200024057600080fd5b505af115801562000255573d6000803e3d6000fd5b505050506000898989600260009054906101000a90046001600160a01b0316604051620002829062000aa5565b6001600160a01b03948516815292841660208401526001600160e81b03199091166040830152919091166060820152608001604051809103906000f080158015620002d1573d6000803e3d6000fd5b50600080546001600160a01b0319166001600160a01b0383811691821790925560405163ee0b544560e01b8152600481019190915291925084169063ee0b544590602401600060405180830381600087803b1580156200033057600080fd5b505af115801562000345573d6000803e3d6000fd5b50505050806001600160a01b031663b516af706040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156200038557600080fd5b505af11580156200039a573d6000803e3d6000fd5b5050604051630a84c56d60e41b81526001600160a01b0389811660048301528416925063a84c56d09150602401600060405180830381600087803b158015620003e257600080fd5b505af1158015620003f7573d6000803e3d6000fd5b50506040516327f2bf3d60e11b81526001600160a01b03888116600483015284169250634fe57e7a9150602401600060405180830381600087803b1580156200043f57600080fd5b505af115801562000454573d6000803e3d6000fd5b505050506000841115620004bf57604051633f48c67160e21b8152600481018590526001600160a01b0382169063fd2319c490602401600060405180830381600087803b158015620004a557600080fd5b505af1158015620004ba573d6000803e3d6000fd5b505050505b6000546040516392eefe9b60e01b81526001600160a01b039182166004820152908316906392eefe9b90602401600060405180830381600087803b1580156200050757600080fd5b505af11580156200051c573d6000803e3d6000fd5b505060405163f2fde38b60e01b81526001600160a01b038a811660048301528416925063f2fde38b9150602401600060405180830381600087803b1580156200056457600080fd5b505af115801562000579573d6000803e3d6000fd5b505060405163f2fde38b60e01b81526001600160a01b038a811660048301528516925063f2fde38b9150602401600060405180830381600087803b158015620005c157600080fd5b505af1158015620005d6573d6000803e3d6000fd5b505060405163f2fde38b60e01b81526001600160a01b038a811660048301528616925063f2fde38b9150602401600060405180830381600087803b1580156200061e57600080fd5b505af115801562000633573d6000803e3d6000fd5b50505050505050505050505050505050565b6003546001600160a01b03163314620006c75760405162461bcd60e51b815260206004820152603d60248201527f55706772616465436f6e74726f6c6c65723a204f6e6c79206465706c6f79657260448201527f2063616e2072657665727420746f204c617374436f6e74726f6c6c6572000000606482015260840162000179565b60405163ee0b544560e01b81526001600160a01b0380861660048301528591859185919083169063ee0b544590602401600060405180830381600087803b1580156200071257600080fd5b505af115801562000727573d6000803e3d6000fd5b50505050826001600160a01b031663b516af706040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156200076757600080fd5b505af11580156200077c573d6000803e3d6000fd5b50506040516392eefe9b60e01b81526001600160a01b038a81166004830152841692506392eefe9b9150602401600060405180830381600087803b158015620007c457600080fd5b505af1158015620007d9573d6000803e3d6000fd5b505060405163f2fde38b60e01b81526001600160a01b0387811660048301528616925063f2fde38b9150602401600060405180830381600087803b1580156200082157600080fd5b505af115801562000836573d6000803e3d6000fd5b505060405163f2fde38b60e01b81526001600160a01b0387811660048301528416925063f2fde38b9150602401600060405180830381600087803b1580156200087e57600080fd5b505af115801562000893573d6000803e3d6000fd5b505060405163f2fde38b60e01b81526001600160a01b0387811660048301528516925063f2fde38b9150602401600060405180830381600087803b158015620008db57600080fd5b505af1158015620008f0573d6000803e3d6000fd5b5050505050505050505050565b6003546001600160a01b031633146200097f5760405162461bcd60e51b815260206004820152603760248201527f55706772616465436f6e74726f6c6c65723a204f6e6c79206465706c6f79657260448201527f2063616e207472616e73666572206f776e657273686970000000000000000000606482015260840162000179565b60005460405163f2fde38b60e01b81526001600160a01b0383811660048301529091169063f2fde38b90602401600060405180830381600087803b158015620009c757600080fd5b505af1158015620009dc573d6000803e3d6000fd5b505060025460405163f2fde38b60e01b81526001600160a01b038581166004830152909116925063f2fde38b9150602401600060405180830381600087803b15801562000a2857600080fd5b505af115801562000a3d573d6000803e3d6000fd5b505060015460405163f2fde38b60e01b81526001600160a01b038581166004830152909116925063f2fde38b9150602401600060405180830381600087803b15801562000a8957600080fd5b505af115801562000a9e573d6000803e3d6000fd5b5050505050565b61400d8062000c1383390190565b80356001600160a01b038116811462000acb57600080fd5b919050565b60008060008060008060008060006101208a8c03121562000af057600080fd5b62000afb8a62000ab3565b985062000b0b60208b0162000ab3565b975062000b1b60408b0162000ab3565b965062000b2b60608b0162000ab3565b955060808a01356001600160e81b03198116811462000b4957600080fd5b945062000b5960a08b0162000ab3565b935062000b6960c08b0162000ab3565b925062000b7960e08b0162000ab3565b91506101008a013590509295985092959850929598565b6000806000806080858703121562000ba757600080fd5b62000bb28562000ab3565b935062000bc26020860162000ab3565b925062000bd26040860162000ab3565b915062000be26060860162000ab3565b905092959194509250565b60006020828403121562000c0057600080fd5b62000c0b8262000ab3565b939250505056fe60c06040526006805460ff191660121790553480156200001e57600080fd5b506040516200400d3803806200400d83398101604081905262000041916200049b565b600180546001600160a01b031916331790556002805460ff60a01b19169055836000828282826001600160a01b03831615806200007c575081155b620000f45760405162461bcd60e51b815260206004820152603f60248201527f656974686572206120746f6b656e2073746f72616765206d757374206265206960448201527f6e697469616c697a6564206f72206e6f20696e697469616c20737570706c790060648201526084015b60405180910390fd5b6001600160a01b038316620001ab57604051620001119062000470565b604051809103906000f0801580156200012e573d6000803e3d6000fd5b50600380546001600160a01b0319166001600160a01b039290921691821790556040516310f29c1d60e11b8152336004820152602481018490526321e5383a90604401600060405180830381600087803b1580156200018c57600080fd5b505af1158015620001a1573d6000803e3d6000fd5b50505050620001c7565b600380546001600160a01b0319166001600160a01b0385161790555b600480546001600160a01b0319166001600160a01b03831617905546608052620002af604080518082018252601281527139ba30b73230b93221b7b73a3937b63632b960711b60209182015281517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818301527fe5448f65bca72ba1b802be60235c06fea7a9898bd3b218fd4783069ca85a96e4818401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a0808301919091528351808303909101815260c0909101909252815191012090565b60a05250620002c491506000905033620003c0565b5050506001600160a01b0383166200032b5760405162461bcd60e51b8152602060048201526024808201527f76616c696461746f722063616e6e6f7420626520746865206e756c6c206164646044820152637265737360e01b6064820152608401620000eb565b60405163ad41534960e01b8152600a60048201526001600160a01b0384166024820152736a2f117b2e35e59ee35022186ae6b365dcab84ad9063ad4153499060440160006040518083038186803b1580156200038657600080fd5b505af41580156200039b573d6000803e3d6000fd5b5050600b805462ffffff191660e89590951c9490941790935550620005079350505050565b620003cc8282620003d0565b5050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16620003cc576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556200042c3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b61096780620036a683390190565b80516001600160a01b03811681146200049657600080fd5b919050565b60008060008060808587031215620004b257600080fd5b620004bd856200047e565b9350620004cd602086016200047e565b60408601519093506001600160e81b031981168114620004ec57600080fd5b9150620004fc606086016200047e565b905092959194509250565b60805160a0516131796200052d6000396000610e0201526000610d1401526131796000f3fe608060405234801561001057600080fd5b506004361061035c5760003560e01c806375071d2a116101d3578063a84c56d011610104578063e974fee9116100a2578063ef31f7aa1161007c578063ef31f7aa1461073e578063f27c5f6e14610751578063f2fde38b14610764578063fd2319c41461077757600080fd5b8063e974fee914610705578063ebbc3d4614610718578063ee0b54451461072b57600080fd5b8063d547741f116100de578063d547741f146106b9578063dd62ed3e146106cc578063e174fd94146106df578063e30c3978146106f257600080fd5b8063a84c56d01461068b578063b516af701461069e578063d505accf146106a657600080fd5b80638da5cb5b1161017157806391d148541161014b57806391d148541461065d5780639e7f43ca146106705780639ea33e1914610683578063a217fddf1461043d57600080fd5b80638da5cb5b146106245780638fb81d98146106375780639137c1a71461064a57600080fd5b80637ecebe00116101ad5780637ecebe00146105c3578063802d441f146105e35780638456cb59146105f65780638ba47bdd146105fe57600080fd5b806375071d2a1461058657806375b238fc1461059b578063774d5409146105b057600080fd5b8063329e0587116102ad5780634e71e0c81161024b5780635c975abb116102255780635c975abb1461053b57806367a89a721461054d57806369569a511461056057806370a082311461057357600080fd5b80634e71e0c81461050d5780634eb00754146105155780634fe57e7a1461052857600080fd5b806336568abe1161028757806336568abe146104b65780633cd1570f146104c95780633f4ba83a146104dc5780634a36703b146104e457600080fd5b8063329e05871461048a5780633408f73a1461049d5780633644e515146104ae57600080fd5b806325ec2eb01161031a5780632ff2e9dc116102f45780632ff2e9dc1461043d578063313ce56714610445578063322ec0fb14610464578063326ecb051461047757600080fd5b806325ec2eb0146104045780632c19e8b5146104175780632f2ff15d1461042a57600080fd5b80623074ff1461036157806301ffc9a71461038b5780631195e07e146103ae5780631327d3d8146103b657806318160ddd146103cb578063248a9ca3146103e1575b600080fd5b6004546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b61039e61039936600461292b565b61078a565b6040519015158152602001610382565b61036e6107c1565b6103c96103c436600461296a565b61083d565b005b6103d36108c9565b604051908152602001610382565b6103d36103ef366004612987565b60009081526020819052604090206001015490565b61039e61041236600461296a565b610937565b6103d36104253660046129a0565b610970565b6103c96104383660046129f1565b610a34565b6103d3600081565b6006546104529060ff1681565b60405160ff9091168152602001610382565b61039e610472366004612a21565b610a5f565b61039e61048536600461296a565b610cdc565b61039e61049836600461296a565b610cf6565b6003546001600160a01b031661036e565b6103d3610d10565b6103c96104c43660046129f1565b610e24565b6103d36104d7366004612a78565b610ea2565b6103c9610fd9565b6103d36104f236600461296a565b6001600160a01b031660009081526008602052604090205490565b6103c9610ffa565b61039e610523366004612aef565b61108f565b6103c961053636600461296a565b61111b565b600254600160a01b900460ff1661039e565b6103c961055b36600461296a565b611181565b6103c961056e36600461296a565b6111e7565b6103d361058136600461296a565b61125a565b6103d360008051602061310483398151915281565b6103d360008051602061312483398151915281565b61039e6105be366004612a21565b6112c9565b6103d36105d136600461296a565b60076020526000908152604090205481565b6103c96105f136600461296a565b61136e565b6103c96113ce565b600b5461060b9060e81b81565b6040516001600160e81b03199091168152602001610382565b60015461036e906001600160a01b031681565b6103c9610645366004612b8a565b6113ed565b6103c961065836600461296a565b611477565b61039e61066b3660046129f1565b6114ea565b61039e61067e366004612bdf565b611513565b6009546103d3565b6103c961069936600461296a565b61163f565b6103c96116a5565b6103c96106b4366004612aef565b611726565b6103c96106c73660046129f1565b611995565b6103d36106da366004612c52565b6119bb565b61039e6106ed366004612a21565b611a55565b60025461036e906001600160a01b031681565b61039e610713366004612c80565b611b6b565b6103c961072636600461296a565b611c8b565b6103c961073936600461296a565b611cf1565b61039e61074c366004612ce7565b611d63565b6103c961075f366004612dbe565b611fa6565b6103c961077236600461296a565b6120ee565b6103c9610785366004612987565b612161565b60006001600160e01b03198216637965db0b60e01b14806107bb57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60405163189c65c360e21b8152600a6004820152600090736a2f117b2e35e59ee35022186ae6b365dcab84ad90636271970c90602401602060405180830381865af4158015610814573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108389190612dea565b905090565b6001546001600160a01b0316331461085457600080fd5b60405163ad41534960e01b8152600a60048201526001600160a01b0382166024820152736a2f117b2e35e59ee35022186ae6b365dcab84ad9063ad4153499060440160006040518083038186803b1580156108ae57600080fd5b505af41580156108c2573d6000803e3d6000fd5b5050505050565b60035460408051636c9c2faf60e01b815290516000926001600160a01b031691636c9c2faf9160048083019260209291908290030181865afa158015610913573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108389190612e07565b6004546000906001600160a01b03838116911614806107bb5750506001600160a01b031660009081526005602052604090205460ff1690565b600061097a610d10565b604080517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c960208201526001600160a01b03808a169282019290925290871660608201526080810186905260a0810185905260c0810184905260e00160405160208183030381529060405280519060200120604051602001610a1392919061190160f01b81526002810192909252602282015260420190565b60405160208183030381529060405280519060200120905095945050505050565b600082815260208190526040902060010154610a5081336121b0565b610a5a8383612214565b505050565b6000610a6a33610937565b610a7357600080fd5b8382610a8d600080516020613104833981519152836114ea565b610af95760405162461bcd60e51b815260206004820152603260248201527f4d696e7461626c65436f6e74726f6c6c65723a2063616c6c6572206973206e6f6044820152711d0818481cde5cdd195b481858d8dbdd5b9d60721b60648201526084015b60405180910390fd5b6001600160a01b038216600090815260086020526040902054811115610b89576040805162461bcd60e51b81526020600482015260248101919091527f4d696e7461626c65436f6e74726f6c6c65723a2063616c6c6572206973206e6f60448201527f7420616c6c6f77656420746f20706572666f726d207468697320616374696f6e6064820152608401610af0565b600254600160a01b900460ff1615610bb35760405162461bcd60e51b8152600401610af090612e20565b610bbc85612298565b6001600160a01b038616600090815260086020526040902054610be0908590612e60565b6001600160a01b0387811660009081526008602052604090819020929092556003549151632c30a71d60e21b815291811660048301528616602482015260448101859052730fc041a4b6a3f634445804daafd03f202337c1259063b0c29c7490606401602060405180830381865af4158015610c60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c849190612e77565b610cd05760405162461bcd60e51b815260206004820152601f60248201527f4d696e7461626c65436f6e74726f6c6c65723a206d696e74206661696c6564006044820152606401610af0565b50600195945050505050565b60006107bb600080516020613104833981519152836114ea565b60006107bb600080516020613124833981519152836114ea565b60007f00000000000000000000000000000000000000000000000000000000000000004614610dff5750604080518082018252601281527139ba30b73230b93221b7b73a3937b63632b960711b60209182015281517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818301527fe5448f65bca72ba1b802be60235c06fea7a9898bd3b218fd4783069ca85a96e4818401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a0808301919091528351808303909101815260c0909101909252815191012090565b507f000000000000000000000000000000000000000000000000000000000000000090565b6001600160a01b0381163314610e945760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610af0565b610e9e8282612453565b5050565b6000610ead33610937565b610eb657600080fd5b87610ecf600080516020613104833981519152826114ea565b610eeb5760405162461bcd60e51b8152600401610af090612e99565b600254600160a01b900460ff1615610f155760405162461bcd60e51b8152600401610af090612e20565b610f1e87612298565b6003546040516323dc89cd60e21b81526001600160a01b039182166004820152898216602482015290881660448201526064810187905260ff8616608482015260a4810185905260c48101849052736a2f117b2e35e59ee35022186ae6b365dcab84ad90638f7227349060e401602060405180830381865af4158015610fa8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fcc9190612e07565b9998505050505050505050565b6001546001600160a01b03163314610ff057600080fd5b610ff86124b8565b565b6002546001600160a01b0316331461101157600080fd5b6002546001546040516001600160a01b0392831692909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600254600180546001600160a01b0319166001600160a01b03909216918217905561107d90600090612555565b600280546001600160a01b0319169055565b600061109a33610937565b6110a357600080fd5b6001600160a01b038816301461110d5760405162461bcd60e51b815260206004820152602960248201527f6f6e6c7920616c6c6f77207468697320636f6e747261637420746f206265207460448201526834329031b0b63632b960b91b6064820152608401610af0565b506001979650505050505050565b6001546001600160a01b0316331461113257600080fd5b61114a60008051602061312483398151915282610a34565b6040516001600160a01b038216907f5c7eb798b922f0164aa9c5340006161c64436190a49eebc58b4e6e0715700ae690600090a250565b6001546001600160a01b0316331461119857600080fd5b6111b060008051602061312483398151915282611995565b6040516001600160a01b038216907fc3198db98a2c50068f0a99b9297e60b2dbf0eafcde57e366e70a29f887c44e1090600090a250565b6001546001600160a01b031633146111fe57600080fd5b6004546040516001600160a01b038084169216907fcb01f884fc4203d4c1643cb0e126faeb397682c122ca8c0433776d42cdc0060a90600090a3600480546001600160a01b0319166001600160a01b0392909216919091179055565b60035460405163f8b2cb4f60e01b81526001600160a01b038381166004830152600092169063f8b2cb4f90602401602060405180830381865afa1580156112a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107bb9190612e07565b60006112d433610937565b6112dd57600080fd5b60035460405163365feff160e01b8152730c06ccf38114ddfc35e07427b9424adcca9f44f89163365feff191611325916001600160a01b031690889088908890600401612ee3565b602060405180830381865af4158015611342573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113669190612e77565b949350505050565b6001546001600160a01b0316331461138557600080fd5b6001600160a01b038116600081815260056020526040808220805460ff19169055517f10cf5a523a14a54e61c21610dc10c01e40e2ebc37baa3effd74032f7d3865e6d9190a250565b6001546001600160a01b031633146113e557600080fd5b610ff861255f565b6001546001600160a01b0316331461140457600080fd5b6001600160a01b03831660009081526005602052604090819020805460ff19166001179055516114379083908390612f0d565b604051908190038120906001600160a01b038516907fec75908259de4d038ff5f2b6b99e3725bc21871f4d2a44adeff9bb814afbc9f790600090a3505050565b6001546001600160a01b0316331461148e57600080fd5b6003546040516001600160a01b038084169216907fdaaa9d417a3107fd3d9db02eba3eeafbae2b8af16ee08c534f5bc449054c1c4c90600090a3600380546001600160a01b0319166001600160a01b0392909216919091179055565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b600254600090600160a01b900460ff16156115405760405162461bcd60e51b8152600401610af090612e20565b6040516332c5a6eb60e01b8152600a60048201526001600160a01b0380881660248301528616604482015260648101859052736a2f117b2e35e59ee35022186ae6b365dcab84ad906332c5a6eb90608401602060405180830381865af41580156115ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115d29190612e77565b6116285760405162461bcd60e51b815260206004820152602160248201527f7472616e73666572416e6443616c6c2072657175657374206e6f742076616c696044820152601960fa1b6064820152608401610af0565b61163586868686866125c4565b9695505050505050565b6001546001600160a01b0316331461165657600080fd5b61166e60008051602061310483398151915282610a34565b6040516001600160a01b038216907fdfb5b1167ef9eadf5cac67570f1a2971a6f6175303b9d4166a65a11d0a294e3490600090a250565b6001546001600160a01b031633146116bc57600080fd5b600360009054906101000a90046001600160a01b03166001600160a01b0316634e71e0c86040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561170c57600080fd5b505af1158015611720573d6000803e3d6000fd5b50505050565b428410156117765760405162461bcd60e51b815260206004820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152606401610af0565b60006001611782610d10565b6001600160a01b038a811660008181526007602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa15801561188e573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906118c45750876001600160a01b0316816001600160a01b0316145b6119015760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a4a3a722a960911b6044820152606401610af0565b5060035460405163365feff160e01b8152730c06ccf38114ddfc35e07427b9424adcca9f44f89163365feff19161194a916001600160a01b0316908b908b908b90600401612ee3565b602060405180830381865af4158015611967573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061198b9190612e77565b5050505050505050565b6000828152602081905260409020600101546119b181336121b0565b610a5a8383612453565b600354604051630822ebe760e11b81526001600160a01b03918216600482015283821660248201529082166044820152600090730c06ccf38114ddfc35e07427b9424adcca9f44f890631045d7ce90606401602060405180830381865af4158015611a2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4e9190612e07565b9392505050565b600254600090600160a01b900460ff1615611a825760405162461bcd60e51b8152600401610af090612e20565b6040516332c5a6eb60e01b8152600a60048201526001600160a01b0380861660248301528416604482015260648101839052736a2f117b2e35e59ee35022186ae6b365dcab84ad906332c5a6eb90608401602060405180830381865af4158015611af0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b149190612e77565b611b605760405162461bcd60e51b815260206004820152601a60248201527f7472616e736665722072657175657374206e6f742076616c69640000000000006044820152606401610af0565b61136684848461266e565b600254600090600160a01b900460ff1615611b985760405162461bcd60e51b8152600401610af090612e20565b6040516332c5a6eb60e01b8152600a60048201526001600160a01b0380861660248301528416604482015260648101839052736a2f117b2e35e59ee35022186ae6b365dcab84ad906332c5a6eb90608401602060405180830381865af4158015611c06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2a9190612e77565b611c765760405162461bcd60e51b815260206004820152601e60248201527f7472616e7366657246726f6d2072657175657374206e6f742076616c696400006044820152606401610af0565b611c82858585856126d3565b95945050505050565b6001546001600160a01b03163314611ca257600080fd5b611cba60008051602061310483398151915282611995565b6040516001600160a01b038216907f21bfb3de07221bc6197a8c23f7a059308b7a741f259cf4ef3b519cde0fde7ac390600090a250565b6001546001600160a01b03163314611d0857600080fd5b60035460405163f2fde38b60e01b81526001600160a01b0383811660048301529091169063f2fde38b90602401600060405180830381600087803b158015611d4f57600080fd5b505af11580156108c2573d6000803e3d6000fd5b600033611d7e600080516020613104833981519152826114ea565b611d9a5760405162461bcd60e51b8152600401610af090612e99565b600254600160a01b900460ff1615611dc45760405162461bcd60e51b8152600401610af090612e20565b60035460405163c5d5b08960e01b8152730fc041a4b6a3f634445804daafd03f202337c1259163c5d5b08991611e0e916001600160a01b0316908a908a908a908a90600401612f75565b602060405180830381865af4158015611e2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e4f9190612e77565b611e9b5760405162461bcd60e51b815260206004820152601f60248201527f4d696e7461626c65436f6e74726f6c6c65723a206275726e206661696c6564006044820152606401610af0565b60048054604051630e08f2bb60e21b81526001600160a01b038981169382019390935260248101889052604481018790526000606482018190526084820181905260a48201529116908190633823caec9060c4016020604051808303816000875af1158015611f0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f329190612e77565b611f995760405162461bcd60e51b815260206004820152603260248201527f4d696e7461626c65436f6e74726f6c6c65723a20546f6b656e46726f6e74656e6044820152711908189d5c9b8818d85b1b0819985a5b195960721b6064820152608401610af0565b5060019695505050505050565b611fbe600080516020613124833981519152336114ea565b61201d5760405162461bcd60e51b815260206004820152602a60248201527f53797374656d526f6c653a2063616c6c6572206973206e6f7420616e2061646d6044820152691a5b881858d8dbdd5b9d60b21b6064820152608401610af0565b6009548111156120955760405162461bcd60e51b815260206004820152603d60248201527f4d696e7461626c65436f6e74726f6c6c65723a20616c6c6f77616e636520657860448201527f6365656473206d6178696d756d20736574746564206279206f776e65720000006064820152608401610af0565b6001600160a01b03821660008181526008602052604090819020839055517f8fe74a1bbab5a9534a04463cd7b9423b985ed316426821cace8ed4aeac5a4d14906120e29084815260200190565b60405180910390a25050565b6001546001600160a01b0316331461210557600080fd5b6002546040516001600160a01b038084169216907f8573d4aae9f7fb051c6b88d7440011a1c12376acda6603a45f45bad36a8db4ce90600090a3600280546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b0316331461217857600080fd5b6040518181527f34affbf2a21d1f1d12e5e49bdca58fb75dba6879f5430f2fbf5c1d07476018d29060200160405180910390a1600955565b6121ba82826114ea565b610e9e576121d2816001600160a01b0316601461278f565b6121dd83602061278f565b6040516020016121ee929190612fba565b60408051601f198184030181529082905262461bcd60e51b8252610af09160040161302f565b61221e82826114ea565b610e9e576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556122543390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6001600160a01b0381166122e55760405162461bcd60e51b815260206004820152601460248201527306d757374206e6f742073656e6420746f203078360641b6044820152606401610af0565b6001600160a01b03811630141561233e5760405162461bcd60e51b815260206004820152601b60248201527f6d757374206e6f742073656e6420746f20636f6e74726f6c6c657200000000006044820152606401610af0565b6003546001600160a01b038281169116141561239c5760405162461bcd60e51b815260206004820152601e60248201527f6d757374206e6f742073656e6420746f20746f6b656e2073746f7261676500006044820152606401610af0565b6004546001600160a01b03828116911614156123fa5760405162461bcd60e51b815260206004820152601960248201527f6d757374206e6f742073656e6420746f2066726f6e74656e64000000000000006044820152606401610af0565b61240381610937565b156124505760405162461bcd60e51b815260206004820181905260248201527f6d757374206e6f742073656e6420746f2062726964676546726f6e74656e64736044820152606401610af0565b50565b61245d82826114ea565b15610e9e576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600254600160a01b900460ff166125085760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610af0565b6002805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b610e9e8282612214565b600254600160a01b900460ff16156125895760405162461bcd60e51b8152600401610af090612e20565b6002805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586125383390565b60006125cf33610937565b6125d857600080fd5b6125e185612298565b600354604051631eb8bccb60e01b8152732d80dbf04d0802abd7a342dafa5d7cb42bfbb52f91631eb8bccb9161262d916001600160a01b0316908a908a908a908a908a90600401613042565b602060405180830381865af415801561264a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116359190612e77565b600061267933610937565b61268257600080fd5b61268b83612298565b60035460405163226f6c5d60e11b8152730c06ccf38114ddfc35e07427b9424adcca9f44f8916344ded8ba91611325916001600160a01b031690889088908890600401612ee3565b60006126de33610937565b6126e757600080fd5b6126f083612298565b60035460405163f3a0ddf960e01b81526001600160a01b03918216600482015286821660248201528582166044820152908416606482015260848101839052730c06ccf38114ddfc35e07427b9424adcca9f44f89063f3a0ddf99060a401602060405180830381865af415801561276b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c829190612e77565b6060600061279e83600261309f565b6127a99060026130be565b67ffffffffffffffff8111156127c1576127c1612cd1565b6040519080825280601f01601f1916602001820160405280156127eb576020820181803683370190505b509050600360fc1b81600081518110612806576128066130d6565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110612835576128356130d6565b60200101906001600160f81b031916908160001a905350600061285984600261309f565b6128649060016130be565b90505b60018111156128dc576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110612898576128986130d6565b1a60f81b8282815181106128ae576128ae6130d6565b60200101906001600160f81b031916908160001a90535060049490941c936128d5816130ec565b9050612867565b508315611a4e5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610af0565b60006020828403121561293d57600080fd5b81356001600160e01b031981168114611a4e57600080fd5b6001600160a01b038116811461245057600080fd5b60006020828403121561297c57600080fd5b8135611a4e81612955565b60006020828403121561299957600080fd5b5035919050565b600080600080600060a086880312156129b857600080fd5b85356129c381612955565b945060208601356129d381612955565b94979496505050506040830135926060810135926080909101359150565b60008060408385031215612a0457600080fd5b823591506020830135612a1681612955565b809150509250929050565b600080600060608486031215612a3657600080fd5b8335612a4181612955565b92506020840135612a5181612955565b929592945050506040919091013590565b803560ff81168114612a7357600080fd5b919050565b600080600080600080600060e0888a031215612a9357600080fd5b8735612a9e81612955565b96506020880135612aae81612955565b95506040880135612abe81612955565b945060608801359350612ad360808901612a62565b925060a0880135915060c0880135905092959891949750929550565b600080600080600080600060e0888a031215612b0a57600080fd5b8735612b1581612955565b96506020880135612b2581612955565b95506040880135945060608801359350612ad360808901612a62565b60008083601f840112612b5357600080fd5b50813567ffffffffffffffff811115612b6b57600080fd5b602083019150836020828501011115612b8357600080fd5b9250929050565b600080600060408486031215612b9f57600080fd5b8335612baa81612955565b9250602084013567ffffffffffffffff811115612bc657600080fd5b612bd286828701612b41565b9497909650939450505050565b600080600080600060808688031215612bf757600080fd5b8535612c0281612955565b94506020860135612c1281612955565b935060408601359250606086013567ffffffffffffffff811115612c3557600080fd5b612c4188828901612b41565b969995985093965092949392505050565b60008060408385031215612c6557600080fd5b8235612c7081612955565b91506020830135612a1681612955565b60008060008060808587031215612c9657600080fd5b8435612ca181612955565b93506020850135612cb181612955565b92506040850135612cc181612955565b9396929550929360600135925050565b634e487b7160e01b600052604160045260246000fd5b60008060008060808587031215612cfd57600080fd5b8435612d0881612955565b93506020850135925060408501359150606085013567ffffffffffffffff80821115612d3357600080fd5b818701915087601f830112612d4757600080fd5b813581811115612d5957612d59612cd1565b604051601f8201601f19908116603f01168101908382118183101715612d8157612d81612cd1565b816040528281528a6020848701011115612d9a57600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b60008060408385031215612dd157600080fd5b8235612ddc81612955565b946020939093013593505050565b600060208284031215612dfc57600080fd5b8151611a4e81612955565b600060208284031215612e1957600080fd5b5051919050565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b600082821015612e7257612e72612e4a565b500390565b600060208284031215612e8957600080fd5b81518015158114611a4e57600080fd5b6020808252602a908201527f53797374656d526f6c653a2063616c6c6572206973206e6f7420612073797374604082015269195b481858d8dbdd5b9d60b21b606082015260800190565b6001600160a01b039485168152928416602084015292166040820152606081019190915260800190565b8183823760009101908152919050565b60005b83811015612f38578181015183820152602001612f20565b838111156117205750506000910152565b60008151808452612f61816020860160208601612f1d565b601f01601f19169290920160200192915050565b6001600160a01b03868116825285166020820152604081018490526060810183905260a060808201819052600090612faf90830184612f49565b979650505050505050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351612ff2816017850160208801612f1d565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351613023816028840160208801612f1d565b01602801949350505050565b602081526000611a4e6020830184612f49565b6001600160a01b0387811682528681166020830152851660408201526060810184905260a06080820181905281018290526000828460c0840137600060c0848401015260c0601f19601f8501168301019050979650505050505050565b60008160001904831182151516156130b9576130b9612e4a565b500290565b600082198211156130d1576130d1612e4a565b500190565b634e487b7160e01b600052603260045260246000fd5b6000816130fb576130fb612e4a565b50600019019056fe5719df9ef2c4678b547f89e4f5ae410dbf400fc51cf3ded434c55f6adea2c43fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775a2646970667358221220ac8334c970a8c49b9b6cda46ecf7729d760f98b7a57ff0a42dc1fa92a8e5b89164736f6c634300080b0033608060405234801561001057600080fd5b50600080546001600160a01b03191633179055341561002e57600080fd5b61092a8061003d6000396000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c80638da5cb5b11610086578063cf8eeb7e11610063578063cf8eeb7e14610180578063e30c397814610193578063f2fde38b146101a6578063f8b2cb4f146101b957005b80638da5cb5b1461013a5780639f727c2714610165578063c7c7e9ea1461016d57005b806317ffc320146100cb57806321e5383a146100de5780632aed7f3f146100f157806333dd1b8a146101045780634e71e0c8146101175780636c9c2faf1461011f575b005b6100c96100d93660046107f6565b6101cc565b6100c96100ec366004610813565b61026f565b6100c96100ff3660046107f6565b610304565b6100c961011236600461083f565b610377565b6100c9610414565b61012761048f565b6040519081526020015b60405180910390f35b60005461014d906001600160a01b031681565b6040516001600160a01b039091168152602001610131565b6100c961050a565b61012761017b366004610880565b61055e565b6100c961018e366004610813565b6105f3565b60015461014d906001600160a01b031681565b6100c96101b43660046107f6565b610658565b6101276101c73660046107f6565b610661565b6000546001600160a01b031633146101e357600080fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa15801561022a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061024e91906108b9565b60005490915061026b906001600160a01b038481169116836106ed565b5050565b6000546001600160a01b0316331461028657600080fd5b604051637aeb0ed560e01b8152600260048201526001600160a01b03831660248201526044810182905273ddfe2c5f94909420cf55827fffa09a7ff9b2ab7790637aeb0ed5906064015b60006040518083038186803b1580156102e857600080fd5b505af41580156102fc573d6000803e3d6000fd5b505050505050565b6000546001600160a01b0316331461031b57600080fd5b60005460405163f2fde38b60e01b81526001600160a01b039182166004820152829182169063f2fde38b90602401600060405180830381600087803b15801561036357600080fd5b505af11580156102fc573d6000803e3d6000fd5b6000546001600160a01b0316331461038e57600080fd5b604051635599b4b760e01b8152600260048201526001600160a01b038085166024830152831660448201526064810182905273ddfe2c5f94909420cf55827fffa09a7ff9b2ab7790635599b4b79060840160006040518083038186803b1580156103f757600080fd5b505af415801561040b573d6000803e3d6000fd5b50505050505050565b6001546001600160a01b0316331461042b57600080fd5b600154600080546040516001600160a01b0393841693909116917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a360018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6040516272f9a560e41b81526002600482015260009073ddfe2c5f94909420cf55827fffa09a7ff9b2ab779063072f9a5090602401602060405180830381865af41580156104e1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050591906108b9565b905090565b6000546001600160a01b0316331461052157600080fd5b600080546040516001600160a01b03909116914780156108fc02929091818181858888f1935050505015801561055b573d6000803e3d6000fd5b50565b604051634ed7570f60e11b8152600260048201526001600160a01b0380841660248301528216604482015260009073ddfe2c5f94909420cf55827fffa09a7ff9b2ab7790639daeae1e90606401602060405180830381865af41580156105c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ec91906108b9565b9392505050565b6000546001600160a01b0316331461060a57600080fd5b604051636ce399cf60e11b8152600260048201526001600160a01b03831660248201526044810182905273ddfe2c5f94909420cf55827fffa09a7ff9b2ab779063d9c7339e906064016102d0565b61055b8161076e565b604051632c2ab3c960e21b8152600260048201526001600160a01b038216602482015260009073ddfe2c5f94909420cf55827fffa09a7ff9b2ab779063b0aacf2490604401602060405180830381865af41580156106c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106e791906108b9565b92915050565b60405163a9059cbb60e01b81526001600160a01b0383811660048301526024820183905284169063a9059cbb906044016020604051808303816000875af115801561073c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061076091906108d2565b61076957600080fd5b505050565b6000546001600160a01b0316331461078557600080fd5b6001546040516001600160a01b038084169216907f8573d4aae9f7fb051c6b88d7440011a1c12376acda6603a45f45bad36a8db4ce90600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b038116811461055b57600080fd5b60006020828403121561080857600080fd5b81356105ec816107e1565b6000806040838503121561082657600080fd5b8235610831816107e1565b946020939093013593505050565b60008060006060848603121561085457600080fd5b833561085f816107e1565b9250602084013561086f816107e1565b929592945050506040919091013590565b6000806040838503121561089357600080fd5b823561089e816107e1565b915060208301356108ae816107e1565b809150509250929050565b6000602082840312156108cb57600080fd5b5051919050565b6000602082840312156108e457600080fd5b815180151581146105ec57600080fdfea26469706673582212207716b8a5d7375d18127e10682c27c5bcacca02792efc569198f750c8b441c03664736f6c634300080b0033a26469706673582212202d8816f13a4eb98a8109a1b134c07cedc75a954c1771f658206e94743a18786a64736f6c634300080b0033
Deployed Bytecode
0x60806040523480156200001157600080fd5b50600436106200006a5760003560e01c8063027798d8146200006f5780630bace4ce14620000885780633941456c146200009f5780634b24ea4714620000cf5780639c130c0514620000e3578063f2fde38b14620000f7575b600080fd5b620000866200008036600462000ad0565b6200010e565b005b620000866200009936600462000b90565b62000645565b600254620000b3906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b600054620000b3906001600160a01b031681565b600154620000b3906001600160a01b031681565b620000866200010836600462000bed565b620008fd565b6003546001600160a01b03163314620001825760405162461bcd60e51b815260206004820152602b60248201527f55706772616465436f6e74726f6c6c65723a204f6e6c79206465706c6f79657260448201526a040c6c2dc40d8c2eadcc6d60ab1b60648201526084015b60405180910390fd5b600180546001600160a01b03808c166001600160a01b0319928316811790935560028054918c16919092168117909155604080516309ce3c1960e31b815290518391634e71e0c891600480830192600092919082900301818387803b158015620001eb57600080fd5b505af115801562000200573d6000803e3d6000fd5b50505050806001600160a01b0316634e71e0c86040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156200024057600080fd5b505af115801562000255573d6000803e3d6000fd5b505050506000898989600260009054906101000a90046001600160a01b0316604051620002829062000aa5565b6001600160a01b03948516815292841660208401526001600160e81b03199091166040830152919091166060820152608001604051809103906000f080158015620002d1573d6000803e3d6000fd5b50600080546001600160a01b0319166001600160a01b0383811691821790925560405163ee0b544560e01b8152600481019190915291925084169063ee0b544590602401600060405180830381600087803b1580156200033057600080fd5b505af115801562000345573d6000803e3d6000fd5b50505050806001600160a01b031663b516af706040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156200038557600080fd5b505af11580156200039a573d6000803e3d6000fd5b5050604051630a84c56d60e41b81526001600160a01b0389811660048301528416925063a84c56d09150602401600060405180830381600087803b158015620003e257600080fd5b505af1158015620003f7573d6000803e3d6000fd5b50506040516327f2bf3d60e11b81526001600160a01b03888116600483015284169250634fe57e7a9150602401600060405180830381600087803b1580156200043f57600080fd5b505af115801562000454573d6000803e3d6000fd5b505050506000841115620004bf57604051633f48c67160e21b8152600481018590526001600160a01b0382169063fd2319c490602401600060405180830381600087803b158015620004a557600080fd5b505af1158015620004ba573d6000803e3d6000fd5b505050505b6000546040516392eefe9b60e01b81526001600160a01b039182166004820152908316906392eefe9b90602401600060405180830381600087803b1580156200050757600080fd5b505af11580156200051c573d6000803e3d6000fd5b505060405163f2fde38b60e01b81526001600160a01b038a811660048301528416925063f2fde38b9150602401600060405180830381600087803b1580156200056457600080fd5b505af115801562000579573d6000803e3d6000fd5b505060405163f2fde38b60e01b81526001600160a01b038a811660048301528516925063f2fde38b9150602401600060405180830381600087803b158015620005c157600080fd5b505af1158015620005d6573d6000803e3d6000fd5b505060405163f2fde38b60e01b81526001600160a01b038a811660048301528616925063f2fde38b9150602401600060405180830381600087803b1580156200061e57600080fd5b505af115801562000633573d6000803e3d6000fd5b50505050505050505050505050505050565b6003546001600160a01b03163314620006c75760405162461bcd60e51b815260206004820152603d60248201527f55706772616465436f6e74726f6c6c65723a204f6e6c79206465706c6f79657260448201527f2063616e2072657665727420746f204c617374436f6e74726f6c6c6572000000606482015260840162000179565b60405163ee0b544560e01b81526001600160a01b0380861660048301528591859185919083169063ee0b544590602401600060405180830381600087803b1580156200071257600080fd5b505af115801562000727573d6000803e3d6000fd5b50505050826001600160a01b031663b516af706040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156200076757600080fd5b505af11580156200077c573d6000803e3d6000fd5b50506040516392eefe9b60e01b81526001600160a01b038a81166004830152841692506392eefe9b9150602401600060405180830381600087803b158015620007c457600080fd5b505af1158015620007d9573d6000803e3d6000fd5b505060405163f2fde38b60e01b81526001600160a01b0387811660048301528616925063f2fde38b9150602401600060405180830381600087803b1580156200082157600080fd5b505af115801562000836573d6000803e3d6000fd5b505060405163f2fde38b60e01b81526001600160a01b0387811660048301528416925063f2fde38b9150602401600060405180830381600087803b1580156200087e57600080fd5b505af115801562000893573d6000803e3d6000fd5b505060405163f2fde38b60e01b81526001600160a01b0387811660048301528516925063f2fde38b9150602401600060405180830381600087803b158015620008db57600080fd5b505af1158015620008f0573d6000803e3d6000fd5b5050505050505050505050565b6003546001600160a01b031633146200097f5760405162461bcd60e51b815260206004820152603760248201527f55706772616465436f6e74726f6c6c65723a204f6e6c79206465706c6f79657260448201527f2063616e207472616e73666572206f776e657273686970000000000000000000606482015260840162000179565b60005460405163f2fde38b60e01b81526001600160a01b0383811660048301529091169063f2fde38b90602401600060405180830381600087803b158015620009c757600080fd5b505af1158015620009dc573d6000803e3d6000fd5b505060025460405163f2fde38b60e01b81526001600160a01b038581166004830152909116925063f2fde38b9150602401600060405180830381600087803b15801562000a2857600080fd5b505af115801562000a3d573d6000803e3d6000fd5b505060015460405163f2fde38b60e01b81526001600160a01b038581166004830152909116925063f2fde38b9150602401600060405180830381600087803b15801562000a8957600080fd5b505af115801562000a9e573d6000803e3d6000fd5b5050505050565b61400d8062000c1383390190565b80356001600160a01b038116811462000acb57600080fd5b919050565b60008060008060008060008060006101208a8c03121562000af057600080fd5b62000afb8a62000ab3565b985062000b0b60208b0162000ab3565b975062000b1b60408b0162000ab3565b965062000b2b60608b0162000ab3565b955060808a01356001600160e81b03198116811462000b4957600080fd5b945062000b5960a08b0162000ab3565b935062000b6960c08b0162000ab3565b925062000b7960e08b0162000ab3565b91506101008a013590509295985092959850929598565b6000806000806080858703121562000ba757600080fd5b62000bb28562000ab3565b935062000bc26020860162000ab3565b925062000bd26040860162000ab3565b915062000be26060860162000ab3565b905092959194509250565b60006020828403121562000c0057600080fd5b62000c0b8262000ab3565b939250505056fe60c06040526006805460ff191660121790553480156200001e57600080fd5b506040516200400d3803806200400d83398101604081905262000041916200049b565b600180546001600160a01b031916331790556002805460ff60a01b19169055836000828282826001600160a01b03831615806200007c575081155b620000f45760405162461bcd60e51b815260206004820152603f60248201527f656974686572206120746f6b656e2073746f72616765206d757374206265206960448201527f6e697469616c697a6564206f72206e6f20696e697469616c20737570706c790060648201526084015b60405180910390fd5b6001600160a01b038316620001ab57604051620001119062000470565b604051809103906000f0801580156200012e573d6000803e3d6000fd5b50600380546001600160a01b0319166001600160a01b039290921691821790556040516310f29c1d60e11b8152336004820152602481018490526321e5383a90604401600060405180830381600087803b1580156200018c57600080fd5b505af1158015620001a1573d6000803e3d6000fd5b50505050620001c7565b600380546001600160a01b0319166001600160a01b0385161790555b600480546001600160a01b0319166001600160a01b03831617905546608052620002af604080518082018252601281527139ba30b73230b93221b7b73a3937b63632b960711b60209182015281517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818301527fe5448f65bca72ba1b802be60235c06fea7a9898bd3b218fd4783069ca85a96e4818401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a0808301919091528351808303909101815260c0909101909252815191012090565b60a05250620002c491506000905033620003c0565b5050506001600160a01b0383166200032b5760405162461bcd60e51b8152602060048201526024808201527f76616c696461746f722063616e6e6f7420626520746865206e756c6c206164646044820152637265737360e01b6064820152608401620000eb565b60405163ad41534960e01b8152600a60048201526001600160a01b0384166024820152736a2f117b2e35e59ee35022186ae6b365dcab84ad9063ad4153499060440160006040518083038186803b1580156200038657600080fd5b505af41580156200039b573d6000803e3d6000fd5b5050600b805462ffffff191660e89590951c9490941790935550620005079350505050565b620003cc8282620003d0565b5050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16620003cc576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556200042c3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b61096780620036a683390190565b80516001600160a01b03811681146200049657600080fd5b919050565b60008060008060808587031215620004b257600080fd5b620004bd856200047e565b9350620004cd602086016200047e565b60408601519093506001600160e81b031981168114620004ec57600080fd5b9150620004fc606086016200047e565b905092959194509250565b60805160a0516131796200052d6000396000610e0201526000610d1401526131796000f3fe608060405234801561001057600080fd5b506004361061035c5760003560e01c806375071d2a116101d3578063a84c56d011610104578063e974fee9116100a2578063ef31f7aa1161007c578063ef31f7aa1461073e578063f27c5f6e14610751578063f2fde38b14610764578063fd2319c41461077757600080fd5b8063e974fee914610705578063ebbc3d4614610718578063ee0b54451461072b57600080fd5b8063d547741f116100de578063d547741f146106b9578063dd62ed3e146106cc578063e174fd94146106df578063e30c3978146106f257600080fd5b8063a84c56d01461068b578063b516af701461069e578063d505accf146106a657600080fd5b80638da5cb5b1161017157806391d148541161014b57806391d148541461065d5780639e7f43ca146106705780639ea33e1914610683578063a217fddf1461043d57600080fd5b80638da5cb5b146106245780638fb81d98146106375780639137c1a71461064a57600080fd5b80637ecebe00116101ad5780637ecebe00146105c3578063802d441f146105e35780638456cb59146105f65780638ba47bdd146105fe57600080fd5b806375071d2a1461058657806375b238fc1461059b578063774d5409146105b057600080fd5b8063329e0587116102ad5780634e71e0c81161024b5780635c975abb116102255780635c975abb1461053b57806367a89a721461054d57806369569a511461056057806370a082311461057357600080fd5b80634e71e0c81461050d5780634eb00754146105155780634fe57e7a1461052857600080fd5b806336568abe1161028757806336568abe146104b65780633cd1570f146104c95780633f4ba83a146104dc5780634a36703b146104e457600080fd5b8063329e05871461048a5780633408f73a1461049d5780633644e515146104ae57600080fd5b806325ec2eb01161031a5780632ff2e9dc116102f45780632ff2e9dc1461043d578063313ce56714610445578063322ec0fb14610464578063326ecb051461047757600080fd5b806325ec2eb0146104045780632c19e8b5146104175780632f2ff15d1461042a57600080fd5b80623074ff1461036157806301ffc9a71461038b5780631195e07e146103ae5780631327d3d8146103b657806318160ddd146103cb578063248a9ca3146103e1575b600080fd5b6004546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b61039e61039936600461292b565b61078a565b6040519015158152602001610382565b61036e6107c1565b6103c96103c436600461296a565b61083d565b005b6103d36108c9565b604051908152602001610382565b6103d36103ef366004612987565b60009081526020819052604090206001015490565b61039e61041236600461296a565b610937565b6103d36104253660046129a0565b610970565b6103c96104383660046129f1565b610a34565b6103d3600081565b6006546104529060ff1681565b60405160ff9091168152602001610382565b61039e610472366004612a21565b610a5f565b61039e61048536600461296a565b610cdc565b61039e61049836600461296a565b610cf6565b6003546001600160a01b031661036e565b6103d3610d10565b6103c96104c43660046129f1565b610e24565b6103d36104d7366004612a78565b610ea2565b6103c9610fd9565b6103d36104f236600461296a565b6001600160a01b031660009081526008602052604090205490565b6103c9610ffa565b61039e610523366004612aef565b61108f565b6103c961053636600461296a565b61111b565b600254600160a01b900460ff1661039e565b6103c961055b36600461296a565b611181565b6103c961056e36600461296a565b6111e7565b6103d361058136600461296a565b61125a565b6103d360008051602061310483398151915281565b6103d360008051602061312483398151915281565b61039e6105be366004612a21565b6112c9565b6103d36105d136600461296a565b60076020526000908152604090205481565b6103c96105f136600461296a565b61136e565b6103c96113ce565b600b5461060b9060e81b81565b6040516001600160e81b03199091168152602001610382565b60015461036e906001600160a01b031681565b6103c9610645366004612b8a565b6113ed565b6103c961065836600461296a565b611477565b61039e61066b3660046129f1565b6114ea565b61039e61067e366004612bdf565b611513565b6009546103d3565b6103c961069936600461296a565b61163f565b6103c96116a5565b6103c96106b4366004612aef565b611726565b6103c96106c73660046129f1565b611995565b6103d36106da366004612c52565b6119bb565b61039e6106ed366004612a21565b611a55565b60025461036e906001600160a01b031681565b61039e610713366004612c80565b611b6b565b6103c961072636600461296a565b611c8b565b6103c961073936600461296a565b611cf1565b61039e61074c366004612ce7565b611d63565b6103c961075f366004612dbe565b611fa6565b6103c961077236600461296a565b6120ee565b6103c9610785366004612987565b612161565b60006001600160e01b03198216637965db0b60e01b14806107bb57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60405163189c65c360e21b8152600a6004820152600090736a2f117b2e35e59ee35022186ae6b365dcab84ad90636271970c90602401602060405180830381865af4158015610814573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108389190612dea565b905090565b6001546001600160a01b0316331461085457600080fd5b60405163ad41534960e01b8152600a60048201526001600160a01b0382166024820152736a2f117b2e35e59ee35022186ae6b365dcab84ad9063ad4153499060440160006040518083038186803b1580156108ae57600080fd5b505af41580156108c2573d6000803e3d6000fd5b5050505050565b60035460408051636c9c2faf60e01b815290516000926001600160a01b031691636c9c2faf9160048083019260209291908290030181865afa158015610913573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108389190612e07565b6004546000906001600160a01b03838116911614806107bb5750506001600160a01b031660009081526005602052604090205460ff1690565b600061097a610d10565b604080517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c960208201526001600160a01b03808a169282019290925290871660608201526080810186905260a0810185905260c0810184905260e00160405160208183030381529060405280519060200120604051602001610a1392919061190160f01b81526002810192909252602282015260420190565b60405160208183030381529060405280519060200120905095945050505050565b600082815260208190526040902060010154610a5081336121b0565b610a5a8383612214565b505050565b6000610a6a33610937565b610a7357600080fd5b8382610a8d600080516020613104833981519152836114ea565b610af95760405162461bcd60e51b815260206004820152603260248201527f4d696e7461626c65436f6e74726f6c6c65723a2063616c6c6572206973206e6f6044820152711d0818481cde5cdd195b481858d8dbdd5b9d60721b60648201526084015b60405180910390fd5b6001600160a01b038216600090815260086020526040902054811115610b89576040805162461bcd60e51b81526020600482015260248101919091527f4d696e7461626c65436f6e74726f6c6c65723a2063616c6c6572206973206e6f60448201527f7420616c6c6f77656420746f20706572666f726d207468697320616374696f6e6064820152608401610af0565b600254600160a01b900460ff1615610bb35760405162461bcd60e51b8152600401610af090612e20565b610bbc85612298565b6001600160a01b038616600090815260086020526040902054610be0908590612e60565b6001600160a01b0387811660009081526008602052604090819020929092556003549151632c30a71d60e21b815291811660048301528616602482015260448101859052730fc041a4b6a3f634445804daafd03f202337c1259063b0c29c7490606401602060405180830381865af4158015610c60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c849190612e77565b610cd05760405162461bcd60e51b815260206004820152601f60248201527f4d696e7461626c65436f6e74726f6c6c65723a206d696e74206661696c6564006044820152606401610af0565b50600195945050505050565b60006107bb600080516020613104833981519152836114ea565b60006107bb600080516020613124833981519152836114ea565b60007f00000000000000000000000000000000000000000000000000000000000000004614610dff5750604080518082018252601281527139ba30b73230b93221b7b73a3937b63632b960711b60209182015281517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818301527fe5448f65bca72ba1b802be60235c06fea7a9898bd3b218fd4783069ca85a96e4818401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a0808301919091528351808303909101815260c0909101909252815191012090565b507f000000000000000000000000000000000000000000000000000000000000000090565b6001600160a01b0381163314610e945760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610af0565b610e9e8282612453565b5050565b6000610ead33610937565b610eb657600080fd5b87610ecf600080516020613104833981519152826114ea565b610eeb5760405162461bcd60e51b8152600401610af090612e99565b600254600160a01b900460ff1615610f155760405162461bcd60e51b8152600401610af090612e20565b610f1e87612298565b6003546040516323dc89cd60e21b81526001600160a01b039182166004820152898216602482015290881660448201526064810187905260ff8616608482015260a4810185905260c48101849052736a2f117b2e35e59ee35022186ae6b365dcab84ad90638f7227349060e401602060405180830381865af4158015610fa8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fcc9190612e07565b9998505050505050505050565b6001546001600160a01b03163314610ff057600080fd5b610ff86124b8565b565b6002546001600160a01b0316331461101157600080fd5b6002546001546040516001600160a01b0392831692909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600254600180546001600160a01b0319166001600160a01b03909216918217905561107d90600090612555565b600280546001600160a01b0319169055565b600061109a33610937565b6110a357600080fd5b6001600160a01b038816301461110d5760405162461bcd60e51b815260206004820152602960248201527f6f6e6c7920616c6c6f77207468697320636f6e747261637420746f206265207460448201526834329031b0b63632b960b91b6064820152608401610af0565b506001979650505050505050565b6001546001600160a01b0316331461113257600080fd5b61114a60008051602061312483398151915282610a34565b6040516001600160a01b038216907f5c7eb798b922f0164aa9c5340006161c64436190a49eebc58b4e6e0715700ae690600090a250565b6001546001600160a01b0316331461119857600080fd5b6111b060008051602061312483398151915282611995565b6040516001600160a01b038216907fc3198db98a2c50068f0a99b9297e60b2dbf0eafcde57e366e70a29f887c44e1090600090a250565b6001546001600160a01b031633146111fe57600080fd5b6004546040516001600160a01b038084169216907fcb01f884fc4203d4c1643cb0e126faeb397682c122ca8c0433776d42cdc0060a90600090a3600480546001600160a01b0319166001600160a01b0392909216919091179055565b60035460405163f8b2cb4f60e01b81526001600160a01b038381166004830152600092169063f8b2cb4f90602401602060405180830381865afa1580156112a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107bb9190612e07565b60006112d433610937565b6112dd57600080fd5b60035460405163365feff160e01b8152730c06ccf38114ddfc35e07427b9424adcca9f44f89163365feff191611325916001600160a01b031690889088908890600401612ee3565b602060405180830381865af4158015611342573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113669190612e77565b949350505050565b6001546001600160a01b0316331461138557600080fd5b6001600160a01b038116600081815260056020526040808220805460ff19169055517f10cf5a523a14a54e61c21610dc10c01e40e2ebc37baa3effd74032f7d3865e6d9190a250565b6001546001600160a01b031633146113e557600080fd5b610ff861255f565b6001546001600160a01b0316331461140457600080fd5b6001600160a01b03831660009081526005602052604090819020805460ff19166001179055516114379083908390612f0d565b604051908190038120906001600160a01b038516907fec75908259de4d038ff5f2b6b99e3725bc21871f4d2a44adeff9bb814afbc9f790600090a3505050565b6001546001600160a01b0316331461148e57600080fd5b6003546040516001600160a01b038084169216907fdaaa9d417a3107fd3d9db02eba3eeafbae2b8af16ee08c534f5bc449054c1c4c90600090a3600380546001600160a01b0319166001600160a01b0392909216919091179055565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b600254600090600160a01b900460ff16156115405760405162461bcd60e51b8152600401610af090612e20565b6040516332c5a6eb60e01b8152600a60048201526001600160a01b0380881660248301528616604482015260648101859052736a2f117b2e35e59ee35022186ae6b365dcab84ad906332c5a6eb90608401602060405180830381865af41580156115ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115d29190612e77565b6116285760405162461bcd60e51b815260206004820152602160248201527f7472616e73666572416e6443616c6c2072657175657374206e6f742076616c696044820152601960fa1b6064820152608401610af0565b61163586868686866125c4565b9695505050505050565b6001546001600160a01b0316331461165657600080fd5b61166e60008051602061310483398151915282610a34565b6040516001600160a01b038216907fdfb5b1167ef9eadf5cac67570f1a2971a6f6175303b9d4166a65a11d0a294e3490600090a250565b6001546001600160a01b031633146116bc57600080fd5b600360009054906101000a90046001600160a01b03166001600160a01b0316634e71e0c86040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561170c57600080fd5b505af1158015611720573d6000803e3d6000fd5b50505050565b428410156117765760405162461bcd60e51b815260206004820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152606401610af0565b60006001611782610d10565b6001600160a01b038a811660008181526007602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa15801561188e573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906118c45750876001600160a01b0316816001600160a01b0316145b6119015760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a4a3a722a960911b6044820152606401610af0565b5060035460405163365feff160e01b8152730c06ccf38114ddfc35e07427b9424adcca9f44f89163365feff19161194a916001600160a01b0316908b908b908b90600401612ee3565b602060405180830381865af4158015611967573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061198b9190612e77565b5050505050505050565b6000828152602081905260409020600101546119b181336121b0565b610a5a8383612453565b600354604051630822ebe760e11b81526001600160a01b03918216600482015283821660248201529082166044820152600090730c06ccf38114ddfc35e07427b9424adcca9f44f890631045d7ce90606401602060405180830381865af4158015611a2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4e9190612e07565b9392505050565b600254600090600160a01b900460ff1615611a825760405162461bcd60e51b8152600401610af090612e20565b6040516332c5a6eb60e01b8152600a60048201526001600160a01b0380861660248301528416604482015260648101839052736a2f117b2e35e59ee35022186ae6b365dcab84ad906332c5a6eb90608401602060405180830381865af4158015611af0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b149190612e77565b611b605760405162461bcd60e51b815260206004820152601a60248201527f7472616e736665722072657175657374206e6f742076616c69640000000000006044820152606401610af0565b61136684848461266e565b600254600090600160a01b900460ff1615611b985760405162461bcd60e51b8152600401610af090612e20565b6040516332c5a6eb60e01b8152600a60048201526001600160a01b0380861660248301528416604482015260648101839052736a2f117b2e35e59ee35022186ae6b365dcab84ad906332c5a6eb90608401602060405180830381865af4158015611c06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2a9190612e77565b611c765760405162461bcd60e51b815260206004820152601e60248201527f7472616e7366657246726f6d2072657175657374206e6f742076616c696400006044820152606401610af0565b611c82858585856126d3565b95945050505050565b6001546001600160a01b03163314611ca257600080fd5b611cba60008051602061310483398151915282611995565b6040516001600160a01b038216907f21bfb3de07221bc6197a8c23f7a059308b7a741f259cf4ef3b519cde0fde7ac390600090a250565b6001546001600160a01b03163314611d0857600080fd5b60035460405163f2fde38b60e01b81526001600160a01b0383811660048301529091169063f2fde38b90602401600060405180830381600087803b158015611d4f57600080fd5b505af11580156108c2573d6000803e3d6000fd5b600033611d7e600080516020613104833981519152826114ea565b611d9a5760405162461bcd60e51b8152600401610af090612e99565b600254600160a01b900460ff1615611dc45760405162461bcd60e51b8152600401610af090612e20565b60035460405163c5d5b08960e01b8152730fc041a4b6a3f634445804daafd03f202337c1259163c5d5b08991611e0e916001600160a01b0316908a908a908a908a90600401612f75565b602060405180830381865af4158015611e2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e4f9190612e77565b611e9b5760405162461bcd60e51b815260206004820152601f60248201527f4d696e7461626c65436f6e74726f6c6c65723a206275726e206661696c6564006044820152606401610af0565b60048054604051630e08f2bb60e21b81526001600160a01b038981169382019390935260248101889052604481018790526000606482018190526084820181905260a48201529116908190633823caec9060c4016020604051808303816000875af1158015611f0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f329190612e77565b611f995760405162461bcd60e51b815260206004820152603260248201527f4d696e7461626c65436f6e74726f6c6c65723a20546f6b656e46726f6e74656e6044820152711908189d5c9b8818d85b1b0819985a5b195960721b6064820152608401610af0565b5060019695505050505050565b611fbe600080516020613124833981519152336114ea565b61201d5760405162461bcd60e51b815260206004820152602a60248201527f53797374656d526f6c653a2063616c6c6572206973206e6f7420616e2061646d6044820152691a5b881858d8dbdd5b9d60b21b6064820152608401610af0565b6009548111156120955760405162461bcd60e51b815260206004820152603d60248201527f4d696e7461626c65436f6e74726f6c6c65723a20616c6c6f77616e636520657860448201527f6365656473206d6178696d756d20736574746564206279206f776e65720000006064820152608401610af0565b6001600160a01b03821660008181526008602052604090819020839055517f8fe74a1bbab5a9534a04463cd7b9423b985ed316426821cace8ed4aeac5a4d14906120e29084815260200190565b60405180910390a25050565b6001546001600160a01b0316331461210557600080fd5b6002546040516001600160a01b038084169216907f8573d4aae9f7fb051c6b88d7440011a1c12376acda6603a45f45bad36a8db4ce90600090a3600280546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b0316331461217857600080fd5b6040518181527f34affbf2a21d1f1d12e5e49bdca58fb75dba6879f5430f2fbf5c1d07476018d29060200160405180910390a1600955565b6121ba82826114ea565b610e9e576121d2816001600160a01b0316601461278f565b6121dd83602061278f565b6040516020016121ee929190612fba565b60408051601f198184030181529082905262461bcd60e51b8252610af09160040161302f565b61221e82826114ea565b610e9e576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556122543390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6001600160a01b0381166122e55760405162461bcd60e51b815260206004820152601460248201527306d757374206e6f742073656e6420746f203078360641b6044820152606401610af0565b6001600160a01b03811630141561233e5760405162461bcd60e51b815260206004820152601b60248201527f6d757374206e6f742073656e6420746f20636f6e74726f6c6c657200000000006044820152606401610af0565b6003546001600160a01b038281169116141561239c5760405162461bcd60e51b815260206004820152601e60248201527f6d757374206e6f742073656e6420746f20746f6b656e2073746f7261676500006044820152606401610af0565b6004546001600160a01b03828116911614156123fa5760405162461bcd60e51b815260206004820152601960248201527f6d757374206e6f742073656e6420746f2066726f6e74656e64000000000000006044820152606401610af0565b61240381610937565b156124505760405162461bcd60e51b815260206004820181905260248201527f6d757374206e6f742073656e6420746f2062726964676546726f6e74656e64736044820152606401610af0565b50565b61245d82826114ea565b15610e9e576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600254600160a01b900460ff166125085760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610af0565b6002805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b610e9e8282612214565b600254600160a01b900460ff16156125895760405162461bcd60e51b8152600401610af090612e20565b6002805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586125383390565b60006125cf33610937565b6125d857600080fd5b6125e185612298565b600354604051631eb8bccb60e01b8152732d80dbf04d0802abd7a342dafa5d7cb42bfbb52f91631eb8bccb9161262d916001600160a01b0316908a908a908a908a908a90600401613042565b602060405180830381865af415801561264a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116359190612e77565b600061267933610937565b61268257600080fd5b61268b83612298565b60035460405163226f6c5d60e11b8152730c06ccf38114ddfc35e07427b9424adcca9f44f8916344ded8ba91611325916001600160a01b031690889088908890600401612ee3565b60006126de33610937565b6126e757600080fd5b6126f083612298565b60035460405163f3a0ddf960e01b81526001600160a01b03918216600482015286821660248201528582166044820152908416606482015260848101839052730c06ccf38114ddfc35e07427b9424adcca9f44f89063f3a0ddf99060a401602060405180830381865af415801561276b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c829190612e77565b6060600061279e83600261309f565b6127a99060026130be565b67ffffffffffffffff8111156127c1576127c1612cd1565b6040519080825280601f01601f1916602001820160405280156127eb576020820181803683370190505b509050600360fc1b81600081518110612806576128066130d6565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110612835576128356130d6565b60200101906001600160f81b031916908160001a905350600061285984600261309f565b6128649060016130be565b90505b60018111156128dc576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110612898576128986130d6565b1a60f81b8282815181106128ae576128ae6130d6565b60200101906001600160f81b031916908160001a90535060049490941c936128d5816130ec565b9050612867565b508315611a4e5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610af0565b60006020828403121561293d57600080fd5b81356001600160e01b031981168114611a4e57600080fd5b6001600160a01b038116811461245057600080fd5b60006020828403121561297c57600080fd5b8135611a4e81612955565b60006020828403121561299957600080fd5b5035919050565b600080600080600060a086880312156129b857600080fd5b85356129c381612955565b945060208601356129d381612955565b94979496505050506040830135926060810135926080909101359150565b60008060408385031215612a0457600080fd5b823591506020830135612a1681612955565b809150509250929050565b600080600060608486031215612a3657600080fd5b8335612a4181612955565b92506020840135612a5181612955565b929592945050506040919091013590565b803560ff81168114612a7357600080fd5b919050565b600080600080600080600060e0888a031215612a9357600080fd5b8735612a9e81612955565b96506020880135612aae81612955565b95506040880135612abe81612955565b945060608801359350612ad360808901612a62565b925060a0880135915060c0880135905092959891949750929550565b600080600080600080600060e0888a031215612b0a57600080fd5b8735612b1581612955565b96506020880135612b2581612955565b95506040880135945060608801359350612ad360808901612a62565b60008083601f840112612b5357600080fd5b50813567ffffffffffffffff811115612b6b57600080fd5b602083019150836020828501011115612b8357600080fd5b9250929050565b600080600060408486031215612b9f57600080fd5b8335612baa81612955565b9250602084013567ffffffffffffffff811115612bc657600080fd5b612bd286828701612b41565b9497909650939450505050565b600080600080600060808688031215612bf757600080fd5b8535612c0281612955565b94506020860135612c1281612955565b935060408601359250606086013567ffffffffffffffff811115612c3557600080fd5b612c4188828901612b41565b969995985093965092949392505050565b60008060408385031215612c6557600080fd5b8235612c7081612955565b91506020830135612a1681612955565b60008060008060808587031215612c9657600080fd5b8435612ca181612955565b93506020850135612cb181612955565b92506040850135612cc181612955565b9396929550929360600135925050565b634e487b7160e01b600052604160045260246000fd5b60008060008060808587031215612cfd57600080fd5b8435612d0881612955565b93506020850135925060408501359150606085013567ffffffffffffffff80821115612d3357600080fd5b818701915087601f830112612d4757600080fd5b813581811115612d5957612d59612cd1565b604051601f8201601f19908116603f01168101908382118183101715612d8157612d81612cd1565b816040528281528a6020848701011115612d9a57600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b60008060408385031215612dd157600080fd5b8235612ddc81612955565b946020939093013593505050565b600060208284031215612dfc57600080fd5b8151611a4e81612955565b600060208284031215612e1957600080fd5b5051919050565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b600082821015612e7257612e72612e4a565b500390565b600060208284031215612e8957600080fd5b81518015158114611a4e57600080fd5b6020808252602a908201527f53797374656d526f6c653a2063616c6c6572206973206e6f7420612073797374604082015269195b481858d8dbdd5b9d60b21b606082015260800190565b6001600160a01b039485168152928416602084015292166040820152606081019190915260800190565b8183823760009101908152919050565b60005b83811015612f38578181015183820152602001612f20565b838111156117205750506000910152565b60008151808452612f61816020860160208601612f1d565b601f01601f19169290920160200192915050565b6001600160a01b03868116825285166020820152604081018490526060810183905260a060808201819052600090612faf90830184612f49565b979650505050505050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351612ff2816017850160208801612f1d565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351613023816028840160208801612f1d565b01602801949350505050565b602081526000611a4e6020830184612f49565b6001600160a01b0387811682528681166020830152851660408201526060810184905260a06080820181905281018290526000828460c0840137600060c0848401015260c0601f19601f8501168301019050979650505050505050565b60008160001904831182151516156130b9576130b9612e4a565b500290565b600082198211156130d1576130d1612e4a565b500190565b634e487b7160e01b600052603260045260246000fd5b6000816130fb576130fb612e4a565b50600019019056fe5719df9ef2c4678b547f89e4f5ae410dbf400fc51cf3ded434c55f6adea2c43fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775a2646970667358221220ac8334c970a8c49b9b6cda46ecf7729d760f98b7a57ff0a42dc1fa92a8e5b89164736f6c634300080b0033608060405234801561001057600080fd5b50600080546001600160a01b03191633179055341561002e57600080fd5b61092a8061003d6000396000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c80638da5cb5b11610086578063cf8eeb7e11610063578063cf8eeb7e14610180578063e30c397814610193578063f2fde38b146101a6578063f8b2cb4f146101b957005b80638da5cb5b1461013a5780639f727c2714610165578063c7c7e9ea1461016d57005b806317ffc320146100cb57806321e5383a146100de5780632aed7f3f146100f157806333dd1b8a146101045780634e71e0c8146101175780636c9c2faf1461011f575b005b6100c96100d93660046107f6565b6101cc565b6100c96100ec366004610813565b61026f565b6100c96100ff3660046107f6565b610304565b6100c961011236600461083f565b610377565b6100c9610414565b61012761048f565b6040519081526020015b60405180910390f35b60005461014d906001600160a01b031681565b6040516001600160a01b039091168152602001610131565b6100c961050a565b61012761017b366004610880565b61055e565b6100c961018e366004610813565b6105f3565b60015461014d906001600160a01b031681565b6100c96101b43660046107f6565b610658565b6101276101c73660046107f6565b610661565b6000546001600160a01b031633146101e357600080fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa15801561022a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061024e91906108b9565b60005490915061026b906001600160a01b038481169116836106ed565b5050565b6000546001600160a01b0316331461028657600080fd5b604051637aeb0ed560e01b8152600260048201526001600160a01b03831660248201526044810182905273ddfe2c5f94909420cf55827fffa09a7ff9b2ab7790637aeb0ed5906064015b60006040518083038186803b1580156102e857600080fd5b505af41580156102fc573d6000803e3d6000fd5b505050505050565b6000546001600160a01b0316331461031b57600080fd5b60005460405163f2fde38b60e01b81526001600160a01b039182166004820152829182169063f2fde38b90602401600060405180830381600087803b15801561036357600080fd5b505af11580156102fc573d6000803e3d6000fd5b6000546001600160a01b0316331461038e57600080fd5b604051635599b4b760e01b8152600260048201526001600160a01b038085166024830152831660448201526064810182905273ddfe2c5f94909420cf55827fffa09a7ff9b2ab7790635599b4b79060840160006040518083038186803b1580156103f757600080fd5b505af415801561040b573d6000803e3d6000fd5b50505050505050565b6001546001600160a01b0316331461042b57600080fd5b600154600080546040516001600160a01b0393841693909116917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a360018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6040516272f9a560e41b81526002600482015260009073ddfe2c5f94909420cf55827fffa09a7ff9b2ab779063072f9a5090602401602060405180830381865af41580156104e1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050591906108b9565b905090565b6000546001600160a01b0316331461052157600080fd5b600080546040516001600160a01b03909116914780156108fc02929091818181858888f1935050505015801561055b573d6000803e3d6000fd5b50565b604051634ed7570f60e11b8152600260048201526001600160a01b0380841660248301528216604482015260009073ddfe2c5f94909420cf55827fffa09a7ff9b2ab7790639daeae1e90606401602060405180830381865af41580156105c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ec91906108b9565b9392505050565b6000546001600160a01b0316331461060a57600080fd5b604051636ce399cf60e11b8152600260048201526001600160a01b03831660248201526044810182905273ddfe2c5f94909420cf55827fffa09a7ff9b2ab779063d9c7339e906064016102d0565b61055b8161076e565b604051632c2ab3c960e21b8152600260048201526001600160a01b038216602482015260009073ddfe2c5f94909420cf55827fffa09a7ff9b2ab779063b0aacf2490604401602060405180830381865af41580156106c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106e791906108b9565b92915050565b60405163a9059cbb60e01b81526001600160a01b0383811660048301526024820183905284169063a9059cbb906044016020604051808303816000875af115801561073c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061076091906108d2565b61076957600080fd5b505050565b6000546001600160a01b0316331461078557600080fd5b6001546040516001600160a01b038084169216907f8573d4aae9f7fb051c6b88d7440011a1c12376acda6603a45f45bad36a8db4ce90600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b038116811461055b57600080fd5b60006020828403121561080857600080fd5b81356105ec816107e1565b6000806040838503121561082657600080fd5b8235610831816107e1565b946020939093013593505050565b60008060006060848603121561085457600080fd5b833561085f816107e1565b9250602084013561086f816107e1565b929592945050506040919091013590565b6000806040838503121561089357600080fd5b823561089e816107e1565b915060208301356108ae816107e1565b809150509250929050565b6000602082840312156108cb57600080fd5b5051919050565b6000602082840312156108e457600080fd5b815180151581146105ec57600080fdfea26469706673582212207716b8a5d7375d18127e10682c27c5bcacca02792efc569198f750c8b441c03664736f6c634300080b0033a26469706673582212202d8816f13a4eb98a8109a1b134c07cedc75a954c1771f658206e94743a18786a64736f6c634300080b0033
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.