Project - Building a DEX

ahhha theres actually no bugs its juts versoning issues i would imagine. can you try to cpmpletely remove node delete it from roaming app data too. if your still csnt get it to work i can meet you on a video call and see if i can walk you through it

yeah that video on youtube is outdated, so nothing from that either. :hot_face:

since i already paid for this month ill have to try again.

1 Like

Are u around today ill try jump on a call woth you to grt it resolved

Hello, I stuck with a first test, where we should have enough ETH deposited, it seems the depositETH function is not working, any ideas?

contract('Dex limit order', (accounts) => {
  it('should have enough eth deposited such that eth >= buy order value', 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 });
    let balance = await dex.balances(accounts[0], web3.utils.fromUtf8('ETH'));
    assert.equal(balance.toNumber(), 10);
  });
    function depositEth() payable external {
        balances[msg.sender][bytes32("ETH")] = balances[msg.sender][bytes32("ETH")].add(msg.value);
    }
  1) Contract: Dex limit order
       should have enough eth deposited such that eth >= buy order value:

      AssertionError: expected 0 to equal 10
      + expected - actual

      -0
      +10
1 Like

try

balances[msg.sender][bytes("ETH")] += msg.value

and change

dex.depositETH({value: 10})

to

await dex.depositETH({value: web3.utils.toWei("10", "ether"})

the await is the key heare but you should realise that you are depositing 10 wei in your code whereas i assume you want to deposit 10 ether. so you need to do a conversion as per the method i use above

Thank you, yes await was the problem

1 Like

Iā€™m a little confused by the fact that weā€™re storing the balances of various tokens directly in our contract. Would it not make more sense to check the userā€™s actual balance in each individual token contract? Is that possible. For example, checking how much ETH a user actually has, in reality, rather than whatever our specific contract says they have.

Any thought on this?

1 Like

yes u can get balances like this but cannot use this method to keep track of user balances in the dex contract. because if one person deposits 10 link and u check link balance of the contract using 1ER20(tokenMapping[LINK][msg.sender).address).balanceOf(addresss.this) then this will trturn the entire contract balance. but when somone else deposits link then there is a distribution of the token contract balance between users which this method cannot account for. so we nnedd a mapping to allow us to keep track of ths distribuyion

Thanks for the response @mcgrane5.
It sounds like youā€™re saying that when using this method itā€™s only possible to get the full balance of the contract itself and not of individual accounts/addresses that hold some of the token. In my testing however it does seem possible to get the balance of an arbitrary address from an arbitrary ERC20 contract.
A simple call like this seems to do the trick:
uint userAccountBalance = IERC20(tokenContractAddress).balanceOf(userAccountAddress);

That should essentially allow us to keep track of every account balance in any ERC20 token contract that we choose to support, and use a single source of truth (the token contract) to do so.
What do you think of this approach? Am I mistaken with any of this?

1 Like

yeah that call can work for querying someones balance of any erc20. but we want to get the balances of ppls tokens withtin the dex contract. the user may have that balance split across multiple scā€™s so their token balance could be different that their balance of the same token in the dex contract

Thanks @mcgrane5.
I think I misunderstood how this DEX should work at first.

Iā€™m probably getting ahead of myself, and maybe this is too deep for this course, but I like to have a thorough understanding of what Iā€™m trying to build before I actually build it. So it would be helpful to have an explanation of exactly how this DEX should work, especially since there are so many different types of DEXes and so there isnā€™t really a simple shared understanding of ā€œthis is how a DEX worksā€.
With that said, hereā€™s my understanding of how this DEX should work from a high level.

Users deposit certain tokens into the DEX and the DEX contract holds these tokens/funds until a user withdraws them. Based on the balances of various tokens (from previous deposits) stored in the DEX contract, users can try to execute trades. If the userā€™s balance is sufficient to fulfill the trade and there are sufficient orders on the opposite ā€œsideā€ to match the ā€œpriceā€ and enough of the ā€œamountā€, then the trade gets executed. A trade in this context only means that their balances stored in the DEX contract are updated, but no transfers actually take place during a trade. Transfers only occur when a user deposits or withdraws from the DEX.
In this way the DEX essentially acts very similar to a centralized exchange in that it holds funds and trades happen internally. Users then withdraw those funds at a later time.

Is that about right?

1 Like

your exactly right with your description yes. this dex works very similar to the way centralised exchanges work where we have the concept of an orderbook that gets filled and traders on both sides come together anf setle each others trades. dexes like uniswap are much different. they are called AMMā€™s or automated market makers and in these exchanges you have the concept of token pairs. the total balance or amount of tokens in this pair contract is always constant and the only thing that changes is the ration of the tokens balances that make up the total. x * y = k. where k = const. x = token1 reserves. y = token2 reserves. to create a uniswap market u need to provide two tokens in equal amount

for example if we have 100 eth at 50 euro each and 5000 dai at 1 euro each in the pair. then the total worth in euro is 5000 each. so the toal reserves ar 5000 * 5000 = 2,500,000. so this 2,500000 is the number that will always stay constant and then the price is determined from the ration of the reserves. so this on a high level is the theory of AMMā€™s.

BUT yes your dead right on your explaination of the dex in this course

1 Like

Got it, thanks.
I appreciate the added detail around AMMs. Iā€™m looking forward to learning more and building something like that one of these days.

1 Like

I am getting the error below after trying the better migrations under the project dex

Transaction: 0xd5ae3629fd3163520049c04d312b7de18cecccab91eb125eae9359cf105acb05 exited with an error (status 0). Reason given: Token does not exist.
Please check that the transaction:
- satisfies all conditions set by Solidity require statements.
- does not trigger a Solidity revert statement.

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


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

wallet contract here

// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <= 0.8.0;

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

contract Wallet is Ownable{
    using SafeMath for uint256;
    
    struct Token {
        bytes32 tiker;
        address tokenAddress;
    }

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

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

    modifier tokenExist( bytes32 ticker) {
       require(tokenMapping[ticker].tokenAddress != address(0), "Token does not exist");
       _;
    }

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

    function deposit(uint amount, bytes32 ticker) tokenExist(ticker) external {   
        IERC20(tokenMapping[ticker].tokenAddress).transferFrom(msg.sender, address(this), amount);
        balances[msg.sender][ticker]= balances[msg.sender][ticker].add(amount);
    }

    function withdraw(uint amount, bytes32 ticker) tokenExist(ticker) external {

        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);
    }

}

1 Like

no you should handle the deploymnets of your individual contracts seperately

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

your trying to deploy both in the one file.which im going to assume (could be wrong) is the error. make a specific migrations for your token conyract and deploy that on its own.

I am following this video in the project and running into my issue
https://academy.moralis.io/lessons/better-migration

1 Like

can u share project code. can u push it to github ill have a look

https://github.com/scott815/dex201

1 Like

hey @Scott815 took your code into my machine. it works fine. are you sure your in the truffle develop console and executing truffle migrate. this is the output from my terminal. it works as expected