Assignment - Limit Order Test

Hi @mcgrane5 ,

Thanks much for the prompt reply, and for the explanations and thoughts about the edge cases, some of which I hadn’t thought about!

Anyway…below is my response. #2 is my most important item and is where I am currently blocked so would appreciate any comments/suggestions regarding #2.

  1. Appreciate the code example for the delete function. Filip talked about something similar in his video on clearing filled orders from the order book. My plan was to implement something similar to your example, but, in true TDD fashion, not until my test fails at that point (could not find a delete function) :slight_smile:

  2. However, as you write, we first need to identify the index we want to delete. To do this, I want to generate a list of orders specific to a particular trader, so the trader can pick one of his orders to delete. I don’t want the whole BUY order book because I don’t want the trader to delete someone else’s order. This would be similar to a UI where a trader logs in and views a list of his current orders on an Orders screen.

And this is exactly where my test is currently failing. The traderBuyLimitOrders array is returning empty and I am getting the AssertionError (expected 0 to equal 3). See the When section of the test.

In order to make this assertion pass, I believe I need to figure out how to load an array with a subset of Orders where:

  • trader = trader1.address
  • ticker = Tokens.LINK
  • Side = Side.BUY

so, 3 filter criteria, not just the 2 filter criteria we use for orderBook.

To do this, in the Dex.sol code, I wrapped the original orderBook mapping inside another mapping named traderOrderBook. See my code above. But this does not seem to be working. Seems like we should be able to create a mapping based on 3 keys. Do you have any comments or suggestions?

  1. Regarding your last tip, so far my tests are running pretty fast. And I actually like the TDD approach of writing the tests first and then writing just enough code, and only the code required, to make the tests pass (à la Red, Green, Refactor). In any event, I want to keep coding this way for a while, get used to it, and see what I think. So far I like it because the tests make the requirements explicit (instead of in my head) and subsequently the tests are always there to catch problems when I refactor, such as your suggestion to move the sorting procedures to a separate function.

  2. Lastly, I am currently coding in Atom on a Mac. So I have no way to easily try out code via point and click, like in Remix. So debugging is a challenge, and as a last resort, I have had to copy my files to Remix just to get the point & click and debugging features. I see that many of the Moralis instructors, including Ivan in a recent video I watched, use VisualStudio. Do you recommend that I move to VisualStudio? Does VisualStudio support point & click debugging similar to Remix?

Many thanks and look forward to your comments about #2. Best!

1 Like

Hey @pivot i have read your reply jusy now and im excited to form my reaponse as detailed as i can. I am currently out for new years so i will not be able to rwply until tomorrow. Hope this is ok but ill be as soon as i can.

1 Like

@mcgrane5… No worries. Happy New Year and enjoy the celebration!

Here’s my attempt. I may not understand fully what parameters dex.createLimitOrder() needs yet, so I’ll be updating that as I come to better understand what’s needed.

Something I tried to do here and need to test once dex.createLimitOrder() is functional, is having a before() function that get’s called before any of the it() functions are called; before() preps things for the test so I don’t need to re-setup anything in each test, or hope that a previous test set something up before hand.

const Dex = artifacts.require("Dex");
const Link = artifacts.require("Link");
const truffleAssert = require("truffle-assertions");

