Assignment - Limit Order Test

All tests passed, I still don’t feel 100% confident in this but the tests pass and as far as I can see, the logic makes sense. :grimacing:

    function createLimitOrder(Side side, bytes32 ticker, uint256 amount, uint256 price) public {
        if (side == Side.BUY) {
            require(balances[msg.sender]["ETH"] >= amount.mul(price));
        } else if (side == Side.SELL) {
            require (balances[msg.sender][ticker] >= amount);
        }

        Order[] storage orders = orderBook[ticker][uint(side)];
        // [Order1, Order2, Order3]
        orders.push(Order(orderId, msg.sender, side, ticker, amount, price));
        // loop to put it in place
        if (side == Side.SELL) {
        for (uint i = 1; i < orders.length; i++) {
            if (orders[orders.length - i].price < orders[orders.length - (i+1)].price) {
                Order memory higherOrder = orders[orders.length - (i+1)];
                orders[orders.length - (i+1)] = orders[orders.length - i];
                orders[orders.length - i] = higherOrder;
            } else {
                break;
            }
        }} else if (side == Side.BUY) {
        for (uint i = 1; i < orders.length; i++) {
            if (orders[orders.length - i].price > orders[orders.length - (i+1)].price) {
                Order memory lowerOrder = orders[orders.length - (i+1)];
                orders[orders.length - (i+1)] = orders[orders.length - i];
                orders[orders.length - i] = lowerOrder;
            } else {
                break;
            }
        }
        }
        orderId = orderId.add(1);
    }
1 Like

Hey @jak, hope you are well.

Thanks for notified man, will fixit ASAP! :nerd_face:

Carlos Z

1 Like

Here is my dextest code. Looking at Fillip’s solution, am I right to assume that the tests for the sell orders do not need LINK to be approved prior to running? It’s difficult to troubleshoot without the limit order function being written… Also, is there a way to simplify the code so that the contract.deployed() declaration does not need to be repeated for each it() statement? Thanks.

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

contract("Dex", accounts => {
    //The user only inputs ticker supported by dex
    it("should not allow limit orders for tokens not supported", 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.passes(
            dex.createLimitOrder(web3.utils.fromUtf8("LINK"), 0, 0, 0)
        )
        await truffleAssert.reverts(
            dex.createLimitOrder(web3.utils.fromUtf8("ASDF"), 0, 0, 0)
        )
    })
    //The user must have ETH deposited such that deposited eth >= buy order value
    it("should only be possible buy tokens up to total ETH value deposited", async () => {
        let dex = await Dex.deployed()
        await dex.depositEth({value: 5})
        await truffleAssert.reverts(
            dex.createLimitOrder(web3.utils.fromUtf8("LINK"), 0, 10, 1)
        )
        await truffleAssert.passes(
            dex.createLimitOrder(web3.utils.fromUtf8("LINK"), 0, 10, 0.5)
        )
    })
    //The user must have enough tokens deposited such that the token balance > sell order amount
    it("should only be possible sell up to total token amount deposited", async () => {
        let dex = await Dex.deployed()
        let link = await Link.deployed()
        await link.approve(dex.address, 20);
        await dex.deposit(20, web3.utils.fromUtf8("LINK"))
        await truffleAssert.reverts(
            dex.createLimitOrder(web3.utils.fromUtf8("LINK"), 1, 30, 0.5)
        )
        await truffleAssert.passes(
            dex.createLimitOrder(web3.utils.fromUtf8("LINK"), 1, 20, 6)
        )
    })
    //The BUY order book should be ordered on price from highest to lowest starting at index 0
    it("should sort buy orders correctly", async () => {
        let dex = await Dex.deployed()
        await dex.depositEth({value: 40})
        await dex.createLimitOrder(web3.utils.fromUtf8("LINK"), 0, 5, 3)
        await dex.createLimitOrder(web3.utils.fromUtf8("LINK"), 0, 3, 5)
        await dex.createLimitOrder(web3.utils.fromUtf8("LINK"), 0, 1, 4)
        let book = await dex.getOrderBook(web3.utils.fromUtf8("LINK"), 0)
        assert(book.length > 0, "there are no orders in the orderbook")
        for(i=0; i<book.length-1; i++){
            assert(book[i].price >= book[i+1].price, "Orderbook is not sorted correctly")
        }
    })
    //The SELL order book should be ordered on price from lowest to highest
    it("should sort sell orders correctly", async () => {
        let dex = await Dex.deployed()
        let link = await Link.deployed()
        await link.approve(dex.address, 9);
        await dex.deposit(9, web3.utils.fromUtf8("LINK"))
        await dex.createLimitOrder(web3.utils.fromUtf8("LINK"), 1, 5, 7)
        await dex.createLimitOrder(web3.utils.fromUtf8("LINK"), 1, 3, 9)
        await dex.createLimitOrder(web3.utils.fromUtf8("LINK"), 1, 1, 8)
        let book = await dex.getOrderBook(web3.utils.fromUtf8("LINK"), 1)
        assert(book.length > 0, "there are no orders in the orderbook")
        for(i=0; i<book.length-1; i++){
            assert(book[i].price <= book[i+1].price, "Orderbook is not sorted correctly")
        }
    })
})
1 Like

