Create a swap function of tokens using solidity without using uniswap ( swap with rate btw)

2.8k Views Asked by At

I am newbie to this field, and just learning some courses online about solidity and creating a simple contract, I would like to ask about a simple project that I try but not successful yet. I want to create a swap function that can swap between 2 tokens that I created from ERC20, WITHOUT using uniswap or something like that, just dev a new function that swap between token A and token B, for example with the rate of 1 token A = 3 token B, the rate was ask to save in a mapping and got config at first, but I dont really know how to setting up the rate for swapping. Could anyone help me out with this, many thanks guys.

Existed Code of Swap contract, just temporary :

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

import "./Token.sol";
import "./safemath.sol";

contract SwapToken {
    using SafeMath for uint;

    Token public token1;
    address public owner1;
    Token public token2;
    address public owner2;
    uint public amount1;
    uint public amount2;
    uint public swapRate;

    constructor(
        address _token1,
        address _owner1,
        address _token2,
        address _owner2,
        uint _amount1
    ) {
        token1 = Token(_token1);
        owner1 = _owner1;
        token2 = Token(_token2);
        owner2 = _owner2;
        swapRate = 3;
        amount1 = _amount1;
        amount2 = _amount1.mul(swapRate);
    }

    function swap() public {
        require(msg.sender == owner1 || msg.sender == owner2, "Not authorized from owners");
        require(
            token1.allowance(owner1, address(this)) >= amount1,
            "Token 1 allowance too low"
        );
        require(
            token2.allowance(owner2, address(this)) >= amount2,
            "Token 2 allowance too low"
        );

        _safeTransferFrom(token1, owner1, owner2, amount1);
        _safeTransferFrom(token2, owner2, owner1, amount2);
    }

    function _safeTransferFrom(
        Token token,
        address sender,
        address recipient,
        uint amount
    ) private {
        bool sent = token.transferFrom(sender, recipient, amount);
        require(sent, "Token transfer failed");
    }
}
2

There are 2 best solutions below

4
On

Let's start with a general answer and we'll build on it as we understand the question better.

I think you are not trying to create a swapping solution with a liquidity pool, but instead, want to match 2 people(?) that want to swap tokens.

A very simplistic approach to it could be

// have a mapping, as your tutor said. This will store information about how a token (token's contract address) and another token (again, contract address) rate against each other.
mapping(address => mapping (address => uint256)) rates;

function setRating(address memory token1, address memory token2, uint256 rate) public {
     rates[token1][token2] = rate;
}

Then, while swapping, check the rate and calculate accordingly.

0
On
// you need to pass which token to swap and how much swap
function swap(address tokenIn, uint amountIn) public {
    // you want only either of two owners call
    require(
        msg.sender == owner1 || msg.sender == owner2,
        "Not authorized from owners"
    );
    require(
        token1.allowance(owner1, address(this)) >= amount1,
        "Token 1 allowance too low"
    );
    require(
        token2.allowance(owner2, address(this)) >= amount2,
        "Token 2 allowance too low"
    );
    // you need to require tokenIn is only token1 or token2 that you store in storage
    require(
        tokenIn == address(token1) || tokenIn == address(token2),
        "Invalid token"
    );
    // make sure you pass positive amount
    require(_amountIn > 0, "invalid amount");
    // define token1 and token2 based on function arg tokenIn
    bool isToken1 = tokenIn == address(token1);
    (   // you are using Token as type instead of IERC20
        Token tokenIn,
        Token tokenOut,
        // reserve1 and reserve2 how many each tokens holds. you should be setting in state
        uint reserve1,
        uint reserve2
    ) = isToken1
            ? (token1, token2, reserve1, reserve2)
            : (token2, token1, reserve2, reserve1);
    // instead token1, tokenIn should be transferred
    // I believe this is what it does
    _safeTransferFrom(tokenIn, owner1, owner2, amount1);
    // calculate the tokenOut including the fee=0.3%. user who wants to swap has to pay for fee
    uint amountInAfterFee = (_amountIn * 997) / 1000;
    // here you need to calculate how much y token will be taken out
    // this is the formula dy=(y*dx)/(x+dx) y and x are reserves, dx is amountInAfterFee
     amountOut =
        (reserve2 * amountInAfterFee) /
        (reserve1 + amountInAfterFee);
    // now you need to send this amountOut to tokenOut or token2 in your contract
    token2.transfer(msg.sender,amountOut)
    // here update the reserves

    // I dont think that you need this
    // _safeTransferFrom(token2, owner2, owner1, amount2);
}