-
Notifications
You must be signed in to change notification settings - Fork 15
/
VirtualAugurShare.sol
164 lines (139 loc) · 5.29 KB
/
VirtualAugurShare.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
pragma solidity 0.4.24;
import { SafeMath } from "openzeppelin-solidity/contracts/math/SafeMath.sol";
import { IERC20 } from "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
import { Ownable } from "openzeppelin-solidity/contracts/ownership/Ownable.sol";
import { UnlimitedAllowanceToken } from "./UnlimitedAllowanceToken.sol";
/**
* @title VirtualAugurShare
* @author Veil
*
* WETH-like token that wraps Augur ERC-20 shares and comes pre-approved for trading on 0x
* The default spender is set to the 0x ERC20 Proxy contract to give unlimited allowance
* without the need to unlock tokens. The underlying Augur ERC-20 share can be redeemed any time.
* The contract implements the Ownable interface. If the token is set to address(0) upon creation,
* it can be updated to an ERC-20 address by the owner. Once the token is set, nothing can change.
*/
contract VirtualAugurShare is UnlimitedAllowanceToken, Ownable {
using SafeMath for uint256;
/* ============ Constants ============ */
string constant public name = "Virtual Augur Share"; // solium-disable-line uppercase
string constant public symbol = "VSHARE"; // solium-disable-line uppercase
uint256 constant public decimals = 18; // solium-disable-line uppercase
/* ============ State variables ============ */
address public token;
address public defaultSpender;
/* ============ Events ============ */
event Deposit(address indexed dest, uint256 amount);
event Withdrawal(address indexed src, uint256 amount);
event SetToken(address indexed token);
/* ============ Constructor ============ */
/**
* Constructor function for VirtualAugurShare token
*
* @param _token Underlying ERC-20 token address to wrap
* @param _defaultSpender This address will have unlimited allowance by default
*/
constructor(address _token, address _defaultSpender) public {
require(_defaultSpender != address(0), "Invalid defaultSpender address");
token = _token;
defaultSpender = _defaultSpender;
}
/* ============ Public Functions ============ */
/**
* @dev Fallback function
*/
function() public {
revert("Fallback function reverts");
}
modifier whenTokenIsSet {
require(token != address(0), "Underlying token is not set");
_;
}
modifier whenTokenIsNotSet {
require(token == address(0), "Underlying token is already set");
_;
}
/**
* Sets the underlying ERC-20 token of the VirtualAugurShare. Only callable by the owner when
* when the token address(0)
*
* @param _token Underlying ERC-20 token address to wrap
*/
function setToken(address _token) public onlyOwner whenTokenIsNotSet returns (bool) {
token = _token;
emit SetToken(_token);
return true;
}
/**
* Buys tokens with the underlying token, exchanging them 1:1 and sets the spender allowance.
* Only callable when token is not address(0)
*
* @param _deposit Amount of tokens to be deposited
* @param _spender Spender address for the allowance
* @param _allowance Allowance amount
*/
function depositAndApprove(uint256 _deposit, address _spender, uint256 _allowance)
public
whenTokenIsSet
returns (bool)
{
deposit(_deposit);
approve(_spender, _allowance);
return true;
}
/**
* Buys tokens with the underlying token, exchanging them 1:1, and transfers them to a target
* address instead of msg.sender. Only callable when the token is not address(0)
*
* @param _amount Amount of tokens to be deposited
* @param _target Address to send the tokens
*/
function depositAndTransfer(uint256 _amount, address _target)
public
whenTokenIsSet
returns (bool)
{
deposit(_amount);
transfer(_target, _amount);
return true;
}
/**
* Buys tokens with the underlying token, exchanging them 1:1. Only callable when the token is
* not address(0)
*
* @param _amount Amount of tokens to be deposited
*/
function deposit(uint256 _amount) public whenTokenIsSet returns (bool) {
require(IERC20(token).transferFrom(msg.sender, address(this), _amount), "Token transfer unsuccessful");
balances[msg.sender] = balances[msg.sender].add(_amount);
totalSupply = totalSupply.add(_amount);
emit Deposit(msg.sender, _amount);
return true;
}
/**
* Withdraw the underlying token, exchanging them 1:1. Only callable when the token is not
* address(0)
*
* @param _amount Amount of tokens to be withdrawn
*/
function withdraw(uint256 _amount) public whenTokenIsSet returns (bool) {
require(balances[msg.sender] >= _amount, "Insufficient user balance");
balances[msg.sender] = balances[msg.sender].sub(_amount);
totalSupply = totalSupply.sub(_amount);
require(IERC20(token).transfer(msg.sender, _amount), "Token transfer failed");
emit Withdrawal(msg.sender, _amount);
return true;
}
/**
* Updates the standard allowance method to return unlimited allowance for the default spender
*
* @param _owner Address that owns the funds
* @param _spender Address that will spend the funds
*/
function allowance(address _owner, address _spender) public view returns (uint256) {
if (_spender == defaultSpender) {
return uint256(-1);
}
return allowed[_owner][_spender];
}
}