hey @Zaqoy. i know the structure of the course does ask us to write the tests first. But you should not do this. write the function first then test it. also yes there is a way. You can declare at the top of your test

beforeEach(async() =>{
        let dex = await Dex.deployed();
        let link = await Link.deployed()
        await dex.addToken(.......)
        await link.approve(....)

    });

for example. Refer to Truffle | Writing Tests in Solidity | Documentation | Truffle Suite for good testing practices

1 Like

I was not able to get dex.depositEth({value: 10}) function to work. Maybe I am missing this function in my wallet contract. Instead I tried to make an ERC 20 token called ETH and that also threw an artifact and deployment error.

Instead of using Eth, I just used Eth2 in place of Eth when checking that you should have neough enough to buy other tokens.

I created another Eth2 contract in Token.sol right below Link contract.

//the user must have ETH deposted such that deposted eth >= buy order value
// the user must have enough tokens deposited such that token balance >= sell order amount
// the BUY order book should be ordred on pirce from highest to lowest starting at index 0

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

contract ("Dex", accounts => {
    it("ETH balance should be >= order buy value", async () => {
        let dex = await Dex.deployed();
        let link = await Link.deployed();
        let eth2 = await Eth2.deployed();
        await link.approve(dex.address,500);
        await eth2.approve(dex.address,500);
        dex.addToken(web3.utils.fromUtf8("Link"),link.address,{from: accounts[0]});
        dex.addToken(web3.utils.fromUtf8("ETH2"),eth2.address,{from: accounts[0]});
        await truffleAssert.reverts(
            dex.createLimitOrder(0,web3.utils.fromUtf8("Link"),1,1)
        )
        await dex.deposit(100,web3.utils.fromUtf8("ETH2"));
        await truffleAssert.passes(
            dex.createLimitOrder(0,web3.utils.fromUtf8("Link"),1,1)
        )
    })
    it("User should have enough tokens to sell", async () => {
        let dex = await Dex.deployed();
        let link = await Link.deployed();
        await link.approve(dex.address,500);
        dex.addToken(web3.utils.fromUtf8("Link"),link.address,{from: accounts[0]});
        await truffleAssert.reverts(
            dex.createLimitOrder(1,web3.utils.fromUtf8("Link"),1,1)
        )
        await dex.deposit(100,web3.utils.fromUtf8("Link"));
        await truffleAssert.passes(
            dex.createLimitOrder(1,web3.utils.fromUtf8("Link"),1,1)
        )
    })
    it("the BUY order book should be ordred on pirce from highest to lowest starting at index 0", 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"));
        dex.addToken(web3.utils.fromUtf8("Link"),link.address,{from: accounts[0]});
        dex.createLimitOrder(0,web3.utils.fromUtf8("Link"),1,10);
        dex.createLimitOrder(0,web3.utils.fromUtf8("Link"),1,30);
        dex.createLimitOrder(0,web3.utils.fromUtf8("Link"),1,20);
        let orderBook = dex.orderBook;

        for (i = 0; i < orderBook.length -1;i++) {
            assert(orderBook[i].price >= orderBook[i+1].price)
        }
    })
    it("the SELL order book should be ordred on pirce from lowest to highest starting at index 0", 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"));
        dex.addToken(web3.utils.fromUtf8("Link"),link.address,{from: accounts[0]});
        dex.createLimitOrder(1,web3.utils.fromUtf8("Link"),1,10);
        dex.createLimitOrder(1,web3.utils.fromUtf8("Link"),1,30);
        dex.createLimitOrder(1,web3.utils.fromUtf8("Link"),1,20);
        let orderBook = dex.orderBook;

        for (i = 0; i < orderBook.length -1;i++) {
            assert(orderBook[i].price <= orderBook[i+1].price)
        }
    })
})

Hi, folks!
Here is my code!

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