contract("Dex", (accounts) => {
  let dex = await Dex.deployed();
  let link = await Link.deployed();
  // TODO: check to see if we can do this, or if the before() function needs to
  // define these values from await. (chris)
  // let ticker = web3.utils.fromUtf8("LINK"); // default
  let linkSymbol = await link.symbol();
  // make sure `ticker` has the correct `Link.symbol()`
  ticker = web3.utils.fromUtf8(linkSymbol);
  let getWalletTickerBalance = async function (_ticker, wallet, account) {
    let balance = await wallet.balances(account, _ticker);
    return balance.toString();
  };
  let getAccountBalance = async function (account) {
    let balance = await web3.eth.getBalance(account);
    return web3.utils.fromWei(balance);
  };

  // before any test is run:
  //// - update `ticker` to match `Link.symbol()`
  // - add the `ticker` token to accounts[0] Dex
  // - approve and deposit 500 `ticker` tokens for accounts[0]
  // - prep the orderBook with some BUY/SELL orders from accounts 4, 5, and 6
  // NOTE: before() runs only once before the first test in this block.
  before(function () {
    // let linkSymbol = await link.symbol();
    // // make sure `ticker` has the correct `Link.symbol()`
    // ticker = web3.utils.fromUtf8(linkSymbol);

    // add to token to accounts[0] dex
    dex.addToken(ticker, link.address, {
      from: accounts[0],
    });

    // approve and deposit `ticker` tokens for accounts[0]
    await link.approve(dex.address, 500);
    await dex.deposit("500", ticker);

    // prep the orderBook
    // 3 BUY orders
    for (let i = 4; i <= 6; i++) {
      let amount = i * 100;
      let price = i * 10;
      dex.createLimitOrder(Side.BUY, ticker, amount, price, {
        from: accounts[i],
      });
    }
    // 3 SELL orders
    for (let i = 4; i <= 6; i++) {
      let amount = i * 10;
      let price = i * 100;
      dex.createLimitOrder(Side.SELL, ticker, amount, price, {
        from: accounts[i],
      });
    }
  });

  it("has enough ETH deposited that's >= a buy order value", async () => {
    let balance = getAccountBalance(accounts[0]);
    let orderBook = await dex.getOrderBook(ticker, Side.BUY);
    let enoughEth = false;
    for (let i = 0; i < orderBook.length; i++) {
      if (balance >= orderBook[i].price) {
        enoughEth = true;
        break;
      }
    }
    assert.equal(true, enoughEth);
  });

  it("has enough tokens deposited that's >= a sell order", async () => {
    let balance = getWalletTickerBalance(ticker, dex, accounts[0]);
    let orderBook = await dex.getOrderBook(ticker, Side.SELL);
    let enoughEth = false;
    for (let i = 0; i < orderBook.length; i++) {
      if (balance >= orderBook[i].price) {
        enoughEth = true;
        break;
      }
    }
    assert.equal(true, enoughEth);
  });

  it("correctly orders the BUY order book from highest to lowest price starting at index 0", async () => {
    // i.e. before and after adding orders, the first should always be the highest price:
    // [Order(10), Order(7), Order(6)]
    // add Order(8)
    // [Order(10), Order(8), Order(7), Order(6)]
    let orderBook = await dex.getOrderBook(ticker, Side.BUY);
    let lastPrice = orderBook[0].price;
    let orderedCorrectly = true;
    for (let i = 1; i < orderBook.length; i++) {
      if (lastPrice < orderBook[i].price) {
        orderedCorrectly = false;
        break;
      }
    }
    assert.equal(true, orderedCorrectly);
  });
});
2 Likes

Hi, there is my solution:
/test/auxiliary.js

// aux
module.exports.asciiToBytes32Hex = (s) => {
  let r = "0x";
  let i = 0;
  while (i < 32) {
    if(s[i] === undefined){
      r += "00";
    } else {
      r += (s.charCodeAt(i).toString(16)).padStart(2,"0");
    }
    i++;
  }
  return r;
}
module.exports.bytes32HexToAscii = (s) => {
  let s_ = web3.utils.hexToAscii(s);
  let r = "";
  for (let i = 0; i < 32; i++) {
    if(s_[i] === '\u0000'){break;}
    r+=s_[i];
  }
  return r;
}
module.exports.doThrow = async (f, msgExpr) => {
  try {
    if (f.constructor.name == 'AsyncFunction'){
      await f();
    } else {
      f();
    }
    return false;
  } catch(e){
    if (msgExpr && msgExpr.length > 0){
      if (e.message.startsWith(msgExpr)){
        return true;
      }
      return false;
    }
    return true;
  }
}

