Project - Building a DEX

Happy Friday @dan-i,

I’m stuck again. Everything compiles except I keep getting this:
image

There’s something going on with the Wallet contract - I can’t compile it and therefore my test doesn’t work either.

The js file with my test is here:

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

contract("Dex", accounts => {
    it("Should only be possible for owner to add token", 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("AAVE"), link.address, {from: accounts[1]})
        )
    
    })
    it("should handle deposits correctly", async () => {
        let dex = await Dex.deployed()
        let link = await Link.deployed()
        await link.approve(dex.address, 500);
        await dex.deposit(100, web3.utils.fromUtf8("LINK"));
        await dex.balance(accounts[0], web3.utils.fromUtf8("LINK"));
        let balance = await dex.balances(account[0], web3.utils.fromUtf8("LINK"))
        assert.equal(balance.toNumber(), 100)
    })
})

I’m just following along right now, but before I attempt the order limit assignment I want to be make sure everything runs smoothly. Any ideas?

1 Like

Okay so this is my deposit function, iim pretty sure that im missing 1000 things, but i was looking at the _transfer function from ERC20.sol and i felt like there wasnt any require that i could add to make it more secure, im pretty sure that im wrong in my assumption xD (among other things because the finishing wallet video lasts almost 15 minutes so, sounds like theres gonna be a lot of explaining there) anyways i felt like i wasnt doing enough so i put an assert at the end, that balance should be equal to balance + amount, in case something goes wrong with the deposit??? but okay heres the code:

Summary
pragma solidity 0.8.2;

import "../node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "../node_modules/@openzeppelin/contracts/utils/math/SafeMath.sol";

contract Wallet{

    using SafeMath for uint256;

    struct token{
      bytes32 ticker;
      address tokenAddress;

}

    mapping(bytes32 => token) public tokenMapping;
    bytes32[] public tokenList;

    mapping(address => mapping(bytes32 =>uint256)) public balances;

    function addToken(bytes32 ticker, address tokenAddress) external{
        tokenMapping[ticker] = token(ticker, tokenAddress);
        tokenList.push(ticker);
    }

    function deposit(uint amount, bytes32 ticker) external{
        ERC20(msg.sender).transfer(tokenMapping[ticker].tokenAddress, amount);
        assert(balances[msg.sender][ticker] == balances[msg.sender][ticker] + amount);
    }

    function withdrawal(uint amount, bytes32 ticker) external{
        require(tokenMapping[ticker].tokenAddress != address(0));
        require(balances[msg.sender][ticker] >= amount, "balance not sufficient");
        balances[msg.sender][ticker] = balances[msg.sender][ticker].sub(amount);
        IERC20(tokenMapping[ticker].tokenAddress).transfer(msg.sender, amount);
    }

}

also i was thinking that if i am going to keep using the ERC20s _transfer function, then i should change Filips example of the withdraw function, but first i have to watch filips video, cause im pretty sure i needed to put some requires and who knows what else :thinking:

Hey @wilsonlee123

I think I totally missed your question sorry!
Would you please push your project in a GitHub repo and send me the link to it? I would like to deploy and double check.

Thanks,
Dani

Hey @Carlosvh96

Your code is correct and you are not missing any crucial require statement.
You could check that the balance is > than 0 in your deposit function if you want, or maybe that _tokenAddress is not address(0).
But still the code is correct.

Well done,
Dani

Good day @dan-i,

No worries! Any help is appreciated. Still stuck lol.
https://github.com/wilson-lee88/DEX

Hi @wilsonlee123

You are not deploying Wallet but you are trying to create an instance of it.
In 3_token_migration.js add await deployer.deploy(Wallet); before let wallet = await Wallet.deployed().

There is another issue in that file with dex check it out :slight_smile:

Cheers,
Dani

@dan-i, I think I fixed it.
It’s getting through the migration. But looks like truffle-assertions is not found? I don’t see Fillip importing it in the video though. What am I missing?
image

1 Like

@dani-i Following up on this. Please advise :blush:

1 Like

you probably forgot to install the module, you should try with:

npm install truffle-assertions

https://github.com/rkalis/truffle-assertions

If you have any more questions, please let us know so we can help you! :slight_smile:

Carlos Z.

3 Likes

@thecil Thanks Carlos, that was it :sweat_smile:

Everything can be tested now finally lol.

2 Likes

Hi!

Maybe I’m missing something but when writing the createLimitOrder tests there is a call to a function called “depositEth” that was never added to the wallet or dex, nor is it part of the ERC20 token. I took a stab at building it but was curious if this was something that was missed when building the dex project.

Thanks!!

2 Likes

Hey @Mariano_Collarte

True that function is not shown in the videos, however I am sure you were able to build it with the knowledge you got from the courses :slight_smile:
Feel free to share your function here if you want, so we can check it together.

Happy coding,
Dani

1 Like

Hi guys, I’m wrestling with a problem that I can’t seem to solve. Since Filip showed the testing stuff, I kind of slightly went my own (ish) way to finish the contract. My contract’s logic is:

You place an order. Checks are made if you have enough ETH/tokens. The order gets added to the orderbook, and then ordered. The contract checks(loop) if the buy order with the highest price is higher or equal to the sell order with the lowest price. (as in if I’m willing to buy for price 10, and the other guy selling for price 5, we got a trade).