contract("Dex1", accounts =>{
     
    //the user must have ETH deposited such that deposited eth >= buy order value
    it("user must have ETH deposited such that deposited eth >= buy order value", async () => {
        //await deployer.deploy(Link)
        let dex = await Dex.deployed()
        let link = await Link.deployed() 
        await link.approve(dex.address,500)
        await dex.addToken(web3.utils.fromUtf8("LINK"), link.address)
        await dex.deposit(100,web3.utils.fromUtf8("LINK"))
        let balance = await dex.balances(accounts[0], web3.utils.fromUtf8("LINK")) 
        let buyorder = await dex.creatLimitOrder(web3.utils.fromUtf8("LINK"), Dex.Side.BUY, 50, 1 )  
        assert.isTrue( balance.toNumber() >= buyorder)         
    })
    //the user must have enough tokens deposited such that token balance > sell order 
    it("the user must have enough tokens deposited such that token balance > sell order", async () => {
        //await deployer.deploy(Link)
        let dex = await Dex.deployed()
        let link = await Link.deployed() 
        await link.approve(dex.address,500)
        await dex.addToken(web3.utils.fromUtf8("LINK"), link.address)
        await dex.deposit(100,web3.utils.fromUtf8("LINK"))
        let balance = await dex.balances(accounts[0], web3.utils.fromUtf8("LINK")) 
        let sellorder = await dex.creatLimitOrder(web3.utils.fromUtf8("LINK"), Dex.Side.SELL, 50, 1 )  
        assert.isTrue( balance.toNumber() >= sellorder)         
    })
    //the BUY order book should be ordered on price from highest to lowest starting at index 0
    it("the BUY order book should be ordered on price from highest to lowest starting at index 0", async () => {
        //await deployer.deploy(Link)
        let dex = await Dex.deployed()
        let link = await Link.deployed() 
        await link.approve(dex.address,500)
        await dex.addToken(web3.utils.fromUtf8("LINK"), link.address)
        await dex.deposit(100,web3.utils.fromUtf8("LINK"))
        let balance = await dex.balances(accounts[0], web3.utils.fromUtf8("LINK")) 
        await dex.creatLimitOrder(web3.utils.fromUtf8("LINK"), Dex.Side.BUY, 50, 1 ) 
        await dex.creatLimitOrder(web3.utils.fromUtf8("LINK"), Dex.Side.BUY, 45, 1 )         
        await dex.creatLimitOrder(web3.utils.fromUtf8("LINK"), Dex.Side.BUY, 44, 1 ) 
        let orderBook =  await dex.getOrderBook(accounts[0], Dex.Side.BUY)
        let orderBook_second =  await dex.getOrderBook(accounts[0], Dex.Side.BUY)
        let orderBook_sorted = orderBook.sort(function (a,b){
            if(a.amount > b.amount){return 1;}
            if(a.amount < b.amount){return -1;}
            return 0;
        })
        for(let i = 0; i < orderBook.length; i++){
            assert.isTrue(orderBook[i].amount > orderBook[i+1].amount);
        }
        //assert.isTrue( orderBook_sorted === orderBook_second )           
    })    
})

Here are my test, had some help from Filip’s video, this a whole new concept for me, and I’m still trying to get my head around it:

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

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

contract("Dex", accounts => {
    it("should only allow users with an amount of ETH greater or equal to the order value to create a BUY 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(0, web3.utils.fromUtf8("LINK"), 5, 2)
        ) 

        await dex.deposithEth({value: 10});

        await truffleAssert.passes(
            dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 5, 2)
        )
    })

    it("should only allow users with an amount of LINK greater or equal to the order value to create 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"), 5, 2)
        )

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

        await truffleAssert.passes(
            dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 5, 2)
        )
    })

    it("should ensure that the BUY orderbook is ordered in a descending 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 dex.depositEth({value: 50});

        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 5, 4);
        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 5, 2);
        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 5, 6);

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

        for(let i = 0; i <= orderbook.length - 1; i++){
            assert(orderbook[i].price > orderbook[i+1].price, "Not ordered accordingly")
        }

    })

    it("should ensure that the SELL orderbook is ordered in an ascending 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 link.approve(dex.address, 50);
        await dex.deposit(web3.utils.fromUtf8("LINK"), 50);

        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 5, 4);
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 5, 2);
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 5, 6);

        let orderbook = await getOrderBook(web3.utils.fromUtf8("LINK"), 1);

        for(let i = 0; i <= orderbook.length -1; i++){
            assert(orderbook[i].price < orderbook[i+1].price, "Not ordered accordingly");
        }
    })

    it("should ensure that only approved tokens can be traded", async () => {

        let dex = await Dex.deployed();
        let link = await Link.deployed();

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

        truffleAssert.passes(
            dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 5, 6)
        )

        truffleAssert.reverts(
            dex.createLimitOrder(0, web3.utils.fromUtf8("AAVE"), 5, 4)
        )

        truffleAssert.reverts(
            dex.createLimitOrder(1, web3.utils.fromUtf8("AAVE"), 5, 6)
        )

    })

})

Was not sure how to call Eth balance, so i just used the word “Ethbalance” at :The SELL market order should sell for the highest price available in the orderbook.

How should i have called for the Eth balance?

Also was not sure if we could use decimals.I believe not but then how to write:
price = 0.02

Here is my version:


// The user must have ETH deposited such that deposited eth >= buy order value
// The user must have enough tokens deposited such that token balance >= sell order amount
// The BUY orderbook should be ordered on price from highest to lowest starting at index [0]
// The SELL orderbook should be ordered on price from lowest to highest starting at index [0]
// The BUY market order should get the lowest price available in the orderbook.
// The SELL market order should sell for the highest price available in the orderbook.
// Price should be last order match


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

