Project - Building a DEX

can u share your other code files. seems to be an issue with your migratons the compiler isnt recognising aritfacts.require()

1 Like

@Tomahawk also sorry just forgot to say are you definitely initialising dex and then adding, approving and depositing before you create the limit order. sorry meant to ask that just going off the small code snipit your provided above.

1 Like

Sorry, you are right. I just forgot that since I had to have a pause for a week :smiley: It is better to do it continuously. When I did all the steps (I basically copied commands from dextest.js) it went through ok.

However I tried it with my previous bubble sort and createLimitOrder works as well. So it is weird that with both solutions all steps and createLimitOrder goes through ok manually, but dextest.js goes wrong on the 1) test only with my solution.

1 Like

Yeah i cant rember fully but when i tried it myself with your code i think i was getting an index out of range error. but thats great that its working now. You should play around and write more tests. manually doing them also is a great way to understand exactly what your code is doing. If you go to the forum for the final dex project i wrote a samll post sharing some tips that i found helpful when doing this myself and debuging (because i too was struggling a lot for awhile) if you go read it youll see what i mean (in terms of debugging). I found it really helpful going through my code line by line on paper and eventually youll find the line where your code fails.

1 Like

@mcgrane5

Thanks I read your tips and I actually also did it with paper and pen in previous projects. Not in this one thou.

Anyway, it still does not work, except one part :smiley: To make it easier for now to go through the testing for the first time, I actually copied bubble sort from Philip’s final code on github and also I copied some parts of the testing. Here is the link for my code:

https://github.com/tommahawk25/Dex-v2

And I started to test it manually line by line. Everything works except the 3rd test “Buy order book should be ordered from highest to lowest”

when I run

assert(orderbook[0].price >= orderbook[1].price, “not right order in buy book”)

It says undefined instead of giving me true or false. Don’t really understand what could be wrong here, since for example assert(orderbook.length >0) does work. And also console.log(orderbook[0].price) does work.

This is really strange. Any idea?
image

1 Like

Ohh ok i see. You should actually not do the actually asserts in the console. Undefined is not an error. Its much like when you say let dex = await Dex.deployed() and when you press enter it says undefined. If you want to manually test in the console like you are now to see if your orderbook is soted correctly you can do this.

truffle(develop)> let orderBook = dex.getOrderbook(uint(side), ticker)    
//where uint(side) is 0 or 1 depending on what side of the orderbook your oder is in
//and ticker just is the ticker

**(Note make sure you have actually written the get orderbook function. If you dont it just returns the orderBook struct, but i think Filip covers it in one of the videos so you should have it)**

then when you what you can do is call orderBook like this

truffle(develop)> orderBook

and it will return all of the entries in the orderbook and you can just compare them it should be ordered highest to lowest by price. Now that you know if they are then when you run truffle test, your tests should pass.

The only thing that may cause you hiccups sometimes is the await keyword. But what you should know is if you do it like ive shown above and the orderbook is ordered then your tests should pass, if they dont just play around with them and be careful with the await keyword and the order in which you declare vairiables.

1 Like

@mcgrane5

Everything you said I actually already did. I know that the order is right. I just coudn’t get this assert. I thought when assert(orderbook.length >0) works then the other assert has to work as well. But okay.

However truffle test does not work. I have the 3rd test according to Filip’s one.
image

This is what is strange. Manually it is okay but with dextest.js it gives errors :confused:

Is this the same as with manual? That the assert gives undefined and therefore test goes wrong with AssertionError?

1 Like

@Tomahawk, Yeah this is what i meant about the await keyword Now im not too adept in javascript but i think because these are all async functions the some of the function calls dont all finish at the same time so this fact can cause issues thats my theory anyway but i could be wrong so take that with a grain of salt… When i was doing my testing i ran into these issues the whole time aswell even when i know my tests should pass because i had manually tested them but sometimes they didnt. Its a weird one you just have to play around with your tests. If you can push your code again ill play around with your tests later this evening and see what i can do. Its just all about trying different things and sticking at it. I remember it took me a whole day alone to get my limit order tests working lol

1 Like