/test/Dex.js

const { asciiToBytes32Hex, bytes32HexToAscii, doThrow } = require('./auxiliary.js');
const Dex = artifacts.require("./Dex.sol");
const BNB = artifacts.require("./BNB.sol");

const toBN = web3.utils.toBN;

contract("Dex", async (accounts) => {
  describe("Limit Orders", async () => {
    var dex;
    var tokenBNB;
    const owner = accounts[0];
    const nonOwner = accounts[1];
    const bnbTicker = asciiToBytes32Hex("BNB");
    before("setting up env", async () => {
      dex = await Dex.new();
      tokenBNB = await BNB.new();
      // await wallet.addToken(croTicker, tokenCRO.address);
      await tokenBNB.mint(owner, "10000");
      await tokenBNB.mint(nonOwner, "10000");
      await tokenBNB.mint(randomGuy, "11");
      // charging some eth on the wallet to avoid getting "TokensWallet: contract has too few eth" errors
      await dex.deposit(ethTicker, "10000", {from: accounts[9], value: "10000"});
      // charging some bnb on the wallet to avoid getting "TokensWallet: contract has too few tokens"
      await tokenBNB.increaseAllowance(dex.address, "1", {from: randomGuy});
      await dex.deposit(bnbTicker, "1", {from: randomGuy});
      
      // charging amounts for the actual tests
      // nonOwner wallet balances:
      //    10000 wei
      //    10 bnb
      await tokenBNB.increaseAllowance(dex.address, "10", {from: nonOwner});
      await dex.deposit(bnbTicker, "10", {from: nonOwner});
      await dex.deposit(ethTicker, "10000", {from: nonOwner});
    });
    
    it("The user must have ETH deposited such that deposited eth >= buy order value", async () => {
      let ticker = bnbTicker,
          side = 0, // BUY
          amount = "2",
          price = "5001"; // > "2" * "5000"
      assert.isTrue(
        await doThrow(
          async () => {
            await dex.createLimitOrder(ticker, side, amount, price, {from: nonOwner});
          },
          "Returned error: VM Exception while processing transaction: revert TokensWallet: Balance too low"
        ), 
        "User can create non backed BUY orders"
      );
    });

    it("The user must have enough tokens deposited such that token balance >= sell order amount", async () => {
      let ticker = bnbTicker,
          side = 1, // SELL
          amount = "11", // > "10"
          price = "10000000";
      assert.isTrue(
        await doThrow(
          async () => {
            await dex.createLimitOrder(ticker, side, amount, price, {from: nonOwner});
          },
          "Returned error: VM Exception while processing transaction: revert TokensWallet: Balance too low"
        ), 
        "User can create non backed SELL orders"
      );
    });

    it("The BUY order book should be ordered on price from highest to lowest starting at index 0", async () => {
      let ticker = bnbTicker,
          side = 0, // BUY
          amount = "1", 
          price0 = "10",
          price1 = "9",
          price2 = "8",
          price3 = "7",
          price4 = "6";
      await dex.createLimitOrder(ticker, side, amount, price3, {from: nonOwner});
      await dex.createLimitOrder(ticker, side, amount, price1, {from: nonOwner});
      await dex.createLimitOrder(ticker, side, amount, price2, {from: nonOwner});
      await dex.createLimitOrder(ticker, side, amount, price4, {from: nonOwner});
      await dex.createLimitOrder(ticker, side, amount, price0, {from: nonOwner});
      let orderBook = await dex.getOrderbook(ticker, side);
      assert.isTrue((await orderBook[0].price).toString() == price0, "Wrong BUY orderbook order on item 0");
      assert.isTrue((await orderBook[1].price).toString() == price1, "Wrong BUY orderbook order on item 1");
      assert.isTrue((await orderBook[2].price).toString() == price2, "Wrong BUY orderbook order on item 2");
      assert.isTrue((await orderBook[3].price).toString() == price3, "Wrong BUY orderbook order on item 3");
      assert.isTrue((await orderBook[4].price).toString() == price4, "Wrong BUY orderbook order on item 4");
    });

    it("The SELL order book should be ordered on price from lowest to highest starting at index 0", async () => {
      let ticker = bnbTicker,
          side = 1, // SELL
          amount = "1", 
          price0 = "10",
          price1 = "11",
          price2 = "12",
          price3 = "13",
          price4 = "14";
      await dex.createLimitOrder(ticker, side, amount, price3, {from: nonOwner});
      await dex.createLimitOrder(ticker, side, amount, price1, {from: nonOwner});
      await dex.createLimitOrder(ticker, side, amount, price2, {from: nonOwner});
      await dex.createLimitOrder(ticker, side, amount, price4, {from: nonOwner});
      await dex.createLimitOrder(ticker, side, amount, price0, {from: nonOwner});
      let orderBook = await dex.getOrderbook(ticker, side);
      assert.isTrue((await orderBook[0].price).toString() == price0, "Wrong SELL orderbook order on item 0");
      assert.isTrue((await orderBook[1].price).toString() == price1, "Wrong SELL orderbook order on item 1");
      assert.isTrue((await orderBook[2].price).toString() == price2, "Wrong SELL orderbook order on item 2");
      assert.isTrue((await orderBook[3].price).toString() == price3, "Wrong SELL orderbook order on item 3");
      assert.isTrue((await orderBook[4].price).toString() == price4, "Wrong SELL orderbook order on item 4");
    });
  });
});
1 Like

