generated from DeFiFoFum/hardhat-template
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
3,699 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
1,235 changes: 1,235 additions & 0 deletions
1,235
src/artifacts-apeswap/dex/contracts/NonfungiblePositionManager.json
Large diffs are not rendered by default.
Oops, something went wrong.
161 changes: 161 additions & 0 deletions
161
src/artifacts-apeswap/dex/contracts/NonfungibleTokenPositionDescriptor.json
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
245 changes: 245 additions & 0 deletions
245
src/artifacts-apeswap/dex/contracts/UniswapV3Factory.json
Large diffs are not rendered by default.
Oops, something went wrong.
1,092 changes: 1,092 additions & 0 deletions
1,092
src/artifacts-apeswap/dex/contracts/UniswapV3Pool.json
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' | ||
import { HardhatEthersHelpers } from 'hardhat/types' | ||
import { ether } from './utils' | ||
// Setup DEX Contracts | ||
import UniswapV3Factory from './artifacts-apeswap/dex/contracts/UniswapV3Factory.json' | ||
import UniswapV3Pool from './artifacts-apeswap/dex/contracts/UniswapV3Pool.json' | ||
import NonfungiblePositionManagerBuild from './artifacts-apeswap/dex/contracts/NonfungiblePositionManager.json' | ||
import NFTDescriptorBuild from './artifacts-apeswap/dex/contracts/NFTDescriptor.json' | ||
import SwapRouterBuild from './artifacts-apeswap/dex/contracts/SwapRouter.json' | ||
import NonfungibleTokenPositionDescriptorBuild from './artifacts-apeswap/dex/contracts/NonfungibleTokenPositionDescriptor.json' | ||
|
||
// Setup Token Contracts | ||
import ERC20MockBuild from './artifacts-apeswap/token/contracts/ERC20Mock.json' | ||
import WNativeBuild from './artifacts-apeswap/token/contracts/WNative.json' | ||
|
||
// Import Contract Types | ||
import { | ||
ApePair, | ||
ApePair__factory, | ||
ERC20Mock, | ||
ERC20Mock__factory, | ||
WNative__factory, | ||
UniswapV3Factory__factory, | ||
NFTDescriptor__factory, | ||
SwapRouter__factory, | ||
NonfungiblePositionManager__factory, | ||
NonfungibleTokenPositionDescriptor__factory, | ||
} from '../typechain-types' | ||
|
||
/** | ||
* Deploy a mock dex. | ||
* | ||
* - LP fees are sent to `feeTo` | ||
* - Initial LP tokens are minted to `alice` | ||
*/ | ||
// NOTE: Currently does not create a BANANA/WBNB pair | ||
export async function deployMockDex( | ||
ethers: HardhatEthersHelpers, | ||
[owner, feeTo, alice]: [ | ||
SignerWithAddress, | ||
SignerWithAddress, | ||
SignerWithAddress | ||
], | ||
numPairs = 2 | ||
) { | ||
const SwapRouter = (await ethers.getContractFactory( | ||
SwapRouterBuild.abi, | ||
SwapRouterBuild.bytecode | ||
)) as SwapRouter__factory | ||
const uniV3Factory = (await ethers.getContractFactory( | ||
UniswapV3Factory.abi, | ||
UniswapV3Factory.bytecode | ||
)) as UniswapV3Factory__factory | ||
const nonfungiblePositionManager = (await ethers.getContractFactory( | ||
NonfungiblePositionManagerBuild.abi, | ||
NonfungiblePositionManagerBuild.bytecode | ||
)) as NonfungiblePositionManager__factory | ||
const NFTDescriptor = (await ethers.getContractFactory( | ||
NFTDescriptorBuild.abi, | ||
NFTDescriptorBuild.bytecode | ||
)) as NFTDescriptor__factory | ||
|
||
const nftDescriptor = await NFTDescriptor.deploy() | ||
const re = new RegExp('__(.*?)__') | ||
const NonfungibleTokenPositionDescriptorBuildByteCode: any = | ||
NonfungibleTokenPositionDescriptorBuild.bytecode.replace( | ||
re, | ||
nftDescriptor.address.split('0x')[1] | ||
) | ||
|
||
const nonfungibleTokenPositionDescriptor = (await ethers.getContractFactory( | ||
NonfungibleTokenPositionDescriptorBuild.abi, | ||
NonfungibleTokenPositionDescriptorBuildByteCode | ||
)) as NonfungibleTokenPositionDescriptor__factory | ||
// Setup Token Contracts | ||
const ERC20Mock = (await ethers.getContractFactory( | ||
ERC20MockBuild.abi, | ||
ERC20MockBuild.bytecode | ||
)) as ERC20Mock__factory | ||
const WNative = (await ethers.getContractFactory( | ||
WNativeBuild.abi, | ||
WNativeBuild.bytecode | ||
)) as WNative__factory | ||
|
||
const TOKEN_BASE_BALANCE = ether('1000') | ||
const WBNB_BASE_BALANCE = ether('1') | ||
// Setup DEX factory | ||
const dexFactory = await uniV3Factory.connect(owner).deploy() | ||
|
||
// Setup pairs | ||
const mockWBNB = await WNative.connect(owner).deploy() | ||
const positionDescriptor = await nonfungibleTokenPositionDescriptor | ||
.connect(owner) | ||
.deploy( | ||
mockWBNB.address, | ||
'0x4c4f43414c205445535400000000000000000000000000000000000000000000' | ||
) | ||
const positionManager = await nonfungiblePositionManager | ||
.connect(owner) | ||
.deploy(dexFactory.address, mockWBNB.address, positionDescriptor.address) | ||
|
||
const dexRouter = await SwapRouter.deploy( | ||
dexFactory.address, | ||
mockWBNB.address | ||
) | ||
|
||
const mockTokens: ERC20Mock[] = [] | ||
for (let index = 0; index < numPairs; index++) { | ||
// Mint pair token | ||
const mockToken = await ERC20Mock.connect(owner).deploy( | ||
`Mock Token ${index}`, | ||
`MOCK${index}` | ||
) | ||
|
||
await mockToken.connect(owner).mint(TOKEN_BASE_BALANCE) | ||
await mockToken | ||
.connect(owner) | ||
.approve(positionManager.address, TOKEN_BASE_BALANCE) | ||
|
||
await mockWBNB.connect(owner).deposit({ | ||
value: WBNB_BASE_BALANCE, // Adding ETH liquidity which gets exchanged for WETH | ||
}) | ||
await mockWBNB | ||
.connect(owner) | ||
.approve(positionManager.address, WBNB_BASE_BALANCE) | ||
|
||
let token0 = mockWBNB.address | ||
let token1 = mockToken.address | ||
if (mockWBNB.address > mockToken.address) { | ||
token0 = mockToken.address | ||
token1 = mockWBNB.address | ||
} | ||
|
||
await positionManager.createAndInitializePoolIfNecessary( | ||
token0, | ||
token1, | ||
500, | ||
'79229023000000000000000000000', | ||
{ gasLimit: '30000000' } | ||
) | ||
|
||
await positionManager.mint( | ||
{ | ||
token0: token0, | ||
token1: token1, | ||
fee: 500, | ||
tickLower: -887270, | ||
tickUpper: 887270, | ||
amount0Desired: TOKEN_BASE_BALANCE, | ||
amount1Desired: WBNB_BASE_BALANCE, | ||
amount0Min: 0, | ||
amount1Min: 0, | ||
recipient: owner.address, | ||
deadline: '999999999999999', | ||
}, | ||
{ gasLimit: '30000000' } | ||
) | ||
|
||
// NOTE: Alternative way to create pairs directly through ApeFactory | ||
// Create an initial pair | ||
// await dexFactory.createPair(mockWBNB.address, mockToken.address); | ||
// const pairCreated = await ApePair.at(await dexFactory.allPairs(index)); | ||
|
||
// // Obtain LP Tokens | ||
// await mockWBNB.transfer(pairCreated.address, WBNB_BASE_BALANCE); | ||
// await mockToken.transfer(pairCreated.address, TOKEN_BASE_BALANCE); | ||
// await pairCreated.mint(alice); | ||
|
||
mockTokens.push(mockToken) | ||
} | ||
|
||
return { | ||
dexFactory, | ||
dexRouter, | ||
positionManager, | ||
positionDescriptor, | ||
mockWBNB, | ||
mockTokens, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import { time, loadFixture } from '@nomicfoundation/hardhat-network-helpers' | ||
import { ether } from '../src/utils' | ||
import { dexV3 } from '../src' | ||
|
||
/** | ||
* hardhat-chai-matchers reference | ||
* https://hardhat.org/hardhat-chai-matchers/docs/reference | ||
* | ||
* The @nomicfoundation/hardhat-chai-matchers plugin is meant to be a drop-in replacement | ||
* for the @nomiclabs/hardhat-waffle plugin | ||
* | ||
* https://hardhat.org/hardhat-chai-matchers/docs/migrate-from-waffle | ||
* | ||
* VSCode + Hardhat: | ||
* https://marketplace.visualstudio.com/items?itemName=NomicFoundation.hardhat-solidity | ||
*/ | ||
import { anyValue } from '@nomicfoundation/hardhat-chai-matchers/withArgs' | ||
import { expect } from 'chai' | ||
// @ts-ignore | ||
import { ethers } from 'hardhat' | ||
|
||
// Setup Token Contracts | ||
import ERC20MockBuild from '../src/artifacts-apeswap/token/contracts/ERC20Mock.json' | ||
|
||
// Import Contract Types | ||
import { ERC20Mock__factory } from '../typechain-types' | ||
|
||
describe('V3 DEX', function () { | ||
// We define a fixture to reuse the same setup in every test. | ||
// We use loadFixture to run this setup once, snapshot that state, | ||
// and reset Hardhat Network to that snapshot in every test. | ||
async function deployMockDexFixture() { | ||
// Contracts are deployed using the first signer/account by default | ||
const [owner, feeTo, alice] = await ethers.getSigners() | ||
|
||
const ERC20Mock = (await ethers.getContractFactory( | ||
ERC20MockBuild.abi, | ||
ERC20MockBuild.bytecode | ||
)) as ERC20Mock__factory | ||
|
||
const { | ||
dexFactory, | ||
dexRouter, | ||
positionDescriptor, | ||
positionManager, | ||
mockWBNB, | ||
mockTokens, | ||
} = await dexV3.deployMockDex(ethers, [owner, feeTo, alice], 2) // accounts passed will be used in the deployment | ||
|
||
return { | ||
dexFactory, | ||
dexRouter, | ||
positionDescriptor, | ||
positionManager, | ||
mockWBNB, | ||
mockTokens, | ||
accounts: { | ||
owner, | ||
feeTo, | ||
alice, | ||
}, | ||
} | ||
} | ||
|
||
it('should have pair', async () => { | ||
const mockDex = await loadFixture(deployMockDexFixture) | ||
expect( | ||
( | ||
await mockDex.dexFactory.getPool( | ||
mockDex.mockTokens[0].address, | ||
mockDex.mockWBNB.address, | ||
500 | ||
) | ||
).toString() | ||
).to.not.equal('0x0000000000000000000000000000000000000000') | ||
}) | ||
|
||
it('should swap', async () => { | ||
const mockDex = await loadFixture(deployMockDexFixture) | ||
const token0 = mockDex.mockTokens[0] | ||
const mockWBNB = mockDex.mockWBNB | ||
const account = mockDex.accounts.owner.address | ||
|
||
const bnbBalanceBefore = await mockWBNB.balanceOf(account) | ||
|
||
await token0.approve(mockDex.dexRouter.address, ether('0.01')) | ||
await mockDex.dexRouter.exactInputSingle({ | ||
tokenIn: token0.address, | ||
tokenOut: mockWBNB.address, | ||
fee: 500, | ||
recipient: account, | ||
deadline: '99999999999999', | ||
amountIn: ether('0.01'), | ||
amountOutMinimum: 0, | ||
sqrtPriceLimitX96: 0, | ||
}) | ||
|
||
const bnbBalanceAfter = await mockWBNB.balanceOf(account) | ||
expect(Number(bnbBalanceAfter)).to.be.gt( | ||
Number(bnbBalanceBefore), | ||
'Did not receive any bnb on swap' | ||
) | ||
}) | ||
}) |