@mcgrane5 I have checked “await” already before according to Filip’s code. There wasn’t the problem.

However I finally found the mistake! Stupid typo in dextest.js! Rofl. I didin’t really checked for typos because I was used to .sol file where it gave the errors. Didn’t know that .js files doesn’t give errors. Learnt something new at least.

Now I can continue with my code. Thank you for your time! I know it was really exhausting.

1 Like

@Tomahawk Hahah no worries my pleasure. Glad we got there in the end. Perseverance is key.

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

module.exports = async function (deployer, network, accounts) {
  await deployer.deploy(Link);
  let dex = await Dex.deployed()
  let link = await Link.deployed()
  await link.approve(dex.address, 500)
  dex.addToken(web3.utils.fromUtf8("LINK"), link.address)
  await dex.deposit(100, web3.utils.fromUtf8("LINK"))
  let balanmceOfLink = dex.balances(accounts[0], web3.utils.fromUtf8("LINK"));
  console.log(balanmceOfLink);
};

const Dex = artifacts.require(“Dex”);

module.exports = function (deployer) {

deployer.deploy(Dex);

};

````const Migrations = artifacts.require("Migrations");

module.exports = function (deployer) {
  deployer.deploy(Migrations);
};``

const Dex = artifacts.reqiure(“Dex”)
const Link = artifacts.reqiure(“LINK”)
const truffleAssert = require(‘truffle-assertions’);

contract(“Dex”, accounts => {
it(“should only be possible for owner to add 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 deposits correctly”, async () => {
let dex = await Dex.deployed()
let link = await Link.deployed()
link.approve(dex.address, 500);
dex.deposit(100, web3.utils.fromUtf8(“LINK”));
let balance = await dex.balances(accounts[0], web3.utils.fromUtf8(“LINK”))
truffleAssert.equal(balanc.toNumber(), 100 )

})
it("should handle withdraws correctly", async () => {
    let dex = await Dex.deployed()
    let link = await Link.deployed()
    await truffleAssert.reverts(dex.withdraw(500, web3.utils.fromUtf8("LINK")))

})
it("should handle correct withdraws correctly", async () => {
    let dex = await Dex.deployed()
    let link = await Link.deployed()
    await truffleAssert.passes(dex.withdraw(500, web3.utils.fromUtf8("LINK")))

})

})

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

contract("Dex", accounts => {
    it("should only be possible for owner to add 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 deposits correctly", async () => {
        let dex = await Dex.deployed()
        let link = await Link.deployed()
        link.approve(dex.address, 500);
        dex.deposit(100, web3.utils.fromUtf8("LINK"));
        let balance = await dex.balances(accounts[0], web3.utils.fromUtf8("LINK"))
        truffleAssert.equal(balanc.toNumber(), 100 )
    
    })
    it("should handle withdraws correctly", async () => {
        let dex = await Dex.deployed()
        let link = await Link.deployed()
        await truffleAssert.reverts(dex.withdraw(500, web3.utils.fromUtf8("LINK")))
    
    })
    it("should handle correct withdraws correctly", async () => {
        let dex = await Dex.deployed()
        let link = await Link.deployed()
        await truffleAssert.passes(dex.withdraw(500, web3.utils.fromUtf8("LINK")))
    
    })
})
const Link = artifacts.require("Link");
const Dex = artifacts.require("Dex");

module.exports = async function (deployer, network, accounts) {
  await deployer.deploy(Link);
  let dex = await Dex.deployed()
  let link = await Link.deployed()
  await link.approve(dex.address, 500)
  dex.addToken(web3.utils.fromUtf8("LINK"), link.address)
  await dex.deposit(100, web3.utils.fromUtf8("LINK"))
  let balanmceOfLink = dex.balances(accounts[0], web3.utils.fromUtf8("LINK"));
  console.log(balanmceOfLink);
};

image

My deposit function looks different from filip’s, but I wondered if approval is necessary to complete the transfer effectively. If I am not mistaken, the approved statement checks if the funds are sufficient to send before allowing it to go through. So does this make my second require statement a little repetitive or not? Also is it okay to leave the approve statement even though filip never used it?

Hi,

