ethereum-waffle#MockProvider TypeScript Examples
The following examples show how to use
ethereum-waffle#MockProvider.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: utilities.ts From apeswap-swap-core with GNU General Public License v3.0 | 7 votes |
export async function mineBlock(provider: Web3Provider | MockProvider, timestamp: number): Promise<void> {
await new Promise(async (resolve, reject) => {
;(provider.provider.sendAsync as any)(
{ jsonrpc: '2.0', method: 'evm_mine', params: [timestamp] },
(error: any, result: any): void => {
if (error) {
reject(error)
} else {
resolve(result)
}
}
)
})
}
Example #2
Source File: ExampleOracleSimple.spec.ts From pancake-swap-testnet with MIT License | 6 votes |
describe('ExampleOracleSimple', () => {
const provider = new MockProvider({
hardfork: 'istanbul',
mnemonic: 'horn horn horn horn horn horn horn horn horn horn horn horn',
gasLimit: 9999999
})
const [wallet] = provider.getWallets()
const loadFixture = createFixtureLoader(provider, [wallet])
let token0: Contract
let token1: Contract
let pair: Contract
let exampleOracleSimple: Contract
async function addLiquidity() {
await token0.transfer(pair.address, token0Amount)
await token1.transfer(pair.address, token1Amount)
await pair.mint(wallet.address, overrides)
}
beforeEach(async function() {
const fixture = await loadFixture(v2Fixture)
token0 = fixture.token0
token1 = fixture.token1
pair = fixture.pair
await addLiquidity()
exampleOracleSimple = await deployContract(
wallet,
ExampleOracleSimple,
[fixture.factoryV2.address, token0.address, token1.address],
overrides
)
})
it('update', async () => {
const blockTimestamp = (await pair.getReserves())[2]
await mineBlock(provider, blockTimestamp + 60 * 60 * 23)
await expect(exampleOracleSimple.update(overrides)).to.be.reverted
await mineBlock(provider, blockTimestamp + 60 * 60 * 24)
await exampleOracleSimple.update(overrides)
const expectedPrice = encodePrice(token0Amount, token1Amount)
expect(await exampleOracleSimple.price0Average()).to.eq(expectedPrice[0])
expect(await exampleOracleSimple.price1Average()).to.eq(expectedPrice[1])
expect(await exampleOracleSimple.consult(token0.address, token0Amount)).to.eq(token1Amount)
expect(await exampleOracleSimple.consult(token1.address, token1Amount)).to.eq(token0Amount)
})
})
Example #3
Source File: useGasPrice.test.tsx From useDApp with MIT License | 6 votes |
describe('useGasPrice', () => {
const mockProvider = new MockProvider()
const secondMockProvider = new MockProvider({ ganacheOptions: { _chainIdRpc: SECOND_TEST_CHAIN_ID } as any })
it('retrieves gas price', async () => {
const { result, waitForCurrent } = await renderWeb3Hook(useGasPrice)
await waitForCurrent((val) => val !== undefined)
expect(result.error).to.be.undefined
expect(result.current?.toNumber()).to.be.a('number')
})
it('retrieves gas price for multi chain', async () => {
await testMultiChainUseGasPrice(ChainId.Localhost)
await testMultiChainUseGasPrice(SECOND_TEST_CHAIN_ID)
})
const testMultiChainUseGasPrice = async (chainId: number) => {
const { result, waitForCurrent } = await renderWeb3Hook(() => useGasPrice({ chainId }), {
mockProvider: {
[ChainId.Localhost]: mockProvider,
[SECOND_TEST_CHAIN_ID]: secondMockProvider,
},
})
await waitForCurrent((val) => val !== undefined)
expect(result.error).to.be.undefined
expect(result.current?.toNumber()).to.be.a('number')
}
})
Example #4
Source File: readonlyNetworksProvider.test.ts From useDApp with MIT License | 6 votes |
describe('ReadonlyNetworksProvider', () => {
it('getProvidersFromConfig creates provider for each network that has URL', async () => {
const urls = {
[Mainnet.chainId]: 'mainnetUrl',
[Rinkeby.chainId]: 'rinkebyUrl',
[Kovan.chainId]: 'kovanUrl',
}
const providers = getProvidersFromConfig(urls)
expect(Object.keys(providers)).to.deep.equal([
Mainnet.chainId.toString(),
Rinkeby.chainId.toString(),
Kovan.chainId.toString(),
])
expect(providers[Mainnet.chainId]).to.be.instanceOf(JsonRpcProvider)
})
it('getProvidersFromConfig fetches provider object', async () => {
const mockProvider = new MockProvider()
const urls = {
[Localhost.chainId]: mockProvider,
}
const providers = getProvidersFromConfig(urls)
expect(Object.keys(providers)).to.deep.equal([Localhost.chainId.toString()])
expect(providers[Localhost.chainId]).to.eq(mockProvider)
})
})
Example #5
Source File: connectContractToSigner.test.ts From useDApp with MIT License | 6 votes |
describe('connectContractToSigner', () => {
const mockProvider = new MockProvider()
const [deployer] = mockProvider.getWallets()
let token: Contract
beforeEach(async () => {
token = new Contract(deployer.address, ERC20Interface)
})
it('throws error without signer', () => {
expect(() => connectContractToSigner(token)).to.throw('No signer available in contract, options or library')
})
it('noop if contract has signer', () => {
const signer = mockProvider.getSigner()
const connectedContract = token.connect(signer)
expect(connectContractToSigner(connectedContract).signer).to.eq(signer)
})
it('takes signer from options', () => {
const signer = mockProvider.getSigner()
const connectedContract = connectContractToSigner(token, { signer })
expect(connectedContract.signer).to.eq(signer)
})
it('takes signer from library', async () => {
const { result, waitForCurrent } = await renderWeb3Hook(() => useEthers(), { mockProvider })
await waitForCurrent((val) => val?.library !== undefined)
const { library } = result.current
const connectedContract = connectContractToSigner(token, undefined, library)
expect(connectedContract.signer).to.be.deep.eq(library?.getSigner())
})
})
Example #6
Source File: createMockProvider.ts From useDApp with MIT License | 6 votes |
createMockProvider = async (opts: CreateMockProviderOptions = {}): Promise<CreateMockProviderResult> => {
const chainId = opts.chainId ?? ChainId.Mainnet
const provider = new MockProvider({ ganacheOptions: { _chainIdRpc: chainId } as any })
const multicallAddresses = await deployMulticall(provider, chainId)
return {
provider,
multicallAddresses,
wallets: provider.getWallets(),
}
}
Example #7
Source File: deployMulticall.ts From useDApp with MIT License | 6 votes |
deployMulticall = async (provider: MockProvider, chainId: number) => {
const multicall = await deployContract((await provider.getWallets())[0], {
bytecode: MultiCall.bytecode,
abi: MultiCall.abi,
})
const multicallAddresses = { [chainId]: multicall.address }
return multicallAddresses
}
Example #8
Source File: ApeFactory.spec.ts From apeswap-swap-core with GNU General Public License v3.0 | 5 votes |
describe('ApeFactory', () => {
const provider = new MockProvider(
{
ganacheOptions: {
hardfork: 'istanbul',
mnemonic: 'horn horn horn horn horn horn horn horn horn horn horn horn',
gasLimit: 9999999
}
})
const [wallet, other] = provider.getWallets()
const loadFixture = createFixtureLoader([wallet], provider)
let factory: Contract
beforeEach(async () => {
const fixture = await loadFixture(factoryFixture)
factory = fixture.factory
})
it('feeTo, feeToSetter, allPairsLength', async () => {
expect(await factory.feeTo()).to.eq(AddressZero)
expect(await factory.feeToSetter()).to.eq(wallet.address)
expect(await factory.allPairsLength()).to.eq(0)
})
async function createPair(tokens: [string, string]) {
const bytecode = `0x${ApePair.bytecode}`
const create2Address = getCreate2Address(factory.address, tokens, bytecode)
await expect(factory.createPair(...tokens))
.to.emit(factory, 'PairCreated')
.withArgs(TEST_ADDRESSES[0], TEST_ADDRESSES[1], create2Address, BigNumber.from(1))
await expect(factory.createPair(...tokens)).to.be.reverted // ApeSwap: PAIR_EXISTS
await expect(factory.createPair(...tokens.slice().reverse())).to.be.reverted // ApeSwap: PAIR_EXISTS
expect(await factory.getPair(...tokens)).to.eq(create2Address)
expect(await factory.getPair(...tokens.slice().reverse())).to.eq(create2Address)
expect(await factory.allPairs(0)).to.eq(create2Address)
expect(await factory.allPairsLength()).to.eq(1)
const pair = new Contract(create2Address, JSON.stringify(ApePair.abi), provider as any)
expect(await pair.factory()).to.eq(factory.address)
expect(await pair.token0()).to.eq(TEST_ADDRESSES[0])
expect(await pair.token1()).to.eq(TEST_ADDRESSES[1])
}
it('createPair', async () => {
await createPair(TEST_ADDRESSES)
})
it('createPair:reverse', async () => {
await createPair(TEST_ADDRESSES.slice().reverse() as [string, string])
})
it('createPair:gas', async () => {
const tx = await factory.createPair(...TEST_ADDRESSES)
const receipt = await tx.wait()
expect(receipt.gasUsed).to.eq(2505099)
})
it('setFeeTo', async () => {
await expect(factory.connect(other).setFeeTo(other.address)).to.be.revertedWith('ApeSwap: FORBIDDEN')
await factory.setFeeTo(wallet.address)
expect(await factory.feeTo()).to.eq(wallet.address)
})
it('setFeeToSetter', async () => {
await expect(factory.connect(other).setFeeToSetter(other.address)).to.be.revertedWith('ApeSwap: FORBIDDEN')
await factory.setFeeToSetter(other.address)
expect(await factory.feeToSetter()).to.eq(other.address)
await expect(factory.setFeeToSetter(wallet.address)).to.be.revertedWith('ApeSwap: FORBIDDEN')
})
})
Example #9
Source File: VvsFactory.spec.ts From vvs-swap-core with GNU General Public License v3.0 | 5 votes |
describe("VVSFactory", () => {
const provider = new MockProvider({
ganacheOptions: {
hardfork: "istanbul",
mnemonic: "horn horn horn horn horn horn horn horn horn horn horn horn",
gasLimit: 9999999
}
});
const [wallet, other] = provider.getWallets();
const loadFixture = createFixtureLoader([wallet, other], provider);
let factory: Contract;
beforeEach(async () => {
const fixture = await loadFixture(factoryFixture);
factory = fixture.factory;
});
it("feeTo, feeToSetter, allPairsLength", async () => {
expect(await factory.feeTo()).to.eq(AddressZero);
expect(await factory.feeToSetter()).to.eq(wallet.address);
expect(await factory.allPairsLength()).to.eq(0);
});
async function createPair(tokens: [string, string]) {
const bytecode = `0x${VVSPair.evm.bytecode.object}`;
const create2Address = getCreate2Address(factory.address, tokens, bytecode);
await expect(factory.createPair(...tokens))
.to.emit(factory, "PairCreated")
.withArgs(TEST_ADDRESSES[0], TEST_ADDRESSES[1], create2Address, BigNumber.from(1));
await expect(factory.createPair(...tokens)).to.be.reverted; // VVS: PAIR_EXISTS
await expect(factory.createPair(...tokens.slice().reverse())).to.be.reverted; // VVS: PAIR_EXISTS
expect(await factory.getPair(...tokens)).to.eq(create2Address);
expect(await factory.getPair(...tokens.slice().reverse())).to.eq(create2Address);
expect(await factory.allPairs(0)).to.eq(create2Address);
expect(await factory.allPairsLength()).to.eq(1);
const pair = new Contract(create2Address, JSON.stringify(VVSPair.abi), provider);
expect(await pair.factory()).to.eq(factory.address);
expect(await pair.token0()).to.eq(TEST_ADDRESSES[0]);
expect(await pair.token1()).to.eq(TEST_ADDRESSES[1]);
}
it("createPair", async () => {
await createPair(TEST_ADDRESSES);
});
it("createPair:reverse", async () => {
await createPair(TEST_ADDRESSES.slice().reverse() as [string, string]);
});
it("createPair:gas", async () => {
const tx = await factory.createPair(...TEST_ADDRESSES);
const receipt = await tx.wait();
expect(receipt.gasUsed).to.eq(2550645);
});
it("setFeeTo", async () => {
await expect(factory.connect(other).setFeeTo(other.address)).to.be.revertedWith("VVS: FORBIDDEN");
await factory.setFeeTo(wallet.address);
expect(await factory.feeTo()).to.eq(wallet.address);
});
it("setFeeToSetter", async () => {
await expect(factory.connect(other).setFeeToSetter(other.address)).to.be.revertedWith("VVS: FORBIDDEN");
await factory.setFeeToSetter(other.address);
expect(await factory.feeToSetter()).to.eq(other.address);
await expect(factory.setFeeToSetter(wallet.address)).to.be.revertedWith("VVS: FORBIDDEN");
});
});
Example #10
Source File: AmmSpec2.ts From perpetual-protocol with GNU General Public License v3.0 | 5 votes |
describe("Amm Unit Test 2 (Waffle)", async () => {
const [wallet1, wallet2] = new MockProvider().getWallets()
let amm: Amm
let l2PriceFeed: MockContract
let quoteToken: MockContract
let clearingHouse: MockContract
const AmmArtifact = await artifacts.readArtifact(ContractFullyQualifiedName.Amm)
const IERC20Artifact = await artifacts.readArtifact(ContractFullyQualifiedName.IERC20)
const L2PriceFeedArtifact = await artifacts.readArtifact(ContractFullyQualifiedName.L2PriceFeed)
beforeEach(async () => {
quoteToken = await deployMockContract(wallet1, IERC20Artifact.abi)
clearingHouse = await deployMockContract(wallet1, [])
l2PriceFeed = await deployMockContract(wallet1, L2PriceFeedArtifact.abi)
amm = ((await deployContract(wallet1, AmmArtifact, [], { gasLimit: 6000000 })) as unknown) as Amm
await amm.initialize(
parseEther("1000"),
parseEther("100"),
parseEther("0.9"), // tradeLimitRatio
parseEther("3600"), // fundingPeriod - 1hr
l2PriceFeed.address,
utils.formatBytes32String("ETH"),
quoteToken.address,
BigNumber.from(0), // fluctuation
BigNumber.from(0), // toll
BigNumber.from(0), // spread
)
await amm.setCounterParty(clearingHouse.address)
amm.connect(clearingHouse.address)
})
describe("price", () => {
it("getUnderlyingPrice", async () => {
const price = parseEther("1")
const priceFeedKeyBytes32 = await amm.priceFeedKey()
const priceFeedKeyStr = utils.parseBytes32String(priceFeedKeyBytes32)
expect(priceFeedKeyStr).eq("ETH")
await l2PriceFeed.mock.getPrice.withArgs(priceFeedKeyBytes32).returns(price)
expect((await amm.getUnderlyingPrice()).d).deep.eq(price)
})
})
describe("setCap", () => {
it("change maxHoldingBaseAsset and openInterestNotionalCap", async () => {
await expect(amm.setCap({ d: 100 }, { d: 200 }))
.to.emit(amm, "CapChanged")
.withArgs("100", "200")
expect((await amm.getMaxHoldingBaseAsset()).d).deep.eq(BigNumber.from(100))
expect((await amm.getOpenInterestNotionalCap()).d).deep.eq(BigNumber.from(200))
})
})
describe("setPriceFeed", () => {
it("set priceFeed correctly", async () => {
const updatedPriceFeed = "0x77F9710E7d0A19669A13c055F62cd80d313dF022"
expect(await amm.priceFeed()).to.eq(l2PriceFeed.address)
await expect(amm.setPriceFeed(updatedPriceFeed))
.to.emit(amm, "PriceFeedUpdated")
.withArgs(updatedPriceFeed)
expect(await amm.priceFeed()).to.eq(updatedPriceFeed)
})
it("set priceFeed via non-owner causes revert transaction", async () => {
await expect(amm.connect(wallet2).setPriceFeed(l2PriceFeed.address)).to.be.revertedWith(
"PerpFiOwnableUpgrade: caller is not the owner",
)
})
it("revert if priceFeed address is zero", async () => {
await expect(amm.setPriceFeed(constants.AddressZero)).to.be.revertedWith("invalid PriceFeed address")
})
})
})
Example #11
Source File: UniswapV2Router02.spec.ts From pancake-swap-testnet with MIT License | 5 votes |
describe('UniswapV2Router02', () => {
const provider = new MockProvider({
hardfork: 'istanbul',
mnemonic: 'horn horn horn horn horn horn horn horn horn horn horn horn',
gasLimit: 9999999
})
const [wallet] = provider.getWallets()
const loadFixture = createFixtureLoader(provider, [wallet])
let token0: Contract
let token1: Contract
let router: Contract
beforeEach(async function() {
const fixture = await loadFixture(v2Fixture)
token0 = fixture.token0
token1 = fixture.token1
router = fixture.router02
})
it('getAmountsOut', async () => {
await token0.approve(router.address, MaxUint256)
await token1.approve(router.address, MaxUint256)
console.log( token0.address,
token1.address,
bigNumberify(10000),
bigNumberify(10000),
0,
0,
wallet.address,
MaxUint256,
overrides)
await router.addLiquidity(
token0.address,
token1.address,
bigNumberify(10000),
bigNumberify(10000),
0,
0,
wallet.address,
MaxUint256,
overrides
)
await expect(router.getAmountsOut(bigNumberify(2), [token0.address])).to.be.revertedWith(
'UniswapV2Library: INVALID_PATH'
)
const path = [token0.address, token1.address]
expect(await router.getAmountsOut(bigNumberify(2), path)).to.deep.eq([bigNumberify(2), bigNumberify(1)])
})
})
Example #12
Source File: UniswapV2Migrator.spec.ts From pancake-swap-testnet with MIT License | 5 votes |
describe('UniswapV2Migrator', () => {
const provider = new MockProvider({
hardfork: 'istanbul',
mnemonic: 'horn horn horn horn horn horn horn horn horn horn horn horn',
gasLimit: 9999999
})
const [wallet] = provider.getWallets()
const loadFixture = createFixtureLoader(provider, [wallet])
let WETHPartner: Contract
let WETHPair: Contract
let router: Contract
let migrator: Contract
let WETHExchangeV1: Contract
beforeEach(async function() {
const fixture = await loadFixture(v2Fixture)
WETHPartner = fixture.WETHPartner
WETHPair = fixture.WETHPair
router = fixture.router01 // we used router01 for this contract
migrator = fixture.migrator
WETHExchangeV1 = fixture.WETHExchangeV1
})
it('migrate', async () => {
const WETHPartnerAmount = expandTo18Decimals(1)
const ETHAmount = expandTo18Decimals(4)
await WETHPartner.approve(WETHExchangeV1.address, MaxUint256)
await WETHExchangeV1.addLiquidity(bigNumberify(1), WETHPartnerAmount, MaxUint256, {
...overrides,
value: ETHAmount
})
await WETHExchangeV1.approve(migrator.address, MaxUint256)
const expectedLiquidity = expandTo18Decimals(2)
const WETHPairToken0 = await WETHPair.token0()
await expect(
migrator.migrate(WETHPartner.address, WETHPartnerAmount, ETHAmount, wallet.address, MaxUint256, overrides)
)
.to.emit(WETHPair, 'Transfer')
.withArgs(AddressZero, AddressZero, MINIMUM_LIQUIDITY)
.to.emit(WETHPair, 'Transfer')
.withArgs(AddressZero, wallet.address, expectedLiquidity.sub(MINIMUM_LIQUIDITY))
.to.emit(WETHPair, 'Sync')
.withArgs(
WETHPairToken0 === WETHPartner.address ? WETHPartnerAmount : ETHAmount,
WETHPairToken0 === WETHPartner.address ? ETHAmount : WETHPartnerAmount
)
.to.emit(WETHPair, 'Mint')
.withArgs(
router.address,
WETHPairToken0 === WETHPartner.address ? WETHPartnerAmount : ETHAmount,
WETHPairToken0 === WETHPartner.address ? ETHAmount : WETHPartnerAmount
)
expect(await WETHPair.balanceOf(wallet.address)).to.eq(expectedLiquidity.sub(MINIMUM_LIQUIDITY))
})
})
Example #13
Source File: PancakeFactory.spec.ts From pancake-swap-testnet with MIT License | 5 votes |
describe('PancakeFactory', () => {
const provider = new MockProvider({
hardfork: 'istanbul',
mnemonic: 'horn horn horn horn horn horn horn horn horn horn horn horn',
gasLimit: 9999999
})
const [wallet, other] = provider.getWallets()
const loadFixture = createFixtureLoader(provider, [wallet, other])
let factory: Contract
beforeEach(async () => {
const fixture = await loadFixture(factoryFixture)
factory = fixture.factory
})
it('feeTo, feeToSetter, allPairsLength', async () => {
expect(await factory.feeTo()).to.eq(AddressZero)
expect(await factory.feeToSetter()).to.eq(wallet.address)
expect(await factory.allPairsLength()).to.eq(0)
})
async function createPair(tokens: [string, string]) {
const bytecode = `0x${PancakePair.evm.bytecode.object}`
const create2Address = getCreate2Address(factory.address, tokens, bytecode)
await expect(factory.createPair(...tokens))
.to.emit(factory, 'PairCreated')
.withArgs(TEST_ADDRESSES[0], TEST_ADDRESSES[1], create2Address, bigNumberify(1))
await expect(factory.createPair(...tokens)).to.be.reverted // Pancake: PAIR_EXISTS
await expect(factory.createPair(...tokens.slice().reverse())).to.be.reverted // Pancake: PAIR_EXISTS
expect(await factory.getPair(...tokens)).to.eq(create2Address)
expect(await factory.getPair(...tokens.slice().reverse())).to.eq(create2Address)
expect(await factory.allPairs(0)).to.eq(create2Address)
expect(await factory.allPairsLength()).to.eq(1)
const pair = new Contract(create2Address, JSON.stringify(PancakePair.abi), provider)
expect(await pair.factory()).to.eq(factory.address)
expect(await pair.token0()).to.eq(TEST_ADDRESSES[0])
expect(await pair.token1()).to.eq(TEST_ADDRESSES[1])
}
it('createPair', async () => {
await createPair(TEST_ADDRESSES)
})
it('createPair:reverse', async () => {
await createPair(TEST_ADDRESSES.slice().reverse() as [string, string])
})
it('createPair:gas', async () => {
const tx = await factory.createPair(...TEST_ADDRESSES)
const receipt = await tx.wait()
expect(receipt.gasUsed).to.eq(2509120)
})
it('setFeeTo', async () => {
await expect(factory.connect(other).setFeeTo(other.address)).to.be.revertedWith('Pancake: FORBIDDEN')
await factory.setFeeTo(wallet.address)
expect(await factory.feeTo()).to.eq(wallet.address)
})
it('setFeeToSetter', async () => {
await expect(factory.connect(other).setFeeToSetter(other.address)).to.be.revertedWith('Pancake: FORBIDDEN')
await factory.setFeeToSetter(other.address)
expect(await factory.feeToSetter()).to.eq(other.address)
await expect(factory.setFeeToSetter(wallet.address)).to.be.revertedWith('Pancake: FORBIDDEN')
})
})
Example #14
Source File: getAdminWallet.ts From useDApp with MIT License | 5 votes |
export async function getAdminWallet(provider: MockProvider) {
return await provider.getWallets()[9]
}
Example #15
Source File: estimateGasLimit.test.ts From useDApp with MIT License | 5 votes |
// 21000 * 1.1
describe('estimateGasLimit', () => {
const mockProvider = new MockProvider()
const [signer, receiver] = mockProvider.getWallets()
it('sending ether transaction', async () => {
const gasLimit = await estimateGasLimit(
{
value: 1,
to: receiver.address,
},
signer,
0
)
expect(gasLimit).to.equal(BASE_TX_COST)
})
it('sending ether transaction with limit', async () => {
const gasLimit = await estimateGasLimit(
{
value: 1,
to: receiver.address,
},
signer,
10
)
expect(gasLimit).to.equal(LIMITED_TX_COST)
})
it('sending ether transaction with gasLimit', async () => {
const gasLimit = await estimateGasLimit(
{
value: 1,
to: receiver.address,
gasLimit: BASE_TX_COST,
},
signer,
0
)
expect(gasLimit).to.equal(BASE_TX_COST)
})
it('sending ether transaction with limit with gasLimit', async () => {
const gasLimit = await estimateGasLimit(
{
value: 1,
to: receiver.address,
gasLimit: BASE_TX_COST,
},
signer,
10
)
expect(gasLimit).to.equal(LIMITED_TX_COST)
})
})
Example #16
Source File: useSendTransaction.test.ts From useDApp with MIT License | 5 votes |
describe('useSendTransaction', () => {
const mockProvider = new MockProvider()
const [spender, receiver, secondReceiver] = mockProvider.getWallets()
it('success', async () => {
const { result, waitForCurrent } = await renderWeb3Hook(useSendTransaction, { mockProvider })
const spenderBalance = await spender.getBalance()
const receiverBalance = await receiver.getBalance()
await result.current.sendTransaction({ to: receiver.address, value: BigNumber.from(10), gasPrice: 0 })
await waitForCurrent((val) => val.state !== undefined)
expect(result.current.state.status).to.eq('Success')
expect(await receiver.getBalance()).to.eq(receiverBalance.add(10))
expect(await spender.getBalance()).to.eq(spenderBalance.sub(10))
})
it('sends with different signer', async () => {
const receiverBalance = await receiver.getBalance()
const secondReceiverBalance = await secondReceiver.getBalance()
const { result, waitForCurrent, waitForNextUpdate } = await renderWeb3Hook(
() => useSendTransaction({ signer: receiver }),
{
mockProvider,
}
)
await waitForNextUpdate()
await result.current.sendTransaction({ to: secondReceiver.address, value: BigNumber.from(10) })
await waitForCurrent((val) => val.state != undefined)
expect(result.current.state.status).to.eq('Success')
expect(await secondReceiver.getBalance()).to.eq(secondReceiverBalance.add(10))
expect(await receiver.getBalance()).to.not.eq(receiverBalance)
})
it('Exception(invalid sender)', async () => {
const { result, waitForCurrent, waitForNextUpdate } = await renderWeb3Hook(useSendTransaction, { mockProvider })
await waitForNextUpdate()
await result.current.sendTransaction({ to: '0x1', value: utils.parseEther('1') })
await waitForCurrent((val) => val.state !== undefined)
expect(result.current.state.status).to.eq('Exception')
expect(result.current.state.errorMessage).to.eq('invalid address')
})
})
Example #17
Source File: UniswapV2Router01.spec.ts From pancake-swap-testnet with MIT License | 4 votes |
describe('UniswapV2Router{01,02}', () => {
for (const routerVersion of Object.keys(RouterVersion)) {
const provider = new MockProvider({
hardfork: 'istanbul',
mnemonic: 'horn horn horn horn horn horn horn horn horn horn horn horn',
gasLimit: 9999999
})
const [wallet] = provider.getWallets()
const loadFixture = createFixtureLoader(provider, [wallet])
let token0: Contract
let token1: Contract
let WETH: Contract
let WETHPartner: Contract
let factory: Contract
let router: Contract
let pair: Contract
let WETHPair: Contract
let routerEventEmitter: Contract
beforeEach(async function() {
const fixture = await loadFixture(v2Fixture)
token0 = fixture.token0
token1 = fixture.token1
WETH = fixture.WETH
WETHPartner = fixture.WETHPartner
factory = fixture.factoryV2
router = {
[RouterVersion.UniswapV2Router01]: fixture.router01,
[RouterVersion.UniswapV2Router02]: fixture.router02
}[routerVersion as RouterVersion]
pair = fixture.pair
WETHPair = fixture.WETHPair
routerEventEmitter = fixture.routerEventEmitter
})
afterEach(async function() {
expect(await provider.getBalance(router.address)).to.eq(Zero)
})
describe(routerVersion, () => {
it('factory, WETH', async () => {
expect(await router.factory()).to.eq(factory.address)
expect(await router.WETH()).to.eq(WETH.address)
})
it('addLiquidity', async () => {
const token0Amount = expandTo18Decimals(1)
const token1Amount = expandTo18Decimals(4)
const expectedLiquidity = expandTo18Decimals(2)
await token0.approve(router.address, MaxUint256)
await token1.approve(router.address, MaxUint256)
await expect(
router.addLiquidity(
token0.address,
token1.address,
token0Amount,
token1Amount,
0,
0,
wallet.address,
MaxUint256,
overrides
)
)
.to.emit(token0, 'Transfer')
.withArgs(wallet.address, pair.address, token0Amount)
.to.emit(token1, 'Transfer')
.withArgs(wallet.address, pair.address, token1Amount)
.to.emit(pair, 'Transfer')
.withArgs(AddressZero, AddressZero, MINIMUM_LIQUIDITY)
.to.emit(pair, 'Transfer')
.withArgs(AddressZero, wallet.address, expectedLiquidity.sub(MINIMUM_LIQUIDITY))
.to.emit(pair, 'Sync')
.withArgs(token0Amount, token1Amount)
.to.emit(pair, 'Mint')
.withArgs(router.address, token0Amount, token1Amount)
expect(await pair.balanceOf(wallet.address)).to.eq(expectedLiquidity.sub(MINIMUM_LIQUIDITY))
})
it('addLiquidityETH', async () => {
const WETHPartnerAmount = expandTo18Decimals(1)
const ETHAmount = expandTo18Decimals(4)
const expectedLiquidity = expandTo18Decimals(2)
const WETHPairToken0 = await WETHPair.token0()
await WETHPartner.approve(router.address, MaxUint256)
await expect(
router.addLiquidityETH(
WETHPartner.address,
WETHPartnerAmount,
WETHPartnerAmount,
ETHAmount,
wallet.address,
MaxUint256,
{ ...overrides, value: ETHAmount }
)
)
.to.emit(WETHPair, 'Transfer')
.withArgs(AddressZero, AddressZero, MINIMUM_LIQUIDITY)
.to.emit(WETHPair, 'Transfer')
.withArgs(AddressZero, wallet.address, expectedLiquidity.sub(MINIMUM_LIQUIDITY))
.to.emit(WETHPair, 'Sync')
.withArgs(
WETHPairToken0 === WETHPartner.address ? WETHPartnerAmount : ETHAmount,
WETHPairToken0 === WETHPartner.address ? ETHAmount : WETHPartnerAmount
)
.to.emit(WETHPair, 'Mint')
.withArgs(
router.address,
WETHPairToken0 === WETHPartner.address ? WETHPartnerAmount : ETHAmount,
WETHPairToken0 === WETHPartner.address ? ETHAmount : WETHPartnerAmount
)
expect(await WETHPair.balanceOf(wallet.address)).to.eq(expectedLiquidity.sub(MINIMUM_LIQUIDITY))
})
async function addLiquidity(token0Amount: BigNumber, token1Amount: BigNumber) {
await token0.transfer(pair.address, token0Amount)
await token1.transfer(pair.address, token1Amount)
await pair.mint(wallet.address, overrides)
}
it('removeLiquidity', async () => {
const token0Amount = expandTo18Decimals(1)
const token1Amount = expandTo18Decimals(4)
await addLiquidity(token0Amount, token1Amount)
const expectedLiquidity = expandTo18Decimals(2)
await pair.approve(router.address, MaxUint256)
await expect(
router.removeLiquidity(
token0.address,
token1.address,
expectedLiquidity.sub(MINIMUM_LIQUIDITY),
0,
0,
wallet.address,
MaxUint256,
overrides
)
)
.to.emit(pair, 'Transfer')
.withArgs(wallet.address, pair.address, expectedLiquidity.sub(MINIMUM_LIQUIDITY))
.to.emit(pair, 'Transfer')
.withArgs(pair.address, AddressZero, expectedLiquidity.sub(MINIMUM_LIQUIDITY))
.to.emit(token0, 'Transfer')
.withArgs(pair.address, wallet.address, token0Amount.sub(500))
.to.emit(token1, 'Transfer')
.withArgs(pair.address, wallet.address, token1Amount.sub(2000))
.to.emit(pair, 'Sync')
.withArgs(500, 2000)
.to.emit(pair, 'Burn')
.withArgs(router.address, token0Amount.sub(500), token1Amount.sub(2000), wallet.address)
expect(await pair.balanceOf(wallet.address)).to.eq(0)
const totalSupplyToken0 = await token0.totalSupply()
const totalSupplyToken1 = await token1.totalSupply()
expect(await token0.balanceOf(wallet.address)).to.eq(totalSupplyToken0.sub(500))
expect(await token1.balanceOf(wallet.address)).to.eq(totalSupplyToken1.sub(2000))
})
it('removeLiquidityETH', async () => {
const WETHPartnerAmount = expandTo18Decimals(1)
const ETHAmount = expandTo18Decimals(4)
await WETHPartner.transfer(WETHPair.address, WETHPartnerAmount)
await WETH.deposit({ value: ETHAmount })
await WETH.transfer(WETHPair.address, ETHAmount)
await WETHPair.mint(wallet.address, overrides)
const expectedLiquidity = expandTo18Decimals(2)
const WETHPairToken0 = await WETHPair.token0()
await WETHPair.approve(router.address, MaxUint256)
await expect(
router.removeLiquidityETH(
WETHPartner.address,
expectedLiquidity.sub(MINIMUM_LIQUIDITY),
0,
0,
wallet.address,
MaxUint256,
overrides
)
)
.to.emit(WETHPair, 'Transfer')
.withArgs(wallet.address, WETHPair.address, expectedLiquidity.sub(MINIMUM_LIQUIDITY))
.to.emit(WETHPair, 'Transfer')
.withArgs(WETHPair.address, AddressZero, expectedLiquidity.sub(MINIMUM_LIQUIDITY))
.to.emit(WETH, 'Transfer')
.withArgs(WETHPair.address, router.address, ETHAmount.sub(2000))
.to.emit(WETHPartner, 'Transfer')
.withArgs(WETHPair.address, router.address, WETHPartnerAmount.sub(500))
.to.emit(WETHPartner, 'Transfer')
.withArgs(router.address, wallet.address, WETHPartnerAmount.sub(500))
.to.emit(WETHPair, 'Sync')
.withArgs(
WETHPairToken0 === WETHPartner.address ? 500 : 2000,
WETHPairToken0 === WETHPartner.address ? 2000 : 500
)
.to.emit(WETHPair, 'Burn')
.withArgs(
router.address,
WETHPairToken0 === WETHPartner.address ? WETHPartnerAmount.sub(500) : ETHAmount.sub(2000),
WETHPairToken0 === WETHPartner.address ? ETHAmount.sub(2000) : WETHPartnerAmount.sub(500),
router.address
)
expect(await WETHPair.balanceOf(wallet.address)).to.eq(0)
const totalSupplyWETHPartner = await WETHPartner.totalSupply()
const totalSupplyWETH = await WETH.totalSupply()
expect(await WETHPartner.balanceOf(wallet.address)).to.eq(totalSupplyWETHPartner.sub(500))
expect(await WETH.balanceOf(wallet.address)).to.eq(totalSupplyWETH.sub(2000))
})
it('removeLiquidityWithPermit', async () => {
const token0Amount = expandTo18Decimals(1)
const token1Amount = expandTo18Decimals(4)
await addLiquidity(token0Amount, token1Amount)
const expectedLiquidity = expandTo18Decimals(2)
const nonce = await pair.nonces(wallet.address)
const digest = await getApprovalDigest(
pair,
{ owner: wallet.address, spender: router.address, value: expectedLiquidity.sub(MINIMUM_LIQUIDITY) },
nonce,
MaxUint256
)
const { v, r, s } = ecsign(Buffer.from(digest.slice(2), 'hex'), Buffer.from(wallet.privateKey.slice(2), 'hex'))
await router.removeLiquidityWithPermit(
token0.address,
token1.address,
expectedLiquidity.sub(MINIMUM_LIQUIDITY),
0,
0,
wallet.address,
MaxUint256,
false,
v,
r,
s,
overrides
)
})
it('removeLiquidityETHWithPermit', async () => {
const WETHPartnerAmount = expandTo18Decimals(1)
const ETHAmount = expandTo18Decimals(4)
await WETHPartner.transfer(WETHPair.address, WETHPartnerAmount)
await WETH.deposit({ value: ETHAmount })
await WETH.transfer(WETHPair.address, ETHAmount)
await WETHPair.mint(wallet.address, overrides)
const expectedLiquidity = expandTo18Decimals(2)
const nonce = await WETHPair.nonces(wallet.address)
const digest = await getApprovalDigest(
WETHPair,
{ owner: wallet.address, spender: router.address, value: expectedLiquidity.sub(MINIMUM_LIQUIDITY) },
nonce,
MaxUint256
)
const { v, r, s } = ecsign(Buffer.from(digest.slice(2), 'hex'), Buffer.from(wallet.privateKey.slice(2), 'hex'))
await router.removeLiquidityETHWithPermit(
WETHPartner.address,
expectedLiquidity.sub(MINIMUM_LIQUIDITY),
0,
0,
wallet.address,
MaxUint256,
false,
v,
r,
s,
overrides
)
})
describe('swapExactTokensForTokens', () => {
const token0Amount = expandTo18Decimals(5)
const token1Amount = expandTo18Decimals(10)
const swapAmount = expandTo18Decimals(1)
const expectedOutputAmount = bigNumberify('1662497915624478906')
beforeEach(async () => {
await addLiquidity(token0Amount, token1Amount)
await token0.approve(router.address, MaxUint256)
})
it('happy path', async () => {
await expect(
router.swapExactTokensForTokens(
swapAmount,
0,
[token0.address, token1.address],
wallet.address,
MaxUint256,
overrides
)
)
.to.emit(token0, 'Transfer')
.withArgs(wallet.address, pair.address, swapAmount)
.to.emit(token1, 'Transfer')
.withArgs(pair.address, wallet.address, expectedOutputAmount)
.to.emit(pair, 'Sync')
.withArgs(token0Amount.add(swapAmount), token1Amount.sub(expectedOutputAmount))
.to.emit(pair, 'Swap')
.withArgs(router.address, swapAmount, 0, 0, expectedOutputAmount, wallet.address)
})
it('amounts', async () => {
await token0.approve(routerEventEmitter.address, MaxUint256)
await expect(
routerEventEmitter.swapExactTokensForTokens(
router.address,
swapAmount,
0,
[token0.address, token1.address],
wallet.address,
MaxUint256,
overrides
)
)
.to.emit(routerEventEmitter, 'Amounts')
.withArgs([swapAmount, expectedOutputAmount])
})
it('gas', async () => {
// ensure that setting price{0,1}CumulativeLast for the first time doesn't affect our gas math
await mineBlock(provider, (await provider.getBlock('latest')).timestamp + 1)
await pair.sync(overrides)
await token0.approve(router.address, MaxUint256)
await mineBlock(provider, (await provider.getBlock('latest')).timestamp + 1)
const tx = await router.swapExactTokensForTokens(
swapAmount,
0,
[token0.address, token1.address],
wallet.address,
MaxUint256,
overrides
)
const receipt = await tx.wait()
expect(receipt.gasUsed).to.eq(
{
[RouterVersion.UniswapV2Router01]: 101876,
[RouterVersion.UniswapV2Router02]: 101898
}[routerVersion as RouterVersion]
)
}).retries(3)
})
describe('swapTokensForExactTokens', () => {
const token0Amount = expandTo18Decimals(5)
const token1Amount = expandTo18Decimals(10)
const expectedSwapAmount = bigNumberify('557227237267357629')
const outputAmount = expandTo18Decimals(1)
beforeEach(async () => {
await addLiquidity(token0Amount, token1Amount)
})
it('happy path', async () => {
await token0.approve(router.address, MaxUint256)
await expect(
router.swapTokensForExactTokens(
outputAmount,
MaxUint256,
[token0.address, token1.address],
wallet.address,
MaxUint256,
overrides
)
)
.to.emit(token0, 'Transfer')
.withArgs(wallet.address, pair.address, expectedSwapAmount)
.to.emit(token1, 'Transfer')
.withArgs(pair.address, wallet.address, outputAmount)
.to.emit(pair, 'Sync')
.withArgs(token0Amount.add(expectedSwapAmount), token1Amount.sub(outputAmount))
.to.emit(pair, 'Swap')
.withArgs(router.address, expectedSwapAmount, 0, 0, outputAmount, wallet.address)
})
it('amounts', async () => {
await token0.approve(routerEventEmitter.address, MaxUint256)
await expect(
routerEventEmitter.swapTokensForExactTokens(
router.address,
outputAmount,
MaxUint256,
[token0.address, token1.address],
wallet.address,
MaxUint256,
overrides
)
)
.to.emit(routerEventEmitter, 'Amounts')
.withArgs([expectedSwapAmount, outputAmount])
})
})
describe('swapExactETHForTokens', () => {
const WETHPartnerAmount = expandTo18Decimals(10)
const ETHAmount = expandTo18Decimals(5)
const swapAmount = expandTo18Decimals(1)
const expectedOutputAmount = bigNumberify('1662497915624478906')
beforeEach(async () => {
await WETHPartner.transfer(WETHPair.address, WETHPartnerAmount)
await WETH.deposit({ value: ETHAmount })
await WETH.transfer(WETHPair.address, ETHAmount)
await WETHPair.mint(wallet.address, overrides)
await token0.approve(router.address, MaxUint256)
})
it('happy path', async () => {
const WETHPairToken0 = await WETHPair.token0()
await expect(
router.swapExactETHForTokens(0, [WETH.address, WETHPartner.address], wallet.address, MaxUint256, {
...overrides,
value: swapAmount
})
)
.to.emit(WETH, 'Transfer')
.withArgs(router.address, WETHPair.address, swapAmount)
.to.emit(WETHPartner, 'Transfer')
.withArgs(WETHPair.address, wallet.address, expectedOutputAmount)
.to.emit(WETHPair, 'Sync')
.withArgs(
WETHPairToken0 === WETHPartner.address
? WETHPartnerAmount.sub(expectedOutputAmount)
: ETHAmount.add(swapAmount),
WETHPairToken0 === WETHPartner.address
? ETHAmount.add(swapAmount)
: WETHPartnerAmount.sub(expectedOutputAmount)
)
.to.emit(WETHPair, 'Swap')
.withArgs(
router.address,
WETHPairToken0 === WETHPartner.address ? 0 : swapAmount,
WETHPairToken0 === WETHPartner.address ? swapAmount : 0,
WETHPairToken0 === WETHPartner.address ? expectedOutputAmount : 0,
WETHPairToken0 === WETHPartner.address ? 0 : expectedOutputAmount,
wallet.address
)
})
it('amounts', async () => {
await expect(
routerEventEmitter.swapExactETHForTokens(
router.address,
0,
[WETH.address, WETHPartner.address],
wallet.address,
MaxUint256,
{
...overrides,
value: swapAmount
}
)
)
.to.emit(routerEventEmitter, 'Amounts')
.withArgs([swapAmount, expectedOutputAmount])
})
it('gas', async () => {
const WETHPartnerAmount = expandTo18Decimals(10)
const ETHAmount = expandTo18Decimals(5)
await WETHPartner.transfer(WETHPair.address, WETHPartnerAmount)
await WETH.deposit({ value: ETHAmount })
await WETH.transfer(WETHPair.address, ETHAmount)
await WETHPair.mint(wallet.address, overrides)
// ensure that setting price{0,1}CumulativeLast for the first time doesn't affect our gas math
await mineBlock(provider, (await provider.getBlock('latest')).timestamp + 1)
await pair.sync(overrides)
const swapAmount = expandTo18Decimals(1)
await mineBlock(provider, (await provider.getBlock('latest')).timestamp + 1)
const tx = await router.swapExactETHForTokens(
0,
[WETH.address, WETHPartner.address],
wallet.address,
MaxUint256,
{
...overrides,
value: swapAmount
}
)
const receipt = await tx.wait()
expect(receipt.gasUsed).to.eq(
{
[RouterVersion.UniswapV2Router01]: 138770,
[RouterVersion.UniswapV2Router02]: 138770
}[routerVersion as RouterVersion]
)
}).retries(3)
})
describe('swapTokensForExactETH', () => {
const WETHPartnerAmount = expandTo18Decimals(5)
const ETHAmount = expandTo18Decimals(10)
const expectedSwapAmount = bigNumberify('557227237267357629')
const outputAmount = expandTo18Decimals(1)
beforeEach(async () => {
await WETHPartner.transfer(WETHPair.address, WETHPartnerAmount)
await WETH.deposit({ value: ETHAmount })
await WETH.transfer(WETHPair.address, ETHAmount)
await WETHPair.mint(wallet.address, overrides)
})
it('happy path', async () => {
await WETHPartner.approve(router.address, MaxUint256)
const WETHPairToken0 = await WETHPair.token0()
await expect(
router.swapTokensForExactETH(
outputAmount,
MaxUint256,
[WETHPartner.address, WETH.address],
wallet.address,
MaxUint256,
overrides
)
)
.to.emit(WETHPartner, 'Transfer')
.withArgs(wallet.address, WETHPair.address, expectedSwapAmount)
.to.emit(WETH, 'Transfer')
.withArgs(WETHPair.address, router.address, outputAmount)
.to.emit(WETHPair, 'Sync')
.withArgs(
WETHPairToken0 === WETHPartner.address
? WETHPartnerAmount.add(expectedSwapAmount)
: ETHAmount.sub(outputAmount),
WETHPairToken0 === WETHPartner.address
? ETHAmount.sub(outputAmount)
: WETHPartnerAmount.add(expectedSwapAmount)
)
.to.emit(WETHPair, 'Swap')
.withArgs(
router.address,
WETHPairToken0 === WETHPartner.address ? expectedSwapAmount : 0,
WETHPairToken0 === WETHPartner.address ? 0 : expectedSwapAmount,
WETHPairToken0 === WETHPartner.address ? 0 : outputAmount,
WETHPairToken0 === WETHPartner.address ? outputAmount : 0,
router.address
)
})
it('amounts', async () => {
await WETHPartner.approve(routerEventEmitter.address, MaxUint256)
await expect(
routerEventEmitter.swapTokensForExactETH(
router.address,
outputAmount,
MaxUint256,
[WETHPartner.address, WETH.address],
wallet.address,
MaxUint256,
overrides
)
)
.to.emit(routerEventEmitter, 'Amounts')
.withArgs([expectedSwapAmount, outputAmount])
})
})
describe('swapExactTokensForETH', () => {
const WETHPartnerAmount = expandTo18Decimals(5)
const ETHAmount = expandTo18Decimals(10)
const swapAmount = expandTo18Decimals(1)
const expectedOutputAmount = bigNumberify('1662497915624478906')
beforeEach(async () => {
await WETHPartner.transfer(WETHPair.address, WETHPartnerAmount)
await WETH.deposit({ value: ETHAmount })
await WETH.transfer(WETHPair.address, ETHAmount)
await WETHPair.mint(wallet.address, overrides)
})
it('happy path', async () => {
await WETHPartner.approve(router.address, MaxUint256)
const WETHPairToken0 = await WETHPair.token0()
await expect(
router.swapExactTokensForETH(
swapAmount,
0,
[WETHPartner.address, WETH.address],
wallet.address,
MaxUint256,
overrides
)
)
.to.emit(WETHPartner, 'Transfer')
.withArgs(wallet.address, WETHPair.address, swapAmount)
.to.emit(WETH, 'Transfer')
.withArgs(WETHPair.address, router.address, expectedOutputAmount)
.to.emit(WETHPair, 'Sync')
.withArgs(
WETHPairToken0 === WETHPartner.address
? WETHPartnerAmount.add(swapAmount)
: ETHAmount.sub(expectedOutputAmount),
WETHPairToken0 === WETHPartner.address
? ETHAmount.sub(expectedOutputAmount)
: WETHPartnerAmount.add(swapAmount)
)
.to.emit(WETHPair, 'Swap')
.withArgs(
router.address,
WETHPairToken0 === WETHPartner.address ? swapAmount : 0,
WETHPairToken0 === WETHPartner.address ? 0 : swapAmount,
WETHPairToken0 === WETHPartner.address ? 0 : expectedOutputAmount,
WETHPairToken0 === WETHPartner.address ? expectedOutputAmount : 0,
router.address
)
})
it('amounts', async () => {
await WETHPartner.approve(routerEventEmitter.address, MaxUint256)
await expect(
routerEventEmitter.swapExactTokensForETH(
router.address,
swapAmount,
0,
[WETHPartner.address, WETH.address],
wallet.address,
MaxUint256,
overrides
)
)
.to.emit(routerEventEmitter, 'Amounts')
.withArgs([swapAmount, expectedOutputAmount])
})
})
describe('swapETHForExactTokens', () => {
const WETHPartnerAmount = expandTo18Decimals(10)
const ETHAmount = expandTo18Decimals(5)
const expectedSwapAmount = bigNumberify('557227237267357629')
const outputAmount = expandTo18Decimals(1)
beforeEach(async () => {
await WETHPartner.transfer(WETHPair.address, WETHPartnerAmount)
await WETH.deposit({ value: ETHAmount })
await WETH.transfer(WETHPair.address, ETHAmount)
await WETHPair.mint(wallet.address, overrides)
})
it('happy path', async () => {
const WETHPairToken0 = await WETHPair.token0()
await expect(
router.swapETHForExactTokens(
outputAmount,
[WETH.address, WETHPartner.address],
wallet.address,
MaxUint256,
{
...overrides,
value: expectedSwapAmount
}
)
)
.to.emit(WETH, 'Transfer')
.withArgs(router.address, WETHPair.address, expectedSwapAmount)
.to.emit(WETHPartner, 'Transfer')
.withArgs(WETHPair.address, wallet.address, outputAmount)
.to.emit(WETHPair, 'Sync')
.withArgs(
WETHPairToken0 === WETHPartner.address
? WETHPartnerAmount.sub(outputAmount)
: ETHAmount.add(expectedSwapAmount),
WETHPairToken0 === WETHPartner.address
? ETHAmount.add(expectedSwapAmount)
: WETHPartnerAmount.sub(outputAmount)
)
.to.emit(WETHPair, 'Swap')
.withArgs(
router.address,
WETHPairToken0 === WETHPartner.address ? 0 : expectedSwapAmount,
WETHPairToken0 === WETHPartner.address ? expectedSwapAmount : 0,
WETHPairToken0 === WETHPartner.address ? outputAmount : 0,
WETHPairToken0 === WETHPartner.address ? 0 : outputAmount,
wallet.address
)
})
it('amounts', async () => {
await expect(
routerEventEmitter.swapETHForExactTokens(
router.address,
outputAmount,
[WETH.address, WETHPartner.address],
wallet.address,
MaxUint256,
{
...overrides,
value: expectedSwapAmount
}
)
)
.to.emit(routerEventEmitter, 'Amounts')
.withArgs([expectedSwapAmount, outputAmount])
})
})
})
}
})
Example #18
Source File: VvsPair.spec.ts From vvs-swap-core with GNU General Public License v3.0 | 4 votes |
describe("VVSPair", () => {
const provider = new MockProvider({
ganacheOptions: {
hardfork: "istanbul",
mnemonic: "horn horn horn horn horn horn horn horn horn horn horn horn",
gasLimit: 9999999
}
});
const [wallet, other] = provider.getWallets();
const loadFixture = createFixtureLoader([wallet], provider);
let factory: Contract;
let token0: Contract;
let token1: Contract;
let pair: Contract;
beforeEach(async () => {
const fixture = await loadFixture(pairFixture);
factory = fixture.factory;
token0 = fixture.token0;
token1 = fixture.token1;
pair = fixture.pair;
});
it("mint", async () => {
const token0Amount = expandTo18Decimals(1);
const token1Amount = expandTo18Decimals(4);
await token0.transfer(pair.address, token0Amount);
await token1.transfer(pair.address, token1Amount);
const expectedLiquidity = expandTo18Decimals(2);
await expect(pair.mint(wallet.address, overrides))
.to.emit(pair, "Transfer")
.withArgs(AddressZero, AddressZero, MINIMUM_LIQUIDITY)
.to.emit(pair, "Transfer")
.withArgs(AddressZero, wallet.address, expectedLiquidity.sub(MINIMUM_LIQUIDITY))
.to.emit(pair, "Sync")
.withArgs(token0Amount, token1Amount)
.to.emit(pair, "Mint")
.withArgs(wallet.address, token0Amount, token1Amount);
expect(await pair.totalSupply()).to.eq(expectedLiquidity);
expect(await pair.balanceOf(wallet.address)).to.eq(expectedLiquidity.sub(MINIMUM_LIQUIDITY));
expect(await token0.balanceOf(pair.address)).to.eq(token0Amount);
expect(await token1.balanceOf(pair.address)).to.eq(token1Amount);
const reserves = await pair.getReserves();
expect(reserves[0]).to.eq(token0Amount);
expect(reserves[1]).to.eq(token1Amount);
});
async function addLiquidity(token0Amount: BigNumber, token1Amount: BigNumber) {
await token0.transfer(pair.address, token0Amount);
await token1.transfer(pair.address, token1Amount);
await pair.mint(wallet.address, overrides);
}
const swapTestCases: BigNumber[][] = [
[1, 5, 10, "1662497915624478906"],
[1, 10, 5, "453305446940074565"],
[2, 5, 10, "2851015155847869602"],
[2, 10, 5, "831248957812239453"],
[1, 10, 10, "906610893880149131"],
[1, 100, 100, "987158034397061298"],
[1, 1000, 1000, "996006981039903216"]
].map(a => a.map(n => (typeof n === "string" ? BigNumber.from(n) : expandTo18Decimals(n))));
swapTestCases.forEach((swapTestCase, i) => {
it(`getInputPrice:${i}`, async () => {
const [swapAmount, token0Amount, token1Amount, expectedOutputAmount] = swapTestCase;
await addLiquidity(token0Amount, token1Amount);
await token0.transfer(pair.address, swapAmount);
await expect(pair.swap(0, expectedOutputAmount.add(1), wallet.address, "0x", overrides)).to.be.revertedWith(
"VVS: K"
);
await pair.swap(0, expectedOutputAmount, wallet.address, "0x", overrides);
});
});
const optimisticTestCases: BigNumber[][] = [
["997000000000000000", 5, 10, 1], // given amountIn, amountOut = floor(amountIn * .997)
["997000000000000000", 10, 5, 1],
["997000000000000000", 5, 5, 1],
[1, 5, 5, "1003009027081243732"] // given amountOut, amountIn = ceiling(amountOut / .9975)
].map(a => a.map(n => (typeof n === "string" ? BigNumber.from(n) : expandTo18Decimals(n))));
optimisticTestCases.forEach((optimisticTestCase, i) => {
it(`optimistic:${i}`, async () => {
const [outputAmount, token0Amount, token1Amount, inputAmount] = optimisticTestCase;
await addLiquidity(token0Amount, token1Amount);
await token0.transfer(pair.address, inputAmount);
await expect(pair.swap(outputAmount.add(1), 0, wallet.address, "0x", overrides)).to.be.revertedWith("VVS: K");
await pair.swap(outputAmount, 0, wallet.address, "0x", overrides);
});
});
it("swap:token0", async () => {
const token0Amount = expandTo18Decimals(5);
const token1Amount = expandTo18Decimals(10);
await addLiquidity(token0Amount, token1Amount);
const swapAmount = expandTo18Decimals(1);
const expectedOutputAmount = BigNumber.from("1662497915624478906");
await token0.transfer(pair.address, swapAmount);
await expect(pair.swap(0, expectedOutputAmount, wallet.address, "0x", overrides))
.to.emit(token1, "Transfer")
.withArgs(pair.address, wallet.address, expectedOutputAmount)
.to.emit(pair, "Sync")
.withArgs(token0Amount.add(swapAmount), token1Amount.sub(expectedOutputAmount))
.to.emit(pair, "Swap")
.withArgs(wallet.address, swapAmount, 0, 0, expectedOutputAmount, wallet.address);
const reserves = await pair.getReserves();
expect(reserves[0]).to.eq(token0Amount.add(swapAmount));
expect(reserves[1]).to.eq(token1Amount.sub(expectedOutputAmount));
expect(await token0.balanceOf(pair.address)).to.eq(token0Amount.add(swapAmount));
expect(await token1.balanceOf(pair.address)).to.eq(token1Amount.sub(expectedOutputAmount));
const totalSupplyToken0 = await token0.totalSupply();
const totalSupplyToken1 = await token1.totalSupply();
expect(await token0.balanceOf(wallet.address)).to.eq(totalSupplyToken0.sub(token0Amount).sub(swapAmount));
expect(await token1.balanceOf(wallet.address)).to.eq(totalSupplyToken1.sub(token1Amount).add(expectedOutputAmount));
});
it("swap:token1", async () => {
const token0Amount = expandTo18Decimals(5);
const token1Amount = expandTo18Decimals(10);
await addLiquidity(token0Amount, token1Amount);
const swapAmount = expandTo18Decimals(1);
const expectedOutputAmount = BigNumber.from("453305446940074565");
await token1.transfer(pair.address, swapAmount);
await expect(pair.swap(expectedOutputAmount, 0, wallet.address, "0x", overrides))
.to.emit(token0, "Transfer")
.withArgs(pair.address, wallet.address, expectedOutputAmount)
.to.emit(pair, "Sync")
.withArgs(token0Amount.sub(expectedOutputAmount), token1Amount.add(swapAmount))
.to.emit(pair, "Swap")
.withArgs(wallet.address, 0, swapAmount, expectedOutputAmount, 0, wallet.address);
const reserves = await pair.getReserves();
expect(reserves[0]).to.eq(token0Amount.sub(expectedOutputAmount));
expect(reserves[1]).to.eq(token1Amount.add(swapAmount));
expect(await token0.balanceOf(pair.address)).to.eq(token0Amount.sub(expectedOutputAmount));
expect(await token1.balanceOf(pair.address)).to.eq(token1Amount.add(swapAmount));
const totalSupplyToken0 = await token0.totalSupply();
const totalSupplyToken1 = await token1.totalSupply();
expect(await token0.balanceOf(wallet.address)).to.eq(totalSupplyToken0.sub(token0Amount).add(expectedOutputAmount));
expect(await token1.balanceOf(wallet.address)).to.eq(totalSupplyToken1.sub(token1Amount).sub(swapAmount));
});
it("swap:gas", async () => {
const token0Amount = expandTo18Decimals(5);
const token1Amount = expandTo18Decimals(10);
await addLiquidity(token0Amount, token1Amount);
// ensure that setting price{0,1}CumulativeLast for the first time doesn't affect our gas math
await mineBlock(provider, (await provider.getBlock("latest")).timestamp + 1);
await pair.sync(overrides);
const swapAmount = expandTo18Decimals(1);
const expectedOutputAmount = BigNumber.from("453305446940074565");
await token1.transfer(pair.address, swapAmount);
await mineBlock(provider, (await provider.getBlock("latest")).timestamp + 1);
const tx = await pair.swap(expectedOutputAmount, 0, wallet.address, "0x", overrides);
const receipt = await tx.wait();
expect(receipt.gasUsed).to.eq(73462);
});
it("burn", async () => {
const token0Amount = expandTo18Decimals(3);
const token1Amount = expandTo18Decimals(3);
await addLiquidity(token0Amount, token1Amount);
const expectedLiquidity = expandTo18Decimals(3);
await pair.transfer(pair.address, expectedLiquidity.sub(MINIMUM_LIQUIDITY));
await expect(pair.burn(wallet.address, overrides))
.to.emit(pair, "Transfer")
.withArgs(pair.address, AddressZero, expectedLiquidity.sub(MINIMUM_LIQUIDITY))
.to.emit(token0, "Transfer")
.withArgs(pair.address, wallet.address, token0Amount.sub(1000))
.to.emit(token1, "Transfer")
.withArgs(pair.address, wallet.address, token1Amount.sub(1000))
.to.emit(pair, "Sync")
.withArgs(1000, 1000)
.to.emit(pair, "Burn")
.withArgs(wallet.address, token0Amount.sub(1000), token1Amount.sub(1000), wallet.address);
expect(await pair.balanceOf(wallet.address)).to.eq(0);
expect(await pair.totalSupply()).to.eq(MINIMUM_LIQUIDITY);
expect(await token0.balanceOf(pair.address)).to.eq(1000);
expect(await token1.balanceOf(pair.address)).to.eq(1000);
const totalSupplyToken0 = await token0.totalSupply();
const totalSupplyToken1 = await token1.totalSupply();
expect(await token0.balanceOf(wallet.address)).to.eq(totalSupplyToken0.sub(1000));
expect(await token1.balanceOf(wallet.address)).to.eq(totalSupplyToken1.sub(1000));
});
it("price{0,1}CumulativeLast", async () => {
const token0Amount = expandTo18Decimals(3);
const token1Amount = expandTo18Decimals(3);
await addLiquidity(token0Amount, token1Amount);
const blockTimestamp = (await pair.getReserves())[2];
await mineBlock(provider, blockTimestamp + 1);
await pair.sync(overrides);
const initialPrice = encodePrice(token0Amount, token1Amount);
expect(await pair.price0CumulativeLast()).to.eq(initialPrice[0]);
expect(await pair.price1CumulativeLast()).to.eq(initialPrice[1]);
expect((await pair.getReserves())[2]).to.eq(blockTimestamp + 1);
const swapAmount = expandTo18Decimals(3);
await token0.transfer(pair.address, swapAmount);
await mineBlock(provider, blockTimestamp + 10);
// swap to a new price eagerly instead of syncing
await pair.swap(0, expandTo18Decimals(1), wallet.address, "0x", overrides); // make the price nice
expect(await pair.price0CumulativeLast()).to.eq(initialPrice[0].mul(10));
expect(await pair.price1CumulativeLast()).to.eq(initialPrice[1].mul(10));
expect((await pair.getReserves())[2]).to.eq(blockTimestamp + 10);
await mineBlock(provider, blockTimestamp + 20);
await pair.sync(overrides);
const newPrice = encodePrice(expandTo18Decimals(6), expandTo18Decimals(2));
expect(await pair.price0CumulativeLast()).to.eq(initialPrice[0].mul(10).add(newPrice[0].mul(10)));
expect(await pair.price1CumulativeLast()).to.eq(initialPrice[1].mul(10).add(newPrice[1].mul(10)));
expect((await pair.getReserves())[2]).to.eq(blockTimestamp + 20);
});
it("feeTo:off", async () => {
const token0Amount = expandTo18Decimals(1000);
const token1Amount = expandTo18Decimals(1000);
await addLiquidity(token0Amount, token1Amount);
const swapAmount = expandTo18Decimals(1);
const expectedOutputAmount = BigNumber.from("996006981039903216");
await token1.transfer(pair.address, swapAmount);
await pair.swap(expectedOutputAmount, 0, wallet.address, "0x", overrides);
const expectedLiquidity = expandTo18Decimals(1000);
await pair.transfer(pair.address, expectedLiquidity.sub(MINIMUM_LIQUIDITY));
await pair.burn(wallet.address, overrides);
expect(await pair.totalSupply()).to.eq(MINIMUM_LIQUIDITY);
});
it("feeTo:on", async () => {
await factory.setFeeTo(other.address);
const token0Amount = expandTo18Decimals(1000);
const token1Amount = expandTo18Decimals(1000);
await addLiquidity(token0Amount, token1Amount);
const swapAmount = expandTo18Decimals(1);
const expectedOutputAmount = BigNumber.from("996006981039903216");
await token1.transfer(pair.address, swapAmount);
await pair.swap(expectedOutputAmount, 0, wallet.address, "0x", overrides);
const expectedLiquidity = expandTo18Decimals(1000);
await pair.transfer(pair.address, expectedLiquidity.sub(MINIMUM_LIQUIDITY));
await pair.burn(wallet.address, overrides);
expect(await pair.totalSupply()).to.eq(MINIMUM_LIQUIDITY.add("499501123253431"));
expect(await pair.balanceOf(other.address)).to.eq("499501123253431");
//
// // using 1000 here instead of the symbolic MINIMUM_LIQUIDITY because the amounts only happen to be equal...
// // ...because the initial liquidity amounts were equal
expect(await token0.balanceOf(pair.address)).to.eq(BigNumber.from(1000).add("499003367394890"));
expect(await token1.balanceOf(pair.address)).to.eq(BigNumber.from(1000).add("500000374625937"));
});
});
Example #19
Source File: ApeERC20.spec.ts From apeswap-swap-core with GNU General Public License v3.0 | 4 votes |
describe('ApeERC20', () => {
const provider = new MockProvider(
{
ganacheOptions: {
hardfork: 'istanbul',
mnemonic: 'horn horn horn horn horn horn horn horn horn horn horn horn',
gasLimit: 9999999
}
})
const [wallet, other] = provider.getWallets()
let token: Contract
beforeEach(async () => {
token = await deployContract(wallet, ERC20, [TOTAL_SUPPLY])
})
it('name, symbol, decimals, totalSupply, balanceOf, DOMAIN_SEPARATOR, PERMIT_TYPEHASH', async () => {
const name = await token.name()
expect(name).to.eq('ApeSwapFinance LPs')
expect(await token.symbol()).to.eq('APE-LP')
expect(await token.decimals()).to.eq(18)
expect(await token.totalSupply()).to.eq(TOTAL_SUPPLY)
expect(await token.balanceOf(wallet.address)).to.eq(TOTAL_SUPPLY)
expect(await token.DOMAIN_SEPARATOR()).to.eq(
keccak256(
defaultAbiCoder.encode(
['bytes32', 'bytes32', 'bytes32', 'uint256', 'address'],
[
keccak256(
toUtf8Bytes('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)')
),
keccak256(toUtf8Bytes(name)),
keccak256(toUtf8Bytes('1')),
1,
token.address
]
)
)
)
expect(await token.PERMIT_TYPEHASH()).to.eq(
keccak256(toUtf8Bytes('Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)'))
)
})
it('approve', async () => {
await expect(token.approve(other.address, TEST_AMOUNT))
.to.emit(token, 'Approval')
.withArgs(wallet.address, other.address, TEST_AMOUNT)
expect(await token.allowance(wallet.address, other.address)).to.eq(TEST_AMOUNT)
})
it('transfer', async () => {
await expect(token.transfer(other.address, TEST_AMOUNT))
.to.emit(token, 'Transfer')
.withArgs(wallet.address, other.address, TEST_AMOUNT)
expect(await token.balanceOf(wallet.address)).to.eq(TOTAL_SUPPLY.sub(TEST_AMOUNT))
expect(await token.balanceOf(other.address)).to.eq(TEST_AMOUNT)
})
it('transfer:fail', async () => {
await expect(token.transfer(other.address, TOTAL_SUPPLY.add(1))).to.be.reverted // ds-math-sub-underflow
await expect(token.connect(other).transfer(wallet.address, 1)).to.be.reverted // ds-math-sub-underflow
})
it('transferFrom', async () => {
await token.approve(other.address, TEST_AMOUNT)
await expect(token.connect(other).transferFrom(wallet.address, other.address, TEST_AMOUNT))
.to.emit(token, 'Transfer')
.withArgs(wallet.address, other.address, TEST_AMOUNT)
expect(await token.allowance(wallet.address, other.address)).to.eq(0)
expect(await token.balanceOf(wallet.address)).to.eq(TOTAL_SUPPLY.sub(TEST_AMOUNT))
expect(await token.balanceOf(other.address)).to.eq(TEST_AMOUNT)
})
it('transferFrom:max', async () => {
await token.approve(other.address, MaxUint256)
await expect(token.connect(other).transferFrom(wallet.address, other.address, TEST_AMOUNT))
.to.emit(token, 'Transfer')
.withArgs(wallet.address, other.address, TEST_AMOUNT)
expect(await token.allowance(wallet.address, other.address)).to.eq(MaxUint256)
expect(await token.balanceOf(wallet.address)).to.eq(TOTAL_SUPPLY.sub(TEST_AMOUNT))
expect(await token.balanceOf(other.address)).to.eq(TEST_AMOUNT)
})
it('permit', async () => {
const nonce = await token.nonces(wallet.address)
const deadline = MaxUint256
const digest = await getApprovalDigest(
token,
{ owner: wallet.address, spender: other.address, value: TEST_AMOUNT },
nonce,
deadline
)
const { v, r, s } = ecsign(Buffer.from(digest.slice(2), 'hex'), Buffer.from(wallet.privateKey.slice(2), 'hex'))
await expect(token.permit(wallet.address, other.address, TEST_AMOUNT, deadline, v, hexlify(r), hexlify(s)))
.to.emit(token, 'Approval')
.withArgs(wallet.address, other.address, TEST_AMOUNT)
expect(await token.allowance(wallet.address, other.address)).to.eq(TEST_AMOUNT)
expect(await token.nonces(wallet.address)).to.eq(BigNumber.from(1))
})
})
Example #20
Source File: VvsERC20.spec.ts From vvs-swap-core with GNU General Public License v3.0 | 4 votes |
describe("VVSERC20", () => {
const provider = new MockProvider({
ganacheOptions: {
hardfork: "istanbul",
mnemonic: "horn horn horn horn horn horn horn horn horn horn horn horn",
gasLimit: 9999999
}
});
const [wallet, other] = provider.getWallets();
let token: Contract;
beforeEach(async () => {
token = await deployContract(wallet, ERC20, [TOTAL_SUPPLY]);
});
it("name, symbol, decimals, totalSupply, balanceOf, DOMAIN_SEPARATOR, PERMIT_TYPEHASH", async () => {
const name = await token.name();
expect(name).to.eq("VVS Finance LPs");
expect(await token.symbol()).to.eq("VVS-LP");
expect(await token.decimals()).to.eq(18);
expect(await token.totalSupply()).to.eq(TOTAL_SUPPLY);
expect(await token.balanceOf(wallet.address)).to.eq(TOTAL_SUPPLY);
expect(await token.DOMAIN_SEPARATOR()).to.eq(
keccak256(
defaultAbiCoder.encode(
["bytes32", "bytes32", "bytes32", "uint256", "address"],
[
keccak256(
toUtf8Bytes("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")
),
keccak256(toUtf8Bytes(name)),
keccak256(toUtf8Bytes("1")),
1,
token.address
]
)
)
);
expect(await token.PERMIT_TYPEHASH()).to.eq(
keccak256(toUtf8Bytes("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"))
);
});
it("approve", async () => {
await expect(token.approve(other.address, TEST_AMOUNT))
.to.emit(token, "Approval")
.withArgs(wallet.address, other.address, TEST_AMOUNT);
expect(await token.allowance(wallet.address, other.address)).to.eq(TEST_AMOUNT);
});
it("transfer", async () => {
await expect(token.transfer(other.address, TEST_AMOUNT))
.to.emit(token, "Transfer")
.withArgs(wallet.address, other.address, TEST_AMOUNT);
expect(await token.balanceOf(wallet.address)).to.eq(TOTAL_SUPPLY.sub(TEST_AMOUNT));
expect(await token.balanceOf(other.address)).to.eq(TEST_AMOUNT);
});
it("transfer:fail", async () => {
await expect(token.transfer(other.address, TOTAL_SUPPLY.add(1))).to.be.reverted; // ds-math-sub-underflow
await expect(token.connect(other).transfer(wallet.address, 1)).to.be.reverted; // ds-math-sub-underflow
});
it("transferFrom", async () => {
await token.approve(other.address, TEST_AMOUNT);
await expect(token.connect(other).transferFrom(wallet.address, other.address, TEST_AMOUNT))
.to.emit(token, "Transfer")
.withArgs(wallet.address, other.address, TEST_AMOUNT);
expect(await token.allowance(wallet.address, other.address)).to.eq(0);
expect(await token.balanceOf(wallet.address)).to.eq(TOTAL_SUPPLY.sub(TEST_AMOUNT));
expect(await token.balanceOf(other.address)).to.eq(TEST_AMOUNT);
});
it("transferFrom:max", async () => {
await token.approve(other.address, MaxUint256);
await expect(token.connect(other).transferFrom(wallet.address, other.address, TEST_AMOUNT))
.to.emit(token, "Transfer")
.withArgs(wallet.address, other.address, TEST_AMOUNT);
expect(await token.allowance(wallet.address, other.address)).to.eq(MaxUint256);
expect(await token.balanceOf(wallet.address)).to.eq(TOTAL_SUPPLY.sub(TEST_AMOUNT));
expect(await token.balanceOf(other.address)).to.eq(TEST_AMOUNT);
});
it("permit", async () => {
const nonce = await token.nonces(wallet.address);
const deadline = MaxUint256;
const digest = await getApprovalDigest(
token,
{ owner: wallet.address, spender: other.address, value: TEST_AMOUNT },
nonce,
deadline
);
const { v, r, s } = ecsign(Buffer.from(digest.slice(2), "hex"), Buffer.from(wallet.privateKey.slice(2), "hex"));
await expect(token.permit(wallet.address, other.address, TEST_AMOUNT, deadline, v, hexlify(r), hexlify(s)))
.to.emit(token, "Approval")
.withArgs(wallet.address, other.address, TEST_AMOUNT);
expect(await token.allowance(wallet.address, other.address)).to.eq(TEST_AMOUNT);
expect(await token.nonces(wallet.address)).to.eq(BigNumber.from(1));
});
});
Example #21
Source File: StakingRewardsFactory.spec.ts From staking-factory with MIT License | 4 votes |
describe('StakingRewardsFactory', () => {
const provider = new MockProvider({
ganacheOptions: {
hardfork: 'istanbul',
mnemonic: 'horn horn horn horn horn horn horn horn horn horn horn horn',
gasLimit: 9999999,
},
})
const [wallet, wallet1] = provider.getWallets()
const loadFixture = createFixtureLoader([wallet], provider)
let rewardsToken: Contract
let genesis: number
let rewardAmounts: BigNumber[]
let stakingRewardsFactory: Contract
let stakingTokens: Contract[]
beforeEach('load fixture', async () => {
const fixture = await loadFixture(stakingRewardsFactoryFixture)
rewardsToken = fixture.rewardsToken
genesis = fixture.genesis
rewardAmounts = fixture.rewardAmounts
stakingRewardsFactory = fixture.stakingRewardsFactory
stakingTokens = fixture.stakingTokens
})
it('deployment gas', async () => {
const receipt = await provider.getTransactionReceipt(stakingRewardsFactory.deployTransaction.hash)
expect(receipt.gasUsed).to.eq('2080815')
})
describe('#deploy', () => {
it('pushes the token into the list', async () => {
await stakingRewardsFactory.deploy(stakingTokens[1].address, 10000)
expect(await stakingRewardsFactory.stakingTokens(0)).to.eq(stakingTokens[1].address)
})
it('fails if called twice for same token', async () => {
await stakingRewardsFactory.deploy(stakingTokens[1].address, 10000)
await expect(stakingRewardsFactory.deploy(stakingTokens[1].address, 10000)).to.revertedWith(
'StakingRewardsFactory::deploy: already deployed'
)
})
it('can only be called by the owner', async () => {
await expect(stakingRewardsFactory.connect(wallet1).deploy(stakingTokens[1].address, 10000)).to.be.revertedWith(
'Ownable: caller is not the owner'
)
})
it('stores the address of stakingRewards and reward amount', async () => {
await stakingRewardsFactory.deploy(stakingTokens[1].address, 10000)
const [stakingRewards, rewardAmount] = await stakingRewardsFactory.stakingRewardsInfoByStakingToken(
stakingTokens[1].address
)
expect(await provider.getCode(stakingRewards)).to.not.eq('0x')
expect(rewardAmount).to.eq(10000)
})
it('deployed staking rewards has correct parameters', async () => {
await stakingRewardsFactory.deploy(stakingTokens[1].address, 10000)
const [stakingRewardsAddress] = await stakingRewardsFactory.stakingRewardsInfoByStakingToken(
stakingTokens[1].address
)
const stakingRewards = new Contract(stakingRewardsAddress, StakingRewards.abi, provider)
expect(await stakingRewards.rewardsDistribution()).to.eq(stakingRewardsFactory.address)
expect(await stakingRewards.stakingToken()).to.eq(stakingTokens[1].address)
expect(await stakingRewards.rewardsToken()).to.eq(rewardsToken.address)
})
})
describe('#notifyRewardsAmounts', () => {
let totalRewardAmount: BigNumber
beforeEach(() => {
totalRewardAmount = rewardAmounts.reduce((accumulator, current) => accumulator.add(current), BigNumber.from(0))
})
it('called before any deploys', async () => {
await expect(stakingRewardsFactory.notifyRewardAmounts()).to.be.revertedWith(
'StakingRewardsFactory::notifyRewardAmounts: called before any deploys'
)
})
describe('after deploying all staking reward contracts', async () => {
let stakingRewards: Contract[]
beforeEach('deploy staking reward contracts', async () => {
stakingRewards = []
for (let i = 0; i < stakingTokens.length; i++) {
await stakingRewardsFactory.deploy(stakingTokens[i].address, rewardAmounts[i])
const [stakingRewardsAddress] = await stakingRewardsFactory.stakingRewardsInfoByStakingToken(
stakingTokens[i].address
)
stakingRewards.push(new Contract(stakingRewardsAddress, StakingRewards.abi, provider))
}
})
it('gas', async () => {
await rewardsToken.transfer(stakingRewardsFactory.address, totalRewardAmount)
await mineBlock(provider, genesis)
const tx = await stakingRewardsFactory.notifyRewardAmounts()
const receipt = await tx.wait()
expect(receipt.gasUsed).to.eq('416215')
})
it('no op if called twice', async () => {
await rewardsToken.transfer(stakingRewardsFactory.address, totalRewardAmount)
await mineBlock(provider, genesis)
await expect(stakingRewardsFactory.notifyRewardAmounts()).to.emit(rewardsToken, 'Transfer')
await expect(stakingRewardsFactory.notifyRewardAmounts()).to.not.emit(rewardsToken, 'Transfer')
})
it('fails if called without sufficient balance', async () => {
await mineBlock(provider, genesis)
await expect(stakingRewardsFactory.notifyRewardAmounts()).to.be.revertedWith(
'SafeMath: subtraction overflow' // emitted from rewards token
)
})
it('calls notifyRewards on each contract', async () => {
await rewardsToken.transfer(stakingRewardsFactory.address, totalRewardAmount)
await mineBlock(provider, genesis)
await expect(stakingRewardsFactory.notifyRewardAmounts())
.to.emit(stakingRewards[0], 'RewardAdded')
.withArgs(rewardAmounts[0])
.to.emit(stakingRewards[1], 'RewardAdded')
.withArgs(rewardAmounts[1])
.to.emit(stakingRewards[2], 'RewardAdded')
.withArgs(rewardAmounts[2])
.to.emit(stakingRewards[3], 'RewardAdded')
.withArgs(rewardAmounts[3])
})
it('transfers the reward tokens to the individual contracts', async () => {
await rewardsToken.transfer(stakingRewardsFactory.address, totalRewardAmount)
await mineBlock(provider, genesis)
await stakingRewardsFactory.notifyRewardAmounts()
for (let i = 0; i < rewardAmounts.length; i++) {
expect(await rewardsToken.balanceOf(stakingRewards[i].address)).to.eq(rewardAmounts[i])
}
})
it('sets rewardAmount to 0', async () => {
await rewardsToken.transfer(stakingRewardsFactory.address, totalRewardAmount)
await mineBlock(provider, genesis)
for (let i = 0; i < stakingTokens.length; i++) {
const [, amount] = await stakingRewardsFactory.stakingRewardsInfoByStakingToken(stakingTokens[i].address)
expect(amount).to.eq(rewardAmounts[i])
}
await stakingRewardsFactory.notifyRewardAmounts()
for (let i = 0; i < stakingTokens.length; i++) {
const [, amount] = await stakingRewardsFactory.stakingRewardsInfoByStakingToken(stakingTokens[i].address)
expect(amount).to.eq(0)
}
})
it('succeeds when has sufficient balance and after genesis time', async () => {
await rewardsToken.transfer(stakingRewardsFactory.address, totalRewardAmount)
await mineBlock(provider, genesis)
await stakingRewardsFactory.notifyRewardAmounts()
})
})
})
})
Example #22
Source File: StakingRewards.spec.ts From staking-factory with MIT License | 4 votes |
describe('StakingRewards', () => {
const provider = new MockProvider({
ganacheOptions: {
hardfork: 'istanbul',
mnemonic: 'horn horn horn horn horn horn horn horn horn horn horn horn',
gasLimit: 9999999,
},
})
const [wallet, staker, secondStaker] = provider.getWallets()
const loadFixture = createFixtureLoader([wallet], provider)
let stakingRewards: Contract
let rewardsToken: Contract
let stakingToken: Contract
beforeEach(async () => {
const fixture = await loadFixture(stakingRewardsFixture)
stakingRewards = fixture.stakingRewards
rewardsToken = fixture.rewardsToken
stakingToken = fixture.stakingToken
})
it('deploy cost', async () => {
const stakingRewards = await deployContract(wallet, StakingRewards, [
wallet.address,
rewardsToken.address,
stakingToken.address,
])
const receipt = await provider.getTransactionReceipt(stakingRewards.deployTransaction.hash)
expect(receipt.gasUsed).to.eq('1418436')
})
it('rewardsDuration', async () => {
const rewardsDuration = await stakingRewards.rewardsDuration()
expect(rewardsDuration).to.be.eq(REWARDS_DURATION)
})
const reward = expandTo18Decimals(100)
async function start(reward: BigNumber): Promise<{ startTime: BigNumber; endTime: BigNumber }> {
// send reward to the contract
await rewardsToken.transfer(stakingRewards.address, reward)
// must be called by rewardsDistribution
await stakingRewards.notifyRewardAmount(reward)
const startTime: BigNumber = await stakingRewards.lastUpdateTime()
const endTime: BigNumber = await stakingRewards.periodFinish()
expect(endTime).to.be.eq(startTime.add(REWARDS_DURATION))
return { startTime, endTime }
}
it('notifyRewardAmount: full', async () => {
// stake with staker
const stake = expandTo18Decimals(2)
await stakingToken.transfer(staker.address, stake)
await stakingToken.connect(staker).approve(stakingRewards.address, stake)
await stakingRewards.connect(staker).stake(stake)
const { endTime } = await start(reward)
// fast-forward past the reward window
await mineBlock(provider, endTime.add(1).toNumber())
// unstake
await stakingRewards.connect(staker).exit()
const stakeEndTime: BigNumber = await stakingRewards.lastUpdateTime()
expect(stakeEndTime).to.be.eq(endTime)
const rewardAmount = await rewardsToken.balanceOf(staker.address)
expect(reward.sub(rewardAmount).lte(reward.div(10000))).to.be.true // ensure result is within .01%
expect(rewardAmount).to.be.eq(reward.div(REWARDS_DURATION).mul(REWARDS_DURATION))
})
it('stakeWithPermit', async () => {
// stake with staker
const stake = expandTo18Decimals(2)
await stakingToken.transfer(staker.address, stake)
// get permit
const nonce = await stakingToken.nonces(staker.address)
const deadline = constants.MaxUint256
const digest = await getApprovalDigest(
stakingToken,
{ owner: staker.address, spender: stakingRewards.address, value: stake },
nonce,
deadline
)
const { v, r, s } = ecsign(Buffer.from(digest.slice(2), 'hex'), Buffer.from(staker.privateKey.slice(2), 'hex'))
await stakingRewards.connect(staker).stakeWithPermit(stake, deadline, v, r, s)
const { endTime } = await start(reward)
// fast-forward past the reward window
await mineBlock(provider, endTime.add(1).toNumber())
// unstake
await stakingRewards.connect(staker).exit()
const stakeEndTime: BigNumber = await stakingRewards.lastUpdateTime()
expect(stakeEndTime).to.be.eq(endTime)
const rewardAmount = await rewardsToken.balanceOf(staker.address)
expect(reward.sub(rewardAmount).lte(reward.div(10000))).to.be.true // ensure result is within .01%
expect(rewardAmount).to.be.eq(reward.div(REWARDS_DURATION).mul(REWARDS_DURATION))
})
it('notifyRewardAmount: ~half', async () => {
const { startTime, endTime } = await start(reward)
// fast-forward ~halfway through the reward window
await mineBlock(provider, startTime.add(endTime.sub(startTime).div(2)).toNumber())
// stake with staker
const stake = expandTo18Decimals(2)
await stakingToken.transfer(staker.address, stake)
await stakingToken.connect(staker).approve(stakingRewards.address, stake)
await stakingRewards.connect(staker).stake(stake)
const stakeStartTime: BigNumber = await stakingRewards.lastUpdateTime()
// fast-forward past the reward window
await mineBlock(provider, endTime.add(1).toNumber())
// unstake
await stakingRewards.connect(staker).exit()
const stakeEndTime: BigNumber = await stakingRewards.lastUpdateTime()
expect(stakeEndTime).to.be.eq(endTime)
const rewardAmount = await rewardsToken.balanceOf(staker.address)
expect(reward.div(2).sub(rewardAmount).lte(reward.div(2).div(10000))).to.be.true // ensure result is within .01%
expect(rewardAmount).to.be.eq(reward.div(REWARDS_DURATION).mul(endTime.sub(stakeStartTime)))
}).retries(2)
it('notifyRewardAmount: two stakers', async () => {
// stake with first staker
const stake = expandTo18Decimals(2)
await stakingToken.transfer(staker.address, stake)
await stakingToken.connect(staker).approve(stakingRewards.address, stake)
await stakingRewards.connect(staker).stake(stake)
const { startTime, endTime } = await start(reward)
// fast-forward ~halfway through the reward window
await mineBlock(provider, startTime.add(endTime.sub(startTime).div(2)).toNumber())
// stake with second staker
await stakingToken.transfer(secondStaker.address, stake)
await stakingToken.connect(secondStaker).approve(stakingRewards.address, stake)
await stakingRewards.connect(secondStaker).stake(stake)
// fast-forward past the reward window
await mineBlock(provider, endTime.add(1).toNumber())
// unstake
await stakingRewards.connect(staker).exit()
const stakeEndTime: BigNumber = await stakingRewards.lastUpdateTime()
expect(stakeEndTime).to.be.eq(endTime)
await stakingRewards.connect(secondStaker).exit()
const rewardAmount = await rewardsToken.balanceOf(staker.address)
const secondRewardAmount = await rewardsToken.balanceOf(secondStaker.address)
const totalReward = rewardAmount.add(secondRewardAmount)
// ensure results are within .01%
expect(reward.sub(totalReward).lte(reward.div(10000))).to.be.true
expect(totalReward.mul(3).div(4).sub(rewardAmount).lte(totalReward.mul(3).div(4).div(10000)))
expect(totalReward.div(4).sub(secondRewardAmount).lte(totalReward.div(4).div(10000)))
})
})
Example #23
Source File: ApePair.spec.ts From apeswap-swap-core with GNU General Public License v3.0 | 4 votes |
describe('ApePair', () => {
const provider = new MockProvider(
{
ganacheOptions: {
hardfork: 'istanbul',
mnemonic: 'horn horn horn horn horn horn horn horn horn horn horn horn',
gasLimit: 9999999
}
})
const [wallet, other] = provider.getWallets()
const loadFixture = createFixtureLoader([wallet], provider)
let factory: Contract
let token0: Contract
let token1: Contract
let pair: Contract
beforeEach(async () => {
const fixture = await loadFixture(pairFixture)
factory = fixture.factory
token0 = fixture.token0
token1 = fixture.token1
pair = fixture.pair
})
it('mint', async () => {
const token0Amount = expandTo18Decimals(1)
const token1Amount = expandTo18Decimals(4)
await token0.transfer(pair.address, token0Amount)
await token1.transfer(pair.address, token1Amount)
const expectedLiquidity = expandTo18Decimals(2)
await expect(pair.mint(wallet.address, overrides))
.to.emit(pair, 'Transfer')
.withArgs(AddressZero, AddressZero, MINIMUM_LIQUIDITY)
.to.emit(pair, 'Transfer')
.withArgs(AddressZero, wallet.address, expectedLiquidity.sub(MINIMUM_LIQUIDITY))
.to.emit(pair, 'Sync')
.withArgs(token0Amount, token1Amount)
.to.emit(pair, 'Mint')
.withArgs(wallet.address, token0Amount, token1Amount)
expect(await pair.totalSupply()).to.eq(expectedLiquidity)
expect(await pair.balanceOf(wallet.address)).to.eq(expectedLiquidity.sub(MINIMUM_LIQUIDITY))
expect(await token0.balanceOf(pair.address)).to.eq(token0Amount)
expect(await token1.balanceOf(pair.address)).to.eq(token1Amount)
const reserves = await pair.getReserves()
expect(reserves[0]).to.eq(token0Amount)
expect(reserves[1]).to.eq(token1Amount)
})
async function addLiquidity(token0Amount: BigNumber, token1Amount: BigNumber) {
await token0.transfer(pair.address, token0Amount)
await token1.transfer(pair.address, token1Amount)
await pair.mint(wallet.address, overrides)
}
const swapTestCases: BigNumber[][] = [
[1, 5, 10, '1663887962654218072'],
[1, 10, 5, '453718857974177123'],
[2, 5, 10, '2853058890794739851'],
[2, 10, 5, '831943981327109036'],
[1, 10, 10, '907437715948354246'],
[1, 100, 100, '988138378977801540'],
[1, 1000, 1000, '997004989020957084']
].map(a => a.map(n => (typeof n === 'string' ? BigNumber.from(n) : expandTo18Decimals(n))))
swapTestCases.forEach((swapTestCase, i) => {
it(`getInputPrice:${i}`, async () => {
const [swapAmount, token0Amount, token1Amount, expectedOutputAmount] = swapTestCase
await addLiquidity(token0Amount, token1Amount)
await token0.transfer(pair.address, swapAmount)
await expect(pair.swap(0, expectedOutputAmount.add(1), wallet.address, '0x', overrides)).to.be.revertedWith(
'ApeSwap: K'
)
await pair.swap(0, expectedOutputAmount, wallet.address, '0x', overrides)
})
})
const optimisticTestCases: BigNumber[][] = [
['998000000000000000', 5, 10, 1], // given amountIn, amountOut = floor(amountIn * .998)
['998000000000000000', 10, 5, 1],
['998000000000000000', 5, 5, 1],
[1, 5, 5, '1002004008016032065'] // given amountOut, amountIn = ceiling(amountOut / .998)
].map(a => a.map(n => (typeof n === 'string' ? BigNumber.from(n) : expandTo18Decimals(n))))
optimisticTestCases.forEach((optimisticTestCase, i) => {
it(`optimistic:${i}`, async () => {
const [outputAmount, token0Amount, token1Amount, inputAmount] = optimisticTestCase
await addLiquidity(token0Amount, token1Amount)
await token0.transfer(pair.address, inputAmount)
await expect(pair.swap(outputAmount.add(1), 0, wallet.address, '0x', overrides)).to.be.revertedWith('ApeSwap: K')
await pair.swap(outputAmount, 0, wallet.address, '0x', overrides)
})
})
it('swap:token0', async () => {
const token0Amount = expandTo18Decimals(5)
const token1Amount = expandTo18Decimals(10)
await addLiquidity(token0Amount, token1Amount)
const swapAmount = expandTo18Decimals(1)
const expectedOutputAmount = BigNumber.from('1662497915624478906')
await token0.transfer(pair.address, swapAmount)
await expect(pair.swap(0, expectedOutputAmount, wallet.address, '0x', overrides))
.to.emit(token1, 'Transfer')
.withArgs(pair.address, wallet.address, expectedOutputAmount)
.to.emit(pair, 'Sync')
.withArgs(token0Amount.add(swapAmount), token1Amount.sub(expectedOutputAmount))
.to.emit(pair, 'Swap')
.withArgs(wallet.address, swapAmount, 0, 0, expectedOutputAmount, wallet.address)
const reserves = await pair.getReserves()
expect(reserves[0]).to.eq(token0Amount.add(swapAmount))
expect(reserves[1]).to.eq(token1Amount.sub(expectedOutputAmount))
expect(await token0.balanceOf(pair.address)).to.eq(token0Amount.add(swapAmount))
expect(await token1.balanceOf(pair.address)).to.eq(token1Amount.sub(expectedOutputAmount))
const totalSupplyToken0 = await token0.totalSupply()
const totalSupplyToken1 = await token1.totalSupply()
expect(await token0.balanceOf(wallet.address)).to.eq(totalSupplyToken0.sub(token0Amount).sub(swapAmount))
expect(await token1.balanceOf(wallet.address)).to.eq(totalSupplyToken1.sub(token1Amount).add(expectedOutputAmount))
})
it('swap:token1', async () => {
const token0Amount = expandTo18Decimals(5)
const token1Amount = expandTo18Decimals(10)
await addLiquidity(token0Amount, token1Amount)
const swapAmount = expandTo18Decimals(1)
const expectedOutputAmount = BigNumber.from('453305446940074565')
await token1.transfer(pair.address, swapAmount)
await expect(pair.swap(expectedOutputAmount, 0, wallet.address, '0x', overrides))
.to.emit(token0, 'Transfer')
.withArgs(pair.address, wallet.address, expectedOutputAmount)
.to.emit(pair, 'Sync')
.withArgs(token0Amount.sub(expectedOutputAmount), token1Amount.add(swapAmount))
.to.emit(pair, 'Swap')
.withArgs(wallet.address, 0, swapAmount, expectedOutputAmount, 0, wallet.address)
const reserves = await pair.getReserves()
expect(reserves[0]).to.eq(token0Amount.sub(expectedOutputAmount))
expect(reserves[1]).to.eq(token1Amount.add(swapAmount))
expect(await token0.balanceOf(pair.address)).to.eq(token0Amount.sub(expectedOutputAmount))
expect(await token1.balanceOf(pair.address)).to.eq(token1Amount.add(swapAmount))
const totalSupplyToken0 = await token0.totalSupply()
const totalSupplyToken1 = await token1.totalSupply()
expect(await token0.balanceOf(wallet.address)).to.eq(totalSupplyToken0.sub(token0Amount).add(expectedOutputAmount))
expect(await token1.balanceOf(wallet.address)).to.eq(totalSupplyToken1.sub(token1Amount).sub(swapAmount))
})
it('swap:gas', async () => {
const token0Amount = expandTo18Decimals(5)
const token1Amount = expandTo18Decimals(10)
await addLiquidity(token0Amount, token1Amount)
// ensure that setting price{0,1}CumulativeLast for the first time doesn't affect our gas math
await mineBlock(provider, (await provider.getBlock('latest')).timestamp + 1)
await pair.sync(overrides)
const swapAmount = expandTo18Decimals(1)
const expectedOutputAmount = BigNumber.from('453305446940074565')
await token1.transfer(pair.address, swapAmount)
await mineBlock(provider, (await provider.getBlock('latest')).timestamp + 1)
const tx = await pair.swap(expectedOutputAmount, 0, wallet.address, '0x', overrides)
const receipt = await tx.wait()
expect(receipt.gasUsed).to.eq(73462)
})
it('burn', async () => {
const token0Amount = expandTo18Decimals(3)
const token1Amount = expandTo18Decimals(3)
await addLiquidity(token0Amount, token1Amount)
const expectedLiquidity = expandTo18Decimals(3)
await pair.transfer(pair.address, expectedLiquidity.sub(MINIMUM_LIQUIDITY))
await expect(pair.burn(wallet.address, overrides))
.to.emit(pair, 'Transfer')
.withArgs(pair.address, AddressZero, expectedLiquidity.sub(MINIMUM_LIQUIDITY))
.to.emit(token0, 'Transfer')
.withArgs(pair.address, wallet.address, token0Amount.sub(1000))
.to.emit(token1, 'Transfer')
.withArgs(pair.address, wallet.address, token1Amount.sub(1000))
.to.emit(pair, 'Sync')
.withArgs(1000, 1000)
.to.emit(pair, 'Burn')
.withArgs(wallet.address, token0Amount.sub(1000), token1Amount.sub(1000), wallet.address)
expect(await pair.balanceOf(wallet.address)).to.eq(0)
expect(await pair.totalSupply()).to.eq(MINIMUM_LIQUIDITY)
expect(await token0.balanceOf(pair.address)).to.eq(1000)
expect(await token1.balanceOf(pair.address)).to.eq(1000)
const totalSupplyToken0 = await token0.totalSupply()
const totalSupplyToken1 = await token1.totalSupply()
expect(await token0.balanceOf(wallet.address)).to.eq(totalSupplyToken0.sub(1000))
expect(await token1.balanceOf(wallet.address)).to.eq(totalSupplyToken1.sub(1000))
})
it('price{0,1}CumulativeLast', async () => {
const token0Amount = expandTo18Decimals(3)
const token1Amount = expandTo18Decimals(3)
await addLiquidity(token0Amount, token1Amount)
const blockTimestamp = (await pair.getReserves())[2]
await mineBlock(provider, blockTimestamp + 1)
await pair.sync(overrides)
const initialPrice = encodePrice(token0Amount, token1Amount)
expect(await pair.price0CumulativeLast()).to.eq(initialPrice[0])
expect(await pair.price1CumulativeLast()).to.eq(initialPrice[1])
expect((await pair.getReserves())[2]).to.eq(blockTimestamp + 1)
const swapAmount = expandTo18Decimals(3)
await token0.transfer(pair.address, swapAmount)
await mineBlock(provider, blockTimestamp + 10)
// swap to a new price eagerly instead of syncing
await pair.swap(0, expandTo18Decimals(1), wallet.address, '0x', overrides) // make the price nice
expect(await pair.price0CumulativeLast()).to.eq(initialPrice[0].mul(10))
expect(await pair.price1CumulativeLast()).to.eq(initialPrice[1].mul(10))
expect((await pair.getReserves())[2]).to.eq(blockTimestamp + 10)
await mineBlock(provider, blockTimestamp + 20)
await pair.sync(overrides)
const newPrice = encodePrice(expandTo18Decimals(6), expandTo18Decimals(2))
expect(await pair.price0CumulativeLast()).to.eq(initialPrice[0].mul(10).add(newPrice[0].mul(10)))
expect(await pair.price1CumulativeLast()).to.eq(initialPrice[1].mul(10).add(newPrice[1].mul(10)))
expect((await pair.getReserves())[2]).to.eq(blockTimestamp + 20)
})
it('feeTo:off', async () => {
const token0Amount = expandTo18Decimals(1000)
const token1Amount = expandTo18Decimals(1000)
await addLiquidity(token0Amount, token1Amount)
const swapAmount = expandTo18Decimals(1)
const expectedOutputAmount = BigNumber.from('996006981039903216')
await token1.transfer(pair.address, swapAmount)
await pair.swap(expectedOutputAmount, 0, wallet.address, '0x', overrides)
const expectedLiquidity = expandTo18Decimals(1000)
await pair.transfer(pair.address, expectedLiquidity.sub(MINIMUM_LIQUIDITY))
await pair.burn(wallet.address, overrides)
expect(await pair.totalSupply()).to.eq(MINIMUM_LIQUIDITY)
})
it('feeTo:on', async () => {
await factory.setFeeTo(other.address)
const token0Amount = expandTo18Decimals(1000)
const token1Amount = expandTo18Decimals(1000)
await addLiquidity(token0Amount, token1Amount)
const swapAmount = expandTo18Decimals(1)
const expectedOutputAmount = BigNumber.from('996006981039903216')
await token1.transfer(pair.address, swapAmount)
await pair.swap(expectedOutputAmount, 0, wallet.address, '0x', overrides)
const expectedLiquidity = expandTo18Decimals(1000)
await pair.transfer(pair.address, expectedLiquidity.sub(MINIMUM_LIQUIDITY))
await pair.burn(wallet.address, overrides)
// NOTE: Values for a 0.05% Protocol Fee
// expect(await pair.totalSupply()).to.eq(MINIMUM_LIQUIDITY.add('374625795658571'))
// expect(await pair.balanceOf(other.address)).to.eq('374625795658571')
// NOTE: Values for a 0.15% Protocol Fee
expect(await pair.totalSupply()).to.eq(MINIMUM_LIQUIDITY.add('1123878229043267'))
expect(await pair.balanceOf(other.address)).to.eq('1123878229043267')
// using 1000 here instead of the symbolic MINIMUM_LIQUIDITY because the amounts only happen to be equal...
// ...because the initial liquidity amounts were equal
// NOTE: Values for a 0.05% Protocol Fee
// expect(await token0.balanceOf(pair.address)).to.eq(BigNumber.from(1000).add('374252525546167'))
// expect(await token1.balanceOf(pair.address)).to.eq(BigNumber.from(1000).add('375000280969452'))
// NOTE: Values for a 0.15% Protocol Fee
expect(await token0.balanceOf(pair.address)).to.eq(BigNumber.from(1000).add('1122757576638504'))
expect(await token1.balanceOf(pair.address)).to.eq(BigNumber.from(1000).add('1125000842908357'))
})
})
Example #24
Source File: OzContractDeployerSpec.ts From perpetual-protocol with GNU General Public License v3.0 | 4 votes |
// conflict with hardhat-gas-reporter without proxyResolver
describe("OzContractDeployer Spec", () => {
const [wallet] = new MockProvider().getWallets()
const ozContractDeployer: OzContractDeployer = new OzContractDeployer()
const contractNameV1 = "src/mock/UpgradableContractV1.sol:UpgradableContractV1"
const contractNameV2 = "src/mock/UpgradableContractV2.sol:UpgradableContractV2"
// the following two are proxys
let v1: UpgradableContractV1
let v2: UpgradableContractV2
let factoryV2: ContractFactory
let proxyAddr: string
async function getImplementation(proxyAddr: string) {
const proxyAdmin = await upgrades.admin.getInstance()
return proxyAdmin.getProxyImplementation(proxyAddr)
}
beforeEach(async () => {
factoryV2 = await ethers.getContractFactory(contractNameV2)
proxyAddr = await ozContractDeployer.deploy(contractNameV1, [])
v1 = (await ethers.getContractAt(contractNameV1, proxyAddr)) as UpgradableContractV1
})
it("retrieve version that's initialized", async () => {
expect((await v1.version()).toString()).eq("1")
})
it("doesn't have increaseVersion function", async () => {
const wrongV2 = factoryV2.attach(proxyAddr) as UpgradableContractV2
await expect(wrongV2.increaseVersion()).to.be.reverted
})
it("force error, initialization is included in ozContractDeployer.deploy()", async () => {
const v1ImplAddr = await getImplementation(proxyAddr)
const v1Impl = (await ethers.getContractAt(contractNameV1, v1ImplAddr)) as UpgradableContractV1
await expectRevert(v1Impl.initialize(), "Contract instance has already been initialized")
})
describe("upgrade to v2", () => {
beforeEach(async () => {
await ozContractDeployer.upgrade(proxyAddr, contractNameV2, [])
v2 = (await ethers.getContractAt(contractNameV2, proxyAddr)) as UpgradableContractV2
})
it("won't change the proxy address", async () => {
expect(v2.address).eq(proxyAddr)
})
it("won't change state", async () => {
expect((await v2.version()).toString()).eq("1")
})
it("has a new function", async () => {
await v2.increaseVersion()
expect((await v1.version()).toString()).eq("2")
})
it("force error, initialization is included in ozContractDeployer.upgrade()", async () => {
const v2ImplAddr = await getImplementation(v2.address)
const v2Impl = (await ethers.getContractAt(contractNameV2, v2ImplAddr)) as UpgradableContractV2
await expectRevert(v2Impl.initialize(), "Contract instance has already been initialized")
})
})
describe("prepareUpgrade to v2", () => {
let v2ImplAddr: string
beforeEach(async () => {
v2ImplAddr = await ozContractDeployer.prepareUpgrade(proxyAddr, contractNameV2, [])
})
it("ozContractDeployer.prepareUpgrade() returns the implementation address; will be different from proxy address", async () => {
expect(v2ImplAddr).not.eq(proxyAddr)
})
it("won't change state", async () => {
expect((await v1.version()).toString()).eq("1")
})
it("proxy still has no new function", async () => {
const wrongV2 = factoryV2.attach(proxyAddr) as UpgradableContractV2
await expect(wrongV2.increaseVersion()).to.be.reverted
})
it("force error, initialization is included in ozContractDeployer.prepareUpgrade()", async () => {
const v2Impl = (await ethers.getContractAt(contractNameV2, v2ImplAddr)) as UpgradableContractV2
await expectRevert(v2Impl.initialize(), "Contract instance has already been initialized")
})
})
describe("transferProxyAdminOwnership to others", () => {
it("can't transfer to empty address", async () => {
await expect(OzContractDeployer.transferProxyAdminOwnership("0x0000000000000000000000000000000000000000"))
.to.be.reverted
})
it("can't transfer and upgrade once transfer admin to others, but can deploy new and prepareUpgrade", async () => {
await OzContractDeployer.transferProxyAdminOwnership(wallet.address)
await expect(OzContractDeployer.transferProxyAdminOwnership(wallet.address)).to.be.reverted
await expect(ozContractDeployer.upgrade(proxyAddr, contractNameV2, [])).to.be.reverted
await upgrades.prepareUpgrade(v1.address, factoryV2)
const newProxy = await ozContractDeployer.deploy(contractNameV2, [])
await expect(ozContractDeployer.upgrade(newProxy, contractNameV1, [])).to.be.reverted
})
// once transferProxyAdminOwnership has been called, every admin-only tx won't be able to test
})
})
Example #25
Source File: logs.test.ts From useDApp with MIT License | 4 votes |
describe('encodeFilterData', () => {
const mockProvider = new MockProvider()
const [deployer] = mockProvider.getWallets()
let token: Contract
beforeEach(async () => {
token = await deployMockToken(deployer)
})
it('Returns undefined if the filter is undefined', () => {
expect(encodeFilterData(undefined)).to.be.undefined
})
it('Returns FilterByBlockHash when blockHash is valid', () => {
const filter: TypedFilter = {
contract: token,
event: 'Transfer',
args: [],
}
const encodedFilterData = encodeFilterData(filter, undefined, undefined, '0x0') as FilterByBlockHash
expect(encodedFilterData['blockHash']).to.not.be.undefined
})
it('Returns FilterByBlockHash when blockHash, toBlock, and fromBlock are valid', () => {
const filter: TypedFilter = {
contract: token,
event: 'Transfer',
args: [],
}
const encodedFilterData = encodeFilterData(filter, 0, 'latest', '0x0') as FilterByBlockHash
expect(encodedFilterData['blockHash']).to.not.be.undefined
})
it('Returns Filter when toBlock and fromBlock are valid but blockHash is invalid', () => {
const filter: TypedFilter = {
contract: token,
event: 'Transfer',
args: [],
}
const encodedFilterData = encodeFilterData(filter, 0, 'latest', undefined) as Filter
expect(encodedFilterData['toBlock']).to.not.be.undefined
})
it('Returns an error when passed a non-existant event', () => {
const filter: TypedFilter = {
contract: token,
event: 'Transfer2',
args: [],
}
const encodedFilterData = encodeFilterData(filter, 0, 'latest')
expect(encodedFilterData).to.be.a('Error')
})
it('Returns an error when passed an arg for an un-indexed parameter', () => {
const filter: TypedFilter = {
contract: token,
event: 'Transfer',
args: [AddressZero, AddressZero, 10],
}
const encodedFilterData = encodeFilterData(filter, 0, 'latest')
expect(encodedFilterData).to.be.a('Error')
})
it('Returns an error when passed too many args', () => {
const filter: TypedFilter = {
contract: token,
event: 'Transfer',
args: [AddressZero, AddressZero, null, AddressZero],
}
const encodedFilterData = encodeFilterData(filter, 0, 'latest')
expect(encodedFilterData).to.be.a('Error')
})
})
Example #26
Source File: logs.test.ts From useDApp with MIT License | 4 votes |
describe('decodeLogs', () => {
const mockProvider = new MockProvider()
const [deployer] = mockProvider.getWallets()
let token: Contract
beforeEach(async () => {
token = await deployMockToken(deployer)
})
it('Returns undefined if the filter and result are undefined', () => {
expect(decodeLogs(undefined, undefined)).to.be.undefined
})
it('Returns undefined if the result is undefined', () => {
const filter: TypedFilter = {
contract: token,
event: 'Transfer',
args: [],
}
expect(decodeLogs(filter, undefined)).to.be.undefined
})
it('Returns undefined if the filter is undefined', () => {
expect(decodeLogs(undefined, [])).to.be.undefined
})
it('Returns an error if passed an error as the result', () => {
const filter: TypedFilter = {
contract: token,
event: 'Transfer',
args: [],
}
const error = Error('')
const decodedLogs = decodeLogs(filter, error)
expect(decodedLogs?.error).to.equal(error)
expect(decodedLogs?.value).to.be.undefined
})
it('Returns an empty array when passed an empty array of logs', () => {
const filter: TypedFilter = {
contract: token,
event: 'Transfer',
args: [],
}
const logs: Log[] = []
const decodedLogs = decodeLogs(filter, logs)
expect(decodedLogs?.error).to.be.undefined
expect(decodedLogs?.value).to.be.empty
})
it('Returns an error when the event topic is a mismatch', () => {
const filter: TypedFilter = {
contract: token,
event: 'Transfer',
args: [],
}
const logs: Log[] = [
{
address: token.address,
topics: [
ethers.utils.id('Transfer2(address,address,uint256)'),
ethers.utils.hexZeroPad(AddressZero, 32),
ethers.utils.hexZeroPad(AddressZero, 32),
],
data: ethers.utils.hexZeroPad(AddressZero, 32),
blockHash: '0x0',
blockNumber: 0,
logIndex: 0,
transactionIndex: 0,
transactionHash: '0x0',
removed: false,
},
]
const decodedLogs = decodeLogs(filter, logs)
expect(decodedLogs?.value).to.be.undefined
expect(decodedLogs?.error).to.be.a('Error')
})
it('Works when passed valid logs', () => {
const filter: TypedFilter = {
contract: token,
event: 'Transfer',
args: [],
}
const from = AddressZero
const to = deployer.address
const value = BigNumber.from(1)
const blockHash = '0x0'
const blockNumber = 1
const logIndex = 2
const transactionIndex = 3
const removed = true
const transactionHash = '0x11'
const logs: Log[] = [
{
address: token.address,
topics: [
ethers.utils.id('Transfer(address,address,uint256)'),
ethers.utils.hexZeroPad(from, 32),
ethers.utils.hexZeroPad(to, 32),
],
data: ethers.utils.hexZeroPad(ethers.utils.hexlify(value), 32),
blockHash,
blockNumber,
logIndex,
transactionIndex,
transactionHash,
removed,
},
{
address: token.address,
topics: [
ethers.utils.id('Transfer(address,address,uint256)'),
ethers.utils.hexZeroPad(from, 32),
ethers.utils.hexZeroPad(to, 32),
],
data: ethers.utils.hexZeroPad(ethers.utils.hexlify(value), 32),
blockHash,
blockNumber,
logIndex,
transactionIndex,
transactionHash,
removed,
},
]
const decodedLogs = decodeLogs(filter, logs)
expect(decodedLogs?.error).to.be.undefined
const theLogs = decodedLogs as LogsResult<typeof token, 'Transfer'>
expect(theLogs?.value).to.have.length(2)
expect(theLogs?.value![0].blockHash).to.equal(blockHash)
expect(theLogs?.value![0].blockNumber).to.equal(blockNumber)
expect(theLogs?.value![0].removed).to.equal(removed)
expect(theLogs?.value![0].transactionIndex).to.equal(transactionIndex)
expect(theLogs?.value![0].transactionHash).to.equal(transactionHash)
expect(theLogs?.value![0].data.from).to.equal(from)
expect(theLogs?.value![0].data.to).to.equal(to)
expect(theLogs?.value![0].data.value).to.equal(value)
})
})
Example #27
Source File: ExampleSwapToPrice.spec.ts From pancake-swap-testnet with MIT License | 4 votes |
describe('ExampleSwapToPrice', () => {
const provider = new MockProvider({
hardfork: 'istanbul',
mnemonic: 'horn horn horn horn horn horn horn horn horn horn horn horn',
gasLimit: 9999999
})
const [wallet] = provider.getWallets()
const loadFixture = createFixtureLoader(provider, [wallet])
let token0: Contract
let token1: Contract
let pair: Contract
let swapToPriceExample: Contract
let router: Contract
beforeEach(async function() {
const fixture = await loadFixture(v2Fixture)
token0 = fixture.token0
token1 = fixture.token1
pair = fixture.pair
router = fixture.router
swapToPriceExample = await deployContract(
wallet,
ExampleSwapToPrice,
[fixture.factoryV2.address, fixture.router.address],
overrides
)
})
beforeEach('set up price differential of 1:100', async () => {
await token0.transfer(pair.address, expandTo18Decimals(10))
await token1.transfer(pair.address, expandTo18Decimals(1000))
await pair.sync(overrides)
})
beforeEach('approve the swap contract to spend any amount of both tokens', async () => {
await token0.approve(swapToPriceExample.address, MaxUint256)
await token1.approve(swapToPriceExample.address, MaxUint256)
})
it('correct router address', async () => {
expect(await swapToPriceExample.router()).to.eq(router.address)
})
describe('#swapToPrice', () => {
it('requires non-zero true price inputs', async () => {
await expect(
swapToPriceExample.swapToPrice(
token0.address,
token1.address,
0,
0,
MaxUint256,
MaxUint256,
wallet.address,
MaxUint256
)
).to.be.revertedWith('ExampleSwapToPrice: ZERO_PRICE')
await expect(
swapToPriceExample.swapToPrice(
token0.address,
token1.address,
10,
0,
MaxUint256,
MaxUint256,
wallet.address,
MaxUint256
)
).to.be.revertedWith('ExampleSwapToPrice: ZERO_PRICE')
await expect(
swapToPriceExample.swapToPrice(
token0.address,
token1.address,
0,
10,
MaxUint256,
MaxUint256,
wallet.address,
MaxUint256
)
).to.be.revertedWith('ExampleSwapToPrice: ZERO_PRICE')
})
it('requires non-zero max spend', async () => {
await expect(
swapToPriceExample.swapToPrice(token0.address, token1.address, 1, 100, 0, 0, wallet.address, MaxUint256)
).to.be.revertedWith('ExampleSwapToPrice: ZERO_SPEND')
})
it('moves the price to 1:90', async () => {
await expect(
swapToPriceExample.swapToPrice(
token0.address,
token1.address,
1,
90,
MaxUint256,
MaxUint256,
wallet.address,
MaxUint256,
overrides
)
)
// (1e19 + 526682316179835569) : (1e21 - 49890467170695440744) ~= 1:90
.to.emit(token0, 'Transfer')
.withArgs(wallet.address, swapToPriceExample.address, '526682316179835569')
.to.emit(token0, 'Approval')
.withArgs(swapToPriceExample.address, router.address, '526682316179835569')
.to.emit(token0, 'Transfer')
.withArgs(swapToPriceExample.address, pair.address, '526682316179835569')
.to.emit(token1, 'Transfer')
.withArgs(pair.address, wallet.address, '49890467170695440744')
})
it('moves the price to 1:110', async () => {
await expect(
swapToPriceExample.swapToPrice(
token0.address,
token1.address,
1,
110,
MaxUint256,
MaxUint256,
wallet.address,
MaxUint256,
overrides
)
)
// (1e21 + 47376582963642643588) : (1e19 - 451039908682851138) ~= 1:110
.to.emit(token1, 'Transfer')
.withArgs(wallet.address, swapToPriceExample.address, '47376582963642643588')
.to.emit(token1, 'Approval')
.withArgs(swapToPriceExample.address, router.address, '47376582963642643588')
.to.emit(token1, 'Transfer')
.withArgs(swapToPriceExample.address, pair.address, '47376582963642643588')
.to.emit(token0, 'Transfer')
.withArgs(pair.address, wallet.address, '451039908682851138')
})
it('reverse token order', async () => {
await expect(
swapToPriceExample.swapToPrice(
token1.address,
token0.address,
110,
1,
MaxUint256,
MaxUint256,
wallet.address,
MaxUint256,
overrides
)
)
// (1e21 + 47376582963642643588) : (1e19 - 451039908682851138) ~= 1:110
.to.emit(token1, 'Transfer')
.withArgs(wallet.address, swapToPriceExample.address, '47376582963642643588')
.to.emit(token1, 'Approval')
.withArgs(swapToPriceExample.address, router.address, '47376582963642643588')
.to.emit(token1, 'Transfer')
.withArgs(swapToPriceExample.address, pair.address, '47376582963642643588')
.to.emit(token0, 'Transfer')
.withArgs(pair.address, wallet.address, '451039908682851138')
})
it('swap gas cost', async () => {
const tx = await swapToPriceExample.swapToPrice(
token0.address,
token1.address,
1,
110,
MaxUint256,
MaxUint256,
wallet.address,
MaxUint256,
overrides
)
const receipt = await tx.wait()
expect(receipt.gasUsed).to.eq('122329')
}).retries(2) // gas test is inconsistent
})
})
Example #28
Source File: ExampleSlidingWindowOracle.spec.ts From pancake-swap-testnet with MIT License | 4 votes |
describe('ExampleSlidingWindowOracle', () => {
const provider = new MockProvider({
hardfork: 'istanbul',
mnemonic: 'horn horn horn horn horn horn horn horn horn horn horn horn',
gasLimit: 9999999
})
const [wallet] = provider.getWallets()
const loadFixture = createFixtureLoader(provider, [wallet])
let token0: Contract
let token1: Contract
let pair: Contract
let weth: Contract
let factory: Contract
async function addLiquidity(amount0: BigNumber = defaultToken0Amount, amount1: BigNumber = defaultToken1Amount) {
if (!amount0.isZero()) await token0.transfer(pair.address, amount0)
if (!amount1.isZero()) await token1.transfer(pair.address, amount1)
await pair.sync()
}
const defaultWindowSize = 86400 // 24 hours
const defaultGranularity = 24 // 1 hour each
function observationIndexOf(
timestamp: number,
windowSize: number = defaultWindowSize,
granularity: number = defaultGranularity
): number {
const periodSize = Math.floor(windowSize / granularity)
const epochPeriod = Math.floor(timestamp / periodSize)
return epochPeriod % granularity
}
function deployOracle(windowSize: number, granularity: number) {
return deployContract(wallet, ExampleSlidingWindowOracle, [factory.address, windowSize, granularity], overrides)
}
beforeEach('deploy fixture', async function() {
const fixture = await loadFixture(v2Fixture)
token0 = fixture.token0
token1 = fixture.token1
pair = fixture.pair
weth = fixture.WETH
factory = fixture.factoryV2
})
// 1/1/2020 @ 12:00 am UTC
// cannot be 0 because that instructs ganache to set it to current timestamp
// cannot be 86400 because then timestamp 0 is a valid historical observation
const startTime = 1577836800
// must come before adding liquidity to pairs for correct cumulative price computations
// cannot use 0 because that resets to current timestamp
beforeEach(`set start time to ${startTime}`, () => mineBlock(provider, startTime))
it('requires granularity to be greater than 0', async () => {
await expect(deployOracle(defaultWindowSize, 0)).to.be.revertedWith('SlidingWindowOracle: GRANULARITY')
})
it('requires windowSize to be evenly divisible by granularity', async () => {
await expect(deployOracle(defaultWindowSize - 1, defaultGranularity)).to.be.revertedWith(
'SlidingWindowOracle: WINDOW_NOT_EVENLY_DIVISIBLE'
)
})
it('computes the periodSize correctly', async () => {
const oracle = await deployOracle(defaultWindowSize, defaultGranularity)
expect(await oracle.periodSize()).to.eq(3600)
const oracleOther = await deployOracle(defaultWindowSize * 2, defaultGranularity / 2)
expect(await oracleOther.periodSize()).to.eq(3600 * 4)
})
describe('#observationIndexOf', () => {
it('works for examples', async () => {
const oracle = await deployOracle(defaultWindowSize, defaultGranularity)
expect(await oracle.observationIndexOf(0)).to.eq(0)
expect(await oracle.observationIndexOf(3599)).to.eq(0)
expect(await oracle.observationIndexOf(3600)).to.eq(1)
expect(await oracle.observationIndexOf(4800)).to.eq(1)
expect(await oracle.observationIndexOf(7199)).to.eq(1)
expect(await oracle.observationIndexOf(7200)).to.eq(2)
expect(await oracle.observationIndexOf(86399)).to.eq(23)
expect(await oracle.observationIndexOf(86400)).to.eq(0)
expect(await oracle.observationIndexOf(90000)).to.eq(1)
})
it('overflow safe', async () => {
const oracle = await deployOracle(25500, 255) // 100 period size
expect(await oracle.observationIndexOf(0)).to.eq(0)
expect(await oracle.observationIndexOf(99)).to.eq(0)
expect(await oracle.observationIndexOf(100)).to.eq(1)
expect(await oracle.observationIndexOf(199)).to.eq(1)
expect(await oracle.observationIndexOf(25499)).to.eq(254) // 255th element
expect(await oracle.observationIndexOf(25500)).to.eq(0)
})
it('matches offline computation', async () => {
const oracle = await deployOracle(defaultWindowSize, defaultGranularity)
for (let timestamp of [0, 5000, 1000, 25000, 86399, 86400, 86401]) {
expect(await oracle.observationIndexOf(timestamp)).to.eq(observationIndexOf(timestamp))
}
})
})
describe('#update', () => {
let slidingWindowOracle: Contract
beforeEach(
'deploy oracle',
async () => (slidingWindowOracle = await deployOracle(defaultWindowSize, defaultGranularity))
)
beforeEach('add default liquidity', () => addLiquidity())
it('succeeds', async () => {
await slidingWindowOracle.update(token0.address, token1.address, overrides)
})
it('sets the appropriate epoch slot', async () => {
const blockTimestamp = (await pair.getReserves())[2]
expect(blockTimestamp).to.eq(startTime)
await slidingWindowOracle.update(token0.address, token1.address, overrides)
expect(await slidingWindowOracle.pairObservations(pair.address, observationIndexOf(blockTimestamp))).to.deep.eq([
bigNumberify(blockTimestamp),
await pair.price0CumulativeLast(),
await pair.price1CumulativeLast()
])
}).retries(2) // we may have slight differences between pair blockTimestamp and the expected timestamp
// because the previous block timestamp may differ from the current block timestamp by 1 second
it('gas for first update (allocates empty array)', async () => {
const tx = await slidingWindowOracle.update(token0.address, token1.address, overrides)
const receipt = await tx.wait()
expect(receipt.gasUsed).to.eq('116816')
}).retries(2) // gas test inconsistent
it('gas for second update in the same period (skips)', async () => {
await slidingWindowOracle.update(token0.address, token1.address, overrides)
const tx = await slidingWindowOracle.update(token0.address, token1.address, overrides)
const receipt = await tx.wait()
expect(receipt.gasUsed).to.eq('25574')
}).retries(2) // gas test inconsistent
it('gas for second update different period (no allocate, no skip)', async () => {
await slidingWindowOracle.update(token0.address, token1.address, overrides)
await mineBlock(provider, startTime + 3600)
const tx = await slidingWindowOracle.update(token0.address, token1.address, overrides)
const receipt = await tx.wait()
expect(receipt.gasUsed).to.eq('94542')
}).retries(2) // gas test inconsistent
it('second update in one timeslot does not overwrite', async () => {
await slidingWindowOracle.update(token0.address, token1.address, overrides)
const before = await slidingWindowOracle.pairObservations(pair.address, observationIndexOf(0))
// first hour still
await mineBlock(provider, startTime + 1800)
await slidingWindowOracle.update(token0.address, token1.address, overrides)
const after = await slidingWindowOracle.pairObservations(pair.address, observationIndexOf(1800))
expect(observationIndexOf(1800)).to.eq(observationIndexOf(0))
expect(before).to.deep.eq(after)
})
it('fails for invalid pair', async () => {
await expect(slidingWindowOracle.update(weth.address, token1.address)).to.be.reverted
})
})
describe('#consult', () => {
let slidingWindowOracle: Contract
beforeEach(
'deploy oracle',
async () => (slidingWindowOracle = await deployOracle(defaultWindowSize, defaultGranularity))
)
// must come after setting time to 0 for correct cumulative price computations in the pair
beforeEach('add default liquidity', () => addLiquidity())
it('fails if previous bucket not set', async () => {
await slidingWindowOracle.update(token0.address, token1.address, overrides)
await expect(slidingWindowOracle.consult(token0.address, 0, token1.address)).to.be.revertedWith(
'SlidingWindowOracle: MISSING_HISTORICAL_OBSERVATION'
)
})
it('fails for invalid pair', async () => {
await expect(slidingWindowOracle.consult(weth.address, 0, token1.address)).to.be.reverted
})
describe('happy path', () => {
let blockTimestamp: number
let previousBlockTimestamp: number
let previousCumulativePrices: any
beforeEach('add some prices', async () => {
previousBlockTimestamp = (await pair.getReserves())[2]
previousCumulativePrices = [await pair.price0CumulativeLast(), await pair.price1CumulativeLast()]
await slidingWindowOracle.update(token0.address, token1.address, overrides)
blockTimestamp = previousBlockTimestamp + 23 * 3600
await mineBlock(provider, blockTimestamp)
await slidingWindowOracle.update(token0.address, token1.address, overrides)
})
it('has cumulative price in previous bucket', async () => {
expect(
await slidingWindowOracle.pairObservations(pair.address, observationIndexOf(previousBlockTimestamp))
).to.deep.eq([bigNumberify(previousBlockTimestamp), previousCumulativePrices[0], previousCumulativePrices[1]])
}).retries(5) // test flaky because timestamps aren't mocked
it('has cumulative price in current bucket', async () => {
const timeElapsed = blockTimestamp - previousBlockTimestamp
const prices = encodePrice(defaultToken0Amount, defaultToken1Amount)
expect(
await slidingWindowOracle.pairObservations(pair.address, observationIndexOf(blockTimestamp))
).to.deep.eq([bigNumberify(blockTimestamp), prices[0].mul(timeElapsed), prices[1].mul(timeElapsed)])
}).retries(5) // test flaky because timestamps aren't mocked
it('provides the current ratio in consult token0', async () => {
expect(await slidingWindowOracle.consult(token0.address, 100, token1.address)).to.eq(200)
})
it('provides the current ratio in consult token1', async () => {
expect(await slidingWindowOracle.consult(token1.address, 100, token0.address)).to.eq(50)
})
})
describe('price changes over period', () => {
const hour = 3600
beforeEach('add some prices', async () => {
// starting price of 1:2, or token0 = 2token1, token1 = 0.5token0
await slidingWindowOracle.update(token0.address, token1.address, overrides) // hour 0, 1:2
// change the price at hour 3 to 1:1 and immediately update
await mineBlock(provider, startTime + 3 * hour)
await addLiquidity(defaultToken0Amount, bigNumberify(0))
await slidingWindowOracle.update(token0.address, token1.address, overrides)
// change the ratios at hour 6:00 to 2:1, don't update right away
await mineBlock(provider, startTime + 6 * hour)
await token0.transfer(pair.address, defaultToken0Amount.mul(2))
await pair.sync()
// update at hour 9:00 (price has been 2:1 for 3 hours, invokes counterfactual)
await mineBlock(provider, startTime + 9 * hour)
await slidingWindowOracle.update(token0.address, token1.address, overrides)
// move to hour 23:00 so we can check prices
await mineBlock(provider, startTime + 23 * hour)
})
it('provides the correct ratio in consult token0', async () => {
// at hour 23, price of token 0 spent 3 hours at 2, 3 hours at 1, 17 hours at 0.5 so price should
// be less than 1
expect(await slidingWindowOracle.consult(token0.address, 100, token1.address)).to.eq(76)
})
it('provides the correct ratio in consult token1', async () => {
// price should be greater than 1
expect(await slidingWindowOracle.consult(token1.address, 100, token0.address)).to.eq(167)
})
// price has been 2:1 all of 23 hours
describe('hour 32', () => {
beforeEach('set hour 32', () => mineBlock(provider, startTime + 32 * hour))
it('provides the correct ratio in consult token0', async () => {
// at hour 23, price of token 0 spent 3 hours at 2, 3 hours at 1, 17 hours at 0.5 so price should
// be less than 1
expect(await slidingWindowOracle.consult(token0.address, 100, token1.address)).to.eq(50)
})
it('provides the correct ratio in consult token1', async () => {
// price should be greater than 1
expect(await slidingWindowOracle.consult(token1.address, 100, token0.address)).to.eq(200)
})
})
})
})
})
Example #29
Source File: ExampleFlashSwap.spec.ts From pancake-swap-testnet with MIT License | 4 votes |
describe('ExampleFlashSwap', () => {
const provider = new MockProvider({
hardfork: 'istanbul',
mnemonic: 'horn horn horn horn horn horn horn horn horn horn horn horn',
gasLimit: 9999999
})
const [wallet] = provider.getWallets()
const loadFixture = createFixtureLoader(provider, [wallet])
let WETH: Contract
let WETHPartner: Contract
let WETHExchangeV1: Contract
let WETHPair: Contract
let flashSwapExample: Contract
beforeEach(async function() {
const fixture = await loadFixture(v2Fixture)
WETH = fixture.WETH
WETHPartner = fixture.WETHPartner
WETHExchangeV1 = fixture.WETHExchangeV1
WETHPair = fixture.WETHPair
flashSwapExample = await deployContract(
wallet,
ExampleFlashSwap,
[fixture.factoryV2.address, fixture.factoryV1.address, fixture.router.address],
overrides
)
})
it('uniswapV2Call:0', async () => {
// add liquidity to V1 at a rate of 1 ETH / 200 X
const WETHPartnerAmountV1 = expandTo18Decimals(2000)
const ETHAmountV1 = expandTo18Decimals(10)
await WETHPartner.approve(WETHExchangeV1.address, WETHPartnerAmountV1)
await WETHExchangeV1.addLiquidity(bigNumberify(1), WETHPartnerAmountV1, MaxUint256, {
...overrides,
value: ETHAmountV1
})
// add liquidity to V2 at a rate of 1 ETH / 100 X
const WETHPartnerAmountV2 = expandTo18Decimals(1000)
const ETHAmountV2 = expandTo18Decimals(10)
await WETHPartner.transfer(WETHPair.address, WETHPartnerAmountV2)
await WETH.deposit({ value: ETHAmountV2 })
await WETH.transfer(WETHPair.address, ETHAmountV2)
await WETHPair.mint(wallet.address, overrides)
const balanceBefore = await WETHPartner.balanceOf(wallet.address)
// now, execute arbitrage via uniswapV2Call:
// receive 1 ETH from V2, get as much X from V1 as we can, repay V2 with minimum X, keep the rest!
const arbitrageAmount = expandTo18Decimals(1)
// instead of being 'hard-coded', the above value could be calculated optimally off-chain. this would be
// better, but it'd be better yet to calculate the amount at runtime, on-chain. unfortunately, this requires a
// swap-to-price calculation, which is a little tricky, and out of scope for the moment
const WETHPairToken0 = await WETHPair.token0()
const amount0 = WETHPairToken0 === WETHPartner.address ? bigNumberify(0) : arbitrageAmount
const amount1 = WETHPairToken0 === WETHPartner.address ? arbitrageAmount : bigNumberify(0)
await WETHPair.swap(
amount0,
amount1,
flashSwapExample.address,
defaultAbiCoder.encode(['uint'], [bigNumberify(1)]),
overrides
)
const balanceAfter = await WETHPartner.balanceOf(wallet.address)
const profit = balanceAfter.sub(balanceBefore).div(expandTo18Decimals(1))
const reservesV1 = [
await WETHPartner.balanceOf(WETHExchangeV1.address),
await provider.getBalance(WETHExchangeV1.address)
]
const priceV1 = reservesV1[0].div(reservesV1[1])
const reservesV2 = (await WETHPair.getReserves()).slice(0, 2)
const priceV2 =
WETHPairToken0 === WETHPartner.address ? reservesV2[0].div(reservesV2[1]) : reservesV2[1].div(reservesV2[0])
expect(profit.toString()).to.eq('69') // our profit is ~69 tokens
expect(priceV1.toString()).to.eq('165') // we pushed the v1 price down to ~165
expect(priceV2.toString()).to.eq('123') // we pushed the v2 price up to ~123
})
it('uniswapV2Call:1', async () => {
// add liquidity to V1 at a rate of 1 ETH / 100 X
const WETHPartnerAmountV1 = expandTo18Decimals(1000)
const ETHAmountV1 = expandTo18Decimals(10)
await WETHPartner.approve(WETHExchangeV1.address, WETHPartnerAmountV1)
await WETHExchangeV1.addLiquidity(bigNumberify(1), WETHPartnerAmountV1, MaxUint256, {
...overrides,
value: ETHAmountV1
})
// add liquidity to V2 at a rate of 1 ETH / 200 X
const WETHPartnerAmountV2 = expandTo18Decimals(2000)
const ETHAmountV2 = expandTo18Decimals(10)
await WETHPartner.transfer(WETHPair.address, WETHPartnerAmountV2)
await WETH.deposit({ value: ETHAmountV2 })
await WETH.transfer(WETHPair.address, ETHAmountV2)
await WETHPair.mint(wallet.address, overrides)
const balanceBefore = await provider.getBalance(wallet.address)
// now, execute arbitrage via uniswapV2Call:
// receive 200 X from V2, get as much ETH from V1 as we can, repay V2 with minimum ETH, keep the rest!
const arbitrageAmount = expandTo18Decimals(200)
// instead of being 'hard-coded', the above value could be calculated optimally off-chain. this would be
// better, but it'd be better yet to calculate the amount at runtime, on-chain. unfortunately, this requires a
// swap-to-price calculation, which is a little tricky, and out of scope for the moment
const WETHPairToken0 = await WETHPair.token0()
const amount0 = WETHPairToken0 === WETHPartner.address ? arbitrageAmount : bigNumberify(0)
const amount1 = WETHPairToken0 === WETHPartner.address ? bigNumberify(0) : arbitrageAmount
await WETHPair.swap(
amount0,
amount1,
flashSwapExample.address,
defaultAbiCoder.encode(['uint'], [bigNumberify(1)]),
overrides
)
const balanceAfter = await provider.getBalance(wallet.address)
const profit = balanceAfter.sub(balanceBefore)
const reservesV1 = [
await WETHPartner.balanceOf(WETHExchangeV1.address),
await provider.getBalance(WETHExchangeV1.address)
]
const priceV1 = reservesV1[0].div(reservesV1[1])
const reservesV2 = (await WETHPair.getReserves()).slice(0, 2)
const priceV2 =
WETHPairToken0 === WETHPartner.address ? reservesV2[0].div(reservesV2[1]) : reservesV2[1].div(reservesV2[0])
expect(formatEther(profit)).to.eq('0.548043441089763649') // our profit is ~.5 ETH
expect(priceV1.toString()).to.eq('143') // we pushed the v1 price up to ~143
expect(priceV2.toString()).to.eq('161') // we pushed the v2 price down to ~161
})
})