Project - Building a DEX

problem is not with your migrations. You dont have a depositEth function in your code so thats why its failing. its not that your tests are not correct in terms of logic is that youu actuually dont have a “deposiitETH” to call which you should code yourself

yo aslos have a type error “truffleAsset” should be “truffleAssert”. Things like that will help you

1 Like

Having an issue in the terminal running functions:

Uncaught TypeError: wallet.addToken is not a function
    at evalmachine.<anonymous>:0:8
    at sigintHandlersWrap (vm.js:273:12)
    at Script.runInContext (vm.js:142:14)
    at runScript (C:\Users\alex\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\core\lib\console.js:364:1)
    at Console.interpret (C:\Users\alex\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\core\lib\console.js:379:1)
    at bound (domain.js:416:15)
    at REPLServer.runBound [as eval] (domain.js:427:12)
    at REPLServer.onLine (repl.js:821:10)
    at REPLServer.emit (events.js:400:28)
    at REPLServer.emit (domain.js:470:12)

I have defined ‘wallet’ so there should be no issue, but every function isn’t executable, what is the issue? I have included my Wallet.sol file if that needs to be checked, but it compiles properly so there should be no issue.

Wallet.sol

// SPDX-License-Identifier: UNLICENSED

pragma solidity ^0.8.0;

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

contract Wallet is Ownable {

    using SafeMath for uint;

    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 onlyOwner {
        require(tokenAddress != address(0), "Unable to list token");
        tokenMapping[ticker] = Token(ticker, tokenAddress);
        tokenList.push(ticker);
    }

    function deposit(uint amount, bytes32 ticker) external {
        require(tokenMapping[ticker].tokenAddress != address(0), "Token not listed");
        require(IERC20(tokenMapping[ticker].tokenAddress).balanceOf(msg.sender) >= amount, "Insufficient token balance");

        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), "Token not listed");
        require(balances[msg.sender][ticker] >= amount, "Insufficient token balance");

        balances[msg.sender][ticker] = balances[msg.sender][ticker].sub(amount);
        IERC20(tokenMapping[ticker].tokenAddress).transfer(msg.sender, amount);
    }
}

1 Like

ok there is little to go off of here but what you should do is:

1 makea wallet migrauinss file

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

module.exports = function (deployer) {
  deployer.deployWallet);

};

next compile the code

truffle migrate --reset

then declare your contract instance

let wallet = await Wallet.deployed()

lastly no you can call functions. These steps shoud work follow them exacty

1 Like

My migrations file is identical, I have reset migrations in the terminal and have declared the instance, would reinstalling Truffle be the option here?

EDIT: Force reinstalling Truffle worked, thanks for your reply anyway. :+1:

1 Like

In the “Better Migration” lesson, when I migrate 3_token_migration.js, I get this error:

Error: invalid address (argument="address", value=undefined, code=INVALID_ARGUMENT, version=address/5.0.5) (argument="spender", value=undefined, code=INVALID_ARGUMENT, version=abi/5.0.7)
    at module.exports (C:\Users\daniel\ivan\ethereum-201\dex\migrations\3_token_migration.js:8:14)
    at process._tickCallback (internal/process/next_tick.js:68:7)

My code is identical to Fillip’s! It doesn’t seem to like “address” in “wallet.address” and “link.address”.
I tried “wallet.spender” too but it doesn’t work.

Similarly, in the “Creating wallet tests” lesson, the result of running “truffle test” includes this:

Error: invalid address (argument="address", value=undefined, code=INVALID_ARGUMENT, version=address/5.0.5) (argument="spender", value=undefined, code=INVALID_ARGUMENT, version=abi/5.0.7)
    at module.exports (C:\Users\daniel\ivan\ethereum-201\dex\migrations\3_token_migration.js:8:14)
    at process._tickCallback (internal/process/next_tick.js:68:7)
UnhandledRejections detected
Promise {
  <rejected> Error: Dex has not been deployed to detected network (network/artifact mismatch)
      at Object.checkNetworkArtifactMatch (C:\Users\daniel\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\contract\lib\utils\index.js:247:1)
      at Function.deployed (C:\Users\daniel\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\contract\lib\contract\constructorMethods.js:83:1)
      at process._tickCallback (internal/process/next_tick.js:68:7) } Error: Dex has not been deployed to detected network (network/artifact mismatch)
    at Object.checkNetworkArtifactMatch (C:\Users\daniel\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\contract\lib\utils\index.js:247:1)
    at Function.deployed (C:\Users\daniel\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\contract\lib\contract\constructorMethods.js:83:1)
    at process._tickCallback (internal/process/next_tick.js:68:7)
1 Like

Hey @tenbad, hope you are well.

Please share your code in the following way so I can help you review the issue :face_with_monocle:

Carlos Z

hey @tenbad. from your error message above the problem seems to be with you dex migrations as the error says “Dex has not been deployed to the detected network”. So share your wallet migration file there is probably something wrong here. It would be easier for carlos to debug also by pushing your whole code to github its easier to see all pieces of your code in order to debug.

For now just post all your migration files

Having problems with truffle. Whenever I try to run it today, I get this:

