@hyperlane-xyz/core
Version:
Core solidity contracts for Hyperlane
236 lines (207 loc) • 7.59 kB
text/typescript
/* Imports: External */
import { BigNumber, Contract, ContractFactory, utils, Wallet } from 'ethers'
import { ethers } from 'hardhat'
import { UniswapV3Deployer } from 'uniswap-v3-deploy-plugin/dist/deployer/UniswapV3Deployer'
import { FeeAmount, TICK_SPACINGS } from '@uniswap/v3-sdk'
import { abi as NFTABI } from '@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json'
import { abi as RouterABI } from '@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json'
/* Imports: Internal */
import { expect } from './shared/setup'
import { OptimismEnv } from './shared/env'
// Below methods taken from the Uniswap test suite, see
// https://github.com/Uniswap/v3-periphery/blob/main/test/shared/ticks.ts
const getMinTick = (tickSpacing: number) =>
Math.ceil(-887272 / tickSpacing) * tickSpacing
const getMaxTick = (tickSpacing: number) =>
Math.floor(887272 / tickSpacing) * tickSpacing
describe('Contract interactions', () => {
let env: OptimismEnv
let Factory__ERC20: ContractFactory
let otherWallet: Wallet
before(async () => {
env = await OptimismEnv.new()
Factory__ERC20 = await ethers.getContractFactory('ERC20', env.l2Wallet)
otherWallet = Wallet.createRandom().connect(env.l2Wallet.provider)
await env.l2Wallet.sendTransaction({
to: otherWallet.address,
value: utils.parseEther('0.1'),
})
})
describe('ERC20s', () => {
let contract: Contract
before(async () => {
Factory__ERC20 = await ethers.getContractFactory('ERC20', env.l2Wallet)
})
it('should successfully deploy the contract', async () => {
contract = await Factory__ERC20.deploy(100000000, 'OVM Test', 8, 'OVM')
await contract.deployed()
})
it('should support approvals', async () => {
const spender = '0x' + '22'.repeat(20)
const tx = await contract.approve(spender, 1000)
await tx.wait()
let allowance = await contract.allowance(env.l2Wallet.address, spender)
expect(allowance).to.deep.equal(BigNumber.from(1000))
allowance = await contract.allowance(otherWallet.address, spender)
expect(allowance).to.deep.equal(BigNumber.from(0))
const logs = await contract.queryFilter(
contract.filters.Approval(env.l2Wallet.address),
1,
'latest'
)
expect(logs[0].args._owner).to.equal(env.l2Wallet.address)
expect(logs[0].args._spender).to.equal(spender)
expect(logs[0].args._value).to.deep.equal(BigNumber.from(1000))
})
it('should support transferring balances', async () => {
const tx = await contract.transfer(otherWallet.address, 1000)
await tx.wait()
const balFrom = await contract.balanceOf(env.l2Wallet.address)
const balTo = await contract.balanceOf(otherWallet.address)
expect(balFrom).to.deep.equal(BigNumber.from(100000000).sub(1000))
expect(balTo).to.deep.equal(BigNumber.from(1000))
const logs = await contract.queryFilter(
contract.filters.Transfer(env.l2Wallet.address),
1,
'latest'
)
expect(logs[0].args._from).to.equal(env.l2Wallet.address)
expect(logs[0].args._to).to.equal(otherWallet.address)
expect(logs[0].args._value).to.deep.equal(BigNumber.from(1000))
})
it('should support being self destructed', async () => {
const tx = await contract.destroy()
await tx.wait()
const code = await env.l2Wallet.provider.getCode(contract.address)
expect(code).to.equal('0x')
})
})
describe('uniswap', () => {
let contracts: { [name: string]: Contract }
let tokens: Contract[]
before(async () => {
if (
process.env.UNISWAP_POSITION_MANAGER_ADDRESS &&
process.env.UNISWAP_ROUTER_ADDRESS
) {
console.log('Using predeployed Uniswap. Addresses:')
console.log(
`Position manager: ${process.env.UNISWAP_POSITION_MANAGER_ADDRESS}`
)
console.log(`Router: ${process.env.UNISWAP_ROUTER_ADDRESS}`)
contracts = {
positionManager: new Contract(
process.env.UNISWAP_POSITION_MANAGER_ADDRESS,
NFTABI
).connect(env.l2Wallet),
router: new Contract(
process.env.UNISWAP_ROUTER_ADDRESS,
RouterABI
).connect(env.l2Wallet),
}
}
const tokenA = await Factory__ERC20.deploy(100000000, 'OVM1', 8, 'OVM1')
await tokenA.deployed()
const tokenB = await Factory__ERC20.deploy(100000000, 'OVM2', 8, 'OVM2')
await tokenB.deployed()
tokens = [tokenA, tokenB]
tokens.sort((a, b) => {
if (a.address > b.address) {
return 1
}
if (a.address < b.address) {
return -1
}
return 0
})
const tx = await tokens[0].transfer(otherWallet.address, 100000)
await tx.wait()
})
it('should deploy the Uniswap ecosystem', async function () {
if (contracts) {
console.log(
'Skipping Uniswap deployment since addresses are already defined.'
)
this.skip()
return
}
contracts = await UniswapV3Deployer.deploy(env.l2Wallet)
})
it('should deploy and initialize a liquidity pool', async () => {
const tx =
await contracts.positionManager.createAndInitializePoolIfNecessary(
tokens[0].address,
tokens[1].address,
FeeAmount.MEDIUM,
// initial ratio of 1/1
BigNumber.from('79228162514264337593543950336')
)
await tx.wait()
})
it('should approve the contracts', async () => {
for (const wallet of [env.l2Wallet, otherWallet]) {
for (const token of tokens) {
let tx = await token
.connect(wallet)
.approve(contracts.positionManager.address, 100000000)
await tx.wait()
tx = await token
.connect(wallet)
.approve(contracts.router.address, 100000000)
await tx.wait()
}
}
})
it('should mint new positions', async () => {
const tx = await contracts.positionManager.mint(
{
token0: tokens[0].address,
token1: tokens[1].address,
tickLower: getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]),
tickUpper: getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]),
fee: FeeAmount.MEDIUM,
recipient: env.l2Wallet.address,
amount0Desired: 15,
amount1Desired: 15,
amount0Min: 0,
amount1Min: 0,
deadline: Date.now() * 2,
},
{
gasLimit: 10000000,
}
)
await tx.wait()
expect(
await contracts.positionManager.balanceOf(env.l2Wallet.address)
).to.eq(1)
expect(
await contracts.positionManager.tokenOfOwnerByIndex(
env.l2Wallet.address,
0
)
).to.eq(1)
})
it('should swap', async () => {
const tx = await contracts.router.connect(otherWallet).exactInputSingle(
{
tokenIn: tokens[0].address,
tokenOut: tokens[1].address,
fee: FeeAmount.MEDIUM,
recipient: otherWallet.address,
deadline: Date.now() * 2,
amountIn: 10,
amountOutMinimum: 0,
sqrtPriceLimitX96: 0,
},
{
gasLimit: 10000000,
}
)
await tx.wait()
expect(await tokens[1].balanceOf(otherWallet.address)).to.deep.equal(
BigNumber.from('5')
)
})
})
})