My DexTest.js Solution

const Dex = artifacts.require("Dex");
const Link = artifacts.require("Link");

const truffleAssert = require('truffle-assertions');

// The user must have enough ETH deposited in order for ETH deposited >= buy order value

contract(Dex, accounts => {
    it("ETH deposited should be greater than or equal to the buy order value", async () => {
        let dex = await Dex.deployed();
        let link = await Link.deployed();
        // await dex.addToken(web3.utils.fromUtf8("ETH"), dex.address, {from: accounts[0]});

        await truffleAssert.reverts(
            dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 10, 1)
        )
        
        dex.depositETH({value: 10});
        await truffleAssert.passes(
            dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 10, 1)
        )

    });

    // The user must have enough tokens deposited so that tokens deposited >= sell order value
    it("user should have enough tokens deposited to be greater than sell order value", async () => {
        let dex = await Dex.deployed();
        let link = await Link.deployed();

        await truffleAssert.reverts(
            dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 10, 1)
        )
        await link.approve(dex.address, 500);
        await dex.addToken(web3.utils.fromUtf8("LINK"), link.address, {from: accounts[0]});
        dex.deposit(10, web3.utils.fromUtf8("LINK"));
        
        await truffleAssert.passes(
            dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 10, 1)
        )

    });

    // The BUY order book should be ordered on price from highest to lowest starting at index[0]
    it("should have the buy orderbook in the correct sequence", async () => {
        let dex = await Dex.deployed();
        let link = await Link.deployed();
        await link.approve(dex.address, 500);

        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 100);
        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 400);
        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 300);

        let orderBook = await dex.getOrderBook(web3.utils.fromUtf8("LINK"), 0);

        for (let i = 0; i < orderBook.length - 1; i++) {
            assert(orderBook[i].price >= orderBook[i + 1].price, "Orderbook sequence incorrect.");
        }
    });

    // The SELL order book should be ordered on price from lowest to highest starting at index[0]
    it("should have the sell orderbook in the correct sequence", async () => {
        let dex = await Dex.deployed();
        let link = await Link.deployed();
        await link.approve(dex.address, 500);

        await dex.createLimitOrder(1, web3.utils.fromUtf8("Link"), 1, 100);
        await dex.createLimitOrder(1, web3.utils.fromUtf8("Link"), 1, 400);
        await dex.createLimitOrder(1, web3.utils.fromUtf8("Link"), 1, 300);

        let orderBook = await dex.getOrderBook(web3.utils.fromUtf8("Link"), 1);
        
        for (let i = 0; i < orderBook.length - 1; i++) {
            assert(orderBook[i].price <= orderBook[i + 1].price, "Orderbook sequence incorrect.");
        }

    })

})



