Assignment - Limit Order Test

My solution…


// User must have ETH deposited such that deposited eth >= buy order value
// User must have enough 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

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

contract ("Dex", accounts => {
    it("should have more ETH deposited then buy order value amount", async () => {
        let dex = await Dex.deployed();
        let link = await Link.deployed();
        await truffleAssert.reverts( 
            dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 10, 1)
        );
        await dex.depositEth({value:10});
        await truffleAssert.passes(
            dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 10, 1)
        );
    })

    it("should have enough token balance then SELL order amount", 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]});
        await dex.deposit(10, web3.utils.fromUtf8("LINK"));
        await truffleAssert.passes(
            dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 10, 1)
        );
    })

    it("first BUY order in orderBook must have the highest price", async() => {
        let dex = await Dex.deployed();
        let link = await Link.deployed();
        await link.approve(dex.address,40);
        await dex.depositEth({value:100});
        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 20);
        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 10);
        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 30);

        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, "invalid order in BUY orderbook")
        }
    })

    it("first SELL order in orderBook must have the lowest price", async() => {
        let dex = await Dex.deployed();
        let link = await Link.deployed();
        await link.approve(dex.address,40);
        await dex.depositEth({value:100});
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 20);
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 10);
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 30);

        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, "invalid order in SELL orderbook")
        }
    })
})
1 Like

I keep getting this error and I did do the the NPM install truffle-assertions into my DEX folder… any idea what’s going on? been fighting with this for about 4 hours

Error: Cannot find module 'truffle-assertion'
Require stack:
- C:\Users\Andrew\DEX\test\wallettest.js
- C:\Users\Andrew\AppData\Roaming\npm\node_modules\truffle\node_modules\mocha\lib\mocha.js
- C:\Users\Andrew\AppData\Roaming\npm\node_modules\truffle\node_modules\mocha\index.js
- C:\Users\Andrew\AppData\Roaming\npm\node_modules\truffle\build\consoleChild.bundled.js
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:927:15)
    at Function.Module._load (node:internal/modules/cjs/loader:772:27)
    at Module.require (node:internal/modules/cjs/loader:999:19)
    at require (node:internal/modules/cjs/helpers:93:18)
    at Object.<anonymous> (C:\Users\Andrew\DEX\test\wallettest.js:3:23)
    at Module._compile (node:internal/modules/cjs/loader:1095:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1124:10)
    at Module.load (node:internal/modules/cjs/loader:975:32)
    at Function.Module._load (node:internal/modules/cjs/loader:816:12)
    at Module.require (node:internal/modules/cjs/loader:999:19)
    at require (node:internal/modules/cjs/helpers:93:18)
    at C:\Users\Andrew\AppData\Roaming\npm\node_modules\truffle\node_modules\mocha\lib\mocha.js:390:36
    at Array.forEach (<anonymous>)
    at Mocha.loadFiles (C:\Users\Andrew\AppData\Roaming\npm\node_modules\truffle\node_modules\mocha\lib\mocha.js:387:14)
    at Mocha.run (C:\Users\Andrew\AppData\Roaming\npm\node_modules\truffle\node_modules\mocha\lib\mocha.js:961:10)
    at C:\Users\Andrew\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\core\lib\testing\Test.js:151:1
    at new Promise (<anonymous>)
    at Object.run (C:\Users\Andrew\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\core\lib\testing\Test.js:150:1)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at Object.run (C:\Users\Andrew\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\core\lib\commands\test\index.js:160:1)
    at Command.run (C:\Users\Andrew\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\core\lib\command.js:167:1)   

2 Likes

Try with npm install truffle-assertions, apparently you dont have that module installed in your project.

Carlos Z

1 Like

thank you Carlos (that was rather obvious and I should have noted) -
I post my code below and must admit that this was a huge challenge I didn’t manage to solve myself and without the help of going through the forum and checking Filips github solution. So this clearly not uniquely “self-developed” code. Will do a lot more testing examples to become more comfortable with this technique.

Code below:

// BUY SIDE
// 1. The user must have ETH deposited such that deposited eth >= buy order value (always buy with ETH, so need more ETH in account than the order value of the buy order)
// 2. The user (different user) must have enough tokens deposited such that token balance >= sell order amount (enough LINK tokens to sell)
// 3. The first order ([0]) in the BUY order book should have the highest price
// (above is equal: the order of the elements should be ordered on price from highest to lowest)
// add two more myself

// 1. input parameters: address, ticker, ethBalance, buy order value

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


contract("Dex", accounts => {
    
    // The user must have sufficient ETH deposited to create a limit order
    it("should throw an error if ETH balance is too low when creating a BUY limit order", async () => {
        let dex = await Dex.deployed()
        let link = await Link.deployed()
        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)
        )
    })

    // 2. The user (different user) must have enough tokens deposited such that token balance >= sell order amount (enough LINK tokens to sell)
    it("should throw an error if token balance is too low when creating a SELL limit order", async () => {
        let dex = await Dex.deployed()
        let link = await Link.deployed()
        await dex.addToken(web3.utils.fromUtf8("LINK"), link.address, {from: accounts[0]})
        await truffleAssert.reverts(
            dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 10, 1)
        )
        await link.approve(dex.address, 500)
        await dex.deposit(10, web3.utils.fromUtf8("LINK"))
        await truffleAssert.passes(
            dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 10, 1)
        )
    })
    // 3.a) The first order ([0]) in the BUY order book should have the highest price
    it("should throw an error if the first order in the BUY order book doesn't have the highest price", async () => {
        let dex = await Dex.deployed()
        let link = await Link.deployed()
        await link.approve(dex.address, 500)
        await dex.depositEth({value: 3000})
        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 300)
        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 100)
        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 200) 

        let orderbook = 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, "unordered buy order book")
        }
    })
    // 3.b) The first order ([0]) in the SELL order book should have the lowest price
    it("should throw an error if the first order in the SELL order book doesn't have the lowest price", 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, 300)
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 100)
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 200) 

        let orderbook = dex.getOrderBook(web3.utils.fromUtf8("LINK"), 1)
        
        //assert(orderbook.length > 0)
        for(let i = 0; i < orderbook.length -1; i++) {
            assert(orderbook[i].price <= orderbook[i+1].price, "unordered sell order book")
        }
    })
})```
3 Likes

i wouldnt worry about having looked at the solution. testing becomes much easier once youve done it a couple of times

3 Likes

Thank you macgrane5

Another thought has arisen while revisiting my solution.
The fact of including Ether into the same mapping as all other tokens: isn’t that kind of less safe?
Wouldn’t it be better to create a separate mapping just for that and in that way avoid potential hacks?

thx.

2 Likes

hey @yestome. here the balances mapping is a double mapping. So it has two keys that map to some output, namely the token ticker and user address => to their respective balance for that token. So creating multiple “single key” mappings would not be nessecary. For two reasons, firstly you would be making more mappings which would drive up gas price and also you would only having mappings for a certain amount of predefined tokens. If you wanted to add more tokens to your dex for trading you would have to change the contract code to include this new mapping. So using the double mapping is much better.

1 Like

Here is my attempt after some time and looking through some forum solutions. My first experience with writing testing code so still trying to learn the basics, i.e if in one ‘it’ statement we approve and deposit a token, will that token still be approved and in our balance for the next it statement below or do we have to deposit and approve again each time?

Will update solution after looking at Filip’s solution and writing the dex functions.

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

// Tests
// User must have enough ETH deposited when creating a buy order
// User must have enough tokens deposited when creating a sell order
// The BUY order book must be ordered from highest price to lowest price starting from index 0 
// The SELL order book must be ordered from lowest price to highest price starting from index 0


contract ("Dex", accounts => {

    it ("Should revert if user doesn't have enough ETH to fulfill buy order", async () => {
        let dex = await Dex.deployed()
        let link = await Link.deployed()
        let eth = await Eth.deployed()
        await dex.addToken(web3.utils.fromUtf8("ETH"), eth.address, {from: accounts[0]})
        await eth.approve(dex.address, 500);
        await truffleAssert.reverts(
            dex.createLimitOrder(Side.BUY, web3.utils.fromUtf8("LINK"), 10, 1)
        )
        await dex.deposit(web3.utils.fromUtf8("ETH"), 10)
        await truffleAssert.passes(
            dex.createLimitOrder(Side.BUY, web3.utils.fromUtf8("LINK"), 10, 1)
        )
    })
    it ("should revert if user doesn't have enouh tokens to fulfill sell order", async () =>{
        let dex = await Dex.deployed()
        let link = await Link.deployed()
        await truffleAssert.reverts(
            dex.createLimitOrder(Side.SELL, web3.utils.fromUtf8("LINK"), 500, 1)
        )
        await dex.deposit(web3.utils.fromUtf8("LINK"), 500)
        await truffleAssert.passes(
            dex.createLimitOrder(Side.SELL, web3.utils.fromUtf8("LINK"), 500, 1)
        )
    })
    it ("should have the BUY order book ordered from highest to lowest price starting at index 0", async () =>{
        let dex = await Dex.deployed()
        let link = await Link.deployed()
        await dex.deposit(web3.utils.fromUtf8("ETH"), 10)
        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 1)
        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 3)
        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 2)
        let buyOrderBook = await dex.getOrderBook(web3.utils.fromUtf8("LINK"), 0)
        for (let i = 0; i < buyOrderBook.length; i++){
            assert(buyOrderBook[i].price >= buyOrderBook[i+1].price, "BUY orders not in correct price order")
        }
    })
    it ("should have SELL order book ordered from lowest to highest price starting from index 0", async () =>{
        let dex = await Dex.deployed()
        let link = await Link.deployed()
        await dex.deposit(web3.utils.fromUtf8("LINK"), 10)
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 1)
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 3)
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 2)
        let sellOrderBook = await dex.getOrderBook(web3.utils.fromUtf8("LINK"), 1)
        for (let i = 0; i < buyOrderBook.length; i++){
            assert(buyOrderBook[i].price <= buyOrderBook[i+1].price, "SELL orders not in correct price order")
        }
    })

})
1 Like

Thank you @mcgrane5 for your explanations!
While this is informative with regards to the efficiency in terms of gas, it doesn’t really address the core of my question which was rather questioning about the security issue of including Ether within the same mapping. I hope this is clear and would appreciate if you could answer that question. - Thanks again
Yestome

1 Like

Hello and kudos to all here in the forum for timely and competent answers to questions and code samples !!!

I have a more generic question about truffle testing and hope this is not the wrong place to post it:

When writing tests I kind of struggle to understand what parts need to be re-coded within the same “contract”-code-space. Some do, others don’t. In other words how does the state change from one test to another?
For example the let XX variable XX.deployed() needs to be added for every single test (“it”), assuming that deployment doesn’t carry over from one it-test to another.
But then depositEth doesn’t seem that clear of how it changes its state across various it-tests. For example if I add 50000 wei in a first test, then add a createMarketOrder buying 10 link, is the corresponding ethBalance of that account actually reduced, or does the test just pass without altering the state of the ethBalance?
I’m asking this from the perspective of only an existing function header of createMarketOrder in solidity, and therefore am curious how this operates behind the scene and how state is affected by the test so I know what the remaining balance for the next it-test will be.
The same question can be asked for

  • approvals (why do I have to approve again, isn’t this recorded in the state change after passing a test?,
  • addToken (why do I have to add a token once again if is already added within the same “contract”-test-code?
  • as the createMarketOrder function at this stage is still only a header, how can one know if enough ETH is available? limitOrders have different prices and in order to know the amount of ETH to be deducted we need to iterate over all consumed limitOrders to figure out the countervalue in ETH to be deducted. All the same we are testing for enough ETH available - how is that even possible?

In summary, is there some sort of an indication that you could provide to help better understand what needs to be recoded and what carries over from one it-test to following tests?

1 Like

Hi Everyone, I think I missed something somewhere …

Where does the “depositEth” function come from? We did not create it in the wallet as we only have the deposit function for the ERC20 tokens. I missed something somewhere!

I’ll appreciate any help!

1 Like

I have the same question. It seems to have come out of thin air? @Filip?

Hey @yestome

Actually this is quite straight forward to explain.

  1. Whenever you declare const contract = await ContractName.new() you are using a new instance of the contract. All deposits / approvals from a previous instance are removed as you are using a new instance of the project.

  2. For most of your project, you should declare an instance of your contract in the before() function, and keep using that one, without declaring a new instance in every test.

Keep me posted,
Dani

1 Like

Hi @DavidV

Filip coded that function by following the same logic he used in the token deposit function.
You can try something like

 balances[msg.sender]["ETH"] = balances[msg.sender]["ETH"].add(msg.value);
1 Like

Thank you @dan-i! Thats what I did in the end. I just though maybe I missed something that is native to solidity or something. I do get quite confused when to use msg.sender or dex.address or address(this)

Is there a easy guide I can use to keep track of who is interacting with which contract. This is all quite new to me so I’m still a bit on the slow side when figuring these things out.

Thx again for your help!

1 Like

Thanks @dani-i for your answer and improvement proposal!
I have included the before-method in all three testing files now.
market_order_test.js file amended and all 16 tests running successfully.
Code below:
Full code available at: https://github.com/sneicode/DEX

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

contract("Dex", accounts => {

    let dex
    let link

    before (async function(){
        dex = await Dex.deployed()
        link = await Link.deployed()
        await dex.addToken(web3.utils.fromUtf8("LINK"), link.address)
    })
    
    // When creating a SELL market order, the seller needs to have sufficient tokens for the trade
    it("should throw when creating a sell market order with a 0 token balance ", async () => {
        let balance = await dex.balances(accounts[0], web3.utils.fromUtf8("LINK"))
        assert.equal(balance.toNumber(), 0, "initial Link token balance is not 0")

        await truffleAssert.reverts(
            dex.createMarketOrder(1, web3.utils.fromUtf8("LINK"), 10)
        )
    })
    
    // Market orders can be submitted even if the order book is empty
    it("Market orders can be submitted even if the order book is empty", async () => {
        await dex.depositEth({value: 50000})

        let orderbook = await dex.getOrderBook(web3.utils.fromUtf8("LINK"), 0)
        assert(orderbook.length == 0, "buy side orderbook length is not 0")

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

    // Market orders should be filled until the order book is 100% filled
    it("Market orders should not fill more limit orders than the market order amount", async () => {
        // get SELL side orderbook and assure it is empty at start of test
        let orderbook = await dex.getOrderBook(web3.utils.fromUtf8("LINK"), 1)
        assert(orderbook.length == 0, "SELL side order book is not empty at start of test")

        // provide 3 accounts with LINK tokens from account 0
        await link.transfer(accounts[1], 150)
        await link.transfer(accounts[2], 150)
        await link.transfer(accounts[3], 150)

        // approve accounts 1-3 for DEX to sell 50 link tokens per account
        await link.approve(dex.address, 50, {from: accounts[1]})
        await link.approve(dex.address, 50, {from: accounts[2]})
        await link.approve(dex.address, 50, {from: accounts[3]})

        // deposit LINK tokens into Dex 
        await dex.deposit(50, web3.utils.fromUtf8("LINK"), {from: accounts[1]})
        await dex.deposit(50, web3.utils.fromUtf8("LINK"), {from: accounts[2]})
        await dex.deposit(50, web3.utils.fromUtf8("LINK"), {from: accounts[3]})

        // create 3 SELL side limit orders, 1 each for accounts 1 - 3
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 5, 300, {from: accounts[1]})
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 5, 400, {from: accounts[2]})
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 5, 500, {from: accounts[3]})

        // create market order that fills 2/3 of the order book
        await dex.createMarketOrder(0, web3.utils.fromUtf8("LINK"), 10)

        // get SELL side of orderbook once again 
        orderbook = await dex.getOrderBook(web3.utils.fromUtf8("LINK"), 1)
        // assure length is 1, (2 thirds consumed and 1 limitOrder left)
        assert(orderbook.length == 1, "remaining SELL side orders is not 1")
        assert(orderbook[0].filled == 0, "remaining SELL side order should be unfilled")
    
    })
        
    // Market orders should be filled until the order book is empty 
    it("Market orders should be filled until market order is empty", async () => {
        // check if SELL order book has 1 entry remaining
        let orderbook = await dex.getOrderBook(web3.utils.fromUtf8("LINK"), 1)
        assert(orderbook.length == 1, "SELL side order book should have 1 order left")

        // add 2 sell side limit orders to orderbook
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 5, 400, {from: accounts[1]})
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 5, 500, {from: accounts[2]})

        // check buyer link balance before adding new market order
        let beforeBalance = await dex.balances(accounts[0], web3.utils.fromUtf8("LINK"))

        // create Market order that goes beyond available tokens (15 available, 35 missing)
        await dex.createMarketOrder(0, web3.utils.fromUtf8("LINK"), 50)

        // check buyer link balance after adding new market order
        let updatedBalance = await dex.balances(accounts[0], web3.utils.fromUtf8("LINK"))

        // buyer should have 15 link more even that marketorder was for 50 link
        assert.equal(beforeBalance.toNumber() + 15, updatedBalance.toNumber())
    })


    // the eth balance of the buyer should decrease with the filled amount
    it("the eth balance of the buyer should decrease with the filled ammount", async () => {
        // seller deposit link and creates sell limit order for 1 Link
        await link.approve(dex.address, 500, {from: accounts[1]})
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 300, {from: accounts[1]})

        // check buyer eth balance before and after adding new market order
        let beforeBalance = await dex.balances(accounts[0], web3.utils.fromUtf8("ETH"))

        await dex.createMarketOrder(0, web3.utils.fromUtf8("LINK"), 1)
        let updatedBalance = await dex.balances(accounts[0], web3.utils.fromUtf8("ETH"))

        assert.equal(beforeBalance.toNumber() - 300, updatedBalance.toNumber())
    })

    // the token balances of the limit order sellers should decrease with the filled amount
    it("the token balances of the limit order sellers should decrease with the filled amount", async () => {
        let orderbook = await dex.getOrderBook(web3.utils.fromUtf8("LINK"), 1)
        assert(orderbook.length == 0, "Sell side orderbook should be empty at start of test")
        
        // seller account [2] deposit link
        await link.approve(dex.address, 500, {from: accounts[2]})
        await dex.deposit(50, web3.utils.fromUtf8("LINK"), {from: accounts[2]})
        
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 300, {from: accounts[1]})
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 400, {from: accounts[2]})

        // check seller link balances before trade 
        let account1beforeBalance = await dex.balances(accounts[1], web3.utils.fromUtf8("LINK"))
        let account2beforeBalance = await dex.balances(accounts[2], web3.utils.fromUtf8("LINK"))
        
        // account[0] buys 2 available Link
        await dex.createMarketOrder(0, web3.utils.fromUtf8("LINK"), 2)

        let account1updatedBalance = await dex.balances(accounts[1], web3.utils.fromUtf8("LINK"))
        let account2updatedBalance = await dex.balances(accounts[2], web3.utils.fromUtf8("LINK"))

        assert.equal(account1beforeBalance.toNumber() - 1, account1updatedBalance.toNumber())
        assert.equal(account2beforeBalance.toNumber() - 1, account2updatedBalance.toNumber())
    })

    // Filled limit orders should be removed from the orderbook
    it("Filled limit orders should be removed from the orderbook", async () => {
        // seller deposit link tokens and creates a limitorder for 1 link at 300 wei
        await link.approve(dex.address, 500)
        await dex.deposit(50, web3.utils.fromUtf8("LINK"))

        await dex.depositEth({value: 10000})

        let orderbook = await dex.getOrderBook(web3.utils.fromUtf8("LINK"), 1)
        
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 300)
        await dex.createMarketOrder(0, web3.utils.fromUtf8("LINK"), 1)

        orderbook = await dex.getOrderBook(web3.utils.fromUtf8("LINK"), 1)
        assert(orderbook.length == 0, "sell side order book shoud be empty after trade")
    })

    // Partly filled limit orders should be modified to represent the filled/remaining amount
    it("partially filled limit orders should be removed from the orderbook", async () => {
        let orderbook = await dex.getOrderBook(web3.utils.fromUtf8("LINK"), 1)
        assert(orderbook.length == 0, "Sell side orderbook should be empty at start of test")

        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 2, 300)
        await dex.createMarketOrder(0, web3.utils.fromUtf8("LINK"), 1)

        orderbook = await dex.getOrderBook(web3.utils.fromUtf8("LINK"), 1)
        // amount - filled should be remaining order amount
        assert.equal(orderbook[0].filled, 1)
        assert.equal(orderbook[0].amount, 2)
    })


}) 

It has taken me a while to sort errors in this testing file but I finally found them (some myself and others comparing to the solution) Some typos and missing “await” flags. -

Note on the side: error hints from the console are not very helpful !!).

Would also like to know more about the challenges to improving this DEX contract that Filip mentions in this video but without him providing further leads?
Could you suggest an example challenge for a “developing developer” ;O) how to improve the contract?
thank you again for your support!
yestome

1 Like

Hey @yestome. Yeah filip talks about those improvements but its like the extra video was never uploaded. There is actually a few things you can do to improve the dex. The first is to do with the balances amd withdrawals. Currently if a person makes a limit order which is pending to get filled the person can still withdraw their full balance. You should make a “reserved” balances or something which prevents users from wothdrawing there full balance if they have any pending limit orders.

Another improvement os with the actual market order sorting algorithm. Because market orders are not stored it becomes impossible to create any market orders ubless there is already limit orders on the opposite side of the book. To fix this you could choose to actually store market orders by pushing them to the orderbook or you could take a more easy approach by not allowing ppl to create market orders unless there is already limit orders on the other side.

Lastly you can improve the limot order function so that if someome creates another limot order on the opposite side with the exact same price and amount that they both get settled. The easiest way to do this would be to partitin the code that settles orders in the market order function into its “settleOrder” function and then call this in both the marekt and limit order functions.

If you want some inspiration please see this repo. @tanu_g did a major improvement on filips main code and made it a lot more robust by adding the fratures described above. If you want some inspiration you could lool at thay code. Congrats for finishing the course g.

https://github.com/tagupta/DEX.git

Evan

1 Like

Excellent input - thank you @mcgrane5

1 balances / withdrawals -> reserved balance (ok)

2 I have a doubt regarding this: “Because market orders are not stored it becomes impossible to create any market orders ubless there is already limit orders on the opposite side of the book.” - Is the fact that we have tested the orderbook to be empty before taking a marketOrder not defying this point? -> see 2nd test in this file: https://github.com/sneicode/DEX/blob/main/test/market_order_test.js

3 matching orders get filled immediately (ok)

Great - I’ll look into these and check @tanu_g 's repo.

Thanks again.
yestome

2 Likes

Hey @yestome. No worries g. In regards to the storing of market orders in filips test file yew it is possible to create market orders while the LO book is empty. Howrver because it does get stored anywhere if you then come along and make a limit order. The markrt order which was made before necer actually gets filled because. If you bear with me for a moment i will show you by running some manual tests in the console for you. However having said that a lot of this comes down to personal preferance

Hey @filip.
You have the order wrong in the course for the Bubble Sort Explanation.

The Bubble Sort Reading should come before the explanation, but the explanation references the ‘reading’ before we’ve done it.

Small change but wanted to let you know nonetheless.
Thanks mate!

1 Like