contract("Dex", accounts => {
    it("should have enough ETH deposited such that deposited eth >= buy order value", async () => {
        
        let dex = await Dex.deployed();
        let Link = await link.deployed();

        await dex.depositETH({value: 3});

        await truffleAssert.reverts(dex.BuyLimitOrder(100, 4, web3.utils.fromUtf8("link")));
        await truffleAssert.passes(dex.BuyLimitOrder(100, 3, web3.utils.fromUtf8("link")));
        
        
    })
    it("should have enough 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 Linkbalance = await dex.balances(accounts[0], web3.utils.fromUtf8("link"));

        await truffleAssert.reverts(dex.SellLimitOrder(200, , web3.utils.fromUtf8("link")));
        await truffleAssert.passes(dex.SellLimitOrder(100, web3.utils.fromUtf8("link")));
    })

    it("The BUY orderbook should be ordered on price from highest to lowest starting at index [0]", async () => {
        
        let dex = await Dex.deployed();
        let Link = await link.deployed();

        let index0 = await dex.orderBook(web3.utils.fromUtf8("link"), 1,[0])
        let index1 = await dex.orderBook(web3.utils.fromUtf8("link"), 1,[1])
        let index2 = await dex.orderBook(web3.utils.fromUtf8("link"), 1,[2])

        assert.true(index0 > index1);
        assert.true(index1 > index2);
        assert.true(index2 > index3);
     
       
       
    })
    it("The SELL orderbook should be ordered on price from lowest to highest starting at index [0]", async () => {
        
        let dex = await Dex.deployed();
        let Link = await link.deployed();

        let index0 = await dex.orderBook(web3.utils.fromUtf8("link"), 0,[0])
        let index1 = await dex.orderBook(web3.utils.fromUtf8("link"), 0,[1])
        let index2 = await dex.orderBook(web3.utils.fromUtf8("link"), 0,[2])

        assert.true(index0 < index1);
        assert.true(index1 < index2);
        assert.true(index2 < index3);
       
    })


})
    it("The BUY market order should get the lowest price available in the orderbook.", async () => {
        let dex = await Dex.deployed();
        let Link = await link.deployed();

        await Link.approve(dex.address, 500);
        await dex.deposit(300, web3.utils.fromUtf8("link"));
        await dex.SellLimitOrder(100, 1,web3.utils.fromUtf8("link"));
        await dex.SellLimitOrder(100, 2,web3.utils.fromUtf8("link"));
        await dex.SellLimitOrder(100, 3,web3.utils.fromUtf8("link"));

        await dex.depositETH({value: 3});
        await dex.BuyMarketOrder(1, web3.utils.fromUtf8("link"));

        let balance = await dex.balances(accounts[0], web3.utils.fromUtf8("link"));

        assert.equal(balance.toNumber(), 100);


    })

    it("The SELL market order should sell for the highest price available in the orderbook.", async () => {
         let dex = await Dex.deployed();
        let Link = await link.deployed();

        await dex.depositETH({value: 6});

        await dex.BuyLimitOrder(100, 3,web3.utils.fromUtf8("link"));
        await dex.BuyLimitOrder(100, 2,web3.utils.fromUtf8("link"));
        await dex.BuyLimitOrder(100, 1,web3.utils.fromUtf8("link"));

        await Link.approve(dex.address, 500);
        await dex.deposit(300, web3.utils.fromUtf8("link"));

        await dex.SellMarketOrder(100, web3.utils.fromUtf8("link"));

        let balance = await dex.balances(accounts[0], web3.utils.fromUtf8("link"));

        assert.equal(Ethbalance.toNumber(), 3);
    })

    it("// Price should be last order match", async () => {
        let dex = await Dex.deployed();
        let Link = await link.deployed();

        await dex.depositETH({value: 6});

        await dex.BuyLimitOrder(100, 3,web3.utils.fromUtf8("link"));
        await dex.BuyLimitOrder(100, 2,web3.utils.fromUtf8("link"));
        await dex.BuyLimitOrder(100, 1,web3.utils.fromUtf8("link"));

        await Link.approve(dex.address, 500);
        await dex.deposit(300, web3.utils.fromUtf8("link"));

        await dex.SellLimitOrder(100, 1,web3.utils.fromUtf8("link"));
        await dex.SellLimitOrder(100, 2,web3.utils.fromUtf8("link"));

        assert.equal(Price.toNumber(), 0.02);

    })
})


1 Like
// Create Limit Order:

const DEX = artifacts.require("DEX")
const Token = artifacts.require("MyToken")
const truffleAssert = require('truffle-assertions'); 