1 Like

Can anybody help me with this error? Error: Returned error: VM Exception while processing transaction: out of gas

Here is my code, when I comment out the array listOrders, the error is just a revert. I need to figure out how to work around this gas issue. Thanks in advanced!

function createLimitOrder(
        Side side,
        bytes32 ticker,
        uint256 amount,
        uint256 price
    ) public {

        Order[] storage listOrders = orders[ticker][uint256(side)];

        listOrders.push(
            Order(nextOrderId, msg.sender, side, ticker, amount, price)
        );

        uint i = listOrders.length > 0 ? listOrders.length -1 : 0;
        
        if (side == Side.BUY) {
            require(balances[msg.sender]["ETH"] >= amount.mul(price));

                while(i > 0) {
                    if (listOrders[i - 1].price > listOrders[i].price) {
                        break;
                    }

                    Order memory orderToMove = listOrders[i - 1];
                    listOrders[i - 1] = listOrders[i];
                    listOrders[i] = orderToMove;
                    i--;

                } 
        } else if (side == Side.SELL) {
            require(balances[msg.sender][ticker] >= amount.mul(price));

            while(i > 0) {
                if (listOrders[i - 1].price < listOrders[i].price) {
                    break;
                }

                Order memory orderToMove = listOrders[i - 1];
                listOrders[i - 1] = listOrders[i];
                listOrders[i] = orderToMove;
                i--;

            }
        }
        nextOrderId++;
    }
1 Like

can you try taking out both of the require statements and see if it works. just wanna see something

yes I commented out the require for both BUY and SELL sides and this is error message. It gets rid of the gas error but now says it did not fail.

0 passing (2s)
  4 failing

  1) Contract: function TruffleContract() {
      this.constructor = temp;
      return Contract.apply(this, arguments);
    }
       ETH deposited should be greater than or equal to the buy order value:
     AssertionError: Did not fail
      at fails (node_modules/truffle-assertions/index.js:161:9)
      at processTicksAndRejections (node:internal/process/task_queues:96:5)
      at Context.<anonymous> (test/DexTest.js:14:9)

  2) Contract: function TruffleContract() {
      this.constructor = temp;
      return Contract.apply(this, arguments);
    }
       user should have enough tokens deposited to be greater than sell order value:
     AssertionError: Did not fail
      at fails (node_modules/truffle-assertions/index.js:161:9)
      at processTicksAndRejections (node:internal/process/task_queues:96:5)
      at Context.<anonymous> (test/DexTest.js:30:9)

  3) Contract: function TruffleContract() {
      this.constructor = temp;
      return Contract.apply(this, arguments);
    }
       should have the buy orderbook in the correct sequence:
     AssertionError: Unspecified AssertionError
      at Context.<anonymous> (test/DexTest.js:55:9)
      at processTicksAndRejections (node:internal/process/task_queues:96:5)

  4) Contract: function TruffleContract() {
      this.constructor = temp;
      return Contract.apply(this, arguments);
    }
       should have the sell orderbook in the correct sequence:
     AssertionError: Unspecified AssertionError
      at Context.<anonymous> (test/DexTest.js:73:9)
      at runMicrotasks (<anonymous>)
      at processTicksAndRejections (node:internal/process/task_queues:96:5)

1 Like

ok i think i can may see whats happening here. If im wrong push your code to github and ill have a look. If the functon executes when the require statements are commented out (as suggested by the “did not fail message”) then this means the issue seems to be the balances. if you call the balance function fo link and eth for the user what does it say

can u push your code to github and ill take a look

Yes, thank you so much for your help! Here is my github link.

https://github.com/diehlca17/Personal-Projects/tree/main/dex

