> ## Documentation Index
> Fetch the complete documentation index at: https://docs-hosting.axiomesh.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Build Dapps

This guide will introduce how to set up development tools on MacOS and develop Dapps on AxiomLedger. Here, we'll use the well-known decentralized exchange [Uniswap@V2](https://uniswap.org/) as an example.

Please familiarize yourself with the basic concepts of [Uniswap](https://docs.uniswap.org/) before using the following tutorial for project deployment and experience!

The following steps will take the Aries testnet as an example. If you want to try it on the mainnet or other testnets, you can view related resources on the [Resources](/en/documentation/getting-started/resources/resources) page.

## Development Environment Configuration

First, you need to install some necessary development tools, including Git, NodeJs, etc.

### Install Homebrew

Homebrew is a package manager for MacOS that can help us easily install and manage software. Install Homebrew:

```shell theme={null}
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

### Install Git

Install Git by Homebrew:

```shell theme={null}
brew install git
git --version
```

### Install NVM

Install NVM by curl or wget. Here we provide the curl command:

```shell theme={null}
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash
```

After installing NVM, close and reopen the Terminal, or run the following command to enable NVM:

```shell theme={null}
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
nvm --version
```

### Install Node.js

Install  `Node.js v20` and `Node.js v16` using NVM. Later, you may need to use different Node versions to deploy different `Uniswap` components.

```shell theme={null}
nvm install 16
nvm install 20
node --version
```

## Retrieve Uniswap\@V2 Source Code

Since `Uniswap v2` requires multiple components, you need to retrieve them in sequence from the official repository to form the following package structure:

```text theme={null}
Uniswap-v2
  default-token-list
  interface-2.6.5
  uniswap-contract
    contract
      lib
      v2-core
      v2-periphery
  uniswap-sdk
```

We've already organized the complete project code for you, which can be obtained from the [test repository](https://github.com/axiomesh/embrace/tree/main). The command is:

```shell theme={null}
git clone https://github.com/axiomesh/embrace.git
```

## Deploy Uniswap\@V2 Contract

### Init Hardhat

Initialize the Hardhat project under the uniswap-contract package and clone the relevant contract files from the official repository according to the package format mentioned above. If you are using our test repo, please route to the right package and run below code:

```shell theme={null}
cd embrace/dapps/dexes/uniswap-v2/uniswap-contract
npm install
npx hardhat
```

At this point, you need to modify the `networks` field in the Hardhat configuration file to fit your network.

The account private key is used for deploying contracts on the chain. It can be safely used by setting it as an environment variable. Use the command `export YOUR_PRIVATE_KEY = 'YOUR_PRIVATE_KEY'` to write it to the environment variable. Use the `Aries` testnet as an example, the `Hardhat config` is as follows:

```typescript theme={null}
const config: HardhatUserConfig = {
  defaultNetwork: "aries",
  networks: {
    aries: {
      url: "https://rpc4.aries.axiomesh.io",
      accounts: [
        "YOUR_PRIVATE_KEY", // please config your private key through safe ways
      ]
    },
  },
};
```

### Write Contract Deployment Scripts

Write the contract deployment script in the scripts package.

Here is the deployment script for the core contract of Uniswap\@V2 that we have prepared for you. You can find the corresponding file named `deployUniswapV2.js` in the test repository.

```javascript theme={null}
const {ethers} = require("hardhat");

async function main() {

    // step 1 factory
    const [owner] = await ethers.getSigners();
    console.log("owner address:", owner.address)
    const UniswapV2Factory = await ethers.getContractFactory("UniswapV2Factory");
    uniswapV2Factory = await UniswapV2Factory.deploy(owner.address);
    console.log(`FACTORY_ADDR: ${uniswapV2Factory.target}`);
    const factoryAddr = uniswapV2Factory.target;
    await sleep(1000);
    const initCodePairHash = await uniswapV2Factory.INIT_CODE_PAIR_HASH();
    console.log("INIT_CODE_PAIR_HASH:", initCodePairHash);

    // step 2 router2
    const WETH9 = await ethers.getContractFactory("WETH9");
    weth9 = await WETH9.deploy();
    console.log(`WETH_ADDR: ${weth9.target}`);

    const weth9Addr = weth9.target
    const UniswapV2Router02 = await ethers.getContractFactory("UniswapV2Router02");
    router = await UniswapV2Router02.deploy(factoryAddr, weth9Addr);
    console.log(`Router02_ADDR: ${router.target}`);

    // step 3 router1
    const UniswapV2Router01 = await ethers.getContractFactory("UniswapV2Router01");
    router1 = await UniswapV2Router01.deploy(factoryAddr, weth9Addr);
    console.log(`Router01_ADDR: ${router1.target}`);

    // step 4 multicall
    const MulticallForUni = await ethers.getContractFactory("MulticallForUni");
    multicall = await MulticallForUni.deploy();
    console.log(`MULTICALL_ADDR: ${multicall.target}`);

}

main().catch((error) => {
    console.error(error);
    process.exitCode = 1;
});

async function sleep(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms));
}
```

Write the token deployment script in the scripts package.

Here is the token contract deployment script that we have prepared for you. You can find the corresponding file named `deployUniswapTokens.js` in the test repository.

```javascript theme={null}
const {ethers} = require("hardhat");

