Skip to content

Commit 935ea44

Browse files
author
Carlo P. Las Marias
authored
Merge pull request CoinAlpha#44 from yzhang1994/master
Change contract based on Hosho review
2 parents aa11fa0 + 42c6ecb commit 935ea44

File tree

6 files changed

+71
-25
lines changed

6 files changed

+71
-25
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ archive/*
99
coverage/*
1010
coverage.json
1111
coverageEnv/*
12-
.coveralls.yml
12+
.coveralls.yml

contracts/Basket.sol

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ contract Basket is StandardToken {
103103
for (uint i = 0; i < tokens.length; i++) {
104104
address t = tokens[i];
105105
uint w = weights[i];
106-
assert(ERC20(t).transferFrom(msg.sender, this, w.mul(_quantity).div(10 ** decimals)));
106+
require(ERC20(t).transferFrom(msg.sender, this, w.mul(_quantity).div(10 ** decimals)));
107107
}
108108

109109
// charging suppliers a fee for every new basket minted
@@ -129,7 +129,7 @@ contract Basket is StandardToken {
129129
/// @param _quantity Quantity of basket tokens to convert back to original tokens
130130
/// @return success Operation successful
131131
function debundleAndWithdraw(uint _quantity) public returns (bool success) {
132-
assert(debundle(_quantity, msg.sender, msg.sender));
132+
require(debundle(_quantity, msg.sender, msg.sender));
133133
emit LogDebundleAndWithdraw(msg.sender, _quantity);
134134
return true;
135135
}
@@ -185,7 +185,7 @@ contract Basket is StandardToken {
185185
uint bal = outstandingBalance[msg.sender][_token];
186186
require(bal > 0);
187187
outstandingBalance[msg.sender][_token] = 0;
188-
assert(ERC20(_token).transfer(msg.sender, bal));
188+
require(ERC20(_token).transfer(msg.sender, bal));
189189

190190
emit LogWithdraw(msg.sender, _token, bal);
191191
return true;

contracts/BasketEscrow.sol

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ contract BasketEscrow {
136136
public
137137
returns (bool success)
138138
{
139-
assert(ERC20(_basketAddress).transferFrom(msg.sender, this, _amountBasket));
139+
require(ERC20(_basketAddress).transferFrom(msg.sender, this, _amountBasket));
140140
uint index = _createOrder(msg.sender, ETH_ADDRESS, _amountEth, _basketAddress, _amountBasket, _expiration, _nonce);
141141

142142
emit LogSellOrderCreated(index, msg.sender, _basketAddress, _amountEth, _amountBasket, _expiration, _nonce);
@@ -164,6 +164,7 @@ contract BasketEscrow {
164164
internal
165165
returns (uint newOrderIndex)
166166
{
167+
require(_expiration > now);
167168
require(_tokenGet == ETH_ADDRESS || basketRegistry.checkBasketExists(_tokenGet)); // Check: "Order not for ETH or invalid basket"
168169
require(_tokenGive == ETH_ADDRESS || basketRegistry.checkBasketExists(_tokenGive)); // Check: "Order not for ETH or invalid basket"
169170

@@ -222,7 +223,7 @@ contract BasketEscrow {
222223
) public returns (bool success) {
223224
uint cancelledOrderIndex = _cancelOrder(msg.sender, ETH_ADDRESS, _amountEth, _basketAddress, _amountBasket, _expiration, _nonce);
224225

225-
assert(ERC20(_basketAddress).transfer(msg.sender, _amountBasket));
226+
require(ERC20(_basketAddress).transfer(msg.sender, _amountBasket));
226227

227228
emit LogSellOrderCancelled(cancelledOrderIndex, msg.sender, _basketAddress, _amountEth, _amountBasket);
228229
return true;
@@ -277,7 +278,7 @@ contract BasketEscrow {
277278
uint _nonce
278279
) public returns (bool success) {
279280
uint filledOrderIndex = _fillOrder(_orderCreator, _basketAddress, _amountBasket, ETH_ADDRESS, _amountEth, _expiration, _nonce);
280-
assert(ERC20(_basketAddress).transferFrom(msg.sender, _orderCreator, _amountBasket));
281+
require(ERC20(_basketAddress).transferFrom(msg.sender, _orderCreator, _amountBasket));
281282

282283
uint fee = _amountEth.mul(transactionFee).div(10 ** FEE_DECIMALS);
283284
msg.sender.transfer(_amountEth.sub(fee));
@@ -302,7 +303,7 @@ contract BasketEscrow {
302303
uint _nonce
303304
) public payable returns (bool success) {
304305
uint filledOrderIndex = _fillOrder(_orderCreator, ETH_ADDRESS, msg.value, _basketAddress, _amountBasket, _expiration, _nonce);
305-
assert(ERC20(_basketAddress).transfer(msg.sender, _amountBasket));
306+
require(ERC20(_basketAddress).transfer(msg.sender, _amountBasket));
306307

307308
uint fee = msg.value.mul(transactionFee).div(10 ** FEE_DECIMALS);
308309
_orderCreator.transfer(msg.value.sub(fee));

contracts/BasketRegistry.sol

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
pragma solidity 0.4.21;
1919

20+
import "./zeppelin/SafeMath.sol";
21+
2022

2123
contract IBasketRegistry {
2224
// Called by BasketFactory
@@ -35,6 +37,8 @@ contract IBasketRegistry {
3537
* @author CoinAlpha, Inc. <[email protected]>
3638
*/
3739
contract BasketRegistry {
40+
using SafeMath for uint;
41+
3842
// Constants set at contract inception
3943
address public admin;
4044
mapping(address => bool) public basketFactoryMap;
@@ -123,13 +127,13 @@ contract BasketRegistry {
123127
if (arrangerBasketCount[_arranger] == 0) {
124128
arrangerList.push(_arranger);
125129
arrangerIndexFromAddress[_arranger] = arrangerIndex;
126-
arrangerIndex += 1;
130+
arrangerIndex = arrangerIndex.add(1);
127131
}
128-
arrangerBasketCount[_arranger] += 1;
132+
arrangerBasketCount[_arranger] = arrangerBasketCount[_arranger].add(1);
129133

130134
emit LogBasketRegistration(_basketAddress, basketIndex);
131-
basketIndex += 1;
132-
return basketIndex - 1;
135+
basketIndex = basketIndex.add(1);
136+
return basketIndex.sub(1);
133137
}
134138

135139
/// @dev Check if basket exists in registry
@@ -172,7 +176,7 @@ contract BasketRegistry {
172176
/// @param _sender Address that bundled tokens
173177
/// @return success Operation successful
174178
function incrementBasketsMinted(uint _quantity, address _sender) public onlyBasket returns (bool) {
175-
basketMap[msg.sender].totalMinted += _quantity;
179+
basketMap[msg.sender].totalMinted = basketMap[msg.sender].totalMinted.add(_quantity);
176180
emit LogIncrementBasketsMinted(msg.sender, _quantity, _sender);
177181
return true;
178182
}
@@ -182,7 +186,7 @@ contract BasketRegistry {
182186
/// @param _sender Address that debundled tokens
183187
/// @return success Operation successful
184188
function incrementBasketsBurned(uint _quantity, address _sender) public onlyBasket returns (bool) {
185-
basketMap[msg.sender].totalBurned += _quantity;
189+
basketMap[msg.sender].totalBurned = basketMap[msg.sender].totalBurned.add(_quantity);
186190
emit LogIncrementBasketsBurned(msg.sender, _quantity, _sender);
187191
return true;
188192
}

test/1_bundle_tokens.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ contract('TestToken | Basket', (accounts) => {
210210
it('should allow HOLDER_A to depositAndBundle', async () => {
211211
try {
212212
const fee = await basketAB.arrangerFee.call();
213-
const insufficientFee = (amount1 / 2) * (Number(fee) / (10 ** FEE_DECIMALS));
213+
const insufficientFee = (amount1 / 3) * (Number(fee) / (10 ** FEE_DECIMALS));
214214
await basketAB.depositAndBundlePromise(amount1, { from: HOLDER_A, value: insufficientFee, gas: 1e6 });
215215
} catch (err) { assert.equal(doesRevert(err), true, 'did not revert as expected'); }
216216
});
@@ -432,8 +432,24 @@ contract('TestToken | Basket', (accounts) => {
432432
try {
433433
await basketAB.withdrawPromise(tokenB.address, { from: HOLDER_A });
434434
const _balTokenB = await tokenB.balanceOf(HOLDER_A);
435+
const _outstandingTokenB = Number(basketAB.outstandingBalance(HOLDER_A, tokenB.address));
435436
assert.strictEqual(Number(_balTokenB), Number(balTokenB) + amountToDebundle, 'tokenB balance did not increase');
437+
assert.strictEqual(_outstandingTokenB, 0, 'tokenB balance did not decrease');
436438
} catch (err) { assert.throw(`after error: ${err.toString()}`); }
437439
});
440+
441+
it('HOLDER_A should revert transfers of locked tokens', async () => {
442+
try {
443+
await basketAB.withdrawPromise(tokenA.address, { from: HOLDER_A });
444+
} catch (err) { assert.equal(doesRevert(err), true, 'did not revert as expected'); }
445+
});
446+
});
447+
448+
describe('Does not allow withdraw when balance is zero', async () => {
449+
it('HOLDER_B should not be able to withdraw a single token', async () => {
450+
try {
451+
await basketAB.withdrawPromise(tokenB.address, { from: HOLDER_B });
452+
} catch (err) { assert.equal(doesRevert(err), true, 'did not revert as expected'); }
453+
});
438454
});
439455
});

test/3_exchange_baskets.js

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -233,14 +233,29 @@ contract('Basket Escrow', (accounts) => {
233233
} catch (err) { assert.equal(doesRevert(err), true, 'did not revert as expected'); }
234234
});
235235

