From cae6d80906478f8ad72c89c5adc81a23827b4e95 Mon Sep 17 00:00:00 2001 From: Perfect Makanju Date: Fri, 7 Dec 2018 15:45:45 +0100 Subject: [PATCH 1/6] WIP: MarketCollateralPool Test --- test/MarketCollateralPool.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/MarketCollateralPool.js b/test/MarketCollateralPool.js index 7b2fbd0a..f7f2163b 100644 --- a/test/MarketCollateralPool.js +++ b/test/MarketCollateralPool.js @@ -1,4 +1,4 @@ -const MarketContractOraclize = artifacts.require('MarketContractOraclize'); +const MarketContractOraclize = artifacts.require('TestableMarketContractOraclize'); const MarketCollateralPool = artifacts.require('MarketCollateralPool'); const MarketContractRegistry = artifacts.require('MarketContractRegistry'); const CollateralToken = artifacts.require('CollateralToken'); From 4bfb95e4209e03b2c4f6b79c6d2173244448e9f0 Mon Sep 17 00:00:00 2001 From: Perfect Makanju Date: Mon, 10 Dec 2018 20:47:56 +0100 Subject: [PATCH 2/6] Test minPositionTokens and redeemPositionTokens --- test/MarketCollateralPool.js | 234 ++++++++++++++++++++++++----------- test/utility.js | 12 ++ 2 files changed, 176 insertions(+), 70 deletions(-) diff --git a/test/MarketCollateralPool.js b/test/MarketCollateralPool.js index f7f2163b..c49be14d 100644 --- a/test/MarketCollateralPool.js +++ b/test/MarketCollateralPool.js @@ -1,4 +1,4 @@ -const MarketContractOraclize = artifacts.require('TestableMarketContractOraclize'); +const MarketContractOraclize = artifacts.require('MarketContractOraclize'); const MarketCollateralPool = artifacts.require('MarketCollateralPool'); const MarketContractRegistry = artifacts.require('MarketContractRegistry'); const CollateralToken = artifacts.require('CollateralToken'); @@ -35,81 +35,175 @@ contract('MarketCollateralPool', function(accounts) { shortPositionToken = PositionToken.at(await marketContract.SHORT_POSITION_TOKEN()); }); - beforeEach(async function() { - - }); - - it(`should mint position tokens`, async function() { - - // 1. Start with fresh account - const initialBalance = await collateralToken.balanceOf.call(accounts[1]); - assert.equal(initialBalance.toNumber(), 0, 'Account 1 already has a balance'); - - // 2. should fail to mint when user has no collateral. - let error = null; - try { - await collateralPool.mintPositionTokens(marketContract.address, 1, { from: accounts[1] }); - } catch (err) { - error = err; - } - assert.ok(error instanceof Error, 'should not be able to mint with no collateral token balance'); - - // 3. should fail to mint when user has not approved transfer of collateral (erc20 approve) - const accountBalance = await collateralToken.balanceOf.call(accounts[0]); - assert.isTrue(accountBalance.toNumber() != 0, 'Account 0 does not have a balance of collateral'); - - const initialApproval = await collateralToken.allowance.call(accounts[0], collateralPool.address); - assert.equal(initialApproval.toNumber(), 0, 'Account 0 already has an approval'); - - error = null; - try { - await collateralPool.mintPositionTokens(marketContract.address, 1, { from: accounts[0] }); - } catch (err) { - error = err; - } - assert.ok(error instanceof Error, 'should not be able to mint with no collateral approval balance'); - - // 4. should allow to mint when user has collateral tokens and has approved them - const amountToApprove = 1e22; - await collateralToken.approve(collateralPool.address, amountToApprove); - const qtyToMint = 100; - await collateralPool.mintPositionTokens(marketContract.address, qtyToMint, { from: accounts[0]}); - const longPosTokenBalance = await longPositionToken.balanceOf(accounts[0]); - const shortPosTokenBalance = await shortPositionToken.balanceOf(accounts[0]); - - assert.equal(longPosTokenBalance.toNumber(), qtyToMint, `incorrect amount of long tokens minted`); - assert.equal(shortPosTokenBalance.toNumber(), qtyToMint,`incorrect amount of long tokens minted`); - }); - - it(`should lock the correct amount of collateral`, async function() { - - }); - - it(`should redeem token sets`, async function() { - - }); + // forces the contract to be settled + function settleContract() { + await marketContract.oracleCallBack(priceCap.plus(10), {from: accounts[0]}); // price above cap! + } - it(`should return correct amount of collateral when redeemed`, async function() { - - }); - - it(`should redeem single tokens after settlement`, async function() { + beforeEach(async function() { }); - it(`should return correct amount of collateral when redeemed after settlement`, async function() { - + describe('mintPositionTokens()', function() { + it(`should mint position tokens`, async function() { + + // 1. Start with fresh account + const initialBalance = await collateralToken.balanceOf.call(accounts[1]); + assert.equal(initialBalance.toNumber(), 0, 'Account 1 already has a balance'); + + // 2. should fail to mint when user has no collateral. + let error = null; + try { + await collateralPool.mintPositionTokens(marketContract.address, 1, { from: accounts[1] }); + } catch (err) { + error = err; + } + assert.ok(error instanceof Error, 'should not be able to mint with no collateral token balance'); + + // 3. should fail to mint when user has not approved transfer of collateral (erc20 approve) + const accountBalance = await collateralToken.balanceOf.call(accounts[0]); + assert.isTrue(accountBalance.toNumber() != 0, 'Account 0 does not have a balance of collateral'); + + const initialApproval = await collateralToken.allowance.call(accounts[0], collateralPool.address); + assert.equal(initialApproval.toNumber(), 0, 'Account 0 already has an approval'); + + error = null; + try { + await collateralPool.mintPositionTokens(marketContract.address, 1, { from: accounts[0] }); + } catch (err) { + error = err; + } + assert.ok(error instanceof Error, 'should not be able to mint with no collateral approval balance'); + + // 4. should allow to mint when user has collateral tokens and has approved them + const amountToApprove = 1e22; + await collateralToken.approve(collateralPool.address, amountToApprove); + const qtyToMint = 100; + await collateralPool.mintPositionTokens(marketContract.address, qtyToMint, { from: accounts[0]}); + const longPosTokenBalance = await longPositionToken.balanceOf(accounts[0]); + const shortPosTokenBalance = await shortPositionToken.balanceOf(accounts[0]); + + assert.equal(longPosTokenBalance.toNumber(), qtyToMint, `incorrect amount of long tokens minted`); + assert.equal(shortPosTokenBalance.toNumber(), qtyToMint,`incorrect amount of long tokens minted`); + }); + + it(`should lock the correct amount of collateral`, async function() { + // 1. Get initial token balance balance + const initialCollateralBalance = await collateralToken.balanceOf.call(accounts[0]); + + // 2. approve collateral and mint tokens + const amountToApprove = 1e22; + await collateralToken.approve(collateralPool.address, amountToApprove); + const qtyToMint = 100; + await collateralPool.mintPositionTokens(marketContract.address, qtyToMint, { from: accounts[0]}); + + // 3. balance after should be equal to expected balance + const amountToBeLocked = qtyToMint * utility.calculateTotalCollateral(priceFloor, priceCap, qtyMultiplier); + const expectedBalanceAfterMint = initialCollateralBalance.minus(amountToBeLocked); + const actualBalanceAfterMint = await collateralToken.balanceOf.call(accounts[0]) + + assert.equal(expectedBalanceAfterMint.toNumber(), actualBalanceAfterMint.toNumber(), 'incorrect collateral amount locked for minting') + }); }); - it('should fail if settleAndClose() is called before settlement', async () => { - // let error = null; - // let settleAndCloseError = null; - // try { - // await collateralPool.settleAndClose.call(marketContract.address, { from: accounts[0] }); - // } catch (err) { - // settleAndCloseError = err; - // } - // assert.ok(settleAndCloseError instanceof Error, 'settleAndClose() did not fail before settlement'); + describe('redeemPositionTokens()', function() { + it(`should redeem token sets and return correct amount of collateral`, async function() { + // 1. approve collateral and mint tokens + const amountToApprove = 1e22; + await collateralToken.approve(collateralPool.address, amountToApprove); + const qtyToMint = 100; + await collateralPool.mintPositionTokens(marketContract.address, qtyToMint, { from: accounts[0]}); + const initialLongPosTokenBalance = await longPositionToken.balanceOf(accounts[0]); + const initialShortPosTokenBalance = await shortPositionToken.balanceOf(accounts[0]); + + // 2. redeem tokens + const qtyToRedeem = 50; + const collateralBalanceBeforeRedeem = await collateralToken.balanceOf.call(accounts[0]); + await collateralPool.redeemPositionTokens(marketContract.address, qtyToRedeem, { from: accounts[0] }); + + // 3. assert final tokens balance are as expected + const expectedFinalLongPosTokenBalance = initialLongPosTokenBalance.minus(qtyToRedeem); + const expectedFinalShortPosTokenBalance = initialShortPosTokenBalance.minus(qtyToRedeem); + const finalLongPosTokenBalance = await longPositionToken.balanceOf(accounts[0]); + const finalShortPosTokenBalance = await shortPositionToken.balanceOf(accounts[0]); + + assert.equal(expectedFinalLongPosTokenBalance.toNumber(), finalLongPosTokenBalance.toNumber(), 'incorrect long position token balance after redeeming'); + assert.equal(expectedFinalShortPosTokenBalance.toNumber(), finalShortPosTokenBalance.toNumber(), 'incorrect short position token balance after redeeming'); + + // 4. assert correct collateral is returned + const collateralAmountToBeReleased = qtyToRedeem * utility.calculateTotalCollateral(priceFloor, priceCap, qtyMultiplier); + const expectedCollateralBalanceAfterRedeem = collateralBalanceBeforeRedeem.plus(collateralAmountToBeReleased); + const actualCollateralBalanceAfterRedeem = await collateralToken.balanceOf.call(accounts[0]); + + assert.equal(expectedCollateralBalanceAfterRedeem.toNumber(), actualCollateralBalanceAfterRedeem.toNumber(), 'incorrect collateral amount returned after redeeming'); + }); + + it('should fail to redeem single tokens before settlement', async function() { + // 1. approve collateral and mint tokens + const amountToApprove = 1e22; + await collateralToken.approve(collateralPool.address, amountToApprove); + const qtyToMint = 1; + await collateralPool.mintPositionTokens(marketContract.address, qtyToMint, { from: accounts[0]}); + const shortTokenBalance = (await shortPositionToken.balanceOf.call(accounts[0])).toNumber(); + const longTokenBalance = (await longPositionToken.balanceOf.call(accounts[0])).toNumber(); + assert.equal(shortTokenBalance, longTokenBalance, 'long token and short token balances are not equals'); + + // 2. transfer part of the long token + await longPositionToken.transfer(accounts[1], 1, { from: accounts[0]}) + + // 3. attempting to redeem all shorts before settlement should fails + let error = null; + try { + const qtyToRedeem = (await shortPositionToken.balanceOf.call(accounts[0])).toNumber(); + await collateralPool.redeemPositionTokens(marketContract.address, qtyToRedeem, { from: accounts[0] }); + } catch (err) { + error = err; + } + + assert.ok(error instanceof Error, 'should not be able to redeem single tokens before settlement'); + }); + + it(`should redeem single tokens after settlement`, async function() { + // 1. approve collateral and mint tokens + const amountToApprove = 1e22; + await collateralToken.approve(collateralPool.address, amountToApprove); + const qtyToMint = 1; + await collateralPool.mintPositionTokens(marketContract.address, qtyToMint, { from: accounts[0]}); + + // 2. transfer part of the long token + await longPositionToken.transfer(accounts[1], 1, { from: accounts[0]}) + + // 3. force contract to settlement + settleContract(); + + // 4. redeem all position tokens after settlement should pass + let error = null; + try { + const qtyToRedeem = (await shortPositionToken.balanceOf.call(accounts[0])).toNumber(); + await collateralPool.redeemPositionTokens(marketContract.address, qtyToRedeem, { from: accounts[0] }); + } catch (err) { + error = err; + } + + assert.isNull(error, 'should be able to redeem single tokens after settlement'); + }); + + it(`should return correct amount of collateral when redeemed after settlement`, async function() { + + }); + }) + + describe('setlleAndClose()', function() { + it('should fail if settleAndClose() is called before settlement', async () => { + // let error = null; + // let settleAndCloseError = null; + // try { + // await collateralPool.settleAndClose.call(marketContract.address, { from: accounts[0] }); + // } catch (err) { + // settleAndCloseError = err; + // } + // assert.ok(settleAndCloseError instanceof Error, 'settleAndClose() did not fail before settlement'); + }); }); }); diff --git a/test/utility.js b/test/utility.js index 57a5b088..3ce94a88 100644 --- a/test/utility.js +++ b/test/utility.js @@ -63,5 +63,17 @@ module.exports = { } } return maxLoss * Math.abs(qty) * qtyMultiplier; + }, + + /** + * Calculate total collateral required for a price range + * + * @param {number} priceFloor + * @param {number} priceCap + * @param {number} qtyMultiplier + * @return {number} + */ + calculateTotalCollateral(priceFloor, priceCap, qtyMultiplier) { + return (priceCap - priceFloor) * qtyMultiplier; } }; From 2a6a07be654f5333f9c86bb604bc46785f1d7293 Mon Sep 17 00:00:00 2001 From: Perfect Makanju Date: Mon, 10 Dec 2018 21:43:53 +0100 Subject: [PATCH 3/6] Deploy new MarketContract for each test. Test for settleAndClose() --- test/MarketCollateralPool.js | 76 +++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/test/MarketCollateralPool.js b/test/MarketCollateralPool.js index c49be14d..cd23338f 100644 --- a/test/MarketCollateralPool.js +++ b/test/MarketCollateralPool.js @@ -21,27 +21,46 @@ contract('MarketCollateralPool', function(accounts) { const entryOrderPrice = 33025; const accountMaker = accounts[0]; const accountTaker = accounts[1]; + const expiration = new Date().getTime() / 1000 + 60 * 50; // order expires 50 minutes from now. + const oracleDataSoure = 'URL'; + const oracleQuery = 'json(https://api.kraken.com/0/public/Ticker?pair=ETHUSD).result.XETHZUSD.c.0'; before(async function() { - marketContractRegistry = await MarketContractRegistry.deployed(); - var whiteList = await marketContractRegistry.getAddressWhiteList.call(); - marketContract = await MarketContractOraclize.at(whiteList[1]); - collateralPool = await MarketCollateralPool.deployed(); - collateralToken = await CollateralToken.deployed(); - qtyMultiplier = await marketContract.QTY_MULTIPLIER.call(); - priceFloor = await marketContract.PRICE_FLOOR.call(); - priceCap = await marketContract.PRICE_CAP.call(); - longPositionToken = PositionToken.at(await marketContract.LONG_POSITION_TOKEN()); - shortPositionToken = PositionToken.at(await marketContract.SHORT_POSITION_TOKEN()); + marketContractRegistry = await MarketContractRegistry.deployed(); }); // forces the contract to be settled - function settleContract() { + async function settleContract() { await marketContract.oracleCallBack(priceCap.plus(10), {from: accounts[0]}); // price above cap! } beforeEach(async function() { - + collateralPool = await MarketCollateralPool.deployed(); + collateralToken = await CollateralToken.deployed(); + marketContract = await MarketContractOraclize.new( + "MyNewContract", + [ + accounts[0], + collateralToken.address, + collateralPool.address + ], + accounts[0], // substitute our address for the oracleHubAddress so we can callback from queries. + [ + 0, + 150, + 2, + 2, + expiration + ], + oracleDataSoure, + oracleQuery + ); + await marketContractRegistry.addAddressToWhiteList(marketContract.address, {from: accounts[0]}); + qtyMultiplier = await marketContract.QTY_MULTIPLIER.call(); + priceFloor = await marketContract.PRICE_FLOOR.call(); + priceCap = await marketContract.PRICE_CAP.call(); + longPositionToken = PositionToken.at(await marketContract.LONG_POSITION_TOKEN()); + shortPositionToken = PositionToken.at(await marketContract.SHORT_POSITION_TOKEN()); }); describe('mintPositionTokens()', function() { @@ -162,7 +181,20 @@ contract('MarketCollateralPool', function(accounts) { assert.ok(error instanceof Error, 'should not be able to redeem single tokens before settlement'); }); - + }) + + describe('setlleAndClose()', function() { + it('should fail if settleAndClose() is called before settlement', async () => { + let error = null; + let settleAndCloseError = null; + try { + await collateralPool.settleAndClose(marketContract.address, { from: accounts[0] }); + } catch (err) { + settleAndCloseError = err; + } + assert.ok(settleAndCloseError instanceof Error, 'settleAndClose() did not fail before settlement'); + }); + it(`should redeem single tokens after settlement`, async function() { // 1. approve collateral and mint tokens const amountToApprove = 1e22; @@ -174,13 +206,14 @@ contract('MarketCollateralPool', function(accounts) { await longPositionToken.transfer(accounts[1], 1, { from: accounts[0]}) // 3. force contract to settlement - settleContract(); + await settleContract(); // 4. redeem all position tokens after settlement should pass let error = null; try { const qtyToRedeem = (await shortPositionToken.balanceOf.call(accounts[0])).toNumber(); - await collateralPool.redeemPositionTokens(marketContract.address, qtyToRedeem, { from: accounts[0] }); + await collateralPool.settleAndClose(marketContract.address, qtyToRedeem, { from: accounts[0] }); + // await collateralPool.redeemPositionTokens(marketContract.address, qtyToRedeem, { from: accounts[0] }); } catch (err) { error = err; } @@ -191,19 +224,6 @@ contract('MarketCollateralPool', function(accounts) { it(`should return correct amount of collateral when redeemed after settlement`, async function() { }); - }) - - describe('setlleAndClose()', function() { - it('should fail if settleAndClose() is called before settlement', async () => { - // let error = null; - // let settleAndCloseError = null; - // try { - // await collateralPool.settleAndClose.call(marketContract.address, { from: accounts[0] }); - // } catch (err) { - // settleAndCloseError = err; - // } - // assert.ok(settleAndCloseError instanceof Error, 'settleAndClose() did not fail before settlement'); - }); }); }); From 62138bcd0448b2ac5c0c8eb7bc7b624da969e641 Mon Sep 17 00:00:00 2001 From: Perfect Makanju Date: Tue, 11 Dec 2018 17:54:02 +0100 Subject: [PATCH 4/6] Complete test for SettleAndCLose() --- test/MarketCollateralPool.js | 56 +++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/test/MarketCollateralPool.js b/test/MarketCollateralPool.js index cd23338f..6046e872 100644 --- a/test/MarketCollateralPool.js +++ b/test/MarketCollateralPool.js @@ -31,7 +31,9 @@ contract('MarketCollateralPool', function(accounts) { // forces the contract to be settled async function settleContract() { - await marketContract.oracleCallBack(priceCap.plus(10), {from: accounts[0]}); // price above cap! + const settlementPrice = priceCap.plus(10); + await marketContract.oracleCallBack(settlementPrice, {from: accounts[0]}); // price above cap! + return settlementPrice; } beforeEach(async function() { @@ -64,7 +66,7 @@ contract('MarketCollateralPool', function(accounts) { }); describe('mintPositionTokens()', function() { - it(`should mint position tokens`, async function() { + it('should mint position tokens', async function() { // 1. Start with fresh account const initialBalance = await collateralToken.balanceOf.call(accounts[1]); @@ -102,11 +104,11 @@ contract('MarketCollateralPool', function(accounts) { const longPosTokenBalance = await longPositionToken.balanceOf(accounts[0]); const shortPosTokenBalance = await shortPositionToken.balanceOf(accounts[0]); - assert.equal(longPosTokenBalance.toNumber(), qtyToMint, `incorrect amount of long tokens minted`); - assert.equal(shortPosTokenBalance.toNumber(), qtyToMint,`incorrect amount of long tokens minted`); + assert.equal(longPosTokenBalance.toNumber(), qtyToMint, 'incorrect amount of long tokens minted'); + assert.equal(shortPosTokenBalance.toNumber(), qtyToMint,'incorrect amount of long tokens minted'); }); - it(`should lock the correct amount of collateral`, async function() { + it('should lock the correct amount of collateral', async function() { // 1. Get initial token balance balance const initialCollateralBalance = await collateralToken.balanceOf.call(accounts[0]); @@ -126,7 +128,7 @@ contract('MarketCollateralPool', function(accounts) { }); describe('redeemPositionTokens()', function() { - it(`should redeem token sets and return correct amount of collateral`, async function() { + it('should redeem token sets and return correct amount of collateral', async function() { // 1. approve collateral and mint tokens const amountToApprove = 1e22; await collateralToken.approve(collateralPool.address, amountToApprove); @@ -183,7 +185,7 @@ contract('MarketCollateralPool', function(accounts) { }); }) - describe('setlleAndClose()', function() { + describe('settleAndClose()', function() { it('should fail if settleAndClose() is called before settlement', async () => { let error = null; let settleAndCloseError = null; @@ -195,7 +197,7 @@ contract('MarketCollateralPool', function(accounts) { assert.ok(settleAndCloseError instanceof Error, 'settleAndClose() did not fail before settlement'); }); - it(`should redeem single tokens after settlement`, async function() { + it('should redeem single short tokens after settlement', async function() { // 1. approve collateral and mint tokens const amountToApprove = 1e22; await collateralToken.approve(collateralPool.address, amountToApprove); @@ -208,21 +210,47 @@ contract('MarketCollateralPool', function(accounts) { // 3. force contract to settlement await settleContract(); - // 4. redeem all position tokens after settlement should pass + // 4. redeem all short position tokens after settlement should pass + const balanceBeforeRedeem = await shortPositionToken.balanceOf.call(accounts[0]); + const qtyToRedeem = -1; let error = null; try { - const qtyToRedeem = (await shortPositionToken.balanceOf.call(accounts[0])).toNumber(); await collateralPool.settleAndClose(marketContract.address, qtyToRedeem, { from: accounts[0] }); - // await collateralPool.redeemPositionTokens(marketContract.address, qtyToRedeem, { from: accounts[0] }); } catch (err) { error = err; - } - + } assert.isNull(error, 'should be able to redeem single tokens after settlement'); + + // 5. balance of short tokens should be updated. + const expectedBalanceAfterRedeem = balanceBeforeRedeem.plus(qtyToRedeem); + const actualBalanceAfterRedeem = await shortPositionToken.balanceOf.call(accounts[0]); + assert.equal(expectedBalanceAfterRedeem.toNumber(), actualBalanceAfterRedeem.toNumber(), 'short position tokens balance was not reduced'); }); + + it('should return correct amount of collateral when redeemed after settlement', async function() { + // 1. approve collateral and mint tokens + const amountToApprove = 1e22; + await collateralToken.approve(collateralPool.address, amountToApprove); + const qtyToMint = 1; + await collateralPool.mintPositionTokens(marketContract.address, qtyToMint, { from: accounts[0]}); - it(`should return correct amount of collateral when redeemed after settlement`, async function() { + // 2. transfer part of the long token + await longPositionToken.transfer(accounts[1], 1, { from: accounts[0]}) + + // 3. force contract to settlement + const settlementPrice = await settleContract(); + // 4. redeem all shorts on settlement + const collateralBalanceBeforeRedeem = await collateralToken.balanceOf.call(accounts[0]); + const qtyToRedeem = (await shortPositionToken.balanceOf.call(accounts[0])).toNumber(); + await collateralPool.settleAndClose(marketContract.address, -qtyToRedeem, { from: accounts[0] }); + + // 5. should return appropriate collateral + const collateralToReturn = utility.calculateNeededCollateral(priceFloor, priceCap, qtyMultiplier, qtyToRedeem, settlementPrice); + const expectedCollateralBalanceAfterRedeem = collateralBalanceBeforeRedeem.plus(collateralToReturn); + const actualCollateralBalanceAfterRedeem = await collateralToken.balanceOf.call(accounts[0]); + assert.equal(expectedCollateralBalanceAfterRedeem.toNumber(), actualCollateralBalanceAfterRedeem.toNumber(), 'short position tokens balance was not reduced') + }); }); From d2801667863b83724b64d8eebb70eb32152ab353 Mon Sep 17 00:00:00 2001 From: Eswara Sai Date: Wed, 12 Dec 2018 12:33:12 +0530 Subject: [PATCH 5/6] Added test for mintPositionTokens fail if market contract is settled --- test/MarketCollateralPool.js | 116 ++++++++++++++++++++--------------- 1 file changed, 65 insertions(+), 51 deletions(-) diff --git a/test/MarketCollateralPool.js b/test/MarketCollateralPool.js index 6046e872..bc2ad891 100644 --- a/test/MarketCollateralPool.js +++ b/test/MarketCollateralPool.js @@ -7,9 +7,7 @@ const utility = require('./utility.js'); // basic tests to ensure MarketCollateralPool works and is set up to allow trading contract('MarketCollateralPool', function(accounts) { - let balancePerAcct; let collateralToken; - let initBalance; let collateralPool; let marketContract; let marketContractRegistry; @@ -18,21 +16,19 @@ contract('MarketCollateralPool', function(accounts) { let priceCap; let longPositionToken; let shortPositionToken; - const entryOrderPrice = 33025; - const accountMaker = accounts[0]; - const accountTaker = accounts[1]; + const expiration = new Date().getTime() / 1000 + 60 * 50; // order expires 50 minutes from now. const oracleDataSoure = 'URL'; const oracleQuery = 'json(https://api.kraken.com/0/public/Ticker?pair=ETHUSD).result.XETHZUSD.c.0'; before(async function() { - marketContractRegistry = await MarketContractRegistry.deployed(); + marketContractRegistry = await MarketContractRegistry.deployed(); }); // forces the contract to be settled async function settleContract() { const settlementPrice = priceCap.plus(10); - await marketContract.oracleCallBack(settlementPrice, {from: accounts[0]}); // price above cap! + await marketContract.oracleCallBack(settlementPrice, { from: accounts[0] }); // price above cap! return settlementPrice; } @@ -40,7 +36,7 @@ contract('MarketCollateralPool', function(accounts) { collateralPool = await MarketCollateralPool.deployed(); collateralToken = await CollateralToken.deployed(); marketContract = await MarketContractOraclize.new( - "MyNewContract", + 'MyNewContract', [ accounts[0], collateralToken.address, @@ -57,7 +53,8 @@ contract('MarketCollateralPool', function(accounts) { oracleDataSoure, oracleQuery ); - await marketContractRegistry.addAddressToWhiteList(marketContract.address, {from: accounts[0]}); + + await marketContractRegistry.addAddressToWhiteList(marketContract.address, { from: accounts[0] }); qtyMultiplier = await marketContract.QTY_MULTIPLIER.call(); priceFloor = await marketContract.PRICE_FLOOR.call(); priceCap = await marketContract.PRICE_CAP.call(); @@ -67,11 +64,10 @@ contract('MarketCollateralPool', function(accounts) { describe('mintPositionTokens()', function() { it('should mint position tokens', async function() { - // 1. Start with fresh account const initialBalance = await collateralToken.balanceOf.call(accounts[1]); assert.equal(initialBalance.toNumber(), 0, 'Account 1 already has a balance'); - + // 2. should fail to mint when user has no collateral. let error = null; try { @@ -80,14 +76,14 @@ contract('MarketCollateralPool', function(accounts) { error = err; } assert.ok(error instanceof Error, 'should not be able to mint with no collateral token balance'); - + // 3. should fail to mint when user has not approved transfer of collateral (erc20 approve) const accountBalance = await collateralToken.balanceOf.call(accounts[0]); assert.isTrue(accountBalance.toNumber() != 0, 'Account 0 does not have a balance of collateral'); - + const initialApproval = await collateralToken.allowance.call(accounts[0], collateralPool.address); assert.equal(initialApproval.toNumber(), 0, 'Account 0 already has an approval'); - + error = null; try { await collateralPool.mintPositionTokens(marketContract.address, 1, { from: accounts[0] }); @@ -95,35 +91,54 @@ contract('MarketCollateralPool', function(accounts) { error = err; } assert.ok(error instanceof Error, 'should not be able to mint with no collateral approval balance'); - + // 4. should allow to mint when user has collateral tokens and has approved them const amountToApprove = 1e22; await collateralToken.approve(collateralPool.address, amountToApprove); const qtyToMint = 100; - await collateralPool.mintPositionTokens(marketContract.address, qtyToMint, { from: accounts[0]}); + await collateralPool.mintPositionTokens(marketContract.address, qtyToMint, { from: accounts[0] }); const longPosTokenBalance = await longPositionToken.balanceOf(accounts[0]); const shortPosTokenBalance = await shortPositionToken.balanceOf(accounts[0]); - + assert.equal(longPosTokenBalance.toNumber(), qtyToMint, 'incorrect amount of long tokens minted'); - assert.equal(shortPosTokenBalance.toNumber(), qtyToMint,'incorrect amount of long tokens minted'); + assert.equal(shortPosTokenBalance.toNumber(), qtyToMint, 'incorrect amount of long tokens minted'); }); - + it('should lock the correct amount of collateral', async function() { // 1. Get initial token balance balance const initialCollateralBalance = await collateralToken.balanceOf.call(accounts[0]); - + // 2. approve collateral and mint tokens const amountToApprove = 1e22; await collateralToken.approve(collateralPool.address, amountToApprove); const qtyToMint = 100; - await collateralPool.mintPositionTokens(marketContract.address, qtyToMint, { from: accounts[0]}); - + await collateralPool.mintPositionTokens(marketContract.address, qtyToMint, { from: accounts[0] }); + // 3. balance after should be equal to expected balance const amountToBeLocked = qtyToMint * utility.calculateTotalCollateral(priceFloor, priceCap, qtyMultiplier); const expectedBalanceAfterMint = initialCollateralBalance.minus(amountToBeLocked); - const actualBalanceAfterMint = await collateralToken.balanceOf.call(accounts[0]) - - assert.equal(expectedBalanceAfterMint.toNumber(), actualBalanceAfterMint.toNumber(), 'incorrect collateral amount locked for minting') + const actualBalanceAfterMint = await collateralToken.balanceOf.call(accounts[0]); + + assert.equal(expectedBalanceAfterMint.toNumber(), actualBalanceAfterMint.toNumber(), 'incorrect collateral amount locked for minting'); + }); + + it('should fail if contract is settled', async () => { + // 1. force contract to settlement + await settleContract(); + + // 2. approve collateral and mint tokens should fail + const amountToApprove = 1e22; + await collateralToken.approve(collateralPool.address, amountToApprove); + const qtyToMint = 1; + + let error = null; + try { + await collateralPool.mintPositionTokens(marketContract.address, qtyToMint, { from: accounts[0] }); + } catch (err) { + error = err; + } + + assert.ok(error instanceof Error, 'should not be able to mint position tokens after settlement'); }); }); @@ -133,45 +148,45 @@ contract('MarketCollateralPool', function(accounts) { const amountToApprove = 1e22; await collateralToken.approve(collateralPool.address, amountToApprove); const qtyToMint = 100; - await collateralPool.mintPositionTokens(marketContract.address, qtyToMint, { from: accounts[0]}); + await collateralPool.mintPositionTokens(marketContract.address, qtyToMint, { from: accounts[0] }); const initialLongPosTokenBalance = await longPositionToken.balanceOf(accounts[0]); const initialShortPosTokenBalance = await shortPositionToken.balanceOf(accounts[0]); - + // 2. redeem tokens const qtyToRedeem = 50; const collateralBalanceBeforeRedeem = await collateralToken.balanceOf.call(accounts[0]); await collateralPool.redeemPositionTokens(marketContract.address, qtyToRedeem, { from: accounts[0] }); - + // 3. assert final tokens balance are as expected const expectedFinalLongPosTokenBalance = initialLongPosTokenBalance.minus(qtyToRedeem); const expectedFinalShortPosTokenBalance = initialShortPosTokenBalance.minus(qtyToRedeem); const finalLongPosTokenBalance = await longPositionToken.balanceOf(accounts[0]); const finalShortPosTokenBalance = await shortPositionToken.balanceOf(accounts[0]); - + assert.equal(expectedFinalLongPosTokenBalance.toNumber(), finalLongPosTokenBalance.toNumber(), 'incorrect long position token balance after redeeming'); assert.equal(expectedFinalShortPosTokenBalance.toNumber(), finalShortPosTokenBalance.toNumber(), 'incorrect short position token balance after redeeming'); - + // 4. assert correct collateral is returned const collateralAmountToBeReleased = qtyToRedeem * utility.calculateTotalCollateral(priceFloor, priceCap, qtyMultiplier); const expectedCollateralBalanceAfterRedeem = collateralBalanceBeforeRedeem.plus(collateralAmountToBeReleased); const actualCollateralBalanceAfterRedeem = await collateralToken.balanceOf.call(accounts[0]); - + assert.equal(expectedCollateralBalanceAfterRedeem.toNumber(), actualCollateralBalanceAfterRedeem.toNumber(), 'incorrect collateral amount returned after redeeming'); }); - + it('should fail to redeem single tokens before settlement', async function() { // 1. approve collateral and mint tokens const amountToApprove = 1e22; await collateralToken.approve(collateralPool.address, amountToApprove); const qtyToMint = 1; - await collateralPool.mintPositionTokens(marketContract.address, qtyToMint, { from: accounts[0]}); + await collateralPool.mintPositionTokens(marketContract.address, qtyToMint, { from: accounts[0] }); const shortTokenBalance = (await shortPositionToken.balanceOf.call(accounts[0])).toNumber(); const longTokenBalance = (await longPositionToken.balanceOf.call(accounts[0])).toNumber(); assert.equal(shortTokenBalance, longTokenBalance, 'long token and short token balances are not equals'); - + // 2. transfer part of the long token - await longPositionToken.transfer(accounts[1], 1, { from: accounts[0]}) - + await longPositionToken.transfer(accounts[1], 1, { from: accounts[0] }); + // 3. attempting to redeem all shorts before settlement should fails let error = null; try { @@ -180,14 +195,13 @@ contract('MarketCollateralPool', function(accounts) { } catch (err) { error = err; } - + assert.ok(error instanceof Error, 'should not be able to redeem single tokens before settlement'); }); - }) + }); describe('settleAndClose()', function() { it('should fail if settleAndClose() is called before settlement', async () => { - let error = null; let settleAndCloseError = null; try { await collateralPool.settleAndClose(marketContract.address, { from: accounts[0] }); @@ -202,14 +216,14 @@ contract('MarketCollateralPool', function(accounts) { const amountToApprove = 1e22; await collateralToken.approve(collateralPool.address, amountToApprove); const qtyToMint = 1; - await collateralPool.mintPositionTokens(marketContract.address, qtyToMint, { from: accounts[0]}); - + await collateralPool.mintPositionTokens(marketContract.address, qtyToMint, { from: accounts[0] }); + // 2. transfer part of the long token - await longPositionToken.transfer(accounts[1], 1, { from: accounts[0]}) + await longPositionToken.transfer(accounts[1], 1, { from: accounts[0] }); // 3. force contract to settlement await settleContract(); - + // 4. redeem all short position tokens after settlement should pass const balanceBeforeRedeem = await shortPositionToken.balanceOf.call(accounts[0]); const qtyToRedeem = -1; @@ -218,7 +232,7 @@ contract('MarketCollateralPool', function(accounts) { await collateralPool.settleAndClose(marketContract.address, qtyToRedeem, { from: accounts[0] }); } catch (err) { error = err; - } + } assert.isNull(error, 'should be able to redeem single tokens after settlement'); // 5. balance of short tokens should be updated. @@ -232,25 +246,25 @@ contract('MarketCollateralPool', function(accounts) { const amountToApprove = 1e22; await collateralToken.approve(collateralPool.address, amountToApprove); const qtyToMint = 1; - await collateralPool.mintPositionTokens(marketContract.address, qtyToMint, { from: accounts[0]}); - + await collateralPool.mintPositionTokens(marketContract.address, qtyToMint, { from: accounts[0] }); + // 2. transfer part of the long token - await longPositionToken.transfer(accounts[1], 1, { from: accounts[0]}) + await longPositionToken.transfer(accounts[1], 1, { from: accounts[0] }); // 3. force contract to settlement const settlementPrice = await settleContract(); - + // 4. redeem all shorts on settlement const collateralBalanceBeforeRedeem = await collateralToken.balanceOf.call(accounts[0]); const qtyToRedeem = (await shortPositionToken.balanceOf.call(accounts[0])).toNumber(); await collateralPool.settleAndClose(marketContract.address, -qtyToRedeem, { from: accounts[0] }); - + // 5. should return appropriate collateral const collateralToReturn = utility.calculateNeededCollateral(priceFloor, priceCap, qtyMultiplier, qtyToRedeem, settlementPrice); const expectedCollateralBalanceAfterRedeem = collateralBalanceBeforeRedeem.plus(collateralToReturn); const actualCollateralBalanceAfterRedeem = await collateralToken.balanceOf.call(accounts[0]); - assert.equal(expectedCollateralBalanceAfterRedeem.toNumber(), actualCollateralBalanceAfterRedeem.toNumber(), 'short position tokens balance was not reduced') - + assert.equal(expectedCollateralBalanceAfterRedeem.toNumber(), actualCollateralBalanceAfterRedeem.toNumber(), 'short position tokens balance was not reduced'); + }); }); From 050c8bb62c4a7795f542895b34ad019bef9ab554 Mon Sep 17 00:00:00 2001 From: Eswara Sai Date: Wed, 12 Dec 2018 12:53:27 +0530 Subject: [PATCH 6/6] Added test for redemption of long token after settlement --- test/MarketCollateralPool.js | 44 ++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/test/MarketCollateralPool.js b/test/MarketCollateralPool.js index bc2ad891..1ae9dfc9 100644 --- a/test/MarketCollateralPool.js +++ b/test/MarketCollateralPool.js @@ -211,34 +211,48 @@ contract('MarketCollateralPool', function(accounts) { assert.ok(settleAndCloseError instanceof Error, 'settleAndClose() did not fail before settlement'); }); - it('should redeem single short tokens after settlement', async function() { + it('should redeem short and long tokens after settlement', async function() { + let error = null; + // 1. approve collateral and mint tokens const amountToApprove = 1e22; await collateralToken.approve(collateralPool.address, amountToApprove); const qtyToMint = 1; await collateralPool.mintPositionTokens(marketContract.address, qtyToMint, { from: accounts[0] }); - // 2. transfer part of the long token - await longPositionToken.transfer(accounts[1], 1, { from: accounts[0] }); - - // 3. force contract to settlement + // 2. force contract to settlement await settleContract(); - // 4. redeem all short position tokens after settlement should pass - const balanceBeforeRedeem = await shortPositionToken.balanceOf.call(accounts[0]); - const qtyToRedeem = -1; - let error = null; + // 3. redeem all short position tokens after settlement should pass + const shortTokenBalanceBeforeRedeem = await shortPositionToken.balanceOf.call(accounts[0]); + const shortTokenQtyToRedeem = -1; + try { + await collateralPool.settleAndClose(marketContract.address, shortTokenQtyToRedeem, { from: accounts[0] }); + } catch (err) { + error = err; + } + assert.isNull(error, 'should be able to redeem short tokens after settlement'); + + // 4. balance of short tokens should be updated. + const expectedShortTokenBalanceAfterRedeem = shortTokenBalanceBeforeRedeem.plus(shortTokenQtyToRedeem); + const actualShortTokenBalanceAfterRedeem = await shortPositionToken.balanceOf.call(accounts[0]); + assert.equal(expectedShortTokenBalanceAfterRedeem.toNumber(), actualShortTokenBalanceAfterRedeem.toNumber(), 'short position tokens balance was not reduced'); + + // 5. redeem all long position tokens after settlement should pass + const longTokenBalanceBeforeRedeem = await longPositionToken.balanceOf.call(accounts[0]); + const longTokenQtyToRedeem = 1; + error = null; try { - await collateralPool.settleAndClose(marketContract.address, qtyToRedeem, { from: accounts[0] }); + await collateralPool.settleAndClose(marketContract.address, longTokenQtyToRedeem, { from: accounts[0] }); } catch (err) { error = err; } - assert.isNull(error, 'should be able to redeem single tokens after settlement'); + assert.isNull(error, 'should be able to redeem long tokens after settlement'); - // 5. balance of short tokens should be updated. - const expectedBalanceAfterRedeem = balanceBeforeRedeem.plus(qtyToRedeem); - const actualBalanceAfterRedeem = await shortPositionToken.balanceOf.call(accounts[0]); - assert.equal(expectedBalanceAfterRedeem.toNumber(), actualBalanceAfterRedeem.toNumber(), 'short position tokens balance was not reduced'); + // 6. balance of long tokens should be updated. + const expectedLongTokenBalanceAfterRedeem = longTokenBalanceBeforeRedeem.minus(longTokenQtyToRedeem); + const actualLongTokenBalanceAfterRedeem = await longPositionToken.balanceOf.call(accounts[0]); + assert.equal(expectedLongTokenBalanceAfterRedeem.toNumber(), actualLongTokenBalanceAfterRedeem.toNumber(), 'long position tokens balance was not reduced'); }); it('should return correct amount of collateral when redeemed after settlement', async function() {