Contract Name:
WrapperLock
Contract Source Code:
File 1 of 1 : WrapperLock
pragma solidity 0.4.24;
/**
* @dev Collection of functions related to the address type,
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* This test is non-exhaustive, and there may be false-negatives: during the
* execution of a contract's constructor, its address will be reported as
* not containing a contract.
*
* > It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*/
function isContract(address account) internal view returns (bool) {
// This method relies in extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
// solhint-disable-next-line no-inline-assembly
assembly { size := extcodesize(account) }
return size > 0;
}
}
/**
* @title ERC20Basic
* @dev Simpler version of ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/179
*/
contract ERC20Basic {
function totalSupply() public view returns (uint256);
function balanceOf(address who) public view returns (uint256);
function transfer(address to, uint256 value) public returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
}
/**
* @title Basic token
* @dev Basic version of StandardToken, with no allowances.
*/
contract BasicToken is ERC20Basic {
using SafeMath for uint256;
mapping(address => uint256) balances;
uint256 totalSupply_;
/**
* @dev total number of tokens in existence
*/
function totalSupply() public view returns (uint256) {
return totalSupply_;
}
/**
* @dev transfer token for a specified address
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
*/
function transfer(address _to, uint256 _value) public returns (bool) {
require(_to != address(0));
require(_value <= balances[msg.sender]);
// SafeMath.sub will throw if there is not enough balance.
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
Transfer(msg.sender, _to, _value);
return true;
}
/**
* @dev Gets the balance of the specified address.
* @param _owner The address to query the the balance of.
* @return An uint256 representing the amount owned by the passed address.
*/
function balanceOf(address _owner) public view returns (uint256 balance) {
return balances[_owner];
}
}
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* 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 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
callOptionalReturn(token, abi.encodeWithSelector(bytes4(0xa9059cbb), to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
callOptionalReturn(token, abi.encodeWithSelector(bytes4(0x23b872dd), from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
// solhint-disable-next-line max-line-length
require((value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value);
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value);
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves.
// A Solidity high level call has three parts:
// 1. The target address is checked to verify it contains contract code
// 2. The call itself is made, and success asserted
// 3. The return value is decoded, which in turn checks the size of the returned data.
// solhint-disable-next-line max-line-length
require(address(token).isContract(), "SafeERC20: call to non-contract");
// call returns only success in 0.4.24
// solhint-disable-next-line avoid-low-level-calls
bool success = address(token).call(data);
require(success, "SafeERC20: low-level call failed");
}
}
/**
* @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);
}
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
assert(c / a == b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
/**
* @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 OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
function Ownable() public {
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 onlyOwner {
require(newOwner != address(0));
OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
/*
Copyright Ethfinex Inc 2018
Licensed under the Apache License, Version 2.0
http://www.apache.org/licenses/LICENSE-2.0
*/
contract WrapperLock is BasicToken, Ownable {
using SafeERC20 for IERC20;
using SafeMath for uint256;
address public TRANSFER_PROXY_VEFX = 0xdcDb42C9a256690bd153A7B409751ADFC8Dd5851;
address public TRANSFER_PROXY_V2 = 0x95e6f48254609a6ee006f7d493c8e5fb97094cef;
mapping (address => bool) public isSigner;
string public name;
string public symbol;
uint public decimals;
address public originalToken;
mapping (address => uint256) public depositLock;
mapping (address => uint256) public balances;
function WrapperLock(address _originalToken, string _name, string _symbol, uint _decimals) Ownable() {
originalToken = _originalToken;
name = _name;
symbol = _symbol;
decimals = _decimals;
isSigner[msg.sender] = true;
}
// @dev method only for testing, needs to be commented out when deploying
// function addProxy(address _addr) public {
// TRANSFER_PROXY_VEFX = _addr;
// }
function deposit(uint _value, uint _forTime) public returns (bool success) {
require(_forTime >= 1);
require(now + _forTime * 1 hours >= depositLock[msg.sender]);
IERC20(originalToken).safeTransferFrom(msg.sender, address(this), _value);
balances[msg.sender] = balances[msg.sender].add(_value);
totalSupply_ = totalSupply_.add(_value);
depositLock[msg.sender] = now + _forTime * 1 hours;
return true;
}
function withdraw(
uint _value,
uint8 v,
bytes32 r,
bytes32 s,
uint signatureValidUntilBlock
)
public
returns
(bool success)
{
require(balanceOf(msg.sender) >= _value);
if (now <= depositLock[msg.sender]) {
require(block.number < signatureValidUntilBlock);
require(isValidSignature(keccak256(msg.sender, address(this), signatureValidUntilBlock), v, r, s));
}
balances[msg.sender] = balances[msg.sender].sub(_value);
totalSupply_ = totalSupply_.sub(_value);
depositLock[msg.sender] = 0;
IERC20(originalToken).safeTransfer(msg.sender, _value);
return true;
}
function withdrawBalanceDifference() public onlyOwner returns (bool success) {
require(IERC20(originalToken).balanceOf(address(this)).sub(totalSupply_) > 0);
IERC20(originalToken).safeTransfer(msg.sender, IERC20(originalToken).balanceOf(address(this)).sub(totalSupply_));
return true;
}
function withdrawDifferentToken(address _differentToken) public onlyOwner returns (bool) {
require(_differentToken != originalToken);
require(IERC20(_differentToken).balanceOf(address(this)) > 0);
IERC20(_differentToken).safeTransfer(msg.sender, IERC20(_differentToken).balanceOf(address(this)));
return true;
}
function transfer(address _to, uint256 _value) public returns (bool) {
return false;
}
function transferFrom(address _from, address _to, uint _value) public {
require(isSigner[_to] || isSigner[_from]);
assert(msg.sender == TRANSFER_PROXY_VEFX || msg.sender == TRANSFER_PROXY_V2);
balances[_to] = balances[_to].add(_value);
depositLock[_to] = depositLock[_to] > now ? depositLock[_to] : now + 1 hours;
balances[_from] = balances[_from].sub(_value);
Transfer(_from, _to, _value);
}
function allowance(address _owner, address _spender) public constant returns (uint) {
if (_spender == TRANSFER_PROXY_VEFX || _spender == TRANSFER_PROXY_V2) {
return 2**256 - 1;
}
}
function balanceOf(address _owner) public constant returns (uint256) {
return balances[_owner];
}
function isValidSignature(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
)
public
constant
returns (bool)
{
return isSigner[ecrecover(
keccak256("\x19Ethereum Signed Message:\n32", hash),
v,
r,
s
)];
}
function addSigner(address _newSigner) public {
require(isSigner[msg.sender]);
isSigner[_newSigner] = true;
}
function keccak(address _sender, address _wrapper, uint _validTill) public constant returns(bytes32) {
return keccak256(_sender, _wrapper, _validTill);
}
}