ethereum-waffle#deployContract TypeScript Examples

The following examples show how to use ethereum-waffle#deployContract. 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: e2e.test.ts    From bodhi.js with Apache License 2.0 6 votes vote down vote up
describe('e2e test', () => {
  let wallet: Signer;
  let walletTo: Signer;

  before(async () => {
    [wallet, walletTo] = await provider.getWallets();
  });

  after(async () => {
    provider.api.disconnect();
  });

  it('evm block number', async () => {
    let contract = await deployContract(wallet as any, BlockNumberTest);
    let current_block_number = Number(await provider.api.query.system.number());
    let height = await contract.currentBlock();
    expect(await height.toString()).to.eq(current_block_number.toString());
  });
});
Example #2
Source File: fixtures.ts    From vvs-swap-core with GNU General Public License v3.0 6 votes vote down vote up
export async function pairFixture([wallet]: Wallet[], provider: Web3Provider): Promise<PairFixture> {
  const { factory } = await factoryFixture([wallet], provider)

  const tokenA = await deployContract(wallet, ERC20, [expandTo18Decimals(10000)], overrides)
  const tokenB = await deployContract(wallet, ERC20, [expandTo18Decimals(10000)], overrides)

  await factory.createPair(tokenA.address, tokenB.address, overrides)
  const pairAddress = await factory.getPair(tokenA.address, tokenB.address)
  const pair = new Contract(pairAddress, JSON.stringify(VVSPair.abi), provider).connect(wallet)

  const token0Address = (await pair.token0()).address
  const token0 = tokenA.address === token0Address ? tokenA : tokenB
  const token1 = tokenA.address === token0Address ? tokenB : tokenA

  return { factory, token0, token1, pair }
}
Example #3
Source File: fixtures.ts    From staking-factory with MIT License 6 votes vote down vote up
export async function stakingRewardsFactoryFixture(
  [wallet]: Wallet[],
  provider: providers.Web3Provider
): Promise<StakingRewardsFactoryFixture> {
  const rewardsToken = await deployContract(wallet, TestERC20, [expandTo18Decimals(1_000_000_000)])

  // deploy staking tokens
  const stakingTokens = []
  for (let i = 0; i < NUMBER_OF_STAKING_TOKENS; i++) {
    const stakingToken = await deployContract(wallet, TestERC20, [expandTo18Decimals(1_000_000_000)])
    stakingTokens.push(stakingToken)
  }

  // deploy the staking rewards factory
  const { timestamp: now } = await provider.getBlock('latest')
  const genesis = now + 60 * 60
  const rewardAmounts: BigNumber[] = new Array(stakingTokens.length).fill(expandTo18Decimals(10))
  const stakingRewardsFactory = await deployContract(wallet, StakingRewardsFactory, [rewardsToken.address, genesis])

  return { rewardsToken, stakingTokens, genesis, rewardAmounts, stakingRewardsFactory }
}
Example #4
Source File: fixtures.ts    From staking-factory with MIT License 6 votes vote down vote up
export async function stakingRewardsFixture([wallet]: Wallet[]): Promise<StakingRewardsFixture> {
  const rewardsDistribution = wallet.address
  const rewardsToken = await deployContract(wallet, TestERC20, [expandTo18Decimals(1000000)])
  const stakingToken = await deployContract(wallet, UniswapV2ERC20, [expandTo18Decimals(1000000)])

  const stakingRewards = await deployContract(wallet, StakingRewards, [
    rewardsDistribution,
    rewardsToken.address,
    stakingToken.address,
  ])

  return { stakingRewards, rewardsToken, stakingToken }
}
Example #5
Source File: ExampleOracleSimple.spec.ts    From pancake-swap-testnet with MIT License 6 votes vote down vote up
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 #6
Source File: fixtures.ts    From pancake-swap-testnet with MIT License 6 votes vote down vote up
export async function pairFixture(provider: Web3Provider, [wallet]: Wallet[]): Promise<PairFixture> {
  const { factory } = await factoryFixture(provider, [wallet])

  const tokenA = await deployContract(wallet, ERC20, [expandTo18Decimals(10000)], overrides)
  const tokenB = await deployContract(wallet, ERC20, [expandTo18Decimals(10000)], overrides)

  await factory.createPair(tokenA.address, tokenB.address, overrides)
  const pairAddress = await factory.getPair(tokenA.address, tokenB.address)
  const pair = new Contract(pairAddress, JSON.stringify(PancakePair.abi), provider).connect(wallet)

  const token0Address = (await pair.token0()).address
  const token0 = tokenA.address === token0Address ? tokenA : tokenB
  const token1 = tokenA.address === token0Address ? tokenB : tokenA

  return { factory, token0, token1, pair }
}
Example #7
Source File: deployMulticall.ts    From useDApp with MIT License 6 votes vote down vote up
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: fixtures.ts    From apeswap-swap-core with GNU General Public License v3.0 6 votes vote down vote up
export async function pairFixture([wallet]: Wallet[], provider: Web3Provider): Promise<PairFixture> {
  const { factory } = await factoryFixture([wallet], provider)

  const tokenA = await deployContract(wallet, ERC20, [expandTo18Decimals(10000)], overrides)
  const tokenB = await deployContract(wallet, ERC20, [expandTo18Decimals(10000)], overrides)

  await factory.createPair(tokenA.address, tokenB.address, overrides)
  const pairAddress = await factory.getPair(tokenA.address, tokenB.address)
  const pair = new Contract(pairAddress, JSON.stringify(ApePair.abi), provider).connect(wallet)

  const token0Address = (await pair.token0()).address
  const token0 = tokenA.address === token0Address ? tokenA : tokenB
  const token1 = tokenA.address === token0Address ? tokenB : tokenA

  return { factory, token0, token1, pair }
}
Example #9
Source File: HelloWorld.test.ts    From bodhi.js with Apache License 2.0 6 votes vote down vote up
describe('HelloWorld', () => {
  let wallet: Signer;
  let instance: Contract;

  before(async () => {
    [wallet] = await provider.getWallets();
    instance = await deployContract(wallet, HelloWorld);
  });

  after(async () => {
    provider.api.disconnect();
  });

  it('returns the right value after the contract is deployed', async () => {
    console.log(instance.address);
    expect(await instance.helloWorld()).to.equal('Hello World!');
  });
});
Example #10
Source File: fixtures.ts    From apeswap-swap-core with GNU General Public License v3.0 5 votes vote down vote up
export async function factoryFixture([wallet]: Wallet[], _: Web3Provider): Promise<FactoryFixture> {
  const factory = await deployContract(wallet, ApeFactory, [wallet.address], overrides)
  return { factory }
}
Example #11
Source File: fixtures.ts    From vvs-swap-core with GNU General Public License v3.0 5 votes vote down vote up
export async function factoryFixture([wallet]: Wallet[], _: Web3Provider): Promise<FactoryFixture> {
  const factory = await deployContract(wallet, VVSFactory, [wallet.address], overrides)
  return { factory }
}
Example #12
Source File: deployMockToken.tsx    From useDApp with MIT License 5 votes vote down vote up
export async function deployMockToken(deployer: Wallet, initialBalance?: BigNumber) {
  const args = ['MOCKToken', 'MOCK', deployer.address, initialBalance ?? MOCK_TOKEN_INITIAL_BALANCE]
  return await deployContract(deployer, ERC20Mock, args)
}
Example #13
Source File: sortition-sum-tree-factory.test.ts    From sortition-sum-tree-factory with MIT License 5 votes vote down vote up
describe('SortitionSumTreeFactory', () =>
  it('Should successfully keep track of ID ownership of values and draw them from the tree appropriately.', async () => {
    // Deploy contract
    const sortitionSumTreeFactory = await deployContract(wallet, ExposedSortitionSumTreeFactory)

    // Create tree and populate with 4 candidates
    const tree = { key: ethers.utils.formatBytes32String('1'), K: 2 }
    const candidates = {
      bob: {
        ID:
          '0x0000000000000000000000000000000000000000000000000000000000000002',
        value: 15
      },
      dave: {
        ID:
          '0x0000000000000000000000000000000000000000000000000000000000000004',
        value: 5
      },
      alice: {
        ID:
          '0x0000000000000000000000000000000000000000000000000000000000000001',
        value: 10
      },
      carl: {
        ID:
          '0x0000000000000000000000000000000000000000000000000000000000000003',
        value: 20
      }
    }
    await sortitionSumTreeFactory._createTree(tree.key, tree.K)
    for (const candidate of Object.values(candidates)) {
      await sortitionSumTreeFactory._set(
        tree.key,
        candidate.value,
        candidate.ID
      )
    }

    // Test drawing Bob with 13 and Carl with 27
    expect(await sortitionSumTreeFactory._draw(tree.key, 13)).to.equal(
      candidates.bob.ID
    )
    expect(await sortitionSumTreeFactory._draw(tree.key, 27)).to.equal(
      candidates.carl.ID
    )

    // Set Alice to 14 to draw her with 13 and then set her back to 10 to draw Bob again
    await sortitionSumTreeFactory._set(tree.key, 14, candidates.alice.ID)
    expect(await sortitionSumTreeFactory._draw(tree.key, 13)).to.equal(
      candidates.alice.ID
    )
    await sortitionSumTreeFactory._set(tree.key, 10, candidates.alice.ID)
    expect(await sortitionSumTreeFactory._draw(tree.key, 13)).to.equal(
      candidates.bob.ID
    )

    // Remove Carl to draw Dave with 27 and add him back in to draw him again
    await sortitionSumTreeFactory._set(tree.key, 0, candidates.carl.ID)
    expect(await sortitionSumTreeFactory._draw(tree.key, 27)).to.equal(
      candidates.dave.ID
    )
    
    await sortitionSumTreeFactory._set(
      tree.key,
      candidates.carl.value,
      candidates.carl.ID
    )
    expect(await sortitionSumTreeFactory._draw(tree.key, 27)).to.equal(
      candidates.carl.ID
    )

    // Test stake view
    for (const candidate of Object.values(candidates))
      expect(
        await sortitionSumTreeFactory._stakeOf(tree.key, candidate.ID)
      ).to.deep.equal(ethers.utils.bigNumberify(candidate.value))
  })
)
Example #14
Source File: sequencer-batch-append.spec.ts    From integration-tests with MIT License 5 votes vote down vote up
describe('Queue Origin Sequencer Transactions', () => {
  let optimismProvider
  let provider: JsonRpcProvider
  let token
  let signer

  before(async () => {
    const web3 = new Web3Provider(
      ganache.provider({
        mnemonic: Config.Mnemonic(),
      })
    )

    optimismProvider = new OptimismProvider(Config.L2NodeUrlWithPort(), web3)
    provider = new JsonRpcProvider(Config.L2NodeUrlWithPort())
  })

  const initalSupply = 1000
  before(async () => {
    const pre = await provider.getBlock('latest')

    signer = await provider.getSigner()
    token = await deployContract(signer, ERC20, [initalSupply, 'Foo', 8, 'FOO'])

    // Allow the batch to be submitted
    do {
      const tip = await provider.getBlock('latest')
      await sleep(5000)
      if (tip.number === pre.number + 1) {
        break
      }
    } while (true)
  })

  it('should sequencer batch append', async () => {
    const chainId = await signer.getChainId()
    const address = await signer.getAddress()
    const nonce = await provider.getTransactionCount(address)

    const result = await token.transfer(etherbase, 1)
    const receipt = await result.wait()
    assert(receipt)
  })
})
Example #15
Source File: BasicToken.test.ts    From bodhi.js with Apache License 2.0 5 votes vote down vote up
describe('BasicToken', () => {
  let wallet: Signer;
  let walletTo: Signer;
  let emptyWallet: Signer;
  let token: Contract;

  before(async () => {
    [wallet, walletTo, emptyWallet] = await provider.getWallets();
    token = await deployContract(wallet, BasicToken, [1000]);
  });

  after(async () => {
    provider.api.disconnect();
  });

  it('Assigns initial balance', async () => {
    expect(await token.balanceOf(await wallet.getAddress())).to.equal(1000);
  });

  it('Transfer adds amount to destination account', async () => {
    await token.transfer(await walletTo.getAddress(), 7);
    expect(await token.balanceOf(await walletTo.getAddress())).to.equal(7);
  });

  it('Transfer emits event', async () => {
    await expect(token.transfer(await walletTo.getAddress(), 7))
      .to.emit(token, 'Transfer')
      .withArgs(await wallet.getAddress(), await walletTo.getAddress(), 7);
  });

  it('Can not transfer above the amount', async () => {
    await expect(token.transfer(await walletTo.getAddress(), 1007)).to.be.reverted;
  });

  it('Can not transfer from empty account', async () => {
    if (!process.argv.includes('--with-ethereum-compatibility')) {
      // If it is not called by the maintainer, developer, or contract, it needs to be deployed first
      await provider.api.tx.evm.publishContract(token.address).signAndSend(testPairs.alice.address);
    }

    const tokenFromOtherWallet = token.connect(emptyWallet);
    await expect(tokenFromOtherWallet.transfer(await wallet.getAddress(), 1)).to.be.reverted;
  });
});
Example #16
Source File: fixtures.ts    From pancake-swap-testnet with MIT License 5 votes vote down vote up
export async function factoryFixture(_: Web3Provider, [wallet]: Wallet[]): Promise<FactoryFixture> {
  const factory = await deployContract(wallet, PancakeFactory, [wallet.address], overrides)
  return { factory }
}
Example #17
Source File: Prices.test.ts    From bodhi.js with Apache License 2.0 5 votes vote down vote up
describe('Prices', () => {
  let prices: Contract;

  before(async () => {
    const [wallet] = await provider.getWallets();
    prices = await deployContract(wallet as any, Prices);
  });

  after(async () => {
    provider.api.disconnect();
  });

  it('getPrice works', async () => {
    await feedValues('RENBTC', BigNumber.from(34_500).mul(BigNumber.from(10).pow(18)).toString());
    expect(await prices.getPrice(ADDRESS.RENBTC)).to.equal(
      BigNumber.from(34_500).mul(BigNumber.from(10).pow(18)).toString()
    );

    await feedValues('RENBTC', BigNumber.from(33_800).mul(BigNumber.from(10).pow(18)).toString());
    expect(await prices.getPrice(ADDRESS.RENBTC)).to.equal(
      BigNumber.from(33_800).mul(BigNumber.from(10).pow(18)).toString()
    );

    await feedValues('DOT', BigNumber.from(15).mul(BigNumber.from(10).pow(18)).toString());
    expect(await prices.getPrice(ADDRESS.DOT)).to.equal(BigNumber.from(15).mul(BigNumber.from(10).pow(18)).toString());

    await feedValues('DOT', BigNumber.from(16).mul(BigNumber.from(10).pow(18)).toString());
    expect(await prices.getPrice(ADDRESS.DOT)).to.equal(BigNumber.from(16).mul(BigNumber.from(10).pow(18)).toString());

    expect(await prices.getPrice(ADDRESS.AUSD)).to.equal(BigNumber.from(1).mul(BigNumber.from(10).pow(18)).toString());

    expect(await prices.getPrice(ADDRESS.KUSD)).to.equal(0);
  });

  it('ignores invalid address as CurrencyId::erc20', async () => {
    // not system contract
    expect(await prices.getPrice('0x1000000000000000000000000000000000000000')).to.equal(0);
    // Zero address
    await expect(prices.getPrice('0x0000000000000000000000000000000000000000')).to.be.reverted;
  });
});
Example #18
Source File: EVM.test.ts    From bodhi.js with Apache License 2.0 5 votes vote down vote up
describe('EVM', () => {
  let wallet: Signer;
  let walletTo: Signer;
  let evm: Contract;
  let evmPredeployed: Contract;

  before(async () => {
    [wallet, walletTo] = await provider.getWallets();
    evm = await deployContract(wallet as any, EVM);
    evmPredeployed = new ethers.Contract(ADDRESS.EVM, EVM_ABI, wallet as any);
  });

  after(async () => {
    provider.api.disconnect();
  });

  it('evm works', async () => {
    if (!process.argv.includes('--with-ethereum-compatibility')) {
      expect((await evm.newContractExtraBytes()).toString()).to.equal(formatAmount('10_000'));

      expect((await evm.storageDepositPerByte()).toString()).to.equal(formatAmount('100_000_000_000_000'));

      expect((await evm.developerDeposit()).toString()).to.equal(formatAmount('1_000_000_000_000_000_000'));

      expect((await evm.publicationFee()).toString()).to.equal(formatAmount('1_000_000_000_000_000_000'));

      await evmPredeployed.publishContract(evm.address);
    } else {
      expect(await evm.newContractExtraBytes()).to.equal(0);

      expect(await evm.storageDepositPerByte()).to.equal(0);

      expect(await evm.developerDeposit()).to.equal(0);

      expect(await evm.publicationFee()).to.equal(0);
    }

    expect(await evm.maintainerOf(evm.address)).to.equal(await wallet.getAddress());

    // The contract created by the user cannot be transferred through the contract,
    // only through the evm dispatch call `transfer_maintainer`.
    await expect(evm.transferMaintainer(evm.address, await walletTo.getAddress())).to.be.reverted;

    await new Promise(async (resolve) => {
      provider.api.tx.evm
        .transferMaintainer(evm.address, await walletTo.getAddress())
        .signAndSend(testPairs.alice.address, (result) => {
          if (result.status.isFinalized || result.status.isInBlock) {
            resolve(undefined);
          }
        });
    });

    expect(await evm.maintainerOf(evm.address)).to.equal(await walletTo.getAddress());

    expect(await evm.developerStatus(await wallet.getAddress())).to.equal(false);
    await evmPredeployed.developerEnable();
    expect(await evm.developerStatus(await wallet.getAddress())).to.equal(true);
    await evmPredeployed.developerDisable();
    expect(await evm.developerStatus(await wallet.getAddress())).to.equal(false);
  });
});
Example #19
Source File: AmmSpec2.ts    From perpetual-protocol with GNU General Public License v3.0 5 votes vote down vote up
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 #20
Source File: fixtures.ts    From pancake-swap-testnet with MIT License 5 votes vote down vote up
export async function v2Fixture(provider: Web3Provider, [wallet]: Wallet[]): Promise<V2Fixture> {
  // deploy tokens
  const tokenA = await deployContract(wallet, ERC20, [expandTo18Decimals(10000)])
  const tokenB = await deployContract(wallet, ERC20, [expandTo18Decimals(10000)])
  const WETH = await deployContract(wallet, WETH9)
  const WETHPartner = await deployContract(wallet, ERC20, [expandTo18Decimals(10000)])

  // deploy V1
  const factoryV1 = await deployContract(wallet, UniswapV1Factory, [])
  await factoryV1.initializeFactory((await deployContract(wallet, UniswapV1Exchange, [])).address)

  // deploy V2
  const factoryV2 = await deployContract(wallet, PancakeFactory, [wallet.address])

  // deploy routers
  const router01 = await deployContract(wallet, PancakeRouter01, [factoryV2.address, WETH.address], overrides)
  const router02 = await deployContract(wallet, PancakeRouter02, [factoryV2.address, WETH.address], overrides)

  // event emitter for testing
  const routerEventEmitter = await deployContract(wallet, RouterEventEmitter, [])

  // deploy migrator
  const migrator = await deployContract(wallet, PancakeMigrator, [factoryV1.address, router01.address], overrides)

  // initialize V1
  await factoryV1.createExchange(WETHPartner.address, overrides)
  const WETHExchangeV1Address = await factoryV1.getExchange(WETHPartner.address)
  const WETHExchangeV1 = new Contract(WETHExchangeV1Address, JSON.stringify(UniswapV1Exchange.abi), provider).connect(
    wallet
  )

  // initialize V2
  await factoryV2.createPair(tokenA.address, tokenB.address)
  const pairAddress = await factoryV2.getPair(tokenA.address, tokenB.address)
  const pair = new Contract(pairAddress, JSON.stringify(IPancakePair.abi), provider).connect(wallet)

  const token0Address = await pair.token0()
  const token0 = tokenA.address === token0Address ? tokenA : tokenB
  const token1 = tokenA.address === token0Address ? tokenB : tokenA

  await factoryV2.createPair(WETH.address, WETHPartner.address)
  const WETHPairAddress = await factoryV2.getPair(WETH.address, WETHPartner.address)
  const WETHPair = new Contract(WETHPairAddress, JSON.stringify(IPancakePair.abi), provider).connect(wallet)

  return {
    token0,
    token1,
    WETH,
    WETHPartner,
    factoryV1,
    factoryV2,
    router01,
    router02,
    router: router02, // the default router, 01 had a minor bug
    routerEventEmitter,
    migrator,
    WETHExchangeV1,
    pair,
    WETHPair
  }
}
Example #21
Source File: Dex.test.ts    From bodhi.js with Apache License 2.0 4 votes vote down vote up
describe('Dex', () => {
  let wallet: Signer;
  let dex: Contract;

  before(async () => {
    [wallet] = await provider.getWallets();
    dex = await deployContract(wallet as any, Dex);
  });

  after(async () => {
    provider.api.disconnect();
  });

  it('getLiquidityPool works', async () => {
    expect(await dex.getLiquidityPool(ADDRESS.ACA, ADDRESS.AUSD)).to.be.ok;
  });

  it('getLiquidityPool should not works', async () => {
    await expect(dex.getLiquidityPool(ADDRESS.ACA, '0x0000000000000000000001000000000000000000')).to.be.reverted;
  });

  it('getLiquidityTokenAddress works', async () => {
    expect(await dex.getLiquidityTokenAddress(ADDRESS.ACA, ADDRESS.AUSD)).to.equal(ADDRESS.LP_ACA_AUSD);
  });

  it('getLiquidityTokenAddress should not works', async () => {
    await expect(dex.getLiquidityTokenAddress(ADDRESS.ACA, '0x0000000000000000000001000000000000000000')).to.be
      .reverted;
  });

  it('getSwapTargetAmount works', async () => {
    expect(await dex.getSwapTargetAmount([ADDRESS.ACA, ADDRESS.AUSD], 1000)).to.be.ok;
    expect(await dex.getSwapTargetAmount([ADDRESS.ACA, ADDRESS.AUSD, ADDRESS.DOT], 1000)).to.be.ok;
  });

  it('getSwapTargetAmount should not works', async () => {
    await expect(
      dex.getSwapTargetAmount([ADDRESS.ACA, ADDRESS.AUSD, ADDRESS.DOT, ADDRESS.RENBTC, ADDRESS.LDOT], 1000)
    ).to.be.revertedWith('Dex get_swap_target_amount failed');
    await expect(
      dex.getSwapTargetAmount([ADDRESS.ACA, ADDRESS.AUSD, ADDRESS.DOT, ADDRESS.LDOT, ADDRESS.RENBTC], 1000)
    ).to.be.revertedWith('Dex get_swap_target_amount failed');
    await expect(
      dex.getSwapTargetAmount([ADDRESS.ACA, '0x0000000000000000000001000000000000000000'], 1000)
    ).to.be.revertedWith('invalid currency id');
  });

  it('getSwapSupplyAmount works', async () => {
    expect(await dex.getSwapSupplyAmount([ADDRESS.ACA, ADDRESS.AUSD], 1000)).to.be.ok;
    expect(await dex.getSwapSupplyAmount([ADDRESS.ACA, ADDRESS.AUSD, ADDRESS.DOT], 1000)).to.be.ok;
  });

  it('getSwapSupplyAmount should not works', async () => {
    await expect(dex.getSwapSupplyAmount([ADDRESS.ACA], 1000)).to.be.revertedWith('Dex get_swap_supply_amount failed');
    await expect(
      dex.getSwapSupplyAmount([ADDRESS.ACA, ADDRESS.AUSD, ADDRESS.DOT, ADDRESS.LDOT, ADDRESS.RENBTC], 1000)
    ).to.be.revertedWith('Dex get_swap_supply_amount failed');
    await expect(
      dex.getSwapSupplyAmount([ADDRESS.ACA, '0x0000000000000000000001000000000000000000'], 1000)
    ).to.be.revertedWith('invalid currency id');
  });

  it('swapWithExactSupply works', async () => {
    let pool_0 = await dex.getLiquidityPool(ADDRESS.ACA, ADDRESS.AUSD);
    expect(
      await dex.swapWithExactSupply([ADDRESS.ACA, ADDRESS.AUSD], 1_000_000_000_000, 1, {
        value: ethers.utils.parseEther('1'),
        gasLimit: 2_000_000
      })
    ).to.be.ok;

    let pool_1 = await dex.getLiquidityPool(ADDRESS.ACA, ADDRESS.AUSD);
    expect(pool_1[0].sub(pool_0[0])).to.equal(1_000_000_000_000);

    let pool_2 = await dex.getLiquidityPool(ADDRESS.ACA, ADDRESS.AUSD);
    expect(
      await dex.swapWithExactSupply([ADDRESS.ACA, ADDRESS.AUSD, ADDRESS.DOT], 1_000_000_000_000, 1, {
        value: ethers.utils.parseEther('1'),
        gasLimit: 2_000_000
      })
    ).to.be.ok;
    let pool_3 = await dex.getLiquidityPool(ADDRESS.ACA, ADDRESS.AUSD);
    expect(pool_3[0].sub(pool_2[0])).to.equal(1_000_000_000_000);
  });

  it('swapWithExactSupply should not works', async () => {
    await expect(dex.swapWithExactSupply([ADDRESS.ACA], 1000, 1)).to.be.revertedWith('InvalidTradingPathLength');
    await expect(
      dex.swapWithExactSupply([ADDRESS.ACA, ADDRESS.AUSD, ADDRESS.DOT, ADDRESS.LDOT, ADDRESS.RENBTC], 1000, 1)
    ).to.be.revertedWith('InvalidTradingPathLength');
    await expect(
      dex.swapWithExactSupply([ADDRESS.ACA, '0x0000000000000000000001000000000000000000'], 1000, 1)
    ).to.be.revertedWith('invalid currency id');
  });

  it('swapWithExactTarget works', async () => {
    let pool_0 = await dex.getLiquidityPool(ADDRESS.ACA, ADDRESS.AUSD);
    expect(
      await dex.swapWithExactTarget([ADDRESS.ACA, ADDRESS.AUSD], 1, 1_000_000_000_000, {
        value: ethers.utils.parseEther('1'),
        gasLimit: 2_000_000
      })
    ).to.be.ok;

    let pool_1 = await dex.getLiquidityPool(ADDRESS.ACA, ADDRESS.AUSD);
    expect(pool_1[1].sub(pool_0[1])).to.equal(-1);

    let pool_2 = await dex.getLiquidityPool(ADDRESS.AUSD, ADDRESS.DOT);
    expect(
      await dex.swapWithExactTarget([ADDRESS.ACA, ADDRESS.AUSD, ADDRESS.DOT], 1, 1_000_000_000_000, {
        value: ethers.utils.parseEther('1'),
        gasLimit: 2_000_000
      })
    ).to.be.ok;
    let pool_3 = await dex.getLiquidityPool(ADDRESS.AUSD, ADDRESS.DOT);
    expect(pool_3[1].sub(pool_2[1])).to.equal(-1);
  });

  it('swapWithExactTarget should not works', async () => {
    await expect(dex.swapWithExactTarget([ADDRESS.ACA], 1, 1000)).to.be.revertedWith('InvalidTradingPathLength');
    await expect(
      dex.swapWithExactTarget([ADDRESS.ACA, ADDRESS.AUSD, ADDRESS.DOT, ADDRESS.LDOT, ADDRESS.RENBTC], 1, 1000)
    ).to.be.revertedWith('InvalidTradingPathLength');
    await expect(
      dex.swapWithExactTarget([ADDRESS.ACA, '0x0000000000000000000001000000000000000000'], 1, 1000)
    ).to.be.revertedWith('invalid currency id');
  });

  it('addLiquidity and removeLiquidity works', async () => {
    let pool_0 = await dex.getLiquidityPool(ADDRESS.ACA, ADDRESS.AUSD);
    expect(
      await dex.swapWithExactTarget([ADDRESS.ACA, ADDRESS.AUSD], 1_000_000_000_000, 1_000_000_000_000, {
        value: ethers.utils.parseEther('1'),
        gasLimit: 2_000_000
      })
    ).to.be.ok;

    let pool_1 = await dex.getLiquidityPool(ADDRESS.ACA, ADDRESS.AUSD);
    expect(pool_1[1].sub(pool_0[1])).to.equal(-1_000_000_000_000);

    expect(
      await dex.addLiquidity(ADDRESS.ACA, ADDRESS.AUSD, 1_000_000_000_000, 1_000_000_000_000, 0, {
        value: ethers.utils.parseEther('1'),
        gasLimit: 2_000_000
      })
    ).to.be.ok;

    let pool_2 = await dex.getLiquidityPool(ADDRESS.ACA, ADDRESS.AUSD);
    expect(pool_2[1].sub(pool_1[1])).to.equal(1_000_000_000_000);

    expect(
      await dex.removeLiquidity(ADDRESS.ACA, ADDRESS.AUSD, 100_000_000_000, 0, 0, {
        value: ethers.utils.parseEther('1'),
        gasLimit: 2_000_000
      })
    ).to.be.ok;
  });

  it('addLiquidity should not works', async () => {
    await expect(dex.addLiquidity(ADDRESS.ACA, '0x0000000000000000000001000000000000000000', 1, 1000, 0)).to.be
      .reverted;
  });

  it('removeLiquidity should not works', async () => {
    await expect(dex.addLiquidity(ADDRESS.ACA, '0x0000000000000000000001000000000000000000', 1, 1000, 0)).to.be
      .reverted;
  });
});
Example #22
Source File: VvsERC20.spec.ts    From vvs-swap-core with GNU General Public License v3.0 4 votes vote down vote up
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 #23
Source File: StakingRewards.spec.ts    From staking-factory with MIT License 4 votes vote down vote up
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 #24
Source File: ExampleSwapToPrice.spec.ts    From pancake-swap-testnet with MIT License 4 votes vote down vote up
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 #25
Source File: ExampleSlidingWindowOracle.spec.ts    From pancake-swap-testnet with MIT License 4 votes vote down vote up
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 #26
Source File: ExampleFlashSwap.spec.ts    From pancake-swap-testnet with MIT License 4 votes vote down vote up
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
  })
})
Example #27
Source File: PancakeERC20.spec.ts    From pancake-swap-testnet with MIT License 4 votes vote down vote up
describe('PancakeERC20', () => {
  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()

  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('Pancake LPs')
    expect(await token.symbol()).to.eq('Cake-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(bigNumberify(1))
  })
})
Example #28
Source File: Scheduler.test.ts    From bodhi.js with Apache License 2.0 4 votes vote down vote up
describe('Schedule', () => {
  let wallet: Signer;
  let walletTo: Signer;
  let subscriber: Signer;
  let schedule: Contract;

  before(async () => {
    [wallet, walletTo, subscriber] = await provider.getWallets();
    schedule = await new ethers.Contract(ADDRESS.Schedule, SCHEDULE_CALL_ABI, wallet as any);
  });

  after(async () => {
    provider.api.disconnect();
  });

  it('ScheduleCall works', async () => {
    const target_block_number = Number(await provider.api.query.system.number()) + 4;

    const erc20 = new ethers.Contract(ADDRESS.DOT, ERC20_ABI, walletTo as any);
    const tx = await erc20.populateTransaction.transfer(walletTo.getAddress(), 1_000_000);
    // console.log(tx, ethers.utils.hexlify(tx.data as string));

    await schedule.scheduleCall(ADDRESS.DOT, 0, 300000, 10000, 1, ethers.utils.hexlify(tx.data as string));

    let current_block_number = Number(await provider.api.query.system.number());
    let balance = await erc20.balanceOf(await walletTo.getAddress());
    while (current_block_number < target_block_number) {
      await next_block(current_block_number);
      current_block_number = Number(await provider.api.query.system.number());
    }

    let new_balance = await erc20.balanceOf(await walletTo.getAddress());
    expect(new_balance.toString()).to.equal(balance.add(1_000_000).toString());
  });

  it('CancelCall works', async () => {
    const erc20 = new ethers.Contract(ADDRESS.DOT, ERC20_ABI, walletTo as any);
    const tx = await erc20.populateTransaction.transfer(walletTo.getAddress(), 1_000_000);
    // console.log(tx, ethers.utils.hexlify(tx.data as string));

    let iface = new ethers.utils.Interface(SCHEDULE_CALL_ABI);

    let current_block_number = Number(await provider.api.query.system.number());
    await schedule.scheduleCall(ADDRESS.DOT, 0, 300000, 10000, 2, ethers.utils.hexlify(tx.data as string));

    let block_hash = await provider.api.rpc.chain.getBlockHash(current_block_number + 1);
    const data = await provider.api.derive.tx.events(block_hash);

    let event = data.events.filter((item) => provider.api.events.evm.Executed.is(item.event));
    expect(event.length).above(0);

    let decode_log = iface.parseLog((event[event.length - 1].event.data.toJSON() as any)[2][0]);
    await expect(schedule.cancelCall(ethers.utils.hexlify(decode_log.args.task_id)))
      .to.emit(schedule, 'CanceledCall')
      .withArgs(await wallet.getAddress(), ethers.utils.hexlify(decode_log.args.task_id));
  });

  it('RescheduleCall works', async () => {
    const erc20 = new ethers.Contract(ADDRESS.DOT, ERC20_ABI, walletTo as any);
    const tx = await erc20.populateTransaction.transfer(walletTo.getAddress(), 1_000_000);
    // console.log(tx, ethers.utils.hexlify(tx.data as string));

    let iface = new ethers.utils.Interface(SCHEDULE_CALL_ABI);

    let current_block_number = Number(await provider.api.query.system.number());
    await schedule.scheduleCall(ADDRESS.DOT, 0, 300000, 10000, 4, ethers.utils.hexlify(tx.data as string));

    let block_hash = await provider.api.rpc.chain.getBlockHash(current_block_number + 1);
    const data = await provider.api.derive.tx.events(block_hash);

    let event = data.events.filter((item) => provider.api.events.evm.Executed.is(item.event));
    expect(event.length).above(0);

    let decode_log = iface.parseLog((event[event.length - 1].event.data.toJSON() as any)[2][0]);
    await expect(schedule.rescheduleCall(5, ethers.utils.hexlify(decode_log.args.task_id)))
      .to.emit(schedule, 'RescheduledCall')
      .withArgs(await wallet.getAddress(), ethers.utils.hexlify(decode_log.args.task_id));
  });

  it('works with RecurringPayment', async () => {
    const erc20 = new ethers.Contract(ADDRESS.ACA, ERC20_ABI, walletTo as any);
    const transferTo = await ethers.Wallet.createRandom().getAddress();

    const recurringPayment = await deployContract(
      wallet as any,
      RecurringPayment,
      [3, 4, ethers.utils.parseEther('1000'), transferTo],
      { gasLimit: 2_000_000 }
    );
    // ACA as erc20 decimals is 12
    await erc20.transfer(recurringPayment.address, dollar.mul(5000));
    const inital_block_number = Number(await provider.api.query.system.number());
    await recurringPayment.initialize();

    expect((await provider.getBalance(transferTo)).toString()).to.equal('0');
    expect((await erc20.balanceOf(transferTo)).toString()).to.equal('0');

    let current_block_number = Number(await provider.api.query.system.number());

    while (current_block_number < inital_block_number + 5) {
      await next_block(current_block_number);
      current_block_number = Number(await provider.api.query.system.number());
    }

    expect((await provider.getBalance(transferTo)).toString()).to.equal(dollar.mul(1000000000).toString());
    expect((await erc20.balanceOf(transferTo)).toString()).to.equal(dollar.mul(1000).toString());

    current_block_number = Number(await provider.api.query.system.number());
    while (current_block_number < inital_block_number + 14) {
      await next_block(current_block_number);
      current_block_number = Number(await provider.api.query.system.number());
    }

    expect((await provider.getBalance(transferTo)).toString()).to.equal(dollar.mul(3000000000).toString());
    expect((await erc20.balanceOf(transferTo)).toString()).to.equal(dollar.mul(3000).toString());

    current_block_number = Number(await provider.api.query.system.number());
    while (current_block_number < inital_block_number + 17) {
      await next_block(current_block_number);
      current_block_number = Number(await provider.api.query.system.number());
    }

    expect((await provider.getBalance(recurringPayment.address)).toString()).to.equal('0');
    expect((await erc20.balanceOf(recurringPayment.address)).toNumber()).to.equal(0);
    if (!process.argv.includes('--with-ethereum-compatibility')) {
      expect((await provider.getBalance(transferTo)).toString()).to.equal(
        formatAmount('4_999_969_076_152_000_000_000')
      );
      expect((await erc20.balanceOf(transferTo)).toString()).to.equal(formatAmount('4_999_969_076_152_000'));
    } else {
      expect((await provider.getBalance(transferTo)).toString()).to.equal(dollar.mul(5000000000).toString());
      expect((await erc20.balanceOf(transferTo)).toString()).to.equal(dollar.mul(5000).toString());
    }
  });

  it('works with Subscription', async () => {
    const period = 10;
    const subPrice = ethers.utils.parseEther('1000');

    const subscription = await deployContract(wallet as any, Subscription, [subPrice, period], {
      value: ethers.utils.parseEther('5000'),
      gasLimit: 2_000_000
    });
    if (!process.argv.includes('--with-ethereum-compatibility')) {
      // If it is not called by the maintainer, developer, or contract, it needs to be deployed first
      await provider.api.tx.evm.publishContract(subscription.address).signAndSend(testPairs.alice.address);
    }

    expect((await subscription.balanceOf(subscriber.getAddress())).toString()).to.equal('0');
    expect((await subscription.subTokensOf(subscriber.getAddress())).toString()).to.equal('0');
    expect((await subscription.monthsSubscribed(subscriber.getAddress())).toString()).to.equal('0');

    const subscriberContract = subscription.connect(subscriber as any);
    await subscriberContract.subscribe({
      value: ethers.utils.parseEther(formatAmount('10_000')).toString(),
      gasLimit: 2_000_000
    });

    expect((await subscription.balanceOf(subscriber.getAddress())).toString()).to.equal(
      ethers.utils.parseEther(formatAmount('10_000')).sub(subPrice).toString()
    );
    expect((await subscription.subTokensOf(subscriber.getAddress())).toString()).to.equal('1');
    expect((await subscription.monthsSubscribed(subscriber.getAddress())).toString()).to.equal('1');

    let current_block_number = Number(await provider.api.query.system.number());
    for (let i = 0; i < period + 1; i++) {
      await next_block(current_block_number);
      current_block_number = Number(await provider.api.query.system.number());
    }

    expect((await subscription.balanceOf(subscriber.getAddress())).toString()).to.equal(
      ethers.utils.parseEther(formatAmount('10_000')).sub(subPrice.mul(2)).toString()
    );
    expect((await subscription.subTokensOf(subscriber.getAddress())).toString()).to.equal('3');
    expect((await subscription.monthsSubscribed(subscriber.getAddress())).toString()).to.equal('2');

    current_block_number = Number(await provider.api.query.system.number());
    for (let i = 0; i < period + 1; i++) {
      await next_block(current_block_number);
      current_block_number = Number(await provider.api.query.system.number());
    }

    expect((await subscription.balanceOf(subscriber.getAddress())).toString()).to.equal(
      ethers.utils.parseEther(formatAmount('10_000')).sub(subPrice.mul(3)).toString()
    );
    expect((await subscription.subTokensOf(subscriber.getAddress())).toString()).to.equal('6');
    expect((await subscription.monthsSubscribed(subscriber.getAddress())).toString()).to.equal('3');

    await subscriberContract.unsubscribe({ gasLimit: 2_000_000 });

    current_block_number = Number(await provider.api.query.system.number());
    await next_block(current_block_number);

    expect((await subscription.balanceOf(subscriber.getAddress())).toString()).to.equal('0');
    expect((await subscription.subTokensOf(subscriber.getAddress())).toString()).to.equal('6');
    expect((await subscription.monthsSubscribed(subscriber.getAddress())).toString()).to.equal('0');
  });
});
Example #29
Source File: multicall2.test.ts    From useDApp with MIT License 4 votes vote down vote up
describe('Multicall2', () => {
  const mockProvider = new MockProvider()
  const [deployer] = mockProvider.getWallets()
  let tokenContract: Contract
  let multicallContract: Contract

  beforeEach(async () => {
    const args = ['MOCKToken', 'MOCK', deployer.address, '10000']
    tokenContract = await deployContract(deployer, ERC20Mock, args)

    multicallContract = await deployContract(deployer, MultiCall2)
  })

  for (const fastEncoding of [false, true]) {
    describe(fastEncoding ? 'Fast encoding' : 'Ethers encoding', () => {
      const multicall2 = multicall2Factory(fastEncoding)

      it('Retrieves token balance using tryAggregate', async () => {
        const data = new Interface(ERC20Mock.abi).encodeFunctionData('balanceOf', [deployer.address])
        const call: RawCall = {
          address: tokenContract.address,
          data,
          chainId: mockProvider._network.chainId,
        }

        const blockNumber = await mockProvider.getBlockNumber()
        const result = await multicall2(mockProvider, multicallContract.address, blockNumber, [call])
        const { value, success } = result[tokenContract.address]![data] || {}
        expect(success).to.be.true
        expect(BigNumber.from(value)).to.eq('10000')
      })

      it('Fails to retrieve data on block number in the future', async () => {
        const data = new Interface(ERC20Mock.abi).encodeFunctionData('balanceOf', [deployer.address])
        const call: RawCall = {
          address: tokenContract.address,
          data,
          chainId: mockProvider._network.chainId,
        }

        const blockNumber = (await mockProvider.getBlockNumber()) + 1
        await expect(multicall2(mockProvider, multicallContract.address, blockNumber, [call])).to.be.eventually.rejected
      })

      it('Does not fail when retrieving data on block number from the past', async () => {
        const data = new Interface(ERC20Mock.abi).encodeFunctionData('balanceOf', [deployer.address])
        const call: RawCall = {
          address: tokenContract.address,
          data,
          chainId: mockProvider._network.chainId,
        }

        await sendEmptyTx(deployer)
        const blockNumber = (await mockProvider.getBlockNumber()) - 1
        const result = await multicall2(mockProvider, multicallContract.address, blockNumber, [call])
        const { value, success } = result[tokenContract.address]![data] || {}
        expect(success).to.be.true
        expect(BigNumber.from(value)).to.eq('10000')
      })

      it('Does not fail when doing multiple calls at once', async () => {
        const erc20Interface = new Interface(ERC20Mock.abi)

        const calls: RawCall[] = [
          {
            address: tokenContract.address,
            data: erc20Interface.encodeFunctionData('balanceOf', [deployer.address]),
            chainId: mockProvider._network.chainId,
          },
          {
            address: tokenContract.address,
            data: erc20Interface.encodeFunctionData('symbol', []),
            chainId: mockProvider._network.chainId,
          },
          {
            address: tokenContract.address,
            data: erc20Interface.encodeFunctionData('balanceOf', [tokenContract.address]),
            chainId: mockProvider._network.chainId,
          },
        ]

        const blockNumber = await mockProvider.getBlockNumber()
        const result = await multicall2(mockProvider, multicallContract.address, blockNumber, calls)

        let { value, success } = result[calls[0].address]![calls[0].data] || {}
        expect(value).to.equal(BigNumber.from(10000))
        expect(success).to.be.true
        ;({ value, success } = result[calls[1].address]![calls[1].data] || {})
        const decodedSymbol = utils.defaultAbiCoder.decode(['string'], value!)[0]
        expect(decodedSymbol).to.equal('MOCK')
        expect(success).to.be.true
        ;({ value, success } = result[calls[2].address]![calls[2].data] || {})
        expect(value).to.equal(BigNumber.from(0))
        expect(success).to.be.true
      })

      it('Does not fail when some of the calls fail', async () => {
        const erc20Interface = new Interface(ERC20Mock.abi)

        const calls: RawCall[] = [
          {
            address: tokenContract.address,
            data: erc20Interface.encodeFunctionData('balanceOf', [deployer.address]),
            chainId: mockProvider._network.chainId,
          },
          // invalid one
          {
            address: tokenContract.address,
            data: erc20Interface.encodeFunctionData('transferFrom', [
              multicallContract.address,
              deployer.address,
              BigNumber.from(10000),
            ]),
            chainId: mockProvider._network.chainId,
          },
          {
            address: tokenContract.address,
            data: erc20Interface.encodeFunctionData('balanceOf', [tokenContract.address]),
            chainId: mockProvider._network.chainId,
          },
        ]

        const blockNumber = await mockProvider.getBlockNumber()
        const result = await multicall2(mockProvider, multicallContract.address, blockNumber, calls)

        let { value, success } = result[calls[0].address]![calls[0].data] || {}
        expect(value).to.equal(BigNumber.from(10000))
        expect(success).to.be.true
        ;({ value, success } = result[calls[1].address]![calls[1].data] || {})
        const decodedValue = new utils.Interface(['function Error(string)']).decodeFunctionData('Error', value!)[0]
        expect(decodedValue).to.equal('ERC20: transfer amount exceeds balance')
        expect(success).to.be.false
        ;({ value, success } = result[calls[2].address]![calls[2].data] || {})
        expect(value).to.equal(BigNumber.from(0))
        expect(success).to.be.true
      })
    })
  }
})