contract("DEX", accounts => {
    // BUY Order: User balance must be equal or greater than order value
    it("BUY: Should check if user ETH balance is equal or greater than order value", async() => {
        let dex = await DEX.deployed()
        let token = await Token.deployed()
           
        let balance = await dex.balances(accounts[0], web3.utils.fromUtf8("TKN"))

        await truffleAssert.reverts(
            createLimitOrder(BUY, web3.utils.fromUtf8("TKN"), 1, 1)
        )

        await dex.depositEth({value:1})

        await truffleAssert.passes(
            createLimitOrder(BUY, web3.utils.fromUtf8("TKN"), 1, 1)
        )
    })

    // SELL Order: User balance must be equal or greater than order value
    it("SELL: Should check if user balance is equal or greater than order value", async() => {
        let dex = await DEX.deployed()
        let token = await Token.deployed()

        await truffleAssert.reverts(
            createLimitOrder(SELL, web3.utils.fromUtf8("TKN"), 1, 1)
        )

        await token.approve(dex.address, 1000)
        await dex.addToken(web3.utils.fromUtf8("TKN"), token.address)
        await dex.deposit(web3.utils.fromUtf8("TKN"), 1)    
        
        await truffleAssert.passes(
            createLimitOrder(SELL, web3.utils.fromUtf8("TKN"), 1, 1)
        )
    })

    
    // BUY orders price must be sorted in OrdersBook[] from high to low
    it("Should sort BUY orders price from high to low in orderBook[]", async() => {
        let dex = await DEX.deployed()
        let token = await Token.deployed()

        await token.approve(dex.address, 1000);
        await dex.depositEth({value:10});
        await dex.createLimitOrder(BUY, web3.utils.fromUtf8("TKN"), 1, 5)
        await dex.createLimitOrder(BUY, web3.utils.fromUtf8("TKN"), 1, 2)
        await dex.createLimitOrder(BUY, web3.utils.fromUtf8("TKN"), 1, 3)

        let orderBook = await dex.getOrderBook(web3.utils.fromUtf8("TKN"), BUY);

       for (let i = 0; i < orderBook.length - 1; i++) {
            assert(orderBook[i].price >= orderBook[i+1].price, "Wrong order")
        }
            
    })
    
    // SELL orders price must be sorted in OrdersBook[] from low to high
    it("Should sort SELL orders price from low to high in orderBook[]", async() => {
        let dex = await DEX.deployed()
        let token = await Token.deployed()

        await token.approve(dex.address, 1000)
        await dex.addToken(web3.utils.fromUtf8("TKN"), token.address)
        await dex.deposit(web3.utils.fromUtf8("TKN"), 10)   

        await dex.createLimitOrder(BUY, web3.utils.fromUtf8("TKN"), 3, 5)
        await dex.createLimitOrder(BUY, web3.utils.fromUtf8("TKN"), 2, 2)
        await dex.createLimitOrder(BUY, web3.utils.fromUtf8("TKN"), 5, 3)

        let orderBook = await getOrderBook(web3.utils.fromUtf8("TKN"), SELL);

        for(let i = 0; i < orderBook.length - 1; i++) {
            assert(orderBook[i] <= orderBook[i+1], "Wrong order");
        }
    })
})
1 Like

Had a bit of trouble trying to loop through orderbook and check order pricing so I just went with more of a simple check for the orderbook side of things. Regardless, here is my rough attempt at the DEX tests.

dexTest.js

    // LIMIT Order Tests
//The user must have ETH deposited such that deposited eth >= buy order value
//The user must have enough tokens deposited such that the token balance >= sell order amount
//The user should not be allowed to place a buy or sell order for an unsupported token
//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 from lowest to highest starting at index 0

const DEX = artifacts.require("DEX")
const testToken = artifacts.require("testToken")
const truffleAssert = require('truffle-assertions')

contract("DEX", accounts => {
      
        // should reject BUY order because user's ETH balance is < total BUY order amount
    it("should reject invalid BUY orders", async () => {
        let dex = await DEX.deployed();
        let token = await testToken.deployed();
        await dex.addToken(web3.utils.fromUtf8("LINK"), token.address, {from: accounts[0]})
        await truffleAssert.reverts( 
            dex.createLimitOrder(web3.utils.fromUtf8("LINK"), Side.BUY, 1, 5)
        )
    })    

        // should allow user to place BUY order as long as user's ETH balance is >= total BUY order amount
    it("should handle valid BUY orders correctly", async () => {
        let dex = await DEX.deployed();
        let token = await testToken.deployed();
        await dex.depositETH({value:10});
        await truffleAssert.passes( 
            dex.createLimitOrder(web3.utils.fromUtf8("LINK"), Side.BUY, 1, 6)
        )
        await truffleAssert.passes( 
            dex.createLimitOrder(web3.utils.fromUtf8("LINK"), Side.BUY, 3, 4)
        )
    })
        
        // should allow user to place SELL order if user's selected token balance is >= total amount of tokens in SELL order
    it("should handle valid SELL orders correctly", async () => {
        let dex = await DEX.deployed();
        let token = await testToken.deployed();
        await token.approve(dex.address, 500);
        await dex.deposit(50, web3.utils.fromUtf8("LINK"));
        await truffleAssert.passes( 
            dex.createLimitOrder(web3.utils.fromUtf8("LINK"), Side.SELL, 8, 20)
        )
        await truffleAssert.passes( 
            dex.createLimitOrder(web3.utils.fromUtf8("LINK"), Side.SELL, 6, 30)
        )
    })

        // should reject SELL order because user's selected token balance is < total amount of tokens in SELL order
    it("should reject invalid SELL orders", async () => {
        let dex = await DEX.deployed();
        let token = await testToken.deployed();
        await truffleAssert.reverts( 
            dex.createLimitOrder(web3.utils.fromUtf8("LINK"), Side.SELL, 1, 500)
        )
    })

        // should reject SELL & BUY order because token is not supported
    it("should reject SELL/BUY orders for unsupported tokens", async () => {
        let dex = await DEX.deployed();
        let token = await testToken.deployed();
        await dex.depositETH({value:10});
        await truffleAssert.reverts( 
            dex.createLimitOrder(web3.utils.fromUtf8("BTC"), Side.BUY, 10, 1)
        )
        await truffleAssert.reverts( 
            dex.createLimitOrder(web3.utils.fromUtf8("BTC"), Side.SELL, 1, 1)
        )
    })

        // BUY side of orderBook should be ordered from highest to lowest starting at index 0
     it("should arrange BUY orders in the orderBook correctly", async () => {
        let dex = await DEX.deployed();
        let token = await testToken.deployed();
        let buyOrders = await dex.getOrderBook(web3.utils.fromUtf8("LINK"), Side.BUY)
            // lower priced order was put in first so if orderBook is sorting correctly then the first indexed buy order should be the second order placed (LINK, BUY, price=3, amount=4)
        await truffleAssert.passes( 
                // should be 2 buy orders
            assert(buyOrders.length == 2)
                // price of first order should be the highest which should be 3 since there are orders for 1 and 3
            assert(buyOrders[0].price == 3)
                // amount for highest price buy order should be 4
            assert(buyOrders[0].amount == 4)
        )
            
    })

        // SELL side of orderBook should be ordered from lowest to highest starting at index 0
    it("should arrange SELL orders in the orderBook correctly", async () => {
        let dex = await DEX.deployed();
        let token = await testToken.deployed();
        let sellOrders = await dex.getOrderBook(web3.utils.fromUtf8("LINK"), Side.SELL)
            // higher priced order was put in first so if orderBook is sorting correctly then the first indexed sell order should be the second order placed (LINK, sell, price=6, amount=30)
        await truffleAssert.passes( 
                // should be 2 sell orders
            assert(sellOrders.length == 2)
                // price of first order should be the lowest which should be 6 since there are orders for 6 and 8
            assert(sellOrders[0].price == 6)
                // amount for highest price buy order should be 30
            assert(sellOrders[0].amount == 30)
        )
    })

})
1 Like