"truffle : File C:\Users\daniel\AppData\Roaming\npm\truffle.ps1 cannot be loaded because running scripts is disabled on this 
system. For more information, see about_Execution_Policies at https:/go.microsoft.com/fwlink/?LinkID=135170.
At line:1 char:1
+ truffle develop
+ ~~~~~~~
    + CategoryInfo          : SecurityError: (:) [], PSSecurityException
    + FullyQualifiedErrorId : UnauthorizedAccess"

Anyone know what I can do about this to be able to run Truffle?

1 Like

Hey @tenbad, hope you are well.

Try to use CMD (windows prompt) instead powershell, according to the error message, you are not allowed to run scripts on powershell, you could also investigate how to activate it, but is easier to just use CMD to run this scripts.

Carlos Z

1 Like

Check your DM I need help:)!!

I’ve been playing around with truffle like in the third video “Finishing Wallet”.
I deposited LINK in my wallet twice and whenever I check my balances in the terminal I get :

truffle(develop)> wallet.balances(accounts[0], web3.utils.fromUtf8(“LINK”))

BN { negative: 0, words: [ 0, <1 empty item> ], length: 1, red: null }

Seems to me there is 0 Link in my wallet, any idea why? I did the exact same steps as Filip in the video…

You might just need to add the await keyword at the start of the call :nerd_face:

Carlos Z

Hello! Would appreciate for help!

When I try to run:
await wallet.balances(accounts[0], web3.utils.fromUtf8("LINK"))

I get this error message:
(Uncaught TypeError: wallet.balances is not a function)

image

3_token_migration.js file:

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.sol file:

// 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;


    /*
    event depositDone(uint amount, address indexed depositedTo);
    */


    struct Token{
        bytes32 ticker;
        address tokenAddress; 
// we need tokenAddress in order to be able to call the token contract.
    }
// struct Token stores information about the tokens that this contract and wallet support.

   

    mapping(bytes32 => Token) public tokenMapping;
// a mapping that points from bytes32 (token ticker) to the struct object (struct Token).


    bytes32[] public tokenList; 
// here we will have all of the tickers, like id's for ERC20 tokens. 


    mapping(address => mapping(bytes32 => uint256)) public  balances; 
// mapping of addresses that hold multiple ERC20 tokens, bytes32 represents a ticker(tokenId) 
// of a ERC20 token.

    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);
// we save a new token that we save to our tokenMapping.
        tokenList.push(ticker);
// we only add a ticker of a new token to the tokenList, in order to have a list of all token id's.
    }





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


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


    /*
        require(tokenMapping[ticker].tokenAddress != address(0));
// we check so that token exists, so that tokenAddress is not a 0 address.
// we add a modifier tokenExist instead of the require statement.
    */


        require(balances[msg.sender][ticker] >= amount, "Balance not sufficient");
// check that you have the actual balance before withdrawal.
        
        balances[msg.sender][ticker] = balances[msg.sender][ticker].sub(amount);
// to adjust the balances, balance of msg.sender is substracted the amount. Add SafeMath for .sub().

        IERC20(tokenMapping[ticker].tokenAddress).transfer(msg.sender, amount);
// we input tokenAddress and we do transfer call from this contract to msg.sender.


    }
}

Best regards :slight_smile:

1 Like

Hey @Dominykas_Pozleviciu, hope you are well.

The problem is that you can’t access a mapping on that way in truffle, easiest way is to create a getter function, like:

function getBalances(address _toSearch, bytes32 _token) public view (returns uint){
return balances[_toSearch][_token];
}

Carlos Z

1 Like

How did you fix this?

I am working on the first lesson “Building a Wallet”. Filip provided an example of code for a withdraw function:

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

He kind of really quickly went through the interface line of the code (see below) and I don’t quite understand it. I mean, I get that it interacts with the IERC20 contract in Open Zeppelin, but could you please provide a bit more detailed explanation of how it works? I’m confused. thanks!

IERC20(tokenMapping[ticker].tokenAddress).transfer(msg.sender, amount);

Hey @CaliCrypto22, hope you are well.

The IERC20 is related to the standard interface functions for a ERC20 contract.
Check here: https://docs.openzeppelin.com/contracts/4.x/api/token/erc20#IERC20

So basically, using tokenMapping (which is the mapping to store the address of each token, like USDT, based on its bytes32 value of the ticker), filip invoke the transfer function using the interface and the address of a existing contract (a token, like usdt or dai for example).

So what the withdraw function does with that code line at the end, is to transfer an amount of the tokenMapping[ticker].tokenAddress contract (using the IERC20) from that contract to msg.sender.

Like transferring USDT from me to you, but using the IERC20, a contract is capable of interact with other ERC20 contracts. So basically with Interfaces you allow external contracts to interact with yours.

(If you for example want to add Uniswap functionality to your DEX, you will have to learn how to use their interface :nerd_face: )

Hope i explained my self clear, if not, let me know

Carlos Z

1 Like

Thanks! I think I understand better now.

image

I am having this error many times when I compile on this and previous assignments. Solved it by modifying “unchecked”, but this time I probably should leave it there since it is a bigger assignment. Any idea how to solve this “unchecked” thing?

1 Like

u seem to be using an older version of the safemath contract

1 Like