Crypto Currency News

Trending News

Bitcoin
$70,458.05
+264.16
Ethereum
$3,574.15
-11
Litecoin
$94.92
-2.78
DigitalCash
$38.42
+0.09
Monero
$137.06
-1.03
Nxt
$0.00
0
Ethereum Classic
$32.17
+0.4
Dogecoin
$0.22
+0.03

Uniswap 🔀 Testing | HackerNoon

Uniswap is a Decentralized Exchange, running on the Ethereum blockchain (Mainnet and a few more) We are going to focus on swapping between different tokens using forking forking. We will use the fork to test out the implementation of the UnisWap smart contract. The contract is designed to swap between different ERC-20 tokens and get back the tokens that the pair exchange allows traders to exchange with each other. In this article, we will use forking the mainnet to test our smart contract implementation. We are using the fork forking to test the implementation for the first time.

Pari Tomar HackerNoon profile picture

Paris Tomar

Exploring Blockchain to make a change

Uniswap Ethereum tests validate the behavior of your smart contract. They give you confidence that your code performs in the ways that you intend, and does not perform in the ways that it should not.

In the previous article, we learned about mainnet forking and played with Vitalik’s account using impersonate account.

Now we have decided to take this further and test out the Uniswap’s swap implementation. Yes! You heard it correct 😎

But before diving into it, let us understand more about Uniswap

Uniswap is a Decentralized Exchange, running on the Ethereum Blockchain (Mainnet and a few more). As the name suggests, Uniswap is used for Trading ERC20 tokens.

There are 3 main functionalities of Uniswap:

Swap between different tokensAdd liquidity to the market and get rewarded with pair exchange ERC-20 liquid tokensBurn ERC-20 liquid tokens and get back the ERC-20 tokens that the pair exchange allows traders to exchange

In this article, we are going to focus on swapping between different tokens using forking.

NOTE: We recommend you go through the previous part of this article first and then follow along with this article to get a better grip on what’s happening.

So let’s get started! 🥳🥳

1. Create a Project and Initialize It

Use the following commands on your CLI to initialize your project.

mkdir uni_swap && CD uni_swap
npm init -y

Install the required dependencies for the project, run

nm install –save hardhat @nomiclabs/hardhat-ethers @nomiclabs/hardhat-waffle ethers @uniswap/v2-core dotenv

2. Initialize Your Hardhat Project

To initialize your hardhat project, run npx hardhat command in your CLI, and create an empty config.js file.

Customize your hardhat config:

Because we are going to fork the mainnet to test the Uniswap. Therefore, your hardhat config should look something similar to this:

image

Note: Replace the component of the URL with your personal Alchemy API key.

3. Write the smart contract for swap

Create directories for contracts, scripts, and tests for better code organization.

Use the following code in your CLI.

mkdir contracts && mkdir scripts && mkdir tests

In order to write the swap contract, create a file inside the contracts directory and name it testSwap.sol

For the purpose of our contract, we need to include an interface: Uniswap, to use their functions

Writing the smart contract:

Import the interfaces inside your testSwap.sol and create a contract named testSwap

It should look like this:

image

Now, inside testSwap, we need to include the address of the Uniswap routers. It is required for us to do the trade between the tokens.

Use the following code:

//address of the uniswap v2 router
address private constant UNISWAP_V2_ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;

Now, define the function we are going to use for swapping:

// swap function
functions swap(
address _tokenIn,
address _tokenOut,
uint256 _amountIn,
address _to,
uint256 _deadline
) external {
}

We have named our function as swap, inside that we have

  • _tokenIn is the address of the token that we are trading in for
  • _tokenOut is the address of the token we want out of this trade
  • _amountIn is the amount of tokens we are trading
  • _to is the address where we are sending the output token and
  • _deadline is the time during which the transaction should be executed. The transaction will be expired if the deadline time exceeds.

Inside the swap function, the first thing that we’re going to do is transfer the _tokenIn address’ amount inside the contract, using msg.sender.

// transfer the amount in tokens from msg.sender to this contract
IERC20(_tokenIn).transferFrom(msg.Channel, address(this)_amountIn);

Once this is called, the _tokenIn address would have the amount present inside _amountIn.

Next, by calling IERC20 approve you allow the Uniswap contract to spend the _amountIn tokens in this contract

//by calling IERC20 approve you allow the uniswap contract to spend the tokens in this contract
IERC20(_tokenIn).approve(UNISWAP_V2_ROUTER, _amountIn);

Now, one of the parameters we need to call for swapping the tokens is path.

So, we will declare an array of addresses named path.

Address of _tokenIn and the address of _tokenOut.

address[] memory path;
path = newaddress[](2);
path[0] = _tokenIn; // DAI
path[1] = _tokenOut; // WETH

Next, we will call the function getAmountsOut, which is useful for calculating the amount of tokens we should be expecting on doing a swap. It takes an input amount and an array of token addresses. The array, as you would have guessed it, is the path that we have defined above.

uint256[] memory amountsExpected = IUniswapV2Router(UNISWAP_V2_ROUTER).getAmountsOut(
_amountIn, path
);

Then finally, we are going to call the function swapExactTokensforTokens on Uniswap Router, and pass in the parameters.