updated tests after watching next video

dexTest.js

    // LIMIT Order Tests
//The user must have ETH deposited such that deposited eth >= buy order value
//The user must have enough tokens deposited such that the token balance >= sell order amount
//The user should not be allowed to place a buy or sell order for an unsupported token
//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 from lowest to highest starting at index 0

const DEX = artifacts.require("DEX")
const testToken = artifacts.require("testToken")
const truffleAssert = require('truffle-assertions')

contract("DEX", accounts => {
      
        // should reject BUY order because user's ETH balance is < total BUY order amount
    it("should reject invalid BUY orders", async () => {
        let dex = await DEX.deployed();
        let token = await testToken.deployed();
        await dex.addToken(web3.utils.fromUtf8("LINK"), token.address, {from: accounts[0]});
        await truffleAssert.reverts( 
            dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 5, 1)
        )
    })    

        // should allow user to place BUY order as long as user's ETH balance is >= total BUY order amount
    it("should accept valid BUY orders", async () => {
        let dex = await DEX.deployed();
        let token = await testToken.deployed();
        dex.depositEth({value:18});
        await truffleAssert.passes( 
            dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 6, 1)
        )
        await truffleAssert.passes( 
            dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 4, 3)
        )
    })
        
        // should allow user to place SELL order if user's selected token balance is >= total amount of tokens in SELL order
    it("should accept valid SELL orders", async () => {
        let dex = await DEX.deployed();
        let token = await testToken.deployed();
        await token.approve(dex.address, 500);
        await dex.deposit(50, web3.utils.fromUtf8("LINK"));
        await truffleAssert.passes( 
            dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 20, 8)
        )
        await truffleAssert.passes( 
            dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 30, 6)
        )
    })

        // should reject SELL order because user's selected token balance is < total amount of tokens in SELL order
    it("should reject invalid SELL orders", async () => {
        let dex = await DEX.deployed();
        let token = await testToken.deployed();
        await truffleAssert.reverts( 
            dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 500, 1)
        )
    })

        // should reject  BUY & SELL orders because token is not supported
    it("should reject SELL/BUY orders for unsupported tokens", async () => {
        let dex = await DEX.deployed();
        let token = await testToken.deployed();
        dex.depositEth({value: 10});
        await truffleAssert.reverts( 
            dex.createLimitOrder(0, web3.utils.fromUtf8("BTC"), 1, 10)
        )
        await truffleAssert.reverts( 
            dex.createLimitOrder(1, web3.utils.fromUtf8("BTC"), 1, 100)
        )
    })

        //The BUY order book should be ordered on price from highest to lowest starting at index 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 token = await testToken.deployed();
        await token.approve(dex.address, 500);
        await dex.depositEth({value: 1000});
        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 = await dex.getOrderBook(web3.utils.fromUtf8("LINK"), 0);
        assert(orderbook.length > 0, "Not enough orders in BUY orderbook for testing");
        for (let i = 0; i < orderbook.length - 1; i++) {
            assert(orderbook[i].price >= orderbook[i+1].price, "BUY order book is out of order")
        }
    })
        //The SELL order book should be ordered on price from lowest to highest starting at index 0
    it("The SELL order book should be ordered on price from lowest to highest starting at index 0", async () => {
        let dex = await DEX.deployed();
        let token = await testToken.deployed();
        await token.approve(dex.address, 500);
        await dex.deposit(3, web3.utils.fromUtf8("LINK"));
        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 = await dex.getOrderBook(web3.utils.fromUtf8("LINK"), 1);
        assert(orderbook.length > 0, , "Not enough orders in SELL orderbook for testing");
        for (let i = 0; i < orderbook.length - 1; i++) {
            assert(orderbook[i].price <= orderbook[i+1].price, "SELL order book is out of order")
        }
    })
})
1 Like