1 Like

coool ill be back to you in a few hours im just going for a meal now look at it when i get back

1 Like

@diehlca17 ok so there was a few things none of it was to do with your code. The reason the first test failed was because you wrote dex.deposit(...) instead of await dex.deposit(..) they must be asynchrnous calls.

the second test was fine. the third and fourth test failed for small reasons like when you specified assert(orderbook > 0) instead of assert(orderboook.length > 0). and other small things where you only minted msg.sender 1000 tokens so by the time your last test gets called there all used up creating limit orders in the third test. your approval was also too low small things like this i changed. but its all working now sorry the deylay i was at a meal earlier and when i got back it toook me a while to fix
it but here it is anyway

const Dex = artifacts.require("Dex");
const Link = artifacts.require("Link");

const truffleAssert = require('truffle-assertions');

// The user must have enough ETH deposited in order for ETH deposited >= buy order value

contract(Dex, accounts => {
    it("ETH deposited should be greater than or equal to the buy order value", async () => {
        let dex = await Dex.deployed();
        let link = await Link.deployed();

        // await dex.addToken(web3.utils.fromUtf8("ETH"), dex.address, {from: accounts[0]});

        await truffleAssert.reverts(
            dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 10, 1)
        )
        
        await dex.depositETH({value: web3.utils.toWei("10", "ether")});
        await truffleAssert.passes(
            dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 5, 1)
        )

    });

    // The user must have enough tokens deposited so that tokens deposited >= sell order value
    it("user should have enough tokens deposited to be greater than sell order value", async () => {
        let dex = await Dex.deployed();
        let link = await Link.deployed();

        await truffleAssert.reverts(
            dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 20, 1)
        )

        await dex.addToken(web3.utils.fromUtf8("LINK"), link.address, {from: accounts[0]});
        await link.approve(dex.address, 500)
        await dex.deposit(10, web3.utils.fromUtf8("LINK"));
        
        await truffleAssert.passes(
            dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 5, 1)
        )

    });

    // The BUY order book should be ordered on price from highest to lowest starting at index[0]
    it("should have the buy orderbook in the correct sequence", async () => {
        let dex = await Dex.deployed();
        let link = await Link.deployed();
        await link.approve(dex.address, 500);

        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 400);
        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 200);
        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 300);

        let orderBook = await dex.getOrderBook(web3.utils.fromUtf8("LINK"), 0);

        assert(orderBook.length > 0);
        for (let i = 0; i < orderBook.length - 1; i++) {
            assert(orderBook[i].price >= orderBook[i + 1].price, "Orderbook sequence incorrect.");
        }
    });

    // The SELL order book should be ordered on price from lowest to highest starting at index[0]
    it("should have the sell orderbook in the correct sequence", async () => {
        let dex = await Dex.deployed();
        let link = await Link.deployed();
        await link.approve(dex.address, 20000);

        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 100);
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 2400);
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 1100);
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 100);
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 2400);
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 1100);

        let orderBook = await dex.getOrderBook(web3.utils.fromUtf8("Link"), 1);
        console.log(orderBook)
        // assert(orderBook.length > 0);
        for (let i = 0; i < orderBook.length - 1; i++) {
            assert(orderBook[i].price <= orderBook[i + 1].price, "Orderbook sequence incorrect.");
        }

        console.log(orderBook)

    })

})



1 Like

Thanks so much, that helps me clarify things a lot better. I fixed all of these issues on my machine and it completely fixes the 3rd and 4th tests, but then when I uncomment the require statements in the createLimitOrder function, the tests still return the out of gas error. Were you able to get past this issue?

1 Like

yeah ypur tests work perfectly for me on my machine every test passed even with the requires. i think i may know what happenig. close truffle devlop and re-start it and your accounts’ balances will all get reset too 100 ETH, maybe its that you hadnt enough eth to deposit this can happen and did to me a few times because you deposit 10 eth which will use up all of your users eth bal really qyickily. can u share the error screenshot ofit