236+
it('creates and logs buy orders ', async () => {
237+
const instantExpiration = 0;
238+
try {
239+
// exact same params as last order
240+
nonce = Math.random() * 1e7;
241+
const buyOrderParams = [
242+
basketABAddress, amountBasketsToBuy, instantExpiration, nonce,
243+
{ from: HOLDER_A, value: amountEthToSend, gas: 1e6 },
244+
];
245+
await basketEscrow.createBuyOrder(...buyOrderParams);
246+
} catch (err) { assert.equal(doesRevert(err), true, 'did not revert as expected'); }
247+
});
248+
236249
after('update nonce', () => { nonce = Math.random() * 1e7; });
237250
});
238251

239252
describe('Holder_A cancels expired buy order', () => {
253+
const timeDelta = 10; // expires in 10 seconds
254+
240255
before('create second buy order and check initial balance', async () => {
241256
try {
242257
// set expiration time to now to ensure the order will expire
243-
expirationInSeconds = 0;
258+
expirationInSeconds = (new Date().getTime() / 1000) + timeDelta;
244259
const buyOrderParams = [
245260
basketABAddress, amountBasketsToBuy, expirationInSeconds, nonce,
246261
{ from: HOLDER_A, value: amountEthToSend, gas: 1e6 },
@@ -256,6 +271,12 @@ contract('Basket Escrow', (accounts) => {
256271
} catch (err) { assert.throw(`Error creating second buy order: ${err.toString()}`); }
257272
});
258273

274+
it('waits <timeDelta> seconds before proceeding', async () => {
275+
await new Promise((resolve) => {
276+
setTimeout(() => { resolve(); }, timeDelta * 1000);
277+
});
278+
});
279+
259280
it('allows and logs cancellation of buy orders ', async () => {
260281
try {
261282
const cancelBuyParams = [
@@ -432,9 +453,11 @@ contract('Basket Escrow', (accounts) => {
432453
});
433454
});
434455

435-
const instantExpiration = 0;
436456

437457
describe('MARKET_MAKER fails to fill expired orders', () => {
458+
const timeDelta = 20; // 10 seconds
459+
const instantExpiration = (new Date().getTime() / 1000) + timeDelta;
460+
438461
before('creates an order that expires instantly', async () => {
439462
try {
440463
nonce = Math.random() * 1e7;
@@ -443,17 +466,19 @@ contract('Basket Escrow', (accounts) => {
443466
{ from: HOLDER_A, value: amountEthToSend, gas: 1e6 },
444467
];
445468
await basketEscrow.createBuyOrder(...buyOrderParams);
446-
} catch (err) { assert.throw(`Error in creating instantly expired order: ${err.toString()}`); }
469+
} catch (err) { assert.throw(`Error in creating expired order: ${err.toString()}`); }
447470
});
448471

449472
it('cannot fill an expired order', async () => {
450-
try {
451-
const fillBuyParams = [
452-
HOLDER_B, basketABAddress, amountBasketsToBuy, amountEthToSend, instantExpiration, nonce,
453-
{ from: MARKET_MAKER, gas: 1e6 },
454-
];
455-
const _fillBuyResults = await basketEscrow.fillBuyOrder(...fillBuyParams);
456-
} catch (err) { assert.equal(doesRevert(err), true, 'did not revert as expected'); }
473+
setTimeout(async () => {
474+
try {
475+
const fillBuyParams = [
476+
HOLDER_B, basketABAddress, amountBasketsToBuy, amountEthToSend, instantExpiration, nonce,
477+
{ from: MARKET_MAKER, gas: 1e6 },
478+
];
479+
const _fillBuyResults = await basketEscrow.fillBuyOrder(...fillBuyParams);
480+
} catch (err) { assert.equal(doesRevert(err), true, 'did not revert as expected'); }
481+
}, timeDelta * 1000);
457482
});
458483
});
459484

0 commit comments

Comments
 (0)