Introduction
- Uniswap V2-core
- Uniswap V2-periphery
- Uniswap V2-sdk
- Truffle
- Ganache
- Verify plugin for Truffle
- Uniswap V2 Core whitepaper
- Uniswap V2 docs
- Uniswap V2 factory contract
- Uniswap V2 router code
- Remix
- Interface template (Uniswap team didn't make a new repo for V3 interface, but we need a version which is as close as possible to Uniswap V2 for ease of interaction with V2 contracts. So we can use it as a start template)
- Core template
- Periphery template
We will use Rinkeby test network. Deploy through Truffle and use these contracts, exept a section with Remix deployment, where will be a Ropsten network.
tx - short name for transaction
Table of contents
Deploy with Truffle
Core contracts
When replacing the code, you need to pay attention to the places where the prefix 0x is found, you have to save it and replace what follows it
-
Create a new folder CoolSwap-core and copy there the code from Gihub repo.
Create two files:
.env
(deployment data) and.secret
(leave here your mnemonic phrase).Don't lose your private info like mnemonic phrase or API key. All this info in our case will be in dot files that are added to
.gitignore
file to exclude it from git trackingTESTNET_NETWORK_URL="https://rinkeby.infura.io/v3/3cb031735f9a46a69f2babab4fae3e0d"
TESTNET_NETWORK_ID="4"
And add your mnemonic phrase in theEXPLORER_API_KEY="fill it with your key from the explorer account"
.secret
file (just paste words). For mainnet values replace names prefixes withMAINNET_
and of course add your own links -
You can copy a core contracts template or make the same actions as described next.
In the
SwapFactory.sol
contract was added a new line. After factory deployment we need to copy this parameter from the blockchain and paste it in Library:
In thebytes32 public constant INIT_CODE_PAIR_HASH = keccak256(abi.encodePacked(type(SwapPair).creationCode));
SwapERC20.sol
contract we change Uniswap token names with ours:string public constant name = 'Swap-LP-Token';
And were changed all log/file names with Swap name instring public constant symbol = 'SWAP-LP';
SwapFactory.sol
,SwapERC20.sol
andSwapPair.sol
-
At first we download Ganache where you can fast and easy make the first tests locally.
After we've checked that on your machine everything is fine we can more slower deploy on testnet.
Work with Nodejs 16.\* version
Download Ganache and start it (quick start is enough). Correctnpm i
development
settings in thetruffle-config.js
if they doesn't match with Ganache settings. But probable it's fine by default. -
Go to
2_deploy_contracts.js
and fill these variables (adminAddress address will be able to change himself (_feeToSetter) and feeCollectingAddress (_feeTo) in the deployed factory):const adminAddress = "";
const feeCollectingAddress = "";
-
Compile contracts (confirm truffle installation if it wasn't installed):
Deploy contracts on Ganache local blockchain:npx truffle compile
No you probably can see this error in the terminal/console:npx truffle migrate --reset --network development
We setError: Returned error: VM Exception while processing transaction: revert Swap: FORBIDDEN -- Reason given: Swap: FORBIDDEN.
adminAddress
not from local Ganache blockchain. So we can't usesetFeeTo
method, because we call this method we use Ganache blockchain address instead ofadminAddress
(if you didn't set this address from Ganache). If you want to bypass this error just changeadminAddress
with the first one from Ganache or comment this string: In the successful option you have to see something like this: -
Well for now it seems ok. It's more faster to debug/solve problems. Now we deploy it on testnet.
Contracts are already compiled and we can just change a deploy command:
You have to see similar output as with Ganache deployment, but you're able to check it on Ethereum testnet. Copy a factory address (from the explorer or truffle output) and save it. Let's verify the factory:npx truffle migrate --reset --network testnet
Now the contract is verified Go to a Read Contract tab, copynpx truffle run verify SwapFactory --network testnet
INIT_CODE_PAIR_HASH
parameter and save it
Finally we have this parameters:
Factory:INIT_CODE_PAIR_HASH:0x6Bd5A1A63ffF10De3c6B7C667040E9AE1B47fDf2
0xaf88dd15a55596feb9d67243c727bfd6144af12453963809bc91f0cfcf8241bc
Periphery contracts
-
This template has changed names/logs in
SwapLibrary.sol
,SwapRouterV1
andSwapRouterV2
. And for now we have to change only init code hash value in a library: -
Copy
.env
and.secret
files from the CoolSwap-core folder and install dependecies:npm i
-
Go to
2_deploy_contracts.js
and fill these variables:const factoryAddress = "";
For the testnet we can use this WETH contract:const WETH = "";
0xc778417e063141139fce010982780140aa0cd5ab
Use only trusted sources for main networks, like CoinGecko
npx truffle compile
-
Let's do the same actions with Ganache as for core to be sure there're no errors.
After this we deploy contracts on the testnet:
And also verify the router contract:npx truffle migrate --reset --network testnet
npx truffle run verify SwapRouterV2 --network testnet
Here we need only a router address
0xA4E1f3fD10E2397f58926E215Ed331D7cDA14056
Deploy with Remix
- Go to Remix editor and create there two files: CoolSwapFactory.sol, CoolSwapRouter.sol
- Let's begin with factory. Copy Uniswap factory code from the Etherscan: And paste it into the new CoolSwapFactory file:
- Replace ERC20 contract name with CoolSwapERC20. Also replace two constants: name with CoolSwap LP, symbol with Cool-LP. It will be a bonus token which the user will receive for his liquidity:
-
Replace a pair contract name with CoolSwapPair. Also replace
next to it ERC20 contract name:
Also change it in the createPair method:
And finally just a little above change the factory name:
You're able to replace all names (interfaces, logs and so on), but we won't do this
-
Add the following line in the CoolSwapFactory contract:
bytes32 public constant INIT_CODE_HASH = keccak256(abi.encodePacked(type(CoolSwapPair).creationCode));
- Go to "Solidity Compiler" tab. Change compiler version with 0.5.16 if it's different. Enable optimization option and click button "Compile":
- Go to "Deploy & run transaction" tab. Select Injected Web3 in the ENVIRONMENT drop-down. It will use your external wallet. We will use Metamask wallet. If you didn't login in the wallet then login it now, reload page, come back and compile factory contract one more time. And again chose Injected Web3 option. Chose Ropsten network in the Metamask. Select CoolSwapFactory in the CONTRACT drop-down (probably it's already made by default). Set an address in the _feeToSetter field. Contracts will use feeToSetter variable. This variable contains the address that will be able to set an address feeTo which will get protocol commission. Also feeToSetter can change himself to a new one. Now you can see something like this in the deploy tab: If you won't add this address and deploy just with empty field then protocol fee will be disabled (you can set this address in future after deployment). So now click on "Deploy" button and confirm a modal window from external wallet with transaction fee:
- After transaction has been mined you can see all details in the Remix terminal: Copy a transaction hash and go to Ropsten etherscan. Paste this hash in the search field and go to a new contract page. Copy his address and save it somewhere.
-
Come back into Remix deploy tab. Open our CoolSwapFactory contract
and paste _feeTo address in the setFeeTob method. We
will use
0x7371466090234bDE67bB6c8Ba55dB705Fcec4BCB
address without funds. This address will receive protocol fee. Click on this method button and wait while tx will be mined. After that you can check this transaction on the same way as factory tx. - Click on the last button INIT_CODE_HASH that is among CoolSwapFactory options. Copy it (without "bytes32") and save somewhere:
- Go to "File explorers" tab and copy Uniswap router code into CoolSwapRouter.sol. Rename a router contract.
- Replace a hex value in the pairFor method with the INIT_CODE_HASH that we got earlier (replace it without "0x" at the beginning):
- On the compiler tab enable optimization options and compile CoolSwapRouter file. Go to deploy tab. Pass two parameters in the Deploy method with a dot between them: factory address (that we just deployed) and WETH token address. Then deploy contract:
- Make the same actions as after factory deployment and copy CoolSwapRouter address.
Now we have this data:
CoolSwapFactory:0x68d3A8bc9441eF1225521C1E5EC67C6a7509Ce58
CoolSwapRouter:0xB2D64667df4C3608E0d4f3683f6e69914D185C87
INIT_CODE_HASH:0x6be71632e8b409042bcda4b9b5dd96de1a924599be32bb83c12bce7d3355900e
Frontend
Main changes in this interface template:
- Removed all (or almost all) info about first version of Uniswap
- Removed UNI token info
- Removed links to Project analytics (it is not included in this description). And saved only necessary for swap flow pages
- Disabled Coinbase, Fortmatic and Portis options to connect external wallet. You can uncomment it if you have API keys
- Changed source styles just a little. Now the interface is more like Uniswap V3 then V2
- Some fixes, like warnings about no checksummed addresses, etc.
-
Create a new directory: CoolSwap. Copy
start template code in this
directory and nstall dependencies (do not forget about Nodejs 16).
Fill with the a network info
.env
file. In our case it's Rinkeby testnet:REACT_APP_NETWORK_URL="https://rinkeby.infura.io/v3/3cb031735f9a46a69f2babab4fae3e0d"
REACT_APP_CHAIN_ID="4"
-
Let's look at
forks
directory in the project root. We have to change Uniswap sdk to be able use it with our contracts. We will follow the least resistance and copy this builded package in our root directory. Change info directly in the sdk build and replace it in thenode_modules
directory after each dependency installation (automatically of course. NPM makes his job well). You also can do the same action as Uniswap and put your values in the new sdk and create own npm package. In our template we already have this package and npm script which will replace `node_modules` sdk with files from `forks`:
All what we have to do it's replace values there with our saved info from the previous deployment. With our template and contracts we need to change only constants and"postinstall": "rm -rf ./node_modules/@uniswap/sdk; cp -r ./forks/@uniswap/sdk ./node_modules/@uniswap/sdk",
INIT_CODE_HASH
, because we use the same info for our ERC20 contract in the Truffle deployment. Open asrc/constants/index.ts
file. At first copy the oldFACTORY_ADDRESS
address. Here are our constants:export const FACTORY_ADDRESS
export const ROUTER_ADDRESS
export const LP_TOKEN_NAME
export const LP_TOKEN_SYMBOL
-
Find all his coincidences for whole project and replace it with our new factory
(deploy with Truffle):
0x6Bd5A1A63ffF10De3c6B7C667040E9AE1B47fDf2
. An example in Visual Studio Code search tab: For router address change it only in one place, in the same file. Our new router address:0xA4E1f3fD10E2397f58926E215Ed331D7cDA14056
. Now go toforks/@uniswap/sdk/dist/constants.d.ts
and copy the old init code hash value. Do the same steps as for the factory. Find and replace with the new value:0xaf88dd15a55596feb9d67243c727bfd6144af12453963809bc91f0cfcf8241bc
. You probable have your token info. Well repeat the cycle, find old token name/symbol values and replace it. You can find your info in the Verified router contract: -
Install dependencies:
npm i
Do not forget to reinstall the
node_modules
directory if you change something inforks
npm start
-
Now we can check that all works fine. We do not have any pools and can't make swaps.
Connect your external wallet and go to Pool page. Click on a
Create a pair
button: We will use tokens available in the default list. In our example we're creating a new pool, ETH with DAI. Fill form fields. Click on a `Approve` button and wait while transaction will be in the blockchain. After that you press a Supply button. Confirm your actions in the modal window and wait just a while: - Go back to the Pool page and check your pool in the list: Let's make several swaps on the Swap page:
-
It remains for us to check accumulated protocol fee liquidity.
Go to the Pool page and remove some part or all liquidity from the pool:
We see in our
remove liquidity
transaction the feeTo address, where were accumulated tokens sent: Switch in the wallet to the address for collecting commissions. You're able to see the same pool with the amounts that has been accumulated from previous swaps:
These were the minimum actions needed for the exchange to work and to collect the commission.
Additional changes
Token lists
Here is the main file with lists sources.
constants/lists.ts
All lists is available for Ethereum network.
You can add your list address and it will be displayed here:
The simple way to place your list is to add it on Github for example
and copy his address from there. When you placed a list file you need to
press a Raw button and copy a url address:
It has to be the address of this type:
https://raw.githubusercontent.com/(organization or user name)/(repo name)/main/list.json
If there is no urls, then by default is used a Uniswap package with tokens: @uniswap/default-token-list. Replace it with some other package or add it manually in a json file and import them from it.
Language
react-i18next
package
to translate information. Base settings file
in the src/i18.ts
and in the src/index.ts
we just import it.
After that we have to import a translation hook from a react-i18next
package:
import { useTranslation } from 'react-i18next';
Now we need to get a t
function from this hook somewhere
inside your functional component:
const { t } = useTranslation();
And finally use this function with a translation key. For example:
Now all what we need to do is add a swap key and his message value in
translation files. They are here:
Now we already have this message. If you don't just add a key and message
as a value in all translation files. It will automatically detect browser
language and show content in this language.
Example of reflected changes:
User interface
theme/index.tsx
If you want to add a new variables, don't forget add in types file:
theme/styled.d.ts
Logos in the Header component are used here
assets/svg/*
Naming
public/index.html
public/manifest.json
public/locales/*
components/vote/DelegateModal.tsx
connectors/index.ts
Change logs name if you change it in the contracts:
hooks/useSwapCallback.ts
components/PositionCard/index.tsx
components/swap/AdvancedSwapDetails.tsx