I tried restart develop console and also did migrate --reset. Still giving me these errors. Legit only from commenting out require statements. If they are commented out, tests 3 and 4 pass while 1 and 2 do not.

Hi, this is my solution. It looks like I should create a new function called depositEth() in the Wallet contract to let the buyers deposit ether to the Dex contract.

Dex.test.js

const LinkTokenMock = artifacts.require("LinkTokenMock");
const Dex = artifacts.require("DEX");

const truffleAssert = require("truffle-assertions");

contract("DEX test", accounts => {
    it("should only let user, as buyer, create BUY limit order amount less than/equal to their deposited eth", async () => {
        let dex = await Dex.deployed();

        await truffleAssert.reverts(
            dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 10, 4)
        );

        await dex.depositEth({ value: 100 });

        await truffleAssert.passes(
            dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 10, 4)
        );
    });

    it("should only let user, as seller, create SELL limit order amount less than/equal to their deposited token", async () => {
        let dex = await Dex.deployed();
        let link = await LinkTokenMock.deployed();

        await dex.addToken(web3.utils.fromUtf8("LINK"), link.address);

        await truffleAssert.reverts(
            dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 10, 4)
        );

        await link.approve(dex.address, 100);
        await dex.deposit(web3.utils.fromUtf8("LINK"));

        await truffleAssert.passes(
            dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 10, 4)
        );
    });

    it("checks if BUY ORDER list is sorted from highest to lowest starting at index 0", async () => {
        let dex = await Dex.deployed();

        let failed = false;

        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 10, 1);
        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 10, 3);
        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 10, 2);

        let buyOrderBook = await dex.getOrderBook(web3.utils.fromUtf8("LINK"), 0);

        for (i = 0; i < buyOrderBook.length - 1; i++) {
            if (parseInt(buyOrderBook[i + 1].price, 10) > parseInt(buyOrderBook[i].price, 10)) {
                failed = true;
                break;
            }
        }

        assert.equal(failed, false);
    });

    it("checks if SELL ORDER list is sorted from highest to lowest starting at index 0", async () => {
        const dex = await Dex.deployed();
        const link = await LinkTokenMock.deployed();

        let failed = false;

        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 10, 1);
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 10, 3);
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 10, 2);

        let sellOrderBook = await dex.getOrderBook(web3.utils.fromUtf8("LINK"), 1);
        for (i = 0; i < sellOrderBook.length - 1; i++) {
            if (parseInt(sellOrderBook[i + 1].price, 10) > parseInt(sellOrderBook[i].price, 10)) {
                failed = true;
                break;
            }
        }

        assert.equal(failed, false);
    });
});
2 Likes

My code