async function main() {
    //get the account where the contract is deployed
    const [owner] = await ethers.getSigners();
    console.log(`owner address is ${owner.address}`)

    const mintAmount = ethers.getUint("1000000000000000000000000"); // 1000000 10^18

    const AxmToken1 = await ethers.getContractFactory("AxiomToken")
    const axmToken1 = await AxmToken1.deploy("AxiomToken1", "AX1", mintAmount)
    const axmToken2 = await AxmToken1.deploy("AxiomToken2", "AX2", mintAmount)
    const axmToken3 = await AxmToken1.deploy("AxiomToken3", "AX3", mintAmount)
    console.log(`AXMTOKEN1_ADDR: ${axmToken1.target}`);
    console.log(`AXMTOKEN2_ADDR: ${axmToken2.target}`);
    console.log(`AXMTOKEN3_ADDR: ${axmToken3.target}`);
}

main().catch((error) => {
    console.error(error);
    process.exitCode = 1;
});
```

```Solidity theme={null}
contract AxiomToken is ERC20 {
    constructor(string memory _name, string memory _symbol, uint _totalSupply) ERC20(_name, _symbol) {
        if (_totalSupply > 0) {
            _mint(msg.sender, _totalSupply);
        }
    }

    // mint
    function mint(address recipient, uint256 amount) public {
        _mint(recipient, amount);
    }

    // burn
    function burn(address from, uint256 amount) public {
        _burn(from, amount);
    }
}
```

### Deploy Contracts & Record Contract Address

Run the following command to deploy the contracts to the corresponding network. Here, we'll deploy the contracts to the `Aries` testnet as an example.

<Warning>Please note: The first account configured in the hardhat network will be used as the deployment account. You need to ensure that this account has sufficient tokens. For information on how to obtain tokens from the faucet for testing, please refer to the [Resources](/en/documentation/getting-started/resources/resources).</Warning>

```shell theme={null}
npx hardhat run scripts/deployUniswapV2.js --network aries
npx hardhat run scripts/deployUniswapTokens.js --network aries
```

After running the relevant deployment scripts, we can obtain the relevant Uniswap\@V2 contract addresses。After running the relevant ERC20 token deployment script, we can obtain the associated Token contract addresses:

After running the `contract deployment script` and the `ERC20 token deployment script`, you will obtain the `Uniswap@V2 contract address` as well as the `Token contract address`. These addresses will be used in the next steps.

```text theme={null}
OWNER_ADDR
INIT_CODE_PAIR_HASH

FACTORY_ADDR
WETH_ADDR
ROUTER02_ADDR
ROUTER01_ADDR
MULTICALL_ADDR