I think I’m still a little lost. I am having the same issue @DavidV and @suhan_kim. Every time I try to run await dex.depositEth({value: 1000}) I get a type error that states “dex.depositEth is not a function.” I have gone over the code Philip uses in the videos and I coded everything he did in my DEX contract and test files but I cannot run anything that involves ETH. Is there a function that should have been added to the DEX contract?

Any help would be greatly appreciated.

1 Like

Hi Dustin, you need to create that function yourself.

I was a while back, but I think its similar to the deposit function built for any token. IN the case of ETH when called you need to add {value : 1000} to add an input of ETH to the called function.

2 Likes

Oh wow that makes total sense haha. My bad, thanks for the reply!

Here are my tests:

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

contract("Dex", accounts => {

    // TESTS FOR CREATE LIMIT ORDER => function createLimitOrder(Side side, bytes32 ticker, uint amount, uint price)

    // 1) the user must have ETH deposited >= buy order value
    it("should not allow to create BUY limit order greater in value than the user ETH balance", async() => {
        let dex = await Dex.deployed()
        let link = await Link.deployed()
        await truffleAssert.reverts(
            dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 100)
            )
        await dex.depositETH({value:100})
        await truffleAssert.passes(
            dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 100)
        )
    })

    // 2) the user must have TOKEN deposited such that token balance >= sell order amount    
    it("should not allow to create SELL limit order greater in value than the user TOKEN balance", async() => {
        let dex = await Dex.deployed()
        let link = await Link.deployed()
        await truffleAssert.reverts(
            dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 100)
            )
        await dex.deposit(100, web3.utils.fromUtf8("LINK"))
        await truffleAssert.passes(
            dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 100)
        )
    })
    
    // 3) the buy order book should be ordered on price from highest to lowest starting from index 0
    it("should not allow to have the buy order book wrongly ordered", async() => {
        let dex = await Dex.deployed()
        let link = await Link.deployed()
        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 100)
        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 300)
        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 400)
        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 150)
        await dex.createLimitOrder(0, web3.utils.fromUtf8("LINK"), 1, 50)
        let book = await dex.getOrderBook(web3.utils.fromUtf8("LINK"),0)
        for(let i=0;i<book.length-1;i++){
            assert(book[i].price>=book[i+1].price,"Wrong order for buy orders book")
        }  
    })

    // 4) the sell order book should be ordered on price from lowest to highest starting from index 0
    it("should not allow to have the buy order book wrongly ordered", async() => {
        let dex = await Dex.deployed()
        let link = await Link.deployed()
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 50)
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 300)
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 500)
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 100)
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 400)
        let book = await dex.getOrderBook(web3.utils.fromUtf8("LINK"),1)
        for(let i=0;i<=book.length-1;i++){
            assert(book[i].price<book[i+1].price,"Wrong order for sell orders book")
        }  
    })    

})

My Dex tests:

const Dex = artifacts.require("Dex");
const Link = artifacts.require("Link");
const truffleAssert = require("truffle-assertions");
const BUY = 0;
const SELL = 1;


//The user must have ETH deposited such that deposited eth >= buy order value
contract("Dex", accounts => {
    let linkTicker = web3.utils.fromUtf8("LINK");
    it("Should enough ethereum to perform buy order", async () => {
        let dex = await Dex.deployed();
        let link = await Link.deployed();
        let balance = await web3.eth.getBalance(accounts[0]);
        //console.log(await dex.getContractBalance());
        //console.log(balance);
        await truffleAssert.reverts(
            dex.createLimitOrder(BUY, linkTicker, 10, 1, {from: accounts[0]})
        )
        
        await dex.depositEth({value: 10});
        console.log(await web3.eth.getBalance(accounts[0]));
        await truffleAssert.passes(
            dex.createLimitOrder(BUY, linkTicker, 10, 1, {from: accounts[0]})
        )
    });
    //The user must have enough tokens deposited such that token balance >= sell order amount 
    it("Should enough token balance to perform sell order", async () => {
        let dex = await Dex.deployed();
        let link = await Link.deployed();
        
        await truffleAssert.reverts(
            dex.createLimitOrder(SELL, linkTicker, 10, 1)
        )

        await dex.addToken(linkTicker, link.address, {from: accounts[0]})
        await link.approve(dex.address, 10)
        await dex.deposit(10, linkTicker)
        
        await truffleAssert.passes(
            dex.createLimitOrder(SELL, linkTicker, 10, 1)
        )
    });
    //The BUY order book should be ordered on price from highest to lowest starting at index 0
    it("Should have orderbook from highest to lowest starting at index 0", async () => {
        let dex = await Dex.deployed();
        let link = await Link.deployed();
        let orderTestCase = [53, 12, 6, 3, 44, 2, 3];
        let testCasesLength = orderTestCase.length;

        await link.approve(dex.address, 500);
        await dex.depositEth({value: 3000});
        
        let orderBook = await dex.getOrderBook(linkTicker, BUY);

        //Adding to test cases orders from previous tests
        for(let i=0; i<orderBook.length; i++){
            orderTestCase.push(Number(orderBook[i].price));
        }

        //Limit orders
        for(let i=0; i<testCasesLength; i++){
            await dex.createLimitOrder(BUY, linkTicker, 1, orderTestCase[i]);
            //orderBook = await dex.getOrderBook(linkTicker, BUY); - for debugging
            //console.log(orderBook);
        }
        orderBook = await dex.getOrderBook(linkTicker, BUY);

        //Assertions
        sortedOrder = orderTestCase.sort(function(a, b){return b-a});
        console.log(sortedOrder);
        for(let i=0; i<orderBook.length; i++){
            await assert.equal(sortedOrder[i], orderBook[i].price);
        }
    });

    it("Should have orderbook from lowest to highest starting at index 0", async () => {
        let dex = await Dex.deployed();
        let link = await Link.deployed();
        let orderTestCase = [53, 12, 6, 3, 44, 2, 3];
        let testCasesLength = orderTestCase.length;

        await link.approve(dex.address, 500);
        await dex.depositEth({value: 3000});
        
        let orderBook = await dex.getOrderBook(linkTicker, SELL);

        //Adding to test cases orders from previous tests
        for(let i=0; i<orderBook.length; i++){
            orderTestCase.push(Number(orderBook[i].price));
        }

        //Limit orders
        for(let i=0; i<testCasesLength; i++){
            await dex.createLimitOrder(SELL, linkTicker, 1, orderTestCase[i]);
            //orderBook = await dex.getOrderBook(linkTicker, SELL); - for debugging
            //console.log(orderBook);
        }
        orderBook = await dex.getOrderBook(linkTicker, SELL);

        //Assertions
        sortedOrder = orderTestCase.sort(function(a, b){return a-b});
        console.log(sortedOrder);
        for(let i=0; i<orderBook.length; i++){
            await assert.equal(sortedOrder[i], orderBook[i].price);
        }
    });
});
1 Like