uint256[] memory amountsReceived = IUniswapV2Router(UNISWAP_V2_ROUTER).swapExactTokensForTokens(
amountsExpected[0],
(amountsExpected[1]*990)/1000, // accepting a slippage of 1%
path, _to, _deadline );

CONGRATULATIONS! Our contract is ready. 🎉

It should look something similar to this: 👇

image

Use the command npx hardhat compile to check for any error in our smart contract.

Now, it’s time ⌛ to run some tests for our contract!

4. Time for Writing the Test Script

Create a file inside tests folder and name it sample-test.js.

First, we are going to import the ERC20 contract’s abi from Uniswap.

Also, define the structure of the test that we’re going to use with the addresses of the contracts that we’re going to use.

const ERC20ABI = require(“@uniswap/v2-core/build/ERC20.json”).abi;
describe(“Test Swap”, function () {
const DAIAddress = “0x6B175474E89094C44Da98b954EedeAC495271d0F”;
const WETHAddress = “0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2”;
const MyAddress = “0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B”;
const DAI Holder = “0x5d38b4e4783e34e2301a2a36c39a03c45798c4dd”;
}

Here, we have used 4 addresses:

  • DAIAddress other WETHAddress are the addresses for Dai Contract and WETH Contract, respectively, which will be used in the trading
  • MyAddress is the address in which the amount will be traded
  • DAI Holder is the address which we are going to impersonate.

Now, before writing the test script, we will deploy the testSwap smart contract. For that we have the following code:

let TestSwapContract;
beforeEach(async () => {
const TestSwapFactory = wait ethers.getContractFactory(“testSwap”);
TestSwapContract = wait TestSwapFactory.deploy();
wait TestSwapContract.deployed();
})
beforeEach(async () => {
const TestSwapFactory = wait ethers.getContractFactory(“testSwap”);
TestSwapContract = wait TestSwapFactory.deploy();
wait TestSwapContract.deployed();
})

Create a structure for the test script. And impersonate the DAI Holder address which we have defined earlier.

it(“should swap”, async () => {
wait hre.network.provider.request({
method: “hardhat_impersonateAccount”,
params: [DAIHolder],
});
const impersonateSigner = wait ethers.getSigner(DAIHolder);

In the next step, we will get the initial balance of DAI token by using the impersonated account. Later, we will swap the total balance present at the address.

Similarly, we will also get the balance of the WETH tokento observe the swapping of the tokens.

const DAIContract = new ethers.Contract(DAIAddress, ERC20ABI, impersonateSigner)
const DAIHolderBalance = wait DAIContract.balanceOf(impersonateSigner.address)
const WETHContract = new ethers.Contract(WETHAddress, ERC20ABI, impersonateSigner)
const myBalance = wait WETHContract.balanceOf(MyAddress);
console.log(“Initial WETH Balance:”ethers.utils.formatUnits(myBalance.toString()));

Then, we will use the DAI contract to approve the swap of the total balance present in it.

wait DAIContract.approve(TestSwapContract.address, DAIHolderBalance)

For the deadline, we will use the current timestamp of the block.

// getting current timestamp
const latestBlock = wait ethers.provider.getBlockNumber();
const time stamp = (wait ethers.provider.getBlock(latestBlock)).timestamp;

We will do the trade by calling the swap function that we wrote. Passing in the parameters that we have configured above.

And this transaction will be sent from the DAI Holder.

wait TestSwapContract.connect(impersonateSigner).swap(
DAIAddress, WETHAddress, DAIHolderBalance, MyAddress,
time stamp + 1000 // adding 100 milliseconds to the current blocktime
)

Finally, it’s time to test the swap transaction! 😬

const myBalance_updated = wait WETHContract.balanceOf(MyAddress);
console.log(“Balance after Swap:”ethers.utils.formatUnits(myBalance_updated.toString()));
const DAIHolderBalance_updated = wait DAIContract.balanceOf(impersonateSigner.address);

Here, we have first checked the balance of our account after the execution of the swap function.

Below this, we have written some tests to check whether the transaction was true or not!

expect(DAIHolderBalance_updated.eq(BigNumber.from(0))).to.be.true
expect(myBalance_updated.gt(myBalance)).to.be.true;

Since we have swapped the total balance, therefore in the first test we expect the balance of DAI address should be equal to 0 In the second test, we are checking whether the balance in our account is now greater than earlier or not.

Therefore, these are the two tests we are going to run.

The sample-test.js should look similar to the following. It is critical you note the require statements at the start of the file.

image

Of course, feel free to explore and try out more tests with them.

For now, we are going to run these tests using the command npx hardhat test

The results should look like this:

image

As you can see, our initial balance has increased after the swapping is done.

And the test we wrote came out successful!!! 🎉🎉🎉

If you have followed along till the end then congratulations, you have done great.

Follow us on Twitter if you liked our content.

Authors (open to feedback): 👇

Amateur Dev and Pari Tomar

Welcome To The Web3 Writing Contest

tags

Related Stories

Towards a Divine Understanding of Web3: The Death of Corporate CommercialismWhat is the Difference Between Miner Extractable Value and Maximal Extractable ValueExplore What it Means to Build Online Communities in the Age of Web3 What is the Impact of Quantum Computing on Blockchain and Cryptocurrency?When a Stablecoin Isn’t So Stable, Terra and the Crash of UST

Comments are closed.