「Build on Darwinia 2–4」Deploying Uniswap V2 to Crab/Pangolin Network-II
--
This is the second article of the tutorial on the deployment of UNISWAP V2 to Crab/Pangolin network. In the previous article, we introduced the process of deploying the core smart contracts to Pangolin TestNet. In this one, we will continue to explain the corresponding modification to the Interface and SDK components.
Adapting Uniswap V2 Interface to Support Pangolin
The Uniswap V2 Interface is used as a middleware between the smart contracts and the user. The interface relies on external providers (such as MetaMask) and the ethers.js library to connect and interact with the blockchain, respectively.
Deploying the smart contracts to Pangolin was a pretty straightforward task, as it provides a full Ethereum-like environment. Adapting the interface so that it works with our deployment was somewhat more complicated. This is because the interface has two main factors which limit its implementation into a new blockchain: the network chain ID, and the addresses of the deployed contracts. Moreover, the UNISWAP SDK (a package the interface depends on) needs to be modified as well for the same reasons (next section).
The modified interface is included in this Github repo, inside the “uniswap/uniswap-interface” folder. Getting started is quite simple: clone the repo, install the dependencies and run the interface instance.
git clone <https://github.com/darwinia-network/dvm-workshop>
cd uniswap/uniswap-interface
npm install
yarn start
Note that the interface (and SDK) have some contract addresses hardcoded. Since we deploy the contracts to the Pangolin TestNet, we would need to modify the addresses in both the interface and SDK.
The following sections dive into a more detailed breakdown of the actual changes that took place.
Including the Chain ID
The chain ID was introduced in EIP-155. It originated to prevent replay-attacks between ETH and ETC chains that shared the same network ID. The chain ID argument is included in the transaction signature so that two identical transactions will have different v-r-s signature values. Some chain ID values include:
The Uniswap V2 Interface has baked-in some predefined chain IDs so that, once the interface is connected to a blockchain via a provider, it checks that the protocol supports the network you are connecting to.
You can add related Chain IDs to the following files (inside the “uniswap-interface” folder) :
- ./src/connectors/index.ts: add the corresponding chain IDs inside the “supportedChainIds” array:
export const injected = new InjectedConnector({
supportedChainIds: [43],
//supportedChainIds: [1, 3, 4, 5, 42, 44]
})
- ./src/components/Header/index.tsx: add the chain IDs and network labels following the corresponding format inside “NETWORK_LABELS”:
const NETWORK_LABELS: { [chainId in ChainId]: string | null } = {
[ChainId.MAINNET]: null,
[ChainId.PANGOLIN]: 'Pangolin Network',
[ChainId.CRAB]: 'Crab Network',
}
- ./src/constants/index.ts: add the chain IDs following the corresponding format inside “WDEV_ONLY: ChainTokenList”:
const WDEV_ONLY: ChainTokenList = {
[ChainId.MAINNET]: [WDEV[ChainId.MAINNET]],
[ChainId.PANGOLIN]: [WDEV[ChainId.PANGOLIN]],
[ChainId.CRAB]: [WDEV[ChainId.CRAB]],
}
- ./src/state/lists/hooks.ts: add the chain IDs following the corresponding format inside “EMPTY_LIST: TokenAddressMap”:
const EMPTY_LIST: TokenAddressMap = {
[ChainId.MAINNET]: {},
[ChainId.PANGOLIN]: {},
[ChainId.CRAB]: {},
}
In the previous code snippets, the ChainId.* object is imported from the SDK.
Adding the New Contract Addresses
As you would expect, the Uniswap interface is configured to work with the addresses of the contracts deployed to Ethereum. Therefore, the new addresses need to be specified.
The goal was for the interface to work with the Pangolin TestNet. Therefore, some modifications were made so that the address was dependent on the network’s chain ID to which the provider is connected. The files that were modified (inside the uniswap-interface
folder) are listed below. Note that each file imports a crab_address.json file that is located in the ./src
folder, which contains the addresses of the deployment in Pangolin.
- ./src/constants/index.ts: add the corresponding router address. The routerv2 variable is imported
export const ROUTER_ADDRESS: { [key: string]: string } = {
[ChainId.PANGOLIN]: pangolinRouterv2,
[ChainId.CRAB]: crabRouterv2,
}
- ./src/constants/multicall/index.tsx: add the corresponding multicall address
const MULTICALL_NETWORKS: { [chainId in ChainId]: string } = {
[ChainId.MAINNET]: '',
[ChainId.PANGOLIN]: pangolinMulticall,
[ChainId.CRAB]: crabMulticall,
}
- ./src/state/swap/hooks.ts: add the corresponding factory and router addresses inside “BAD_RECIPIENT_ADDRESS”. For testing purposes, this parameter is not required
const BAD_RECIPIENT_ADDRESSES: string[] = [
factory, // v2 factory
routerv2 // v2 router 02
]
Other Changes
Everything related to Uniswap V1 was removed from the files, as no V1 deployment was used in this example.
Other changes also include:
- Logo: file in ./src/assets/images/mainlogo.png
- Links: file in ./src/components/Menu/index.tsx
<MenuItem id="link" href="<https://crab.network/>">
<Home size={14} />
{t('Website')}
</MenuItem>
<MenuItem id="link" href="<https://github.com/darwinia-network/dvm-workshop>">
<Code size={14} />
{t('code')}
</MenuItem>
Adapting Uniswap SDK to Support Pangolin
The SDK contains additional information that is used by the interface as an NPM package. The modified SDK is included in this Github repo, inside the uniswap/uniswap-sdk
folder.
The SDK contains the addresses of the contracts deployed to the Pangolin TestNet. This is all packed and published as an NPM package with the name “crabswap.”
Before building the NPM package, the files listed below need to be modified (inside the “uniswap-sdk” folder). Note that each file imports a crab_address.json
file that is located in the ./src
folder and contains the addresses of the deployment in Pangolin TestNet:
- ./src/constants.ts: add the corresponding chain IDs inside the “ChainId” enum, change the factory address, and modify the init_code hash
export enum ChainId {
MAINNET = 1,
PANGOLIN = 43,
CRAB = 44,
}
...
export const FACTORY_ADDRESS: { [key: string]: string } = {
[ChainId.PANGOLIN]: pangolinFactory,
[ChainId.CRAB]: crabFactory,
}
...
export const INIT_CODE_HASH = '0x01429e880a7972ebfbba904a5bbe32a816e78273e4b38ffa6bdeaebce8adba7c'
- ./src/entities/token.ts: add the WETH (WDEV in this case) token contract address:
export const WDEV = {
[ChainId.MAINNET]: new Token(
ChainId.MAINNET,
'0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
18,
'WETH',
'Wrapped Ether'
),
[ChainId.CRAB]: new Token(ChainId.CRAB, CRAB_WETH, 18, 'WCRAB', 'Wrapped CRAB'),
[ChainId.PANGOLIN]: new Token(ChainId.PANGOLIN, PANGOLIN_WETH, 18, 'WDEV', 'Wrapped Dev')
}
Once all the files have been modified, change package name, version and description inside the package.json
file. When you are ready, log in into your npm account run the publish command:
npm login #enter credentials
npm publish
If you are going to run your custom package in the interface, make sure to add it as a dependency in the package.json
file of the interface folder.
Series Articles:
「Build on Darwinia 2–1」Address Formats in Darwinia
「Build on Darwinia 2–2」EVM-Compatible Crab Smart Chain
「Build on Darwinia 2–3」Deploying UNISWAP V2 to Crab/Pangolin Network — I
Resources:
Developer Documentation: https://docs.crab.network/builders/get-started/darwinia-dev
Developer Telegraph Group: https://t.me/DarwiniaDev
About Crab Network
Crab is a canary network with real economic value for Darwinia, and its positioning is similar to Polkadot’s Kusama Network. You can check Crab status through Polkadot{.js} , Subscan or Subview.
Crab provides smart contract solutions based on DVM (Darwinia Virtual Machine), which is compatible with the EVM (Ethereum Virtual Machine) paradigm at a low level. Therefore, it is easy for projects in the Ethereum ecosystem to migrate to the Crab Smart Chain. (Tips: DVM is built on Frontier with a fully EVM-compatible instruction set and an Ethereum RPC-like external interface.)