dextest.js

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

contract("Dex", accounts => {

    // The user must have enough ETH deposited such that deposited ETH >= BUY order.
    it("The user should have enough ETH deposited to create a BUY 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)
        );
    })

    // The user must have enough tokens deposited such that token balance >= SELL order.
    it("The user should have enough tokens deposited to create a SELL order", 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);
        await dex.deposit(250, web3.utils.fromUtf8("LINK"));

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

    // The orders in the BUY orderbook should go from highest to lowest.
    it("The first order in the BUY orderbook should have the highest 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, 250);
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 100);
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 150);

        // This will push as [250, 100, 150] which is incorrect.

        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, "BUY orders in incorrect order" );
        }
    })

    // The orders in the SELL orderbook should go from lowest to highest.
    it("The first order in the SELL orderbook should 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, 100);
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 250);
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 1, 150);

        // This will push as [100, 250, 150] which is incorrect.

        let orderbook = await 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, "SELL orders in incorrect order" );
        }
    })
})

1 Like

Mine didn’t work.
I went to the following video with the solution and after following the steps didn’t get the same results.
This is what I got

1) Contract: Dex
       should throw an error if token balance is too low when creating SELL limit order:
     Error: Returned error: VM Exception while processing transaction: revert token does not exist -- Reason given: token does not exist.
      at Context.<anonymous> (test/dextest.js:29:19)
      at processTicksAndRejections (internal/process/task_queues.js:93:5)

  2) Contract: Dex
       The BUY order book should be ordered on price from highest to lowest starting at index 0:
     Error: Returned error: VM Exception while processing transaction: revert Insufficient balance -- Reason given: Insufficient balance.
      at Context.<anonymous> (test/dextest.js:39:19)
      at processTicksAndRejections (internal/process/task_queues.js:93:5)

  3) Contract: Dex
       The SELL order book should be ordered on price from lowest to highest starting at index 0:
     Error: Returned error: VM Exception while processing transaction: revert Insufficient balance -- Reason given: Insufficient balance.
      at Context.<anonymous> (test/dextest.js:55:19)
      at processTicksAndRejections (internal/process/task_queues.js:93:5)


I don’t really know what to think. Phillip didn’t define the depositEth function in the wallet for example, I had to copy it from the solution because he didn’t define it in the next video either. It’s like he skipped adding a lot of stuff.

Why don’t we have to add the ETH token?
I added the ETH token manually just like we did with LINK but when taking a look at the solution it wasn’t there.

1 Like

Hey @anorax. the reason that we dont have an ether token is because ethereum the currency is not an erc20 token. Ethereum is the native currency of the ethereum blockchain it has no physical address. ERC20 tokens are different they are nothing but smart contracts that mimic the characteristics of a digital currency in that they have a supply they can be transfered swapped etc. so thats why we dont make an eth token because ethereum is not an erc20 token like link in this example. Thus to deposit ETH into the dex we just make a payable function and msg.value is the amount we deposit. Recall solidity 101.

Secondly the reason your tests are not working i think, is because you havent actually coded the limit order function yet. If i recall correctly filip codes out the tests before the actual limit order function. This is backwards and the pposite of what you would do in practice. Always code the function first and then test it to see if it behaves as expected. The only reason that filip codes the test first is to just introduce us to testing as we have never seen it before.

If i am wrong though and you have coded the limit order function let me know and i will debug it for you if you kindly share your code

1 Like