Skip to content
This repository was archived by the owner on Jan 18, 2023. It is now read-only.

Commit 5eb5987

Browse files
authored
Merge pull request #16 from SetProtocol/0.2.0-more-testing
v0.2.0/More Testing
2 parents 1c6c5fc + dcbb507 commit 5eb5987

File tree

8 files changed

+1833
-338
lines changed

8 files changed

+1833
-338
lines changed

contracts/SetToken.sol

Lines changed: 66 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pragma solidity 0.4.21;
2+
pragma experimental ABIEncoderV2;
23

34

45
import "zeppelin-solidity/contracts/token/ERC20/StandardToken.sol";
@@ -21,18 +22,23 @@ contract SetToken is StandardToken, DetailedERC20("", "", 18), Set {
2122
uint[] public units;
2223
mapping(address => bool) internal isComponent;
2324

24-
25-
struct PartialRedeemStatus {
26-
uint unredeemedBalance;
25+
struct unredeemedComponent {
26+
uint balance;
2727
bool isRedeemed;
2828
}
2929

30-
// Mapping of token address -> user address -> partialRedeemStatus
31-
mapping(address => mapping(address => PartialRedeemStatus)) public unredeemedComponents;
30+
// Mapping of token address -> user address -> unredeemedComponent
31+
mapping(address => mapping(address => unredeemedComponent)) public unredeemedComponents;
3232

3333
event LogPartialRedemption(
3434
address indexed _sender,
35-
uint indexed _quantity
35+
uint indexed _quantity,
36+
address[] _excludedComponents
37+
);
38+
39+
event LogRedeemExcluded(
40+
address indexed _sender,
41+
address[] _components
3642
);
3743

3844
modifier hasSufficientBalance(uint quantity) {
@@ -43,9 +49,9 @@ contract SetToken is StandardToken, DetailedERC20("", "", 18), Set {
4349
_;
4450
}
4551

46-
modifier preventRedeemReEntrancy(address sender, uint quantity) {
52+
modifier preventRedeemReEntrancy(uint quantity) {
4753
// To prevent re-entrancy attacks, decrement the user's Set balance
48-
balances[sender] = balances[sender].sub(quantity);
54+
balances[msg.sender] = balances[msg.sender].sub(quantity);
4955

5056
// Decrement the total token supply
5157
totalSupply = totalSupply.sub(quantity);
@@ -106,14 +112,7 @@ contract SetToken is StandardToken, DetailedERC20("", "", 18), Set {
106112
address currentComponent = components[i];
107113
uint currentUnits = units[i];
108114

109-
// Transfer value is defined as the currentUnits (in GWei)
110-
// multiplied by quantity in Wei divided by the units of gWei.
111-
// We do this to allow fractional units to be defined
112-
uint transferValue = currentUnits.fxpMul(quantity, 10**9);
113-
114-
// Protect against the case that the gWei divisor results in a value that is
115-
// 0 and the user is able to generate Sets without sending a balance
116-
assert(transferValue > 0);
115+
uint transferValue = calculateTransferValue(units[i], quantity);
117116

118117
assert(ERC20(currentComponent).transferFrom(msg.sender, this, transferValue));
119118
}
@@ -124,7 +123,7 @@ contract SetToken is StandardToken, DetailedERC20("", "", 18), Set {
124123
// Increment the total token supply
125124
totalSupply = totalSupply.add(quantity);
126125

127-
LogIssuance(msg.sender, quantity);
126+
emit LogIssuance(msg.sender, quantity);
128127

129128
return true;
130129
}
@@ -139,27 +138,20 @@ contract SetToken is StandardToken, DetailedERC20("", "", 18), Set {
139138
function redeem(uint quantity)
140139
public
141140
hasSufficientBalance(quantity)
142-
preventRedeemReEntrancy(msg.sender, quantity)
141+
preventRedeemReEntrancy(quantity)
143142
returns (bool success)
144143
{
145144
for (uint i = 0; i < components.length; i++) {
146145
address currentComponent = components[i];
147146
uint currentUnits = units[i];
148147

149-
// Transfer value is defined as the currentUnits (in GWei)
150-
// multiplied by quantity in Wei divided by the units of gWei.
151-
// We do this to allow fractional units to be defined
152-
uint transferValue = currentUnits.fxpMul(quantity, 10**9);
153-
154-
// Protect against the case that the gWei divisor results in a value that is
155-
// 0 and the user is able to generate Sets without sending a balance
156-
assert(transferValue > 0);
148+
uint transferValue = calculateTransferValue(units[i], quantity);
157149

158150
// The transaction will fail if any of the components fail to transfer
159151
assert(ERC20(currentComponent).transfer(msg.sender, transferValue));
160152
}
161153

162-
LogRedemption(msg.sender, quantity);
154+
emit LogRedemption(msg.sender, quantity);
163155

164156
return true;
165157
}
@@ -177,7 +169,7 @@ contract SetToken is StandardToken, DetailedERC20("", "", 18), Set {
177169
function partialRedeem(uint quantity, address[] excludedComponents)
178170
public
179171
hasSufficientBalance(quantity)
180-
preventRedeemReEntrancy(msg.sender, quantity)
172+
preventRedeemReEntrancy(quantity)
181173
returns (bool success)
182174
{
183175
// Excluded tokens should be less than the number of components
@@ -188,14 +180,7 @@ contract SetToken is StandardToken, DetailedERC20("", "", 18), Set {
188180
for (uint i = 0; i < components.length; i++) {
189181
bool isExcluded = false;
190182

191-
// Transfer value is defined as the currentUnits (in GWei)
192-
// multiplied by quantity in Wei divided by the units of gWei.
193-
// We do this to allow fractional units to be defined
194-
uint transferValue = units[i].fxpMul(quantity, 10**9);
195-
196-
// Protect against the case that the gWei divisor results in a value that is
197-
// 0 and the user is able to generate Sets without sending a balance
198-
assert(transferValue > 0);
183+
uint transferValue = calculateTransferValue(units[i], quantity);
199184

200185
// This is unideal to do a doubly nested loop, but the number of excludedComponents
201186
// should generally be a small number
@@ -207,22 +192,21 @@ contract SetToken is StandardToken, DetailedERC20("", "", 18), Set {
207192

208193
// If the token is excluded, add to the user's unredeemed component value
209194
if (components[i] == currentExcluded) {
210-
// Ensures there are no duplicates
195+
// Check whether component is already redeemed; Ensures duplicate excludedComponents
196+
// has not been inputted.
211197
bool currentIsRedeemed = unredeemedComponents[components[i]][msg.sender].isRedeemed;
212198
assert(currentIsRedeemed == false);
213199

214-
unredeemedComponents[components[i]][msg.sender].unredeemedBalance += transferValue;
200+
unredeemedComponents[components[i]][msg.sender].balance += transferValue;
215201

216202
// Mark redeemed to ensure no duplicates
217203
unredeemedComponents[components[i]][msg.sender].isRedeemed = true;
218204

219205
isExcluded = true;
220-
221206
}
222207
}
223208

224-
if (isExcluded == false) {
225-
// The transaction will fail if any of the components fail to transfer
209+
if (!isExcluded) {
226210
assert(ERC20(components[i]).transfer(msg.sender, transferValue));
227211
}
228212
}
@@ -233,23 +217,44 @@ contract SetToken is StandardToken, DetailedERC20("", "", 18), Set {
233217
unredeemedComponents[currentExcludedToUnredeem][msg.sender].isRedeemed = false;
234218
}
235219

236-
LogPartialRedemption(msg.sender, quantity);
220+
emit LogPartialRedemption(msg.sender, quantity, excludedComponents);
237221

238222
return true;
239223
}
240224

241-
function redeemExcluded(uint quantity, address excludedComponent)
225+
/**
226+
* @dev Function to withdraw tokens that have previously been excluded when calling
227+
* the redeemExcluded method
228+
*
229+
* This function should be used to retrieve tokens that have previously excluded
230+
* when calling the redeemExcluded function.
231+
*
232+
* @param componentsToRedeem address[] The list of tokens to redeem
233+
* @param quantities uint[] The quantity of Sets desired to redeem in Wei
234+
*/
235+
function redeemExcluded(address[] componentsToRedeem, uint[] quantities)
242236
public
243237
returns (bool success)
244238
{
245-
// Check there is enough balance
246-
uint remainingBalance = unredeemedComponents[excludedComponent][msg.sender].unredeemedBalance;
247-
require(remainingBalance >= quantity);
239+
require(quantities.length > 0);
240+
require(componentsToRedeem.length > 0);
241+
require(quantities.length == componentsToRedeem.length);
248242

249-
// To prevent re-entrancy attacks, decrement the user's Set balance
250-
unredeemedComponents[excludedComponent][msg.sender].unredeemedBalance = remainingBalance.sub(quantity);
243+
for (uint i = 0; i < quantities.length; i++) {
244+
address currentComponent = componentsToRedeem[i];
245+
uint currentQuantity = quantities[i];
246+
247+
// Check there is enough balance
248+
uint remainingBalance = unredeemedComponents[currentComponent][msg.sender].balance;
249+
require(remainingBalance >= currentQuantity);
250+
251+
// To prevent re-entrancy attacks, decrement the user's Set balance
252+
unredeemedComponents[currentComponent][msg.sender].balance = remainingBalance.sub(currentQuantity);
251253

252-
assert(ERC20(excludedComponent).transfer(msg.sender, quantity));
254+
assert(ERC20(currentComponent).transfer(msg.sender, currentQuantity));
255+
}
256+
257+
emit LogRedeemExcluded(msg.sender, componentsToRedeem);
253258

254259
return true;
255260
}
@@ -265,4 +270,16 @@ contract SetToken is StandardToken, DetailedERC20("", "", 18), Set {
265270
function getUnits() public view returns(uint[]) {
266271
return units;
267272
}
273+
274+
function calculateTransferValue(uint currentUnits, uint quantity) internal returns(uint) {
275+
// Transfer value is defined as the currentUnits (in GWei)
276+
// multiplied by quantity in Wei divided by the units of gWei.
277+
// We do this to allow fractional units to be defined
278+
uint transferValue = currentUnits.fxpMul(quantity, 10**9);
279+
280+
// Protect against the case that the gWei divisor results in a value that is
281+
// 0 and the user is able to generate Sets without sending a balance
282+
assert(transferValue > 0);
283+
return transferValue;
284+
}
268285
}
File renamed without changes.

0 commit comments

Comments
 (0)