Deploy Uniswap
Overview
Uniswap is a decentralized exchange (DEX) protocol built on the Ethereum blockchain that allows users to trade Ethereum-based tokens without the need for an intermediary or a centralized exchange. It uses a unique automated market maker (AMM) system to facilitate trades and provide liquidity to the platform.
Uniswap operates on a set of smart contracts that are open-source and decentralized, meaning that they are not controlled by any centralized authority or entity. Instead, users can interact with the smart contracts directly using their Ethereum wallets and participate in the platform's liquidity provision and trading features.
One of the key features of Uniswap is its unique AMM system, which uses a constant product formula to determine the price of tokens on the platform. This means that the price of a token is determined by the ratio of the token's supply and the supply of the other token in the trading pair. This system allows users to trade tokens without the need for order books or centralized matching engines.
Another important feature of Uniswap is its liquidity provision system, which allows users to provide liquidity to the platform in exchange for a share of the trading fees. This means that users can earn a passive income by contributing to the platform's liquidity and helping to facilitate trades between different tokens.
Uniswap has become one of the most popular decentralized exchanges on the Ethereum network, with a wide range of tokens and trading pairs available for users to trade. Its decentralized and open-source nature has made it a popular choice among cryptocurrency enthusiasts who value the principles of decentralization, transparency, and community governance.
Demo
You can try uniswap demo there:
- URL: https://uniswap-demo.waterfall.network
- User Name:
demo
- Password:
demo
Installation
- Refer to the link to install NodeJS.
- Create project dir and go there
mkdir uniswap cd uniswap
Deploy Contracts
v3-core
- Clone repo from github
git clone -n https://github.com/Uniswap/v3-core.git git checkout d8b1c635c275d2a9450bd6a78f3fa2484fef73eb
- Go to
v3-core
directorycd v3-core
- Install packages
yarn install
- Go to Networks - RPC Endpoints page and check params
- Add Waterfall Network to
hardhat.config.js
filenetworks: { ... waterfall: { url: "https://rpc.waterfall.network/rpc", chainId: 333777333, accounts: ['07201008f00b31de405a0af22ff04871044e027878929b7b47569ca76555ff09'], // Private key from your account from: '0xa7062A2Bd7270740f1d15ab70B3Dee189A87b6DE', // Your Deployer Account gasPrice: 20000000000, gas: 3000000, } }
- Create
scripts
directorymkdir scripts
- Create
deploy.js
file inscripts
directory and past next code:async function main() { const UniswapV3Factory = await ethers.getContractFactory('UniswapV3Factory') // Start deployment, returning a promise that resolves to a contract object const uniswapV3Factory = await UniswapV3Factory.deploy() console.log('Contract deployed to address:', uniswapV3Factory.address);//0xb96eb0A6cE4c5C258413E09d5E575966245cAf9F } main() .then(() => process.exit(0)) .catch((error) => { console.error(error) process.exit(1) })
- Deploy contract
npx hardhat run --network waterfall scripts/deploy.js Compilation finished successfully Creating Typechain artifacts in directory typechain for target ethers-v5 Successfully generated Typechain artifacts! Contract deployed to address: 0xc03617E3c4f48680Cb0F9f607DAc1C1e24a5E0d4
- Save the gotten contract address, you will need it later
eg:
0xc03617E3c4f48680Cb0F9f607DAc1C1e24a5E0d4
- Exit to project directory
cd ../
v3-periphery
- Clone repo from github
git clone -n https://github.com/Uniswap/v3-periphery.git git checkout 6cce88e63e176af1ddb6cc56e029110289622317
- Go to
v3-periphery
directorycd v3-periphery
- Install packages
yarn install
- Go to Networks - RPC Endpoints page and check params
- Add Waterfall Network to
hardhat.config.js
filenetworks: { ... waterfall: { url: "https://rpc.waterfall.network/rpc", chainId: 333777333, accounts: ['07201008f00b31de405a0af22ff04871044e027878929b7b47569ca76555ff09'], // Private key from your account from: '0xa7062A2Bd7270740f1d15ab70B3Dee189A87b6DE', // Your Deployer Account gasPrice: 20000000000, gas: 3000000, } }
- Create
scripts
directorymkdir scripts
- Create
deploy.js
file inscripts
directory and past next code:const web3 = require('web3') async function main() { const factoryAdr = '0xc03617E3c4f48680Cb0F9f607DAc1C1e24a5E0d4' const WWATER = await ethers.getContractFactory('WWATER') const _WWATER = await WWATER.deploy() wwaterAdr = _WWATER.address console.log('WWATER deployed at:', wwaterAdr) const UniswapInterfaceMulticall = await ethers.getContractFactory('UniswapInterfaceMulticall') const _UniswapInterfaceMulticall = await UniswapInterfaceMulticall.deploy() console.log('UniswapInterfaceMulticall address:', _UniswapInterfaceMulticall.address) const Quoter = await ethers.getContractFactory('Quoter') const _Quoter = await Quoter.deploy(factoryAdr, wwaterAdr) console.log('Quoter address:', _Quoter.address) const nativeCurrencyLabelBytes = web3.utils.asciiToHex("WATER\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); const NFTDescriptor = await ethers.getContractFactory('NFTDescriptor') const _NFTDescriptor = await NFTDescriptor.deploy() console.log('NFTDescriptor address:', _NFTDescriptor.address) const NonfungibleTokenPositionDescriptor = await ethers.getContractFactory('NonfungibleTokenPositionDescriptor', { libraries: { NFTDescriptor: _NFTDescriptor.address } }) const _NonfungibleTokenPositionDescriptor = await NonfungibleTokenPositionDescriptor.deploy(wwaterAdr, nativeCurrencyLabelBytes) console.log('NonfungibleTokenPositionDescriptor address:', _NonfungibleTokenPositionDescriptor.address) const NonfungibleTokenPositionDescriptorAddr = _NonfungibleTokenPositionDescriptor.address const NonfungiblePositionManager = await ethers.getContractFactory('NonfungiblePositionManager') const _NonfungiblePositionManager = await NonfungiblePositionManager.deploy(factoryAdr, wwaterAdr, NonfungibleTokenPositionDescriptorAddr) console.log('NonfungiblePositionManager address:', _NonfungiblePositionManager.address) const NonfungiblePositionManagerAddr = _NonfungiblePositionManager.address const SwapRouter = await ethers.getContractFactory('SwapRouter') const _SwapRouter = await SwapRouter.deploy(factoryAdr, wwaterAdr) console.log('SwapRouter address:', _SwapRouter.address) const V3Migrator = await ethers.getContractFactory('V3Migrator') const _V3Migrator = await V3Migrator.deploy(factoryAdr, wwaterAdr, NonfungiblePositionManagerAddr) console.log('V3Migrator address:', _V3Migrator.address) } main() .then(() => process.exit(0)) .catch((error) => { console.error(error) process.exit(1) })
- Update
factoryAdr
const which you had when deploy v3-core contracts - Create
contracts/lens/WWATER.sol
file and past next code:pragma solidity =0.7.6; contract WWATER { string public name = "Wrapped Water"; string public symbol = "WWATER"; uint8 public decimals = 18; event Approval(address indexed src, address indexed guy, uint wad); event Transfer(address indexed src, address indexed dst, uint wad); event Deposit(address indexed dst, uint wad); event Withdrawal(address indexed src, uint wad); mapping (address => uint) public balanceOf; mapping (address => mapping (address => uint)) public allowance; receive() external payable { deposit(); } function deposit() public payable { balanceOf[msg.sender] += msg.value; emit Deposit(msg.sender, msg.value); } function withdraw(uint wad) public { require(balanceOf[msg.sender] >= wad); balanceOf[msg.sender] -= wad; msg.sender.transfer(wad); emit Withdrawal(msg.sender, wad); } function totalSupply() public view returns (uint) { return address(this).balance; } function approve(address guy, uint wad) public returns (bool) { allowance[msg.sender][guy] = wad; Approval(msg.sender, guy, wad); return true; } function transfer(address dst, uint wad) public returns (bool) { return transferFrom(msg.sender, dst, wad); } function transferFrom(address src, address dst, uint wad) public returns (bool) { require(balanceOf[src] >= wad); if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) { require(allowance[src][msg.sender] >= wad); allowance[src][msg.sender] -= wad; } balanceOf[src] -= wad; balanceOf[dst] += wad; emit Transfer(src, dst, wad); return true; } }
- Deploy contracts
npx hardhat run --network waterfall scripts/deploy.js Compilation finished successfully Creating Typechain artifacts in directory typechain for target ethers-v5 Successfully generated Typechain artifacts! WWATER deployed at: 0xe748d811b30F140CC18423Ab3244804efE508a93 UniswapInterfaceMulticall address: 0x671787Cf37c82FBb786C74Cb36c46d6867b6bA71 Quoter address: 0x1bB7a05C8e22ebe1d1B38Eefd3803Fc1602fE3F7 NFTDescriptor address: 0xd474986Ed0E49A0088e9852984973822612c8C09 NonfungibleTokenPositionDescriptor address: 0xB9cF42F49D8d86F96133e5f1311427aeb26354C8 NonfungiblePositionManager address: 0x7056652b61f0C39261c2DA41CF81C414366145C5 SwapRouter address: 0x876C9Ec93eB5Eb74719A3874344c05706FaFD5C5 V3Migrator address: 0x9d8A58A91398a3f92654501C1c95D9AAC9B9dcec
- Save the gotten contracts addresses, you will need the later
- Exit to project directory
cd ../
permit2
- Install Founadry
- Clone repo from github
git clone -n https://github.com/Uniswap/permit2.git git checkout db96e06278b78123970183d28f502217bef156f4
- Go to
permit2
directorycd permit2
- Prepare contract
forge install
- Deploy contract
forge create --rpc-url https://rpc.waterfall.network/rpc --private-key [Your private key] src/Permit2.sol:Permit2 Deployer: 0xa7e558Cc6efA1c41270eF4Aa227b3dd6B4a3951E Deployed to: 0xD63366aCeB4dE27B732EC874F8daa2935Be7b6fb Transaction hash: 0x67d1ba0f63ecbccd0dfff015c393c658bbf89cc851f953fe0eda2ff698f126e8
- Save the gotten contract address, you will need it later
eg:0xD63366aCeB4dE27B732EC874F8daa2935Be7b6fb
- Exit to project directory
cd ../
universal-router
- Install Founadry
- Clone repo from github
git clone -n https://github.com/Uniswap/universal-router.git git checkout 4104efca7dc786cec631a51030ffb28bd46e1e5e
- Go to
universal-router
directorycd universal-router
- Install packages
yarn install
- Prepare contract
forge install
- Create
DeployWaterfall.s.sol
inscript/deployParameters
directory and paste next code:
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.15; import {DeployUniversalRouter} from '../DeployUniversalRouter.s.sol'; import {RouterParameters} from 'contracts/base/RouterImmutables.sol'; contract DeployWaterfall is DeployUniversalRouter { function setUp() public override { params = RouterParameters({ permit2: 0xD63366aCeB4dE27B732EC874F8daa2935Be7b6fb, weth9: 0xe748d811b30F140CC18423Ab3244804efE508a93, seaport: UNSUPPORTED_PROTOCOL, seaportV1_4: UNSUPPORTED_PROTOCOL, openseaConduit: UNSUPPORTED_PROTOCOL, nftxZap: UNSUPPORTED_PROTOCOL, x2y2: UNSUPPORTED_PROTOCOL, foundation: UNSUPPORTED_PROTOCOL, sudoswap: UNSUPPORTED_PROTOCOL, elementMarket: UNSUPPORTED_PROTOCOL, nft20Zap: UNSUPPORTED_PROTOCOL, cryptopunks: UNSUPPORTED_PROTOCOL, looksRareV2: UNSUPPORTED_PROTOCOL, routerRewardsDistributor: UNSUPPORTED_PROTOCOL, looksRareRewardsDistributor: UNSUPPORTED_PROTOCOL, looksRareToken: UNSUPPORTED_PROTOCOL, v2Factory: UNSUPPORTED_PROTOCOL, v3Factory: 0xc03617E3c4f48680Cb0F9f607DAc1C1e24a5E0d4, pairInitCodeHash: 0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f, poolInitCodeHash: 0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54 }); } }
- Change permit2, weth9(WWATER) and v3Factory addresses which we got in previous steps
- Compile contracts
forge build
- Deploy contract
forge script --broadcast --rpc-url https://rpc.waterfall.network/rpc --private-key [Your private key] --sig 'run()' script/deployParameters/DeployWaterfall.s.sol:DeployWaterfall == Return == router: contract UniversalRouter 0x51B21B2a088270C0Cb9092ba5d9562792ab9Fe91
- Save the gotten contracts addresses, you will need the later
- Exit to project directory
cd ../
UI
- Clone repo from github
git clone -n https://github.com/Uniswap/interface.git git checkout bc48b4fb0e1abb2c5961ecee3e8cc134dee6ac87
- Go to
interface
directorycd interface
- Install packages
yarn install
- Add support Waterfall network to
src/constants/chains.ts
fileexport enum SupportedChainId { ... WATERFALL = 333777333, } ... export const CHAIN_IDS_TO_NAMES = { ... [SupportedChainId.WATERFALL]: 'waterfall', } ... export const SUPPORTED_GAS_ESTIMATE_CHAIN_IDS = [ ... SupportedChainId.WATERFALL, ] ... export const L1_CHAIN_IDS = [ ... SupportedChainId.WATERFALL, ]
- Add Waterfall Network info to
src/constants/chainInfo.ts
fileconst CHAIN_INFO: ChainInfoMap = { ... [SupportedChainId.WATERFALL]: { networkType: NetworkType.L1, blockWaitMsBeforeWarning: ms`10m`, docs: 'https://waterfall.network/', explorer: 'https://explorer.waterfall.network/', infoLink: 'https://waterfall.network/', label: 'Waterfall', logoUrl: 'https://explorer.waterfall.network/favicon-152-precomposed.png', nativeCurrency: { name: 'Water', symbol: 'Water', decimals: 18 }, }, }
- Create tokens list like there
https://download.nextcloud.in.ua/testnet-tokens.json
You should deploy WRC20 tokens. - Add your tokens list to
src/constants/lists.ts
file... const WATERFALL_LIST = 'https://download.nextcloud.in.ua/testnet-tokens.json' ... export const DEFAULT_ACTIVE_LIST_URLS: string[] = [UNI_LIST, WATERFALL_LIST]
- Add rpc url to
src/constants/networks.ts
fileexport const FALLBACK_URLS = { ... [SupportedChainId.WATERFALL]: [ 'https://rpc.waterfall.network/rpc' ], } ... export const RPC_URLS = { ... [SupportedChainId.WATERFALL]: [...FALLBACK_URLS[SupportedChainId.WATERFALL]], }
- Add rpc provider to
src/constants/providers.ts
fileexport const RPC_PROVIDERS: { [key in SupportedChainId]: StaticJsonRpcProvider } = { ... [SupportedChainId.WATERFALL]: new AppJsonRpcProvider(SupportedChainId.WATERFALL), }
-
Add explorer
src/utils/anonymizeLink.ts
const EXPLORER_HOSTNAMES: { [hostname: string]: true } = { ... 'explorer.waterfall.network': true, }
src/utils/getExplorerLink.ts
const BLOCK_EXPLORER_PREFIXES: { [chainId: number]: string } = { ... [SupportedChainId.WATERFALL]: 'https://explorer.waterfall.network', }
-
Add Waterfall Networ selection in file
src/components/NavBar/ChainSelector.tsx
const NETWORK_SELECTOR_CHAINS = [ ... SupportedChainId.WATERFALL, ]
- Change factory address
node_modules/@uniswap/v3-sdk/dist/constants.d.ts
export declare const FACTORY_ADDRESS = "0xc03617E3c4f48680Cb0F9f607DAc1C1e24a5E0d4";
node_modules/@uniswap/v3-sdk/dist/v3-sdk.cjs.development.js
var FACTORY_ADDRESS = '0xc03617E3c4f48680Cb0F9f607DAc1C1e24a5E0d4';
node_modules/@uniswap/v3-sdk/dist/v3-sdk.esm.js
var FACTORY_ADDRESS = '0xc03617E3c4f48680Cb0F9f607DAc1C1e24a5E0d4';
- Update permit2-sdk module to add contract address which was deployed in previus step
node_modules/@uniswap/permit2-sdk/dist/constants.d.ts
export declare const PERMIT2_ADDRESS = "0xD63366aCeB4dE27B732EC874F8daa2935Be7b6fb";
node_modules/@uniswap/permit2-sdk/dist/permit2-sdk.cjs.development.js
var PERMIT2_ADDRESS = '0xD63366aCeB4dE27B732EC874F8daa2935Be7b6fb';
node_modules/@uniswap/permit2-sdk/dist/permit2-sdk.esm.js
var PERMIT2_ADDRESS = '0xD63366aCeB4dE27B732EC874F8daa2935Be7b6fb';
- Add universal router and permit addresses in
node_modules/@uniswap/universal-router-sdk/dist/universal-router-sdk.cjs.development.js
andnode_modules/@uniswap/universal-router-sdk/dist/universal-router-sdk.esm.js
in... var UNIVERSAL_ROUTER_ADDRESS = function UNIVERSAL_ROUTER_ADDRESS(chainId) { switch (chainId) { ... case 333777333: // waterfall return '0x51B21B2a088270C0Cb9092ba5d9562792ab9Fe91'; default: throw new Error("Universal Router not deployed on chain " + chainId); } }; var WETH_ADDRESS = function WETH_ADDRESS(chainId) { switch (chainId) { ... case 333777333: //waterfall return '0xe748d811b30F140CC18423Ab3244804efE508a93'; default: throw new Error("WETH9 or UniversalRouter not deployed on chain " + chainId); } }; var PERMIT2_ADDRESS = '0xD63366aCeB4dE27B732EC874F8daa2935Be7b6fb';
node_modules/@uniswap/universal-router-sdk/dist/utils/constants.d.ts
export declare const PERMIT2_ADDRESS = "0xD63366aCeB4dE27B732EC874F8daa2935Be7b6fb";
- Update contracts addresses in
src/constants/addresses.ts
file... // Waterfall const WATERFALL_V3_CORE_FACTORY_ADDRESSES = '0xc03617E3c4f48680Cb0F9f607DAc1C1e24a5E0d4' const WATERFALL_V3_MIGRATOR_ADDRESSES = '0x9d8A58A91398a3f92654501C1c95D9AAC9B9dcec' const WATERFALL_MULTICALL_ADDRESS = '0x671787Cf37c82FBb786C74Cb36c46d6867b6bA71' const WATERFALL_QUOTER_ADDRESSES = '0x1bB7a05C8e22ebe1d1B38Eefd3803Fc1602fE3F7' const WATERFALL_NONFUNGIBLE_POSITION_MANAGER_ADDRESSES = '0x7056652b61f0C39261c2DA41CF81C414366145C5' const WATERFALL_SWAP_ROUTER_ADDRESSES = '0x876C9Ec93eB5Eb74719A3874344c05706FaFD5C5' ... export const V3_CORE_FACTORY_ADDRESSES: AddressMap = { ... [SupportedChainId.WATERFALL]: WATERFALL_V3_CORE_FACTORY_ADDRESSES, } ... export const V3_MIGRATOR_ADDRESSES: AddressMap = { ... [SupportedChainId.WATERFALL]: WATERFALL_V3_MIGRATOR_ADDRESSES, } ... export const MULTICALL_ADDRESS: AddressMap = { ... [SupportedChainId.WATERFALL]: WATERFALL_MULTICALL_ADDRESS, } ... export const QUOTER_ADDRESSES: AddressMap = { ... [SupportedChainId.WATERFALL]: WATERFALL_QUOTER_ADDRESSES, } ... export const NONFUNGIBLE_POSITION_MANAGER_ADDRESSES: AddressMap = { ... [SupportedChainId.WATERFALL]: WATERFALL_NONFUNGIBLE_POSITION_MANAGER_ADDRESSES, }
- Go to
src/constants/tokens.ts
and add WRAPPED_NATIVE_CURRENCYexport const WRAPPED_NATIVE_CURRENCY: { [chainId: number]: Token | undefined } = { ... [SupportedChainId.WATERFALL]: new Token( SupportedChainId.WATERFALL, '0xe748d811b30F140CC18423Ab3244804efE508a93', 18, 'WWATER', 'Wraped Water' ), }
- Start
yarn run prepare yarn start