Contract Source Code:
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <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 GSN 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 payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
import "./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 () internal {
_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: GPL-3.0-or-later
pragma solidity >=0.6.0;
// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library TransferHelper {
function safeApprove(
address token,
address to,
uint256 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::safeApprove: approve failed'
);
}
function safeTransfer(
address token,
address to,
uint256 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::safeTransfer: transfer failed'
);
}
function safeTransferFrom(
address token,
address from,
address to,
uint256 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::transferFrom: transferFrom failed'
);
}
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, 'TransferHelper::safeTransferETH: ETH transfer failed');
}
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
interface ICore {
// ----------- Getters -----------
function isBurner(address _address) external view returns (bool);
function isMinter(address _address) external view returns (bool);
function isGovernor(address _address) external view returns (bool);
function isGuardian(address _address) external view returns (bool);
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.6.6;
import './interfaces/IFewFactory.sol';
import './refs/CoreRef.sol';
import './FewWrappedToken.sol';
contract FewFactory is IFewFactory, CoreRef {
mapping(address => address) public override getWrappedToken;
address[] public override allWrappedTokens;
address public override parameter;
event WrappedTokenCreated(address indexed originalToken, address wrappedToken, uint);
constructor(address coreAddress) CoreRef(coreAddress) public {}
function allWrappedTokensLength() external override view returns (uint) {
return allWrappedTokens.length;
}
function paused() public override(IFewFactory, Pausable) view returns (bool) {
return super.paused();
}
function createToken(address originalToken) external override returns (address wrappedToken) {
require(originalToken != address(0));
require(getWrappedToken[originalToken] == address(0)); // single check is sufficient
parameter = originalToken;
wrappedToken = address(new FewWrappedToken{salt: keccak256(abi.encode(originalToken))}());
delete parameter;
getWrappedToken[originalToken] = wrappedToken;
allWrappedTokens.push(wrappedToken);
emit WrappedTokenCreated(originalToken, wrappedToken, allWrappedTokens.length);
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.6.6;
import '@uniswap/lib/contracts/libraries/TransferHelper.sol';
import './interfaces/IFewWrappedToken.sol';
import './libraries/SafeMath.sol';
import './refs/ICoreRef.sol';
import './interfaces/IFewFactory.sol';
/// @title Few Wrapped Token
contract FewWrappedToken is IFewWrappedToken {
using SafeMath for uint;
string public override name;
string public override symbol;
uint8 public override decimals;
uint public override totalSupply;
mapping(address => uint) public override balanceOf;
mapping(address => mapping(address => uint)) public override allowance;
bytes32 public override DOMAIN_SEPARATOR;
// keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
bytes32 public override constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
mapping(address => uint) public override nonces;
address public override factory;
address public override token;
modifier onlyMinter() {
require(ICoreRef(factory).core().isMinter(msg.sender), "CoreRef: Caller is not a minter");
_;
}
modifier onlyBurner() {
require(ICoreRef(factory).core().isBurner(msg.sender), "CoreRef: Caller is not a burner");
_;
}
modifier whenNotPaused() {
require(!IFewFactory(factory).paused(), "CoreRef: Caller is paused");
_;
}
event Mint(address indexed minter, uint256 amount, address indexed to);
event Burn(address indexed burner, uint256 amount, address indexed to);
event Wrap(address indexed sender, uint256 amount, address indexed to);
event Unwrap(address indexed sender, uint256 amount, address indexed to);
/// @notice Few wrapped token constructor
constructor() public {
uint chainId;
assembly {
chainId := chainid()
}
factory = msg.sender;
token = IFewFactory(msg.sender).parameter();
name = string(abi.encodePacked("Few Wrapped ", IERC20(token).name()));
symbol = string(abi.encodePacked("fw", IERC20(token).symbol()));
decimals = IERC20(token).decimals();
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
keccak256(bytes(name)),
keccak256(bytes('1')),
chainId,
address(this)
)
);
}
function _mint(address to, uint value) internal {
totalSupply = totalSupply.add(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(address(0), to, value);
}
function _burn(address from, uint value) internal {
balanceOf[from] = balanceOf[from].sub(value);
totalSupply = totalSupply.sub(value);
emit Transfer(from, address(0), value);
}
function _approve(address owner, address spender, uint value) internal {
allowance[owner][spender] = value;
emit Approval(owner, spender, value);
}
function _transfer(address from, address to, uint value) private {
balanceOf[from] = balanceOf[from].sub(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(from, to, value);
}
function approve(address spender, uint value) external override returns (bool) {
_approve(msg.sender, spender, value);
return true;
}
function transfer(address to, uint value) external override returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
function transferFrom(address from, address to, uint value) external override returns (bool) {
if (allowance[from][msg.sender] != uint(-1)) {
allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
}
_transfer(from, to, value);
return true;
}
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external override {
require(deadline >= block.timestamp, 'Few: EXPIRED');
bytes32 digest = keccak256(
abi.encodePacked(
'\x19\x01',
DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
)
);
address recoveredAddress = ecrecover(digest, v, r, s);
require(recoveredAddress != address(0) && recoveredAddress == owner, 'Few: INVALID_SIGNATURE');
_approve(owner, spender, value);
}
/// @notice mint Few wrapped tokens
/// @param account the account to mint to
/// @param amount the amount to mint
function mint(address account, uint256 amount)
external
override
onlyMinter
whenNotPaused
{
_mint(account, amount);
emit Mint(msg.sender, amount, account);
}
/// @notice burn Few wrapped tokens from caller
/// @param amount the amount to burn
function burn(uint256 amount) public override {
_burn(msg.sender, amount);
emit Burn(msg.sender, amount, msg.sender);
}
/// @notice burn Few wrapped tokens from specified account
/// @param account the account to burn from
/// @param amount the amount to burn
function burnFrom(address account, uint256 amount)
public
override
onlyBurner
whenNotPaused
{
_burn(account, amount);
emit Burn(msg.sender, amount, account);
}
/// @notice exchanges token to Few wrapped token
/// @param amount the amount to wrap
/// @param to wrapped token reciver address
function wrapTo(uint256 amount, address to) public override returns (uint256) {
require(amount > 0, "Few: can't wrap zero token");
TransferHelper.safeTransferFrom(token, msg.sender, address(this), amount);
_mint(to, amount);
emit Wrap(msg.sender, amount, to);
return amount;
}
function wrap(uint256 amount) external override returns (uint256) {
return wrapTo(amount, msg.sender);
}
/// @notice exchange Few wrapped token to token
/// @param amount the amount to unwrap
/// @param to token receiver address
function unwrapTo(uint256 amount, address to) public override returns (uint256) {
require(amount > 0, "Few: zero amount unwrap not allowed");
_burn(msg.sender, amount);
TransferHelper.safeTransfer(address(token), to, amount);
emit Unwrap(msg.sender, amount, to);
return amount;
}
function unwrap(uint256 amount) external override returns (uint256) {
return unwrapTo(amount, msg.sender);
}
}
pragma solidity >=0.5.0;
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);
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import './IERC20.sol';
interface IFewERC20 is IERC20 {
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint);
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
interface IFewFactory {
event WrappedTokenCreated(address indexed originalToken, address wrappedToken, uint);
function getWrappedToken(address originalToken) external view returns (address wrappedToken);
function allWrappedTokens(uint) external view returns (address wrappedToken);
function parameter() external view returns (address);
function allWrappedTokensLength() external view returns (uint);
function paused() external view returns (bool);
function createToken(address originalToken) external returns (address wrappedToken);
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import '../interfaces/IFewERC20.sol';
interface IFewWrappedToken is IFewERC20 {
event Mint(address indexed minter, uint256 amount, address indexed to);
event Burn(address indexed burner, uint256 amount, address indexed to);
event Wrap(address indexed sender, uint256 amount, address indexed to);
event Unwrap(address indexed sender, uint256 amount, address indexed to);
function factory() external view returns (address);
function token() external view returns (address);
function mint(address account, uint256 amount) external;
function burn(uint256 amount) external;
function burnFrom(address account, uint256 amount) external;
function wrapTo(uint256 amount, address to) external returns (uint256);
function wrap(uint256 amount) external returns (uint256);
function unwrapTo(uint256 amount, address to) external returns (uint256);
function unwrap(uint256 amount) external returns (uint256);
}
pragma solidity =0.6.6;
// 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');
}
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity =0.6.6;
import './ICoreRef.sol';
import '@openzeppelin/contracts/utils/Pausable.sol';
/// @title A Reference to Core
/// @notice defines some modifiers and utilities around interacting with Core
abstract contract CoreRef is ICoreRef, Pausable {
ICore private _core;
/// @notice CoreRef constructor
/// @param coreAddress Few Core to reference
constructor(address coreAddress) public {
_core = ICore(coreAddress);
}
modifier onlyMinter() {
require(_core.isMinter(msg.sender), "CoreRef: Caller is not a minter");
_;
}
modifier onlyBurner() {
require(_core.isBurner(msg.sender), "CoreRef: Caller is not a burner");
_;
}
modifier onlyGovernor() {
require(
_core.isGovernor(msg.sender),
"CoreRef: Caller is not a governor"
);
_;
}
modifier onlyGuardianOrGovernor() {
require(
_core.isGovernor(msg.sender) ||
_core.isGuardian(msg.sender),
"CoreRef: Caller is not a guardian or governor"
);
_;
}
/// @notice set new Core reference address
/// @param coreAddress the new core address
function setCore(address coreAddress) external override onlyGovernor {
_core = ICore(coreAddress);
emit CoreUpdate(coreAddress);
}
/// @notice set pausable methods to paused
function pause() public override onlyGuardianOrGovernor {
_pause();
}
/// @notice set pausable methods to unpaused
function unpause() public override onlyGuardianOrGovernor {
_unpause();
}
/// @notice address of the Core contract referenced
/// @return ICore implementation address
function core() public view override returns (ICore) {
return _core;
}
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import '../core/ICore.sol';
/// @title CoreRef interface
interface ICoreRef {
event CoreUpdate(address indexed _core);
function setCore(address coreAddress) external;
function pause() external;
function unpause() external;
function core() external view returns (ICore);
}