Project - Building a DEX

@PaulS96 one thing i forgot to mention is that your witdraw function was payable until i changed it. functions should only be payable if your sending ether into a contract. instead for withdrawing functions you only need the recipient address to be payable and then use the built in transfer function or the call function to send the funds to the recipient.

1 Like

hey sir, im doing testing of adding tokens by owner. 0 is account of owner then why my test is failing ?

Contract: Dex
1) shoul only possibile for owners to add tokens
> No events were emitted

0 passing (6s)
1 failing

  1. Contract: Dex
    shoul only possibile for owners to add tokens :
    ReferenceError: Cannot access ā€˜Dexā€™ before initialization
    at Context. (test\Wallettest.js:7:11)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)

bigint: Failed to load bindings, pure JS will be used (try npm run rebuild?)
This version of ĀµWS is not compatible with your Node.js build:

Error: Cannot find module ā€˜./uws_win32_ia32_72.nodeā€™
Falling back to a NodeJS implementation; performance may be degraded.

const Cpt= artifacts.require("Cpt") 
const Dex= artifacts.require("Dex") 
const truffleAssert = require('truffle-assertions');
contract ("Dex", accounts =>{
it ("shoul only possibile for owners to add tokens ", async() =>{
   
let Dex = await  Dex.deployed()
let Cpt = await Cpt.deployed()
 await truffleAssert.passes(
Dex.addtoken(web3.utils.fromUtf8("Cpt"),Cpt.address,{ from: accounts[0]}))
})
})

can u see why test is failing?

Might be a require getting triggered, can you share the contract ?? it would be much easier for us if you create a github repo for the project.

Carlos Z

1 Like

This is my code.
taking a look at the forum and code on github, I see that in my code it is missing,
check that the tokens exist and event (I will add this item next time).

I tried to use ā€œdelegated callā€ to approve the expense, but this solution does not work. (I approved by the contract and not for user)

I have test my code using a token ā€œmockDaiā€, and i use this function " web3.utils.asciiToHex()" for convert string in byte32.

// SPDX-License-Identifier: Leluk911
pragma solidity 0.8.0;

import "../node_modules/@openzeppelin/contracts/interfaces/IERC20.sol";
import "../node_modules/@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract Wallet is ReentrancyGuard {
    // use this struct for store token in wallet
    struct Token {
        bytes32 tiker;
        address tokenAddress;
    }

    mapping(bytes32 => Token) TokenMapping;
    // array for store Token for Token.tiker
    bytes32[] public TokenList; // only list.. some information give in mapping TokenMapping

    // duble mapping for balance every Token in wallet add
    mapping(address => mapping(bytes32 => uint256)) public balances;

    function addToken(bytes32 _tiker, address _tokenAddress)
        external
        nonReentrant
    {
        // add token information i wallet
        TokenMapping[_tiker] = Token(_tiker, _tokenAddress);
        // push only _tiker.. mapping need for take address.
        TokenList.push(_tiker);
    }

    function deposit(uint256 _amount, bytes32 _tiker) external nonReentrant {
        // before approve this spend
        IERC20(TokenMapping[_tiker].tokenAddress).transferFrom(
            msg.sender,
            address(this),
            _amount
        );
        balances[msg.sender][_tiker] += _amount;
    }

    function withdraw(uint256 _amount, bytes32 _tiker) external nonReentrant {
        require(TokenMapping[_tiker].tokenAddress != address(0)); // address assigne not 0X00000
        require(balances[msg.sender][_tiker] >= _amount, "balance insufficent"); // check balance before
        balances[msg.sender][_tiker] -= _amount; //update balance befor transfer
        IERC20(TokenMapping[_tiker].tokenAddress).transfer(msg.sender, _amount); // transfer
    }
}

1 Like

hey @LELUK911 i will have a look at your code now. are ypu able to post the link to your githib. one thing before i do is that you cannot use delegate call here for this to work. the approve function doesnt work here when you try to call it is because your dex contract makes an external call to your link token. therefore the caller is not you but rather your dex contract. so because this is the case the owner address and the spender address are the same here therefore the alloance will get increased for owner = your wallet and spender - your wallet. the only way to solve this is to execute approve and transferfrom seperately. which is annoying i know.

but anyways ill look at the rest of your code now if you can share the link to your github

1 Like

in fact , my contractā€™s allowance increas, i havenā€™t post on github.

but the function was more or less.

function approveDelegate(address _user, uint _amount, bytes32 _tiker) external{
        address tiker = TokenMapping[_tiker].tokenAddress;
        (bool success,) = tiker.delegatecall(abi.encodeWithSignature("approve(address, uint256)", _user,_amount));
        require(success,"transaction faill");
    }
1 Like

Are you sure this works. im pretty sure your code above wont work. i know from experience that trying to call the approve function externally from another contract wiht delegate call doesnt work as the caller will always be the contract making the call and not the wallet address calling the function itself.

there is no way to bundle an approval and a transferfrom in solidity with erc20s