If there is a match, the contract checks which amount limits the trade (for example, if I want to sell 10 and the other guy wants to buy 5, the trade gets made for 5). Then corresponding balances get adjusted, the orderbook gets adjusted and one (or both) of the orders gets popped from the orderbook.

I’ve uploaded all files into a github thingie( I have never done that before).

https://github.com/KilianZumFelde/Dexproject

I’ve tested the contract when there are no matching orders, and everything seems fine.

The problem is when two orders match (in the dex2 testing contract):

image

I’ve (possibly) narrowed it down to the “popping” instruction:

image

This is within the _matchorder function. (In my test case, buy and sell orders amount matches)

If I comment the pop functions, everything works (the test passes also, since I’m only validating balances, and not the end state of the orderbook).

If I “de comment” the pop function, it throws… Help.

I’ve been struggling with this the entire day, and already vouched to destroy everything related to blockchain if I can’t solve this.

I wanted then to isolate the problem, and just test the pop function in remix. There I discovered that probably my understanding is way lower assumed, because I couldn’t make a simple (pop) function work.

pragma solidity 0.8.0;

contract test{
    uint256[] testarray;
    
    function popustupidfunction() public{
    testarray[0] = 1;
    testarray[1] = 1;
    testarray[2] = 1;
    
    testarray.pop();
    }
}

Getting this error:

image

I don’t understand why its talking to me about value and payable…I just want to try out the pop function :frowning:.

For anyone who takes this on, thanks a bunch!

I’m at the moment developing with a “need to know” mentality (as in, I only dive as deep as I have to in order to advance quickly and not getting stuck with something potentially irrelevant), so you might find weird or perhaps not very elegant/pragmatic developing.

KZF

Hi @KZF

When you upload a project to GitHub please make sure to push all your folders and not just the file so that I can run it with Truffle directly.

This command is failing await dex.PlaceOrder(web3.utils.fromUtf8("klc"), 1000, 1, 1, {from: accounts[6]});

More in depth this function (or any other related to it is failing):

_matchorder(_price, _symbol);

Create smaller tests for each function of your contract and test one by one:

_matchorder
_adjustbalances
_dropMatchedBuyOrder

Tests are not useful if they are as big as yours :slight_smile:
Cheers,
Dani

Hey Dani, thanks for taking an interest! You were extremely correct with your advise about testing.

I went obsessive mode and tested every breath and move of my code; the contract was supposed to evaluate a variable, and then enter only one of three if statements. But due to faulty logic, it continuesly evaluated the variable and entered multiple if statements, and as a byproduct tried to pop arrays that had already been popped and thus were unpoppable!

thx!

kzf

1 Like

Hey everyone, I have a question. Should the deposit function be payable? or it does not need to be since we’re transferring tokens and not ETH? Also, what would happen if I make the function payable?

Many thanks! Code is written below

    function deposit(uint _amount, bytes32 _ticker) tokenExist(_ticker) external payable {
        //checks using tokenExist modifier
        balances[msg.sender][_ticker] = balances[msg.sender][_ticker].add(_amount); //effects
        IERC20(tokenMapping[_ticker].tokenAddress).transferFrom(msg.sender, address(this), _amount); //interactions
    }

All functions that receive ether should be payable.

1 Like

Hello, in one of my unit tests, I receive the error Error: Returned error: VM Exception while processing transaction: revert. Is there any way to debug from truffle?

The test code is below and the error is caused on the createMarketOrder function call.

it("market orders should not fill more limit orders that the market order amount", async () => {
        let orderbook = await dex.getOrderbook(web3.utils.fromUtf8("LINK"), 1);
        assert(orderbook.length == 0, "Sell side orderbook should  be empty at beginning of test")
        await dex.depositETH({ value: '100' });
        //Send LINK tokens to accounts 1,2,3 from account 0
        await link.transfer(accounts[1], 100);
        await link.transfer(accounts[2], 100);
        await link.transfer(accounts[3], 100);

        //approve DEX for accounts 1,2,3
        await link.approve(dex.address, 100, { from: accounts[1] });
        await link.approve(dex.address, 100, { from: accounts[2] });
        await link.approve(dex.address, 100, { from: accounts[3] });

        //approve LINK into DEX accounts 1,2, 3
        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] });

        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 5, 2, { from: accounts[1] });
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 5, 4, { from: accounts[2] });
        await dex.createLimitOrder(1, web3.utils.fromUtf8("LINK"), 5, 3, { from: accounts[3] });
        orderbook = await dex.getOrderbook(web3.utils.fromUtf8("LINK"), 1);
        console.log(orderbook);
        //create market order that should fill 2/3 of the book
        await dex.createMarketOrder(0, web3.utils.fromUtf8("LINK"), 10);
        console.log(orderbook);
        orderbook = await dex.getOrderbook(web3.utils.fromUtf8("LINK"), 1);
        console.log(orderbook.length);
        assert(orderbook.length == 1, "Sell side orderbook should have 1 order left");
        assert(orderbook[0].filled == 0, "Sell side order should have 0 filled");
    })

Hi, quick question - I’m not seeing the Math folder containing SafeMath in my contracts folder. According to the Open Zeppelin forum SafeMath has been slightly modified to benefit from solidity ^0.8.0 new features. What is the work around for using SafeMath? Thanks in advance!

Safemath can be found here:

import "../node_modules/@openzeppelin/contracts/utils/math/SafeMath.sol";

Using, ^0.8.0

1 Like