can I have a quick question? In javascript test, why don’t we have “await” here at dex.depositEth({value: 20}) ?

In Filip’s codes there are some tests, which contain dex.depositEth with await and some tests, which contain dex.depositEth without await. That is something I can’ understand. Thanks.

    it("ETH deposit >= buy order value", async () => {
        let dex = await Dex.deployed()
        let link = await Link.deployed()

        await dex.addToken(web3.utils.sha3("LINK"), link.address, {from: accounts[0]})

        await truffleAssert.reverts(
            //function createLimitOrder(side, ticker, amount, price)
            dex.createLimitOrder(0, web3.utils.sha3("LINK"), 10, 1)
        )
   
        dex.depositEth({value: 20})       

        await truffleAssert.passes(
            //function createLimitOrder(side, ticker, amount, price)
            dex.createLimitOrder(0, web3.utils.sha3("LINK"), 10, 1)
        )
    })

Hi @DJaySplash

This statement is not correct:

If I am not mistaken, the approved statement checks if the funds are sufficient to send before allowing it to go through.

The approve statement sets an allowance from _spender and allows that address to move funds from another wallet.
Check out the approval function code :slight_smile:

Cheers,
Dani

1 Like

Hi @Tomahawk

All contract interactions are async so you should always use await.
Using await makes sure that the code is executed before moving to the next line of code.

Cheers,
Dani

1 Like

Hi All,

Here is my code with the Bubble Sort implemented. Pardon me if this code looks too long and not optimized enough. Would like to get it reviewed with @dan-i and @mcgrane5.

DEX.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

import "../contracts/wallet.sol";

contract Dex is Wallet {
using SafeMath for uint256;


enum Side {
    BUY, 
    SELL
}

struct Order {
    uint id;
    address trader;
    Side side;
    bytes32 ticker;
    uint amount;
    uint price;
}

mapping(bytes32 => mapping(uint => Order[])) public orderBook;

uint orderId = 0;

function getOrderBook(bytes32 ticker, Side side) view public returns (Order[] memory) {

    return orderBook[ticker][uint(side)];

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

    uint ethBalance;
    uint tokenBalance;
    Order memory _order = Order(orderId, msg.sender, side, ticker, amount, price);

    ethBalance = balances[msg.sender][bytes32("ETH")];
    tokenBalance = balances[msg.sender][ticker];

    if (side == Side.BUY){

        require(ethBalance >= amount.mul(price), "Eth balance is not enough");
        orderBook[ticker][uint(side)].push(_order);
        sortDescending(orderBook[ticker][uint(side)]);
        orderId++;
    }
    if (side == Side.SELL){

        require(tokenBalance >= amount, "Token balance is not enough");
        orderBook[ticker][uint(side)].push(_order);
        sortAescending(orderBook[ticker][uint(side)]);
        orderId++ ;
    }

}

function sortDescending(Order[] memory orders) private pure{
    // Bubble Sort

     uint l = orders.length;
     bool swap = true;
     uint numSwap = 0;

     while(swap){

        for(uint i = 0; i < l -1; i++){

             Order memory temp;
            
             if (orders[i].price < orders[i+1].price){
                 temp = orders[i];
                 orders[i] = orders[i+1];
                 orders[i+1] = temp;
                 numSwap++;
                 swap = true;
             }
        }

        if (numSwap == 0){
            swap = false;
        }
 
     }

}

function sortAescending(Order[] memory orders) private pure{
    // Bubble Sort

     uint l = orders.length;
     bool swap = true;
     uint numSwap = 0;

     while(swap){

        for(uint i = 0; i < l -1; i++){

             Order memory temp;
            
             if (orders[i].price > orders[i+1].price){
                 temp = orders[i];
                 orders[i] = orders[i+1];
                 orders[i+1] = temp;
                 numSwap++;
                 swap = true;
             }
        }

        if (numSwap == 0){
            swap = false;
        }
 
     }

}


}

code is also updated in github https://github.com/rays70/DEX

Cheers!

2 Likes

Good job @rays

A good idea is also to write some tests for the sorting function :slight_smile:

hi @dan-i, yes, the tests are in progress :grinning:

1 Like