if this does somehow work and im missing anything do share because fom what i understand is it cant be done.

2 Likes

no no, i explained myself badly because of my bad english.
this function, yes, it works but as you say only for the contract that calls the call ā€¦ therefore the expense is authorized for the contract and not for the user, who, as you say, must authorize the expense himself.

in fact this would be a bad resolution of my experiment, Iā€™m trying to use a different way

PS. I hope my translation was more clear this time

1 Like

yes your exactly right. it is annoying and it would be very handy if you could use delegate call to call a tokens approve function externally but sadly it does not work. very great that you have done your own research to experiment with some lower level functionalitites built into solididy such as delegatcall it shows your on the right path and doing even more learning on your own. great stuff

1 Like

Good Evening!

Having some challenges, wondering if anyone can help me with some suggestions about fixing this:

Source file requires different compiler version (current compiler is 0.8.12+commit.f00d7308.Emscripten.clang) - note that nightly builds are considered to be strictly less than the released version

I tried using the following, but none of these work:
// SPDX-License-Identifier: MIT

pragma solidity >=0.4.22 <0.9.0;

Pragma solidity >=4.5.0 <0.8.0;

pragma solidity ^0.8.0;

pragma solidity >=0.4.22 <0.8.0;

pragma solidity >=0.6.0 <0.8.0;

Much appreciate!

1 Like

in your projects truffle config file make sure that your compiler version matxhes the one your using in your smart conttrat file

1 Like

Awesome! I will check that outšŸ¤©

1 Like

cool let me know if you get it working

1 Like

Hey @mcgrane5
Ended up downgrading my truffle version.
Thanks a millionšŸ˜ƒ

1 Like

Hello @mcgrane5
Having some issues, I did exit VScode just in case it was login/exit issue but when I try to migrate it doesnā€™t work.

Compiler error msg:

2_wallet_migration.js
=====================

ReferenceError: Wallet is not defined
    at module.exports (/Users/hermevillaparedes/Ethereum-201/DEX/migrations/2_wallet_migration.js:4:19)
    at Migration._load (/usr/local/lib/node_modules/truffle/build/webpack:/packages/migrate/Migration.js:55:1)
    at processTicksAndRejections (internal/process/task_queues.js:88:5)
    at Migration.run (/usr/local/lib/node_modules/truffle/build/webpack:/packages/migrate/Migration.js:217:1)
    at Object.runMigrations (/usr/local/lib/node_modules/truffle/build/webpack:/packages/migrate/index.js:150:1)
    at Object.runFrom (/usr/local/lib/node_modules/truffle/build/webpack:/packages/migrate/index.js:110:1)
    at Object.run (/usr/local/lib/node_modules/truffle/build/webpack:/packages/migrate/index.js:87:1)
    at runMigrations (/usr/local/lib/node_modules/truffle/build/webpack:/packages/core/lib/commands/migrate/run.js:76:1)
    at Object.module.exports [as run] (/usr/local/lib/node_modules/truffle/build/webpack:/packages/core/lib/commands/migrate/run.js:44:1)
    at Command.run (/usr/local/lib/node_modules/truffle/build/webpack:/packages/core/lib/command.js:189:1)

I would love your guidance on this challenge:
wallet.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.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 ticker;
        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) 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);

    }

}

Tokens.sol

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

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


contract Link is ERC20 {
    constructor() ERC20("Chainlink", "LINK") {
        _mint(msg.sender, 1000);

    }

}

2_wallet_migration.js

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

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

3_token_migration.js

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

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

Much appreciate! :upside_down_face:

1 Like

hi everyone!
I have a small problem with my code, my first problem is that iā€™m not good in a writing test (iā€™m working on it), but in this case, I test my code in analytic mode and it seems that, for some obscure reason, I am unable to update the ā€œamountā€ of the order in case this is less than the ā€œmarket order amountā€. . with a lot of provably I have the wrong approach with debug, and i donā€™t find my errorā€¦

I have a small problem with my code, my first problem is that iā€™m not good in a writing test (iā€™m working on it), but in this case, I test my code in analytic mode and it seems that, for some obscure reason, I am unable to update the ā€œamountā€ of the order in case this is less than the ā€œmarket order amountā€. . with a lot of provably I have the wrong approach with debug, and i donā€™t find my errorā€¦

this is code:

the function that create error is : createMarketOrderā€¦

// SPDX-License-Identifier: Leluk911
pragma solidity 0.8.0;
pragma experimental ABIEncoderV2;

import "./wallet.sol";