/limit order
    //the user must have ETH such that deposited eth>= buy order value
    //the user must have enought tokens deposited such that token balance >= sell order amount
    //the Buy order book should be ordered on price from highest to lowest starting at index 0
    //The SELL order book should be ordered on price form the lowest to hightest 
    const Dex = artifacts.require("Dex")
    const Link = artifacts.require("Link")
    const truffleAssert = require('truffle-assertions')
    
    contract("Dex", accounts => {
        it("should only be possible for the owner to mint tokens", async()=>
        {
         
            let dex = await Dex.deployed();
            let link = await Link.deployed();
            await truffleAssert.passes(
            dex.addToken(web3.utils.fromUtf8("LINK"), link.address,{from: accounts[0]})
            )
            await truffleAssert.reverts(
                dex.addToken(web3.utils.fromUtf8("LINK"), link.address,{from: accounts[1]})
                )
        })
    
        it("should handle deposit correctly", async()=>
        {
         
            let dex = await Dex.deployed();
            let link = await Link.deployed();
            await link.approve(dex.address,500);
            await dex.deposit(100, web3.utils.fromUtf8("LINK"));
            let balance =  await dex.balances(accounts[0],web3.utils.fromUtf8("LINK"));
           
            assert.equal(balance.toNumber(), 100);
    
            
        })

        it("The user should have enough Ether to buy", async()=>
             {
            let dex = await Dex.deployed();
            let link = await Link.deployed();

            let balance =  await dex.accounts[0].balance; //Getting teh ETh Balance of the address, 100Eth at the begining, enough to test
            await truffleAssert.passes(
            dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 0.2,{from: accounts[0]}) )
            await truffleAssert.reverts(dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 100000,50000,{from: accounts[1]}))

        })

        it(" the user must have enought tokens deposited such that token balance >= sell order amount", async ()=>{
            let dex = await Dex.deployed();
            let link = await Link.deployed();
            await link.approve(dex.address,500);
            await dex.deposit(100, web3.utils.fromUtf8("LINK"));

            let balance =  await dex.balances(accounts[0],web3.utils.fromUtf8("LINK"));
            await truffleAssert.passes(
            dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 100, 1,{from: accounts[0]})
            )

            await truffleAssert.reverts(1, dex.createLimitOrder(web3.utils.fromUtf8("LINK"), 2000, 1,{from: accounts[0]}))

               })
            

        }
        )
        it("the Buy order book should be ordered on price from highest to lowest starting at index 0", async ()=>{
            
            let dex = await Dex.deployed();
            let link = await Link.deployed();
            await link.approve(dex.address,1000);
            await dex.deposit(100, web3.utils.fromUtf8("LINK"));
            await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 100);
            await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 400);
            await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 300);
            let orderBook = await getOrderBook(web3.utils.fromUtf8("LINK"),0); //select the buy order book
        
        
            for ( i=0; i<orderBook.length-1; i++){
                assert(orderBook[i].price > orderBook[i+1].price);
            }
        }
        
    )

    it("The SELL order book should be ordered on price form the lowest to hightest ", async()=> {
        let dex = await Dex.deployed();
        let link = await Link.deployed();
        await link.approve(dex.address,1000);
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 100);
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 400);
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 300);
          let orderBook = await getOrderBook(web3.utils.fromUtf8("LINK"),0);
        
        
        for ( i=0; i<orderBook.length-1; i++){
            assert(orderBook[i].price < orderBook[i+1].price);
        }
       
    })
1 Like

This is my solution:

const Dex = artifacts.require("Dex")
const truffleAssert = require('truffle-assertions');

contract("Limit Order Tests", accounts => {

    //createLimitOrder(Side side, byte32 _ticker, uint _price, uint _amount)

    it("should only allow buy orders if the user has deposited ETH >= the amount of the buy order", async() => {
        let dex = await Dex.deployed();

        await dex.deposit(10, web3.utils.fromUtf8("ETH"), {from: accounts[0]})

        await truffleAssert.passes(
            dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 1000, {from: accounts[0]})
        )
        await truffleAssert.reverts(
            dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 15, 1000, {from: accounts[0]})
        )
    })
    it("should only allow sell orders if the user has deposited LINK >= the amount of the buy order", async() => {
        let dex = await Dex.deployed();

        await dex.deposit(1000, web3.utils.fromUtf8("LINK"), {from: accounts[0]})

        await truffleAssert.passes(
            dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 1000, {from: accounts[0]})
        )
        await truffleAssert.reverts(
            dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 2000, {from: accounts[0]})
        )
    })
    it("should order the buy orders from highest to lowest price", async() => {
        let dex = await Dex.deployed();

        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 5, 1000, {from: accounts[0]})
        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 10, 1000, {from: accounts[0]})
        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 1000, {from: accounts[0]})
        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 3, 1000, {from: accounts[0]})

        let orderBook = await dex.orderBook[web3.utils.fromUtf8("LINK")][0];

        assert.equal(orderBook[0].price, 10);
        assert.equal(orderBook[1].price, 5);
        assert.equal(orderBook[2].price, 3);
        assert.equal(orderBook[3].price, 1);
    })
})
1 Like