AXMTOKEN1_ADDR
AXMTOKEN2_ADDR
AXMTOKEN3_ADDR
```

### Usage

After deploying the aforementioned contracts, you can obtain the contract deployment addresses. These addresses are used to modify hardcoded values in subsequent frontend project, ensuring the smooth deployment of the frontend project.

<Warning>The `INIT_CODE_PAIR_HASH` in the aforementioned contract is actually the hash value of the creationCode of the `UniswapV2Pair` contract. You need to manually modify the following code block. But if you are using our test repository, this part of the modification has already been completed.</Warning>

```solidity theme={null}
function pairFor(address factory, address tokenA, address tokenB) internal pure returns (address pair) {
    (address token0, address token1) = sortTokens(tokenA, tokenB);
    pair = address(uint(keccak256(abi.encodePacked(
            hex'ff',
            factory,
            keccak256(abi.encodePacked(token0, token1)),
            hex'INIT_CODE_PAIR_HASH' // using INIT_CODE_PAIR_HASH produced by deploying contract
        ))));
}
```

## Deploy Interface

Now, let's modify the relevant configurations of the frontend project to locally deploy the `Uniswap@V2` frontend poroject `Interface-2.6.5`.

### Modify Uniswap-SDK

Retrieve the source code basing on the SDK version that the frontend depends on. You need to make some modifications. If you are using our test repository, the related source code has already been integrated in the [test repository](https://github.com/axiomesh/embrace/tree/main/dapps/dexes/uniswap-v2/uniswap-sdk).

```
"@uniswap/sdk": "3.0.3",
```

Enter the uniswap-sdk directory, use nvm to switch the Node.js version to `16.13.2`. Then execute the following command:

```shell theme={null}
cd embrace/dapps/dexes/uniswap-v2/uniswap-sdk
nvm install 16
yarn install
```

#### Modify Network

Since currently Uniswap only supports the Ethereum mainnet and its testnets you need to modify the `ChainId[TESTNET]` in `src/constants.ts` to your desired `chain ID`. Here, we'll take the `AxiomLedger` testnet `Aries` as an example, and you can change the chain ID to `23411`.

```typescript theme={null}
export enum ChainId {
  MAINNET = 65524,
  TESTNET = 23411,
}
```

#### Modify Contract Address

Make necessary changes to `src/constant.ts` based on the factory contract deployed earlier:

```typescript theme={null}
export const FACTORY_ADDRESS = 'FACTORY_ADDR' // using FACTORY_ADDR produced by deploying contract
export const INIT_CODE_HASH = 'INIT_CODE_PAIR_HASH' // using INIT_CODE_PAIR_HASH produced by deploying contract
```

#### Modify WETH Address

Now, modify the contract address corresponding to `src/entities/token.ts`.

Deploy the `WETH` contract on the testnet. Earlier, you've already deployed the `WETH Token` contract on the chain, enter the address into the `WETH_ADDR` in the following code:

```typescript theme={null}
export const WETH = {
  [ChainId.MAINNET]: new Token(ChainId.MAINNET, '0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6', 18, 'WETH', 'Wrapped Ether'),
  [ChainId.TESTNET]: new Token(ChainId.TESTNET, 'WETH_ADDR', 18, 'WETH', 'Wrapped Ether')
}
```

#### Build SDK

Invoke the command under the SDK package in `package.json` to build SDK, or enter the following command in the corresponding package's command line:

```shell theme={null}
cd embrace/dapps/dexes/uniswap-v2/uniswap-sdk
npx tsdx build
```

At this point, a new artifact has produced. You can used it wherever the SDK is needed.

### Default-token-list Modification

Retrieve the source code based on the `default-token-list` version that the frontend depends on, which requires some modifications. If you are using our test repository, the related source code has already been integrated in the [test repository](https://github.com/axiomesh/embrace/tree/main/dapps/dexes/uniswap-v2/default-token-list).

This library will help you generate the relevant [token-lists](https://blog.uniswap.org/token-lists).

Find the corresponding package and manually modify it according to the following format. Since `WETH` is the required contract for `Uniswap@V2`, you need to modify the `address` and `chainId` to your configuration after deployment.

Using `src/tokens/testnet.json` as an example, please fill in the corresponding fields with the `WETH_ADDR`, `AXMTOKEN1_ADDR`, etc., produced after deploying the token contract as mentioned above. The `logoURI` of the test token can be customized. Take `Aries testnet` as an example, you can modify the `chainId` to `23411`.

For other tokens, please read the [token list description](https://blog.uniswap.org/token-lists) and fill in accordingly.

```json theme={null}
[
  {
    "name": "Wrapped Ether",
    "address": "WETH_ADDR",
    "symbol": "WETH",
    "decimals": 18,
    "chainId": 23411,
    "logoURI": "WETH_URL"
  },
  {
    "name": "AxmToken1",
    "address": "AXMTOKEN1_ADDR",
    "symbol": "AX1",
    "decimals": 18,
    "chainId": 23411,
    "logoURI": "AXMTOKEN1_URL"
  },
  //...
]
```

Execute the following command in the current package to construct `uniswap-default.tokenlist.json`, which can be configured and used in the frontend. For instance, see the file in the test repository: `uniswap-v2/interface-2.6.5/src/constants/lists.ts`.

```shell theme={null}
cd embrace/dapps/dexes/uniswap-v2/default-token-list
npm install
npx rimraf build && mkdir -p build && node src/write.js > build/uniswap-default.tokenlist.json
```

This token list can be used in the Uniswap\@V2 frontend project, allowing the frontend to quickly link to the relevant tokens already deployed on the chain. This is convenient for users to view the balances of various tokens, facilitating the swift establishment of liquidity pools.

### Modify Interface

Next is the deployment and construction of the Uniswap\@V2 frontend repository.

Retrieve source code from Uniswap's official repository and switch to `tag 2.6.5`. Of course, our test project has already deployed the related [source code](https://github.com/axiomesh/embrace/tree/main/dapps/dexes/uniswap-v2/interface-2.6.5) for you.

#### Modify Contract Address

First, modify the `ROUTER_ADDRESS` contract address in `src/constants/index.ts`:

```typescript theme={null}
export const ROUTER_ADDRESS = 'ROUTER02_ADDRESS' // using ROUTER02_ADDRESS produced by deploying contract
```

Then modify the multi-signature contract address `MULTICALL_ADDR` in `src/constants/multicall/index.ts`:

```typescript theme={null}
const MULTICALL_NETWORKS: { [chainId in ChainId]: string } = {
  [ChainId.MAINNET]: 'MAINNET_MULTICALL_ADDR',
  [ChainId.TESTNET]: 'MULTICALL_ADDR' // using MULTICALL_ADDR produced by deploying contract
}
```

#### Modify Dependencies and Configurations

Modify the dependency package:

```json theme={null}
"@uniswap/default-token-list": "../default-token-list",
"@uniswap/sdk": "../uniswap-sdk",
```

Adjust the environment configuration. Taking `AxiomLedger` `Aries` testnet as an example, modify the corresponding entries in the `.env` and `.env.production`files to the following values:

```text theme={null}
REACT_APP_CHAIN_ID="23411"
REACT_APP_NETWORK_URL="https://rpc4.aries.axiomesh.io"
```

#### Build and Launch

After making the necessary modifications, execute the following commands to start the Interface frontend locally: (**using Node\@16**)

```shell theme={null}
cd embrace/dapps/dexes/uniswap-v2/Interface
yarn install
npx react-scripts build
npx react-scripts start
```

Now you can experience Uniswap\@V2 built on `AxiomLedger` `Aries` testnet.

## Miscellaneous - Build by Remix

Using `Remix` to build Dapps on `AxiomLedger` is a more convenient choice,  for instance, deploying the `Uniswap@v2`.

Import the factory contract and the routing contract into `Remix`, and select the appropriate Solidity version in the compiler.

During the deployment phase, selecting `ENVIRONMENT` as `Injected Provider - MetaMask` allows for easy connection and deployment to AxiomLedger via `MetaMask`.

Finally, we can select the desired method from the contract method list in `Remix` to invoke.