contract Dex is Wallet {
    enum Side {
        BUY,
        SELL
    }

    struct Order {
        uint256 Id;
        address Trader;
        Side side;
        uint256 amount;
        uint256 price;
        bytes32 Tiker;
    }
    uint256 NewID = 0;

    mapping(bytes32 => mapping(uint256 => Order[])) OrderBook;

    function getOrderBook(bytes32 _tiker, Side _side)
        external
        view
        returns (Order[] memory)
    {
        return OrderBook[_tiker][uint256(_side)];
    }

    function createLimitOrder(
        uint256 _amount,
        uint256 _price,
        bytes32 _tiker,
        Side _side
    ) external {
        //tokenExist(_tiker) {
        if (Side.BUY == _side) {
            require(balances[msg.sender]["ETH"] >= _amount * _price);
        } else if (Side.SELL == _side) {
            require(balances[msg.sender][_tiker] >= _amount);
        }
        Order[] storage orders = OrderBook[_tiker][uint256(_side)];
        orders.push(Order(NewID, msg.sender, _side, _amount, _price, _tiker));

        uint256 i = orders.length > 0 ? orders.length - 1 : 0;
        if (Side.BUY == _side) {
            while (i > 0) {
                if (orders[i - 1].price > orders[i].price) {
                    break;
                }
                Order memory ordersMove = orders[i - 1];
                orders[i - i] = orders[i];
                orders[i] = ordersMove;
                i--;
            }
        } else if (Side.SELL == _side) {
            while (i > 0) {
                if (orders[i - 1].price < orders[i].price) {
                    break;
                }
                Order memory ordersMove = orders[i - 1];
                orders[i - i] = orders[i];
                orders[i] = ordersMove;
                i--;
            }
        }
        NewID++;
    }

    /
    function createMarketOrder(
        uint256 _amount,
        bytes32 _tiker,
        bytes32 _tikerExchange
    ) external {
        // array da usare
        Order[] storage orderSide = OrderBook[_tiker][1];
        // se nn ci sono ordini ci mandi indietro
        if (orderSide.length == 0) {
            revert("Order not present or this amount of coin");
        }
        // variabili per gestire l'rodine d'acquisto
        uint256 orderMArketLeft = _amount;
        uint256 orderMarketComplete = 0;

        // ciclo per pescare gli ordini nell array

        for (
            uint256 index = 0;
            index < orderSide.length && orderMArketLeft > 0;
            index++
        ) {
            // se l'rodine che peschiamo  non completa il nostro ordine rimanente
            if (orderSide[index].amount < orderMArketLeft) {
                // variabile che  ci da la differenza per aggiornare le variabili e inviare i soldi
                // aggiorniamo l'orderbook
                uint256 orderMarketPending = orderMArketLeft -
                    orderSide[index].amount;
                uint256 price = orderSide[index].price;
                // aggiornamenyo variabili per il prossimo ciclo
                orderMArketLeft -= orderMarketPending;
                orderMarketComplete += orderMarketPending;
                // trasferimento soldi dall user al wallet dell'order
                //------> PS deve prima approvare la spesa
                IERC20(TokenMapping[_tikerExchange].tokenAddress).transferFrom(
                    msg.sender,
                    address(this),
                    orderMarketPending * price
                );

                // aggiorniamo il bilancio del orderSeller
                orderSide[index].amount = 0;

                address OrderSeller = orderSide[index].Trader;
                balances[OrderSeller][_tikerExchange] +=
                    orderMarketPending *
                    price;
                //revert(" mi blocco qui al pimo if");
            } else if (orderSide[index].amount > orderMArketLeft) {
                // qua togliamo solo l'amount dall'ordine che rimane aperto comunque
                orderSide[index].amount -= orderMArketLeft;
                // riempiamo la variabile di completamento
                orderMarketComplete += orderMArketLeft;
                // operazioni di spostamento token
                uint256 price = orderSide[index].price;
                //------> PS deve prima approvare la spesa
                IERC20(TokenMapping[_tikerExchange].tokenAddress).transferFrom(
                    msg.sender,
                    address(this),
                    orderMArketLeft * price
                ); // aggiorniamo l'orderbook

                // aggiorniamo il bilancio del orderSeller
                address OrderSeller = orderSide[index].Trader;
                balances[OrderSeller][_tikerExchange] +=
                    orderMArketLeft *
                    price;
                //revert(" mi blocco qui al secondo if");
            }
        }

        while (orderSide.length > 0 && orderSide[0].amount == 0) {
            for (uint256 i = 0; i < orderSide.length - 1; i++) {
                orderSide[i] = orderSide[i + 1];
            }
            orderSide.pop();
        }
    }
}
1 Like

hey @HRMS2021. yeah so the problem is in your migrations

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

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

your variable name is called Migrations, the reason your getting the error saying that wallet is not defined is because you need to change Migrations to Wallet. so the fixed migrations is

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

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

let me know if this works

1 Like

hi @LELUK911. would you be able to explain a little more. what do you mean by testing in analytic mode. and also what is the error that your getting exactly. could you share a screenshot of the error please and i will be on standby to help

1 Like

thank for your help.

for analitik test , i would tell that i doing one transaction for one,

ā€“> here deposit 2 eth

-> this is order book sell WETH

-> one order 1 weth ā€¦

I hope you understand the problem.

the code function, but it dont work like i want