Contract Address Details

0x2D4eB90118f6FBA1191F26Eb39f7FF0573F63C22

Contract Name
EnergiswapRouterGovernedProxy
Creator
0x56054d–9a2108 at 0x89a74a–90a56a
Implementation
0x1a02eb18cd4d1d81a1f535f1f82f35ca8b26af8f
Balance
0.00 NRG
Tokens
Fetching tokens...
Transactions
3,613,111 Transactions
Transfers
0 Transfers
Gas Used
1,994,783,834,924
Last Balance Update
2472338
Contract name:
EnergiswapRouterGovernedProxy




Optimization enabled
true
Compiler version
v0.5.16+commit.9c3226ce




Optimization runs
200
EVM Version
petersburg




Verified at
2021-10-18 18:07:35.487508Z

Constructor Arguments

00000000000000000000000056054dd259ee91add53a988c079cfb17be9a21080000000000000000000000000000000000000000000000000000000000000305

Arg [0] (address) : 0x56054dd259ee91add53a988c079cfb17be9a2108
Arg [1] (address) : 0x0000000000000000000000000000000000000305

              

Contract source code

// Copyright 2021 The Energi Core Authors
// This file is part of Energi Core.
//
// Energi Core is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Energi Core is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Energi Core. If not, see <http://www.gnu.org/licenses/>.
// Energi Governance system is the fundamental part of Energi Core.
// NOTE: It's not allowed to change the compiler due to byte-to-byte
// match requirement.
pragma solidity 0.5.16;
/**
* A little helper to protect contract from being re-entrant in state
* modifying functions.
*/
contract NonReentrant {
uint private entry_guard;
modifier noReentry {
require(entry_guard == 0, "Reentry");
entry_guard = 1;
_;
entry_guard = 0;
}
}
// Copyright 2019 The Energi Core Authors
// This file is part of Energi Core.
//
// Energi Core is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Energi Core is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Energi Core. If not, see <http://www.gnu.org/licenses/>.
interface IStorageBase {
function setOwner(address _newOwner) external;
}
// a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math)
library SafeMath {
function add(uint x, uint y) internal pure returns (uint z) {
require((z = x + y) >= x, 'ds-math-add-overflow');
}
function sub(uint x, uint y) internal pure returns (uint z) {
require((z = x - y) <= x, 'ds-math-sub-underflow');
}
function mul(uint x, uint y) internal pure returns (uint z) {
require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow');
}
}
// Copyright 2021 The Energi Core Authors
// This file is part of Energi Core.
//
// Energi Core is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Energi Core is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Energi Core. If not, see <http://www.gnu.org/licenses/>.
// Energi Governance system is the fundamental part of Energi Core.
// NOTE: It's not allowed to change the compiler due to byte-to-byte
// match requirement.
interface IEnergiswapFactory {
function initialized() external view returns (bool);
function _storage() external view returns (address);
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
function initialize(address _routerProxy, address _pairsManagerProxy, address _pairsERC20Proxy) external;
function destroy(address _newImpl) external;
function migrate(address _oldImpl) external;
function createPair(
address tokenA,
address tokenB
) external returns (address pairProxy);
function setFeeTo(address _feeTo) external;
function setFeeToSetter(address _feeToSetter) external;
function feeTo() external view returns (address _feeTo);
function feeToSetter() external view returns (address _feeToSetter);
function sporkProxy() external view returns (address _sporkProxy);
function getPair(address tokenA, address tokenB) external view returns (address _pair);
function allPairs(uint index) external view returns (address _pair);
function allPairsLength() external view returns (uint);
}
// Copyright 2021 The Energi Core Authors
// This file is part of Energi Core.
//
// Energi Core is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Energi Core is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Energi Core. If not, see <http://www.gnu.org/licenses/>.
// Energi Governance system is the fundamental part of Energi Core.
// NOTE: It's not allowed to change the compiler due to byte-to-byte
// match requirement.
interface IEnergiswapPairsManager {
event Mint(address indexed pair, address indexed sender, uint amount0, uint amount1, address indexed to);
event Burn(address indexed pair, address indexed sender, uint amount0, uint amount1, address indexed to);
event Swap(
address indexed sender,
uint amount0In,
uint amount1In,
uint amount0Out,
uint amount1Out,
address indexed to
);
event Sync(address indexed sender, uint112 reserve0, uint112 reserve1);
function _storage() external view returns (address);
function destroy(address _newImpl) external;
function migrate(address _oldImpl) external;
function registerPair(address _pairProxy, address _pairStorage, address _erc20Storage) external;
function mint(address to) external returns (uint liquidity);
function burn(address to) external returns (uint amount0, uint amount1);
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
function skim(address to) external;
function sync() external;
function approve(address spender, uint value) external returns (bool result);
function transfer(address to, uint value) external returns (bool result);
function transferFrom(address from, address to, uint value) external returns (bool result);
function redeemLiquidity(address router, address owner, uint value) external returns (bool result);
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
function emitApproval(address pair, address owner, address spender, uint value) external;
function emitTransfer(address pair, address from, address to, uint value) external;
function factory() external view returns (address _factory);
function getReserves(address pair) external view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast);
function token0(address pair) external view returns (address _token0);
function token1(address pair) external view returns (address _token1);
function price0CumulativeLast(address pair) external view returns (uint _price0CumulativeLast);
function price1CumulativeLast(address pair) external view returns (uint _price1CumulativeLast);
function kLast(address pair) external view returns (uint _kLast);
}
// Copyright 2019 The Energi Core Authors
// This file is part of Energi Core.
//
// Energi Core is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Energi Core is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Energi Core. If not, see <http://www.gnu.org/licenses/>.
// Energi Governance system is the fundamental part of Energi Core.
// NOTE: It's not allowed to change the compiler due to byte-to-byte
// match requirement.
/**
* Genesis version of GovernedContract interface.
*
* Base Consensus interface for upgradable contracts.
* Unlike common approach, the implementation is NOT expected to be
* called through delegatecall() to minimize risks of shared storage.
*
* NOTE: it MUST NOT change after blockchain launch!
*/
interface IGovernedContract {
// Return actual proxy address for secure validation
function proxy() external returns(address);
// It must check that the caller is the proxy
// and copy all required data from the old address.
function migrate(IGovernedContract _oldImpl) external;
// It must check that the caller is the proxy
// and self destruct to the new address.
function destroy(IGovernedContract _newImpl) external;
// function () external payable; // This line (from original Energi IGovernedContract) is commented because it
// makes truffle migrations fail
}
// SPDX-License-Identifier: GPL-3.0-or-later
// helper methods for interacting with ERC20 tokens and sending WNRG that do not consistently return true/false
library TransferHelper {
function safeApprove(address token, address to, uint value) internal {
// bytes4(keccak256(bytes('approve(address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED');
}
function safeTransfer(address token, address to, uint value) internal {
// bytes4(keccak256(bytes('transfer(address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED');
}
function safeTransferFrom(address token, address from, address to, uint value) internal {
// bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED');
}
function safeTransferNRG(address to, uint value) internal {
(bool success, ) = to.call.value(value)(new bytes(0));
require(success, 'TransferHelper: NRG_TRANSFER_FAILED');
}
}
// Copyright 2019 The Energi Core Authors
// This file is part of Energi Core.
//
// Energi Core is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Energi Core is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Energi Core. If not, see <http://www.gnu.org/licenses/>.
// Energi Governance system is the fundamental part of Energi Core.
// NOTE: It's not allowed to change the compiler due to byte-to-byte
// match requirement.
// Copyright 2019 The Energi Core Authors
// This file is part of Energi Core.
//
// Energi Core is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Energi Core is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Energi Core. If not, see <http://www.gnu.org/licenses/>.
// Energi Governance system is the fundamental part of Energi Core.
// NOTE: It's not allowed to change the compiler due to byte-to-byte
// match requirement.
interface IProposal {
function parent() external view returns(address);
function created_block() external view returns(uint);
function deadline() external view returns(uint);
function fee_payer() external view returns(address payable);
function fee_amount() external view returns(uint);
function accepted_weight() external view returns(uint);
function rejected_weight() external view returns(uint);
function total_weight() external view returns(uint);
function quorum_weight() external view returns(uint);
function isFinished() external view returns(bool);
function isAccepted() external view returns(bool);
function withdraw() external;
function destroy() external;
function collect() external;
function voteAccept() external;
function voteReject() external;
function setFee() external payable;
function canVote(address owner) external view returns(bool);
}
/**
* Interface of UpgradeProposal
*/
contract IUpgradeProposal is IProposal {
function impl() external view returns(IGovernedContract);
}
// Copyright (C) 2020 Energi Core
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// Copyright 2021 The Energi Core Authors
// This file is part of Energi Core.
//
// Energi Core is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Energi Core is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Energi Core. If not, see <http://www.gnu.org/licenses/>.
// Energi Governance system is the fundamental part of Energi Core.
// NOTE: It's not allowed to change the compiler due to byte-to-byte
// match requirement.
// Copyright 2021 The Energi Core Authors
// This file is part of Energi Core.
//
// Energi Core is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Energi Core is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Energi Core. If not, see <http://www.gnu.org/licenses/>.
// Energi Governance system is the fundamental part of Energi Core.
// NOTE: It's not allowed to change the compiler due to byte-to-byte
// match requirement.
// Copyright (C) 2020 Energi Core
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// Copyright 2019 The Energi Core Authors
// This file is part of Energi Core.
//
// Energi Core is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Energi Core is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Energi Core. If not, see <http://www.gnu.org/licenses/>.
// Energi Governance system is the fundamental part of Energi Core.
// NOTE: It's not allowed to change the compiler due to byte-to-byte
// match requirement.
// Copyright 2019 The Energi Core Authors
// This file is part of Energi Core.
//
// Energi Core is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Energi Core is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Energi Core. If not, see <http://www.gnu.org/licenses/>.
interface IEnergiswapGovernedContract {
function proxy() external returns(address);
}
/**
* Genesis version of GovernedContract common base.
*
* Base Consensus interface for upgradable contracts.
* Unlike common approach, the implementation is NOT expected to be
* called through delegatecall() to minimize risks of shared storage.
*
* NOTE: it MUST NOT change after blockchain launch!
*/
contract EnergiswapGovernedContract is IEnergiswapGovernedContract {
address public proxy;
constructor(address _proxy) public {
proxy = _proxy;
}
modifier requireProxy {
require(msg.sender == proxy, "EnergiswapGovernedContract: FORBIDDEN, not proxy");
_;
}
function getProxy() internal view returns(address _proxy) {
_proxy = proxy;
}
// solium-disable-next-line no-empty-blocks
function _migrate(address) internal {}
function _destroy(address _newImpl) internal {
selfdestruct(address(uint160(_newImpl)));
}
function _callerAddress()
internal view
returns (address payable)
{
if (msg.sender == proxy) {
// This is guarantee of the GovernedProxy
// solium-disable-next-line security/no-tx-origin
return tx.origin;
} else {
return msg.sender;
}
}
}
contract EnergiswapRouterAutoProxy is EnergiswapGovernedContract {
constructor (
address _proxy,
address _impl,
address payable _sporkProxy
) public EnergiswapGovernedContract(_proxy) {
// If _proxy is set to address(0), a new EnergiswapRouterGovernedProxy is deployed
if(_proxy == address(0)){
_proxy = address(new EnergiswapRouterGovernedProxy(_impl, _sporkProxy));
}
proxy = _proxy;
}
}
// This file is part of Energi Core.
//
// Energi Core is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Energi Core is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Energi Core. If not, see <http://www.gnu.org/licenses/>.
// Energi Governance system is the fundamental part of Energi Core.
// NOTE: It's not allowed to change the compiler due to byte-to-byte
// match requirement.
/**
* Base for contract storage (SC-14).
*
* NOTE: it MUST NOT change after blockchain launch!
*/
contract StorageBase {
address payable internal owner;
modifier requireOwner {
require(msg.sender == address(owner), "Not owner!");
_;
}
constructor() public {
owner = msg.sender;
}
function setOwner(IGovernedContract _newOwner) external requireOwner {
owner = address(uint160(address(_newOwner)));
}
function kill() external requireOwner {
selfdestruct(msg.sender);
}
}
// Copyright 2019 The Energi Core Authors
// This file is part of Energi Core.
//
// Energi Core is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Energi Core is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Energi Core. If not, see <http://www.gnu.org/licenses/>.
interface IEnergiswapRouterStorage {
function getFactory() external view returns(address _factory);
function getWNRG() external view returns(address _WNRG);
}
// Copyright 2021 The Energi Core Authors
// This file is part of Energi Core.
//
// Energi Core is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Energi Core is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Energi Core. If not, see <http://www.gnu.org/licenses/>.
// Energi Governance system is the fundamental part of Energi Core.
// NOTE: It's not allowed to change the compiler due to byte-to-byte
// match requirement.
interface IERC20 {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
function transfer(address to, uint value) external returns (bool);
function transferFrom(address from, address to, uint value) external returns (bool);
}
// Copyright 2019 The Energi Core Authors
// This file is part of Energi Core.
//
// Energi Core is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Energi Core is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Energi Core. If not, see <http://www.gnu.org/licenses/>.
interface IWNRG {
function deposit() external payable;
function withdraw(uint amount) external;
}
// Copyright 2019 The Energi Core Authors
// This file is part of Energi Core.
//
// Energi Core is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Energi Core is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Energi Core. If not, see <http://www.gnu.org/licenses/>.
// Energi Governance system is the fundamental part of Energi Core.
// NOTE: It's not allowed to change the compiler due to byte-to-byte
// match requirement.
/**
* Genesis version of IGovernedProxy interface.
*
* Base Consensus interface for upgradable contracts proxy.
* Unlike common approach, the implementation is NOT expected to be
* called through delegatecall() to minimize risks of shared storage.
*
* NOTE: it MUST NOT change after blockchain launch!
*/
interface IEnergiswapPairProxy {
function pairsManagerProxy() external view returns (address);
function pairsERC20Proxy() external view returns (address);
function routerProxy() external view returns (address);
function emitMint(address sender, uint amount0, uint amount1, address to) external;
function emitBurn(address sender, uint amount0, uint amount1, address to) external;
function emitSwap(address sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address to) external;
function emitSync(uint112 reserve0, uint112 reserve1) external;
function emitApproval(address owner, address spender, uint value) external;
function emitTransfer(address from, address to, uint value) external;
function safeTransfer(address token, address to, uint value, bytes4 SELECTOR) external;
function getReserves() external view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast);
function token0() external view returns (address _token0);
function token1() external view returns (address _token1);
function price0CumulativeLast() external view returns (uint _price0CumulativeLast);
function price1CumulativeLast() external view returns (uint _price1CumulativeLast);
function kLast() external view returns (uint _kLast);
function name() external view returns(string memory _name);
function symbol() external view returns(string memory _symbol);
function decimals() external view returns(uint8 _decimals);
function totalSupply() external view returns (uint _totalSupply);
function balanceOf(address account) external view returns (uint _balance);
function allowance(address owner, address spender) external view returns (uint _allowance);
function nonce(address owner) external view returns(uint _nonce);
function () external payable;
}
// Copyright (C) 2020 Energi Core
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
library EnergiswapLibrary {
using SafeMath for uint;
// returns sorted token addresses, used to handle return values from pairs sorted in this order
function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) {
require(tokenA != tokenB, 'EnergiswapLibrary: IDENTICAL_ADDRESSES');
(token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
require(token0 != address(0), 'EnergiswapLibrary: ZERO_ADDRESS');
}
// fetches and sorts the reserves for a pair
function getReserves(address factory, address tokenA, address tokenB) internal view returns (uint reserveA, uint reserveB) {
(address token0,) = sortTokens(tokenA, tokenB);
address payable pairProxy = address(uint160(IEnergiswapFactory(factory).getPair(tokenA, tokenB)));
(uint reserve0, uint reserve1,) = IEnergiswapPairProxy(pairProxy).getReserves();
(reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
}
// given some amount of an asset and pair reserves, returns an equivalent amount of the other asset
function quote(uint amountA, uint reserveA, uint reserveB) internal pure returns (uint amountB) {
require(amountA > 0, 'EnergiswapLibrary: INSUFFICIENT_AMOUNT');
require(reserveA > 0 && reserveB > 0, 'EnergiswapLibrary: INSUFFICIENT_LIQUIDITY');
amountB = amountA.mul(reserveB) / reserveA;
}
// given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) {
require(amountIn > 0, 'EnergiswapLibrary: INSUFFICIENT_INPUT_AMOUNT');
require(reserveIn > 0 && reserveOut > 0, 'EnergiswapLibrary: INSUFFICIENT_LIQUIDITY');
uint amountInWithFee = amountIn.mul(997); // 0.3% fee
uint numerator = amountInWithFee.mul(reserveOut);
uint denominator = reserveIn.mul(1000).add(amountInWithFee);
amountOut = numerator / denominator;
}
// given an output amount of an asset and pair reserves, returns a required input amount of the other asset
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) internal pure returns (uint amountIn) {
require(amountOut > 0, 'EnergiswapLibrary: INSUFFICIENT_OUTPUT_AMOUNT');
require(reserveIn > 0 && reserveOut > 0, 'EnergiswapLibrary: INSUFFICIENT_LIQUIDITY');
uint numerator = reserveIn.mul(amountOut).mul(1000);
uint denominator = reserveOut.sub(amountOut).mul(997);
amountIn = (numerator / denominator).add(1);
}
// performs chained getAmountOut calculations on any number of pairs
function getAmountsOut(address factory, uint amountIn, address[] memory path) internal view returns (uint[] memory amounts) {
require(path.length >= 2, 'EnergiswapLibrary: INVALID_PATH');
amounts = new uint[](path.length);
amounts[0] = amountIn;
for (uint i; i < path.length - 1; i++) {
(uint reserveIn, uint reserveOut) = getReserves(factory, path[i], path[i + 1]);
amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut);
}
}
// performs chained getAmountIn calculations on any number of pairs
function getAmountsIn(address factory, uint amountOut, address[] memory path) internal view returns (uint[] memory amounts) {
require(path.length >= 2, 'EnergiswapLibrary: INVALID_PATH');
amounts = new uint[](path.length);
amounts[amounts.length - 1] = amountOut;
for (uint i = path.length - 1; i > 0; i--) {
(uint reserveIn, uint reserveOut) = getReserves(factory, path[i - 1], path[i]);
amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut);
}
}
}
contract EnergiswapRouterStorage is StorageBase, IEnergiswapRouterStorage {
address private factoryProxy;
address private pairsManagerProxy;
address private WNRG;
constructor(
address _factoryProxy,
address _WNRG
) public {
factoryProxy = _factoryProxy;
WNRG = _WNRG;
}
function getFactory() external view returns(address _factory) {
_factory = address(IGovernedProxy(address(uint160(factoryProxy))).impl());
}
function getWNRG() external view returns(address _WNRG) {
_WNRG = WNRG;
}
}
interface IEnergiswapRouter {
function _storage() external view returns (address);
function destroy(address _newImpl) external;
function migrate(address _oldImpl) external;
function() external payable;
function removeLiquidityNRGSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountNRGMin,
address to,
uint deadline
) external returns (uint amountNRG);
function removeLiquidityNRGWithPermitSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountNRGMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountNRG);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
function swapExactNRGForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external payable;
function swapExactTokensForNRGSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
function addLiquidityNRG(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountNRGMin,
address to,
uint deadline
) external payable returns (uint amountToken, uint amountNRG, uint liquidity);
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);
function removeLiquidityNRG(
address token,
uint liquidity,
uint amountTokenMin,
uint amountNRGMin,
address to,
uint deadline
) external returns (uint amountToken, uint amountNRG);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountA, uint amountB);
function removeLiquidityNRGWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountNRGMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountToken, uint amountNRG);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactNRGForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function swapTokensForExactNRG(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapExactTokensForNRG(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapNRGForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}
contract EnergiswapRouter is EnergiswapRouterAutoProxy, IEnergiswapRouter {
using SafeMath for uint;
EnergiswapRouterStorage public _storage;
modifier ensure(uint deadline) {
require(deadline >= block.timestamp, 'EnergiswapRouter: EXPIRED');
_;
}
constructor(
address _factoryProxy,
address _WNRG,
address _sporkProxy,
address _proxy // If set to address(0), EnergiswapRouterGovernedProxy will be deployed by EnergiswapRouterAutoProxy
) public EnergiswapRouterAutoProxy(
_proxy,
address(this),
address(uint160(_sporkProxy))
) {
_storage = new EnergiswapRouterStorage(_factoryProxy, _WNRG); // Deploy EnergiswapRouterStorage contract
}
// This function must be called in order to upgrade to a new EnergiswapRouter implementation
function destroy(address _newImpl) external requireProxy {
// Updates EnergiswapRouterStorage contract with new EnergiswapRouter implementation address as owner
IStorageBase(address(_storage)).setOwner(_newImpl);
// Self-destruct
_destroy(_newImpl);
}
// This function (placeholder) would be called on the new implementation if necessary for the upgrade
function migrate(address _oldImpl) external requireProxy {
_migrate(_oldImpl);
}
function() external payable {
address WNRG = _storage.getWNRG();
assert(msg.sender == WNRG); // only accept WNRG via fallback from the WNRG contract
}
// Get pair proxy address from tokens addresses
function pairFor(address tokenA, address tokenB) internal view returns (address pair) {
pair = IEnergiswapFactory(_storage.getFactory()).getPair(tokenA, tokenB);
}
// **** ADD LIQUIDITY ****
function _addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin
) internal returns (uint amountA, uint amountB) {
// create the pair if it doesn't exist yet
if (pairFor(tokenA, tokenB) == address(0)) {
IEnergiswapFactory(_storage.getFactory()).createPair(
tokenA,
tokenB
);
}
(uint reserveA, uint reserveB) = EnergiswapLibrary.getReserves(
_storage.getFactory(),
tokenA,
tokenB
);
if (reserveA == 0 && reserveB == 0) {
(amountA, amountB) = (amountADesired, amountBDesired);
} else {
uint amountBOptimal = EnergiswapLibrary.quote(amountADesired, reserveA, reserveB);
if (amountBOptimal <= amountBDesired) {
require(amountBOptimal >= amountBMin, 'EnergiswapRouter: INSUFFICIENT_B_AMOUNT');
(amountA, amountB) = (amountADesired, amountBOptimal);
} else {
uint amountAOptimal = EnergiswapLibrary.quote(amountBDesired, reserveB, reserveA);
assert(amountAOptimal <= amountADesired);
require(amountAOptimal >= amountAMin, 'EnergiswapRouter: INSUFFICIENT_A_AMOUNT');
(amountA, amountB) = (amountAOptimal, amountBDesired);
}
}
}
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external ensure(deadline) returns (uint amountA, uint amountB, uint liquidity) {
(amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin);
address pair = pairFor(tokenA, tokenB);
IEnergiswapRouterGovernedProxy(address(uint160(proxy))).safeTransferFrom(tokenA, tx.origin, pair, amountA);
IEnergiswapRouterGovernedProxy(address(uint160(proxy))).safeTransferFrom(tokenB, tx.origin, pair, amountB);
liquidity = IEnergiswapPairsManager(pair).mint(to);
}
function addLiquidityNRG(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountNRGMin,
address to,
uint deadline
) external payable ensure(deadline) returns (uint amountToken, uint amountNRG, uint liquidity) {
address WNRG = _storage.getWNRG();
(amountToken, amountNRG) = _addLiquidity(
token,
WNRG,
amountTokenDesired,
msg.value,
amountTokenMin,
amountNRGMin
);
address pair = pairFor(token, WNRG);
IEnergiswapRouterGovernedProxy(address(uint160(proxy))).safeTransferFrom(token, tx.origin, pair, amountToken);
IWNRG(WNRG).deposit.value(amountNRG)();
assert(IERC20(WNRG).transfer(pair, amountNRG));
liquidity = IEnergiswapPairsManager(pair).mint(to);
// refund dust wnrg, if any
if (msg.value > amountNRG) TransferHelper.safeTransferNRG(tx.origin, msg.value - amountNRG);
}
// **** REMOVE LIQUIDITY ****
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) public ensure(deadline) returns (uint amountA, uint amountB) {
address pair = pairFor(tokenA, tokenB);
IEnergiswapPairsManager(pair).redeemLiquidity(address(proxy), tx.origin, liquidity); // send liquidity to pair
(uint amount0, uint amount1) = IEnergiswapPairsManager(pair).burn(to);
(address token0,) = EnergiswapLibrary.sortTokens(tokenA, tokenB);
(amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
require(amountA >= amountAMin, 'EnergiswapRouter: INSUFFICIENT_A_AMOUNT');
require(amountB >= amountBMin, 'EnergiswapRouter: INSUFFICIENT_B_AMOUNT');
}
function removeLiquidityNRG(
address token,
uint liquidity,
uint amountTokenMin,
uint amountNRGMin,
address to,
uint deadline
) public ensure(deadline) returns (uint amountToken, uint amountNRG) {
address WNRG = _storage.getWNRG();
(amountToken, amountNRG) = removeLiquidity(
token,
WNRG,
liquidity,
amountTokenMin,
amountNRGMin,
address(this),
deadline
);
TransferHelper.safeTransfer(token, to, amountToken);
IWNRG(WNRG).withdraw(amountNRG);
TransferHelper.safeTransferNRG(to, amountNRG);
}
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountA, uint amountB) {
address pair = pairFor(tokenA, tokenB);
uint value = approveMax ? uint(-1) : liquidity;
IEnergiswapPairsManager(pair).permit(tx.origin, address(proxy), value, deadline, v, r, s);
(amountA, amountB) = removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline);
}
function removeLiquidityNRGWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountNRGMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountToken, uint amountNRG) {
address WNRG = _storage.getWNRG();
address pair = pairFor(token, WNRG);
uint value = approveMax ? uint(-1) : liquidity;
IEnergiswapPairsManager(pair).permit(tx.origin, address(proxy), value, deadline, v, r, s);
(amountToken, amountNRG) = removeLiquidityNRG(token, liquidity, amountTokenMin, amountNRGMin, to, deadline);
}
// **** REMOVE LIQUIDITY (supporting fee-on-transfer tokens) ****
function removeLiquidityNRGSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountNRGMin,
address to,
uint deadline
) public ensure(deadline) returns (uint amountNRG) {
address WNRG = _storage.getWNRG();
(, amountNRG) = removeLiquidity(
token,
WNRG,
liquidity,
amountTokenMin,
amountNRGMin,
address(this),
deadline
);
TransferHelper.safeTransfer(token, to, IERC20(token).balanceOf(address(this)));
IWNRG(WNRG).withdraw(amountNRG);
TransferHelper.safeTransferNRG(to, amountNRG);
}
function removeLiquidityNRGWithPermitSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountNRGMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountNRG) {
address WNRG = _storage.getWNRG();
address pair = pairFor(token, WNRG);
uint value = approveMax ? uint(-1) : liquidity;
IEnergiswapPairsManager(pair).permit(tx.origin, address(proxy), value, deadline, v, r, s);
amountNRG = removeLiquidityNRGSupportingFeeOnTransferTokens(
token, liquidity, amountTokenMin, amountNRGMin, to, deadline
);
}
// **** SWAP ****
// requires the initial amount to have already been sent to the first pair
function _swap(uint[] memory amounts, address[] memory path, address _to) internal {
for (uint i; i < path.length - 1; i++) {
(address input, address output) = (path[i], path[i + 1]);
(address token0,) = EnergiswapLibrary.sortTokens(input, output);
uint amountOut = amounts[i + 1];
(uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOut) : (amountOut, uint(0));
address to = i < path.length - 2 ? pairFor(output, path[i + 2]) : _to;
IEnergiswapPairsManager(pairFor(input, output)).swap(
amount0Out, amount1Out, to, new bytes(0)
);
}
}
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external ensure(deadline) returns (uint[] memory amounts) {
amounts = EnergiswapLibrary.getAmountsOut(_storage.getFactory(), amountIn, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'EnergiswapRouter: INSUFFICIENT_OUTPUT_AMOUNT');
IEnergiswapRouterGovernedProxy(address(uint160(proxy))).safeTransferFrom(path[0], tx.origin, pairFor(path[0], path[1]), amounts[0]);
_swap(amounts, path, to);
}
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external ensure(deadline) returns (uint[] memory amounts) {
amounts = EnergiswapLibrary.getAmountsIn(_storage.getFactory(), amountOut, path);
require(amounts[0] <= amountInMax, 'EnergiswapRouter: EXCESSIVE_INPUT_AMOUNT');
IEnergiswapRouterGovernedProxy(address(uint160(proxy))).safeTransferFrom(path[0], tx.origin, pairFor(path[0], path[1]), amounts[0]);
_swap(amounts, path, to);
}
function swapExactNRGForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
external
payable
ensure(deadline)
returns (uint[] memory amounts)
{
address WNRG = _storage.getWNRG();
require(path[0] == WNRG, 'EnergiswapRouter: INVALID_PATH');
amounts = EnergiswapLibrary.getAmountsOut(_storage.getFactory(), msg.value, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'EnergiswapRouter: INSUFFICIENT_OUTPUT_AMOUNT');
IWNRG(WNRG).deposit.value(amounts[0])();
assert(IERC20(WNRG).transfer(pairFor(path[0], path[1]), amounts[0]));
_swap(amounts, path, to);
}
function swapTokensForExactNRG(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
external
ensure(deadline)
returns (uint[] memory amounts)
{
address WNRG = _storage.getWNRG();
require(path[path.length - 1] == WNRG, 'EnergiswapRouter: INVALID_PATH');
amounts = EnergiswapLibrary.getAmountsIn(_storage.getFactory(), amountOut, path);
require(amounts[0] <= amountInMax, 'EnergiswapRouter: EXCESSIVE_INPUT_AMOUNT');
IEnergiswapRouterGovernedProxy(address(uint160(proxy))).safeTransferFrom(path[0], tx.origin, pairFor(path[0], path[1]), amounts[0]);
_swap(amounts, path, address(this));
IWNRG(WNRG).withdraw(amounts[amounts.length - 1]);
TransferHelper.safeTransferNRG(to, amounts[amounts.length - 1]);
}
function swapExactTokensForNRG(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
ensure(deadline)
returns (uint[] memory amounts)
{
address WNRG = _storage.getWNRG();
require(path[path.length - 1] == WNRG, 'EnergiswapRouter: INVALID_PATH');
amounts = EnergiswapLibrary.getAmountsOut(_storage.getFactory(), amountIn, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'EnergiswapRouter: INSUFFICIENT_OUTPUT_AMOUNT');
IEnergiswapRouterGovernedProxy(address(uint160(proxy))).safeTransferFrom(path[0], tx.origin, pairFor(path[0], path[1]), amounts[0]);
_swap(amounts, path, address(this));
IWNRG(WNRG).withdraw(amounts[amounts.length - 1]);
TransferHelper.safeTransferNRG(to, amounts[amounts.length - 1]);
}
function swapNRGForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
external
payable
ensure(deadline)
returns (uint[] memory amounts)
{
address WNRG = _storage.getWNRG();
require(path[0] == WNRG, 'EnergiswapRouter: INVALID_PATH');
amounts = EnergiswapLibrary.getAmountsIn(_storage.getFactory(), amountOut, path);
require(amounts[0] <= msg.value, 'EnergiswapRouter: EXCESSIVE_INPUT_AMOUNT');
IWNRG(WNRG).deposit.value(amounts[0])();
assert(IERC20(WNRG).transfer(pairFor(path[0], path[1]), amounts[0]));
_swap(amounts, path, to);
// refund dust wnrg, if any
if (msg.value > amounts[0]) TransferHelper.safeTransferNRG(tx.origin, msg.value - amounts[0]);
}
// **** SWAP (supporting fee-on-transfer tokens) ****
// requires the initial amount to have already been sent to the first pair
function _swapSupportingFeeOnTransferTokens(address[] memory path, address _to) internal {
for (uint i; i < path.length - 1; i++) {
(address input, address output) = (path[i], path[i + 1]);
(address token0,) = EnergiswapLibrary.sortTokens(input, output);
address pair = pairFor(input, output);
uint amountInput;
uint amountOutput;
{ // scope to avoid stack too deep errors
(uint reserve0, uint reserve1,) = IEnergiswapPairProxy(address(uint160(pair))).getReserves();
(uint reserveInput, uint reserveOutput) = input == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
amountInput = IERC20(input).balanceOf(pair).sub(reserveInput);
amountOutput = EnergiswapLibrary.getAmountOut(amountInput, reserveInput, reserveOutput);
}
(uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOutput) : (amountOutput, uint(0));
address to = i < path.length - 2 ? pairFor(output, path[i + 2]) : _to;
IEnergiswapPairsManager(pair).swap(amount0Out, amount1Out, to, new bytes(0));
}
}
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external ensure(deadline) {
IEnergiswapRouterGovernedProxy(address(uint160(proxy))).safeTransferFrom(path[0], tx.origin, pairFor(path[0], path[1]), amountIn);
uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
_swapSupportingFeeOnTransferTokens(path, to);
require(
IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin,
'EnergiswapRouter: INSUFFICIENT_OUTPUT_AMOUNT'
);
}
function swapExactNRGForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
)
external
payable
ensure(deadline)
{
address WNRG = _storage.getWNRG();
require(path[0] == WNRG, 'EnergiswapRouter: INVALID_PATH');
uint amountIn = msg.value;
IWNRG(WNRG).deposit.value(amountIn)();
assert(IERC20(WNRG).transfer(pairFor(path[0], path[1]), amountIn));
uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
_swapSupportingFeeOnTransferTokens(path, to);
require(
IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin,
'EnergiswapRouter: INSUFFICIENT_OUTPUT_AMOUNT'
);
}
function swapExactTokensForNRGSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
)
external
ensure(deadline)
{
address WNRG = _storage.getWNRG();
require(path[path.length - 1] == WNRG, 'EnergiswapRouter: INVALID_PATH');
IEnergiswapRouterGovernedProxy(address(uint160(proxy))).safeTransferFrom(path[0], tx.origin, pairFor(path[0], path[1]), amountIn);
_swapSupportingFeeOnTransferTokens(path, address(this));
uint amountOut = IERC20(WNRG).balanceOf(address(this));
require(amountOut >= amountOutMin, 'EnergiswapRouter: INSUFFICIENT_OUTPUT_AMOUNT');
IWNRG(WNRG).withdraw(amountOut);
TransferHelper.safeTransferNRG(to, amountOut);
}
// **** LIBRARY FUNCTIONS ****
function quote(uint amountA, uint reserveA, uint reserveB) public pure returns (uint amountB) {
return EnergiswapLibrary.quote(amountA, reserveA, reserveB);
}
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut)
public
pure
returns (uint amountOut)
{
return EnergiswapLibrary.getAmountOut(amountIn, reserveIn, reserveOut);
}
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut)
public
pure
returns (uint amountIn)
{
return EnergiswapLibrary.getAmountIn(amountOut, reserveIn, reserveOut);
}
function getAmountsOut(uint amountIn, address[] memory path)
public
view
returns (uint[] memory amounts)
{
return EnergiswapLibrary.getAmountsOut(_storage.getFactory(), amountIn, path);
}
function getAmountsIn(uint amountOut, address[] memory path)
public
view
returns (uint[] memory amounts)
{
return EnergiswapLibrary.getAmountsIn(_storage.getFactory(), amountOut, path);
}
}
// Copyright 2019 The Energi Core Authors
// This file is part of Energi Core.
//
// Energi Core is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Energi Core is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Energi Core. If not, see <http://www.gnu.org/licenses/>.
// Energi Governance system is the fundamental part of Energi Core.
// NOTE: It's not allowed to change the compiler due to byte-to-byte
// match requirement.
//pragma experimental SMTChecker;
/**
* Genesis version of IGovernedProxy interface.
*
* Base Consensus interface for upgradable contracts proxy.
* Unlike common approach, the implementation is NOT expected to be
* called through delegatecall() to minimize risks of shared storage.
*
* NOTE: it MUST NOT change after blockchain launch!
*/
interface IGovernedProxy {
event UpgradeProposal(
IGovernedContract indexed impl,
IUpgradeProposal proposal
);
event Upgraded(
IGovernedContract indexed impl,
IUpgradeProposal proposal
);
function impl() external view returns(IGovernedContract);
function proposeUpgrade(IGovernedContract _newImpl, uint _period)
external payable returns(IUpgradeProposal);
function upgrade(IUpgradeProposal _proposal) external;
function upgradeProposalImpl(IUpgradeProposal _proposal) external view returns(IGovernedContract new_impl);
function listUpgradeProposals() external view returns(IUpgradeProposal[] memory proposals);
function collectUpgradeProposal(IUpgradeProposal _proposal) external;
function () external payable;
}
// Copyright 2019 The Energi Core Authors
// This file is part of Energi Core.
//
// Energi Core is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Energi Core is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Energi Core. If not, see <http://www.gnu.org/licenses/>.
interface IEnergiswapRouterGovernedProxy {
event UpgradeProposal(
IGovernedContract indexed impl,
IUpgradeProposal proposal
);
event Upgraded(
IGovernedContract indexed impl,
IUpgradeProposal proposal
);
function impl() external view returns (address);
function spork_proxy() external view returns (address);
function safeTransferFrom(address token, address from, address to, uint value) external;
function proposeUpgrade(IGovernedContract _newImpl, uint _period) external payable returns(IUpgradeProposal);
function upgrade(IUpgradeProposal _proposal) external;
function upgradeProposalImpl(IUpgradeProposal _proposal) external view returns(IGovernedContract new_impl);
function listUpgradeProposals() external view returns(IUpgradeProposal[] memory proposals);
function collectUpgradeProposal(IUpgradeProposal _proposal) external;
function proxy() external view returns (address);
function migrate(IGovernedContract) external pure;
function destroy(IGovernedContract) external pure;
function () external payable;
}
// Copyright 2019 The Energi Core Authors
// This file is part of Energi Core.
//
// Energi Core is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Energi Core is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Energi Core. If not, see <http://www.gnu.org/licenses/>.
// Energi Governance system is the fundamental part of Energi Core.
// NOTE: It's not allowed to change the compiler due to byte-to-byte
// match requirement.
interface ISporkRegistry {
function createUpgradeProposal(
IGovernedContract _impl,
uint _period,
address payable _fee_payer
)
external payable
returns (IUpgradeProposal);
function consensusGasLimits()
external view
returns(uint callGas, uint xferGas);
}
/**
* SC-9: This contract has no chance of being updated. It must be stupid simple.
*
* If another upgrade logic is required in the future - it can be done as proxy stage II.
*/
contract EnergiswapRouterGovernedProxy is IEnergiswapRouterGovernedProxy, NonReentrant {
IGovernedContract public impl;
IGovernedProxy public spork_proxy;
mapping(address => IGovernedContract) public upgrade_proposals;
IUpgradeProposal[] public upgrade_proposal_list;
modifier senderOrigin {
// Internal calls are expected to use impl directly.
// That's due to use of call() instead of delegatecall() on purpose.
// solium-disable-next-line security/no-tx-origin
require(tx.origin == msg.sender, "EnergiswapRouterGovernedProxy: FORBIDDEN, only direct calls are allowed!");
_;
}
modifier requireImpl {
require(msg.sender == address(impl), "EnergiswapRouterGovernedProxy: FORBIDDEN, not impl");
_;
}
constructor(address _impl, address payable _sporkProxy) public {
impl = IGovernedContract(_impl);
spork_proxy = IGovernedProxy(_sporkProxy);
}
function safeTransferFrom(address token, address from, address to, uint value) external requireImpl {
// bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'EnergiswapGovernedProxy: TRANSFER_FROM_FAILED');
}
/**
* Pre-create a new contract first.
* Then propose upgrade based on that.
*/
function proposeUpgrade(IGovernedContract _newImpl, uint _period)
external payable
senderOrigin
noReentry
returns(IUpgradeProposal)
{
require(_newImpl != impl, "Already active!");
require(_newImpl.proxy() == address(this), "Wrong proxy!");
ISporkRegistry spork_reg = ISporkRegistry(address(spork_proxy.impl()));
IUpgradeProposal proposal = spork_reg.createUpgradeProposal.value(msg.value)(_newImpl, _period, msg.sender);
upgrade_proposals[address(proposal)] = _newImpl;
upgrade_proposal_list.push(proposal);
emit UpgradeProposal(_newImpl, proposal);
return proposal;
}
/**
* Once proposal is accepted, anyone can activate that.
*/
function upgrade(IUpgradeProposal _proposal)
external
noReentry
{
IGovernedContract new_impl = upgrade_proposals[address(_proposal)];
require(new_impl != impl, "Already active!"); // in case it changes in the flight
require(address(new_impl) != address(0), "Not registered!");
require(_proposal.isAccepted(), "Not accepted!");
IGovernedContract old_impl = impl;
new_impl.migrate(old_impl);
impl = new_impl;
old_impl.destroy(new_impl);
// SECURITY: prevent downgrade attack
_cleanupProposal(_proposal);
// Return fee ASAP
_proposal.destroy();
emit Upgraded(new_impl, _proposal);
}
/**
* Map proposal to implementation
*/
function upgradeProposalImpl(IUpgradeProposal _proposal)
external view
returns(IGovernedContract new_impl)
{
new_impl = upgrade_proposals[address(_proposal)];
}
/**
* Lists all available upgrades
*/
function listUpgradeProposals()
external view
returns(IUpgradeProposal[] memory proposals)
{
uint len = upgrade_proposal_list.length;
proposals = new IUpgradeProposal[](len);
for (uint i = 0; i < len; ++i) {
proposals[i] = upgrade_proposal_list[i];
}
return proposals;
}
/**
* Once proposal is reject, anyone can start collect procedure.
*/
function collectUpgradeProposal(IUpgradeProposal _proposal)
external
noReentry
{
IGovernedContract new_impl = upgrade_proposals[address(_proposal)];
require(address(new_impl) != address(0), "Not registered!");
_proposal.collect();
delete upgrade_proposals[address(_proposal)];
_cleanupProposal(_proposal);
}
function _cleanupProposal(IUpgradeProposal _proposal) internal {
delete upgrade_proposals[address(_proposal)];
uint len = upgrade_proposal_list.length;
for (uint i = 0; i < len; ++i) {
if (upgrade_proposal_list[i] == _proposal) {
upgrade_proposal_list[i] = upgrade_proposal_list[len - 1];
upgrade_proposal_list.pop();
break;
}
}
}
/**
* Related to above
*/
function proxy() external view returns (address) {
return address(this);
}
/**
* SECURITY: prevent on-behalf-of calls
*/
function migrate(IGovernedContract) external pure {
revert("Good try");
}
/**
* SECURITY: prevent on-behalf-of calls
*/
function destroy(IGovernedContract) external pure {
revert("Good try");
}
/**
* Proxy all other calls to implementation.
*/
function ()
external
payable
senderOrigin
{
// SECURITY: senderOrigin() modifier is mandatory
IGovernedContract impl_m = impl;
// solium-disable-next-line security/no-inline-assembly
assembly {
let ptr := mload(0x40)
calldatacopy(ptr, 0, calldatasize())
let res := call(sub(gas(), 10000), impl_m, callvalue(), ptr, calldatasize(), 0, 0)
// NOTE: returndatasize should allow repeatable calls
// what should save one opcode.
returndatacopy(ptr, 0, returndatasize())
switch res
case 0 {
revert(ptr, returndatasize())
}
default {
return(ptr, returndatasize())
}
}
}
}

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","payable":false,"inputs":[{"type":"address","name":"_impl","internalType":"address"},{"type":"address","name":"_sporkProxy","internalType":"address payable"}]},{"type":"event","name":"UpgradeProposal","inputs":[{"type":"address","name":"impl","internalType":"contract IGovernedContract","indexed":true},{"type":"address","name":"proposal","internalType":"contract IUpgradeProposal","indexed":false}],"anonymous":false},{"type":"event","name":"Upgraded","inputs":[{"type":"address","name":"impl","internalType":"contract IGovernedContract","indexed":true},{"type":"address","name":"proposal","internalType":"contract IUpgradeProposal","indexed":false}],"anonymous":false},{"type":"fallback","stateMutability":"payable","payable":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"collectUpgradeProposal","inputs":[{"type":"address","name":"_proposal","internalType":"contract IUpgradeProposal"}],"constant":false},{"type":"function","stateMutability":"pure","payable":false,"outputs":[],"name":"destroy","inputs":[{"type":"address","name":"","internalType":"contract IGovernedContract"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"contract IGovernedContract"}],"name":"impl","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address[]","name":"proposals","internalType":"contract IUpgradeProposal[]"}],"name":"listUpgradeProposals","inputs":[],"constant":true},{"type":"function","stateMutability":"pure","payable":false,"outputs":[],"name":"migrate","inputs":[{"type":"address","name":"","internalType":"contract IGovernedContract"}],"constant":true},{"type":"function","stateMutability":"payable","payable":true,"outputs":[{"type":"address","name":"","internalType":"contract IUpgradeProposal"}],"name":"proposeUpgrade","inputs":[{"type":"address","name":"_newImpl","internalType":"contract IGovernedContract"},{"type":"uint256","name":"_period","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"proxy","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"safeTransferFrom","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"address","name":"from","internalType":"address"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"contract IGovernedProxy"}],"name":"spork_proxy","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"upgrade","inputs":[{"type":"address","name":"_proposal","internalType":"contract IUpgradeProposal"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"new_impl","internalType":"contract IGovernedContract"}],"name":"upgradeProposalImpl","inputs":[{"type":"address","name":"_proposal","internalType":"contract IUpgradeProposal"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"contract IUpgradeProposal"}],"name":"upgrade_proposal_list","inputs":[{"type":"uint256","name":"","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"contract IGovernedContract"}],"name":"upgrade_proposals","inputs":[{"type":"address","name":"","internalType":"address"}],"constant":true}]
            

Deployed ByteCode

0x6080604052600436106100c15760003560e01c80638abf60771161007f578063ce5494bb11610059578063ce5494bb14610137578063d9fc4b6114610324578063dd6a851d1461036d578063ec55688914610382576100c1565b80638abf607714610277578063a1b0e4761461028c578063b364595e146102bf576100c1565b8062f55d9d146101375780630900f0101461016c57806332e3a9051461019f5780635b6dee4c146101ee5780636d5b6c441461021a5780636fa09ab01461024d575b3233146100ff5760405162461bcd60e51b8152600401808060200182810382526048815260200180610f5c6048913960600191505060405180910390fd5b6001546040516001600160a01b03909116903660008237600080368334866127105a03f13d6000833e808015610133573d83f35b3d83fd5b34801561014357600080fd5b5061016a6004803603602081101561015a57600080fd5b50356001600160a01b0316610397565b005b34801561017857600080fd5b5061016a6004803603602081101561018f57600080fd5b50356001600160a01b03166103cf565b3480156101ab57600080fd5b506101d2600480360360208110156101c257600080fd5b50356001600160a01b03166106f3565b604080516001600160a01b039092168252519081900360200190f35b6101d26004803603604081101561020457600080fd5b506001600160a01b03813516906020013561070e565b34801561022657600080fd5b506101d26004803603602081101561023d57600080fd5b50356001600160a01b0316610a4d565b34801561025957600080fd5b506101d26004803603602081101561027057600080fd5b5035610a6b565b34801561028357600080fd5b506101d2610a92565b34801561029857600080fd5b5061016a600480360360208110156102af57600080fd5b50356001600160a01b0316610aa1565b3480156102cb57600080fd5b506102d4610bce565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156103105781810151838201526020016102f8565b505050509050019250505060405180910390f35b34801561033057600080fd5b5061016a6004803603608081101561034757600080fd5b506001600160a01b03813581169160208101358216916040820135169060600135610c68565b34801561037957600080fd5b506101d2610e0e565b34801561038e57600080fd5b506101d2610e1d565b6040805162461bcd60e51b8152602060048201526008602482015267476f6f642074727960c01b604482015290519081900360640190fd5b6000541561040e576040805162461bcd60e51b81526020600482015260076024820152665265656e74727960c81b604482015290519081900360640190fd5b600160008181556001600160a01b03808416825260036020526040909120549154918116911681141561047a576040805162461bcd60e51b815260206004820152600f60248201526e416c7265616479206163746976652160881b604482015290519081900360640190fd5b6001600160a01b0381166104c7576040805162461bcd60e51b815260206004820152600f60248201526e4e6f7420726567697374657265642160881b604482015290519081900360640190fd5b816001600160a01b0316635051a5ec6040518163ffffffff1660e01b815260040160206040518083038186803b15801561050057600080fd5b505afa158015610514573d6000803e3d6000fd5b505050506040513d602081101561052a57600080fd5b505161056d576040805162461bcd60e51b815260206004820152600d60248201526c4e6f742061636365707465642160981b604482015290519081900360640190fd5b6001546040805163ce5494bb60e01b81526001600160a01b03928316600482018190529151919284169163ce5494bb9160248082019260009290919082900301818387803b1580156105be57600080fd5b505af11580156105d2573d6000803e3d6000fd5b5050600180546001600160a01b0319166001600160a01b038681169182179092556040805162f55d9d60e01b8152600481019290925251918516935062f55d9d925060248082019260009290919082900301818387803b15801561063557600080fd5b505af1158015610649573d6000803e3d6000fd5b5050505061065683610e21565b826001600160a01b03166383197ef06040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561069157600080fd5b505af11580156106a5573d6000803e3d6000fd5b5050604080516001600160a01b038781168252915191861693507f5d611f318680d00598bb735d61bacf0c514c6b50e1e5ad30040a4df2b12791c7925081900360200190a250506000805550565b6003602052600090815260409020546001600160a01b031681565b600032331461074e5760405162461bcd60e51b8152600401808060200182810382526048815260200180610f5c6048913960600191505060405180910390fd5b6000541561078d576040805162461bcd60e51b81526020600482015260076024820152665265656e74727960c81b604482015290519081900360640190fd5b60016000819055546001600160a01b03848116911614156107e7576040805162461bcd60e51b815260206004820152600f60248201526e416c7265616479206163746976652160881b604482015290519081900360640190fd5b306001600160a01b0316836001600160a01b031663ec5568896040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561082c57600080fd5b505af1158015610840573d6000803e3d6000fd5b505050506040513d602081101561085657600080fd5b50516001600160a01b0316146108a2576040805162461bcd60e51b815260206004820152600c60248201526b57726f6e672070726f78792160a01b604482015290519081900360640190fd5b60025460408051638abf607760e01b815290516000926001600160a01b031691638abf6077916004808301926020929190829003018186803b1580156108e757600080fd5b505afa1580156108fb573d6000803e3d6000fd5b505050506040513d602081101561091157600080fd5b5051604080516362877ccd60e01b81526001600160a01b038781166004830152602482018790523360448301529151929350600092918416916362877ccd913491606480830192602092919082900301818588803b15801561097257600080fd5b505af1158015610986573d6000803e3d6000fd5b50505050506040513d602081101561099d57600080fd5b50516001600160a01b0380821660008181526003602090815260408083208054958c166001600160a01b031996871681179091556004805460018101825594527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b9093018054909516841790945583519283529251939450927f812eb2689eecf94cfb55caf4a123ea76c6d93eef07dd54a5273b7a4949f7d763929181900390910190a260008055949350505050565b6001600160a01b039081166000908152600360205260409020541690565b60048181548110610a7857fe5b6000918252602090912001546001600160a01b0316905081565b6001546001600160a01b031681565b60005415610ae0576040805162461bcd60e51b81526020600482015260076024820152665265656e74727960c81b604482015290519081900360640190fd5b600160009081556001600160a01b03808316825260036020526040909120541680610b44576040805162461bcd60e51b815260206004820152600f60248201526e4e6f7420726567697374657265642160881b604482015290519081900360640190fd5b816001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610b7f57600080fd5b505af1158015610b93573d6000803e3d6000fd5b5050506001600160a01b038316600090815260036020526040902080546001600160a01b031916905550610bc682610e21565b505060008055565b60045460408051828152602080840282010190915260609190818015610bfe578160200160208202803883390190505b50915060005b81811015610c635760048181548110610c1957fe5b9060005260206000200160009054906101000a90046001600160a01b0316838281518110610c4357fe5b6001600160a01b0390921660209283029190910190910152600101610c04565b505090565b6001546001600160a01b03163314610cb15760405162461bcd60e51b8152600401808060200182810382526032815260200180610f2a6032913960400191505060405180910390fd5b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17815292518251600094606094938a169392918291908083835b60208310610d365780518252601f199092019160209182019101610d17565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114610d98576040519150601f19603f3d011682016040523d82523d6000602084013e610d9d565b606091505b5091509150818015610dcb575080511580610dcb5750808060200190516020811015610dc857600080fd5b50515b610e065760405162461bcd60e51b815260040180806020018281038252602d815260200180610fa4602d913960400191505060405180910390fd5b505050505050565b6002546001600160a01b031681565b3090565b6001600160a01b038116600090815260036020526040812080546001600160a01b0319169055600454905b81811015610f2457826001600160a01b031660048281548110610e6b57fe5b6000918252602090912001546001600160a01b03161415610f1c5760046001830381548110610e9657fe5b600091825260209091200154600480546001600160a01b039092169183908110610ebc57fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506004805480610ef557fe5b600082815260209020810160001990810180546001600160a01b0319169055019055610f24565b600101610e4c565b50505056fe456e6572676973776170526f75746572476f7665726e656450726f78793a20464f5242494444454e2c206e6f7420696d706c456e6572676973776170526f75746572476f7665726e656450726f78793a20464f5242494444454e2c206f6e6c79206469726563742063616c6c732061726520616c6c6f77656421456e6572676973776170476f7665726e656450726f78793a205452414e534645525f46524f4d5f4641494c4544a265627a7a7231582050c68c4dd7afaad81da9db7e43a8aa8e19fe2ec8f2d12165136aa92dba3cd17a64736f6c63430005100032