123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- const { expect } = require("chai")
- const { ethers } = require("hardhat")
- const CONFIG = require("../constants/config.json")
- const { getAddr, deployNew } = require("./util/helpers")
- const { ZERO_ADDRESS } = require("./util/constants")
- describe("Oft:", function () {
- this.timeout(300000)
- let owner, alice, bob, user3, user4, badUser1, fakeContract, router, mockToken, lzEndpoint, bridge
- let chainId, decimals, oft, lzEndpoints, users, mainEndpointId, numEndpoints, initSupplyMainEndpoint, name, symbol
- const getChainBalance = async (endpointId) => {
- return await oft[endpointId].balanceOf(oft[endpointId].address)
- }
- const getUserBalance = async (endpointId, userAddress) => {
- return await oft[endpointId].balanceOf(userAddress)
- }
- const auditGlobalTokenSupply = async function () {
- // make sure the total amount of tokens locked int the mainEndpoint token contract
- // is equal to the total tokens owned by all addresses on all non-mainEndpoint chains
- const mainLockedTokens = await getChainBalance(mainEndpointId)
- let childrenCumulativeTokens = ethers.BigNumber.from(0)
- for (let childEndpointId = 1; childEndpointId < numEndpoints; ++childEndpointId) {
- for (let userId = 0; userId < users.length; ++userId) {
- let childUserBalance = await getUserBalance(childEndpointId, users[userId].address)
- childrenCumulativeTokens = childrenCumulativeTokens.add(childUserBalance)
- }
- }
- expect(mainLockedTokens).to.equal(childrenCumulativeTokens)
- }
- const sendTokens = async (fromUserId, toUserId, qty, fromEndpointId, toEndpointId) => {
- const fromSigner = users[fromUserId]
- const toSigner = users[toUserId]
- const preFromBalance = await getUserBalance(fromEndpointId, fromSigner.address)
- const preToBalance = await getUserBalance(toEndpointId, toSigner.address)
- const localOft = oft[fromEndpointId]
- // send the tokens across chains
- await localOft.connect(fromSigner).sendTokens(toEndpointId, toSigner.address, qty, ZERO_ADDRESS, "0x", {
- value: ethers.utils.parseEther("0.1"),
- })
- const postFromBalance = await getUserBalance(fromEndpointId, fromSigner.address)
- const postToBalance = await getUserBalance(toEndpointId, toSigner.address)
- if (fromUserId === toUserId && fromEndpointId === toEndpointId) {
- // user sends to themselves on the same endpoint
- expect(postFromBalance).to.equal(preFromBalance)
- expect(postToBalance).to.equal(preToBalance)
- } else {
- // final balance check for a user send to a different user,
- // or a user sending to their address on another chain
- expect(postFromBalance).to.equal(preFromBalance.sub(qty))
- expect(postToBalance).to.equal(preToBalance.add(qty))
- }
- // audit the global token supply by comparing the locked tokens on mainendpoint to
- // the cumulative qty of tokens in user wallets on NON main endpoints
- await auditGlobalTokenSupply()
- }
- before(async function () {
- ;({ owner, alice, bob, user3, user4, badUser1, fakeContract } = await getAddr(ethers))
- users = [owner, alice, bob, user3, user4]
- chainId = 1
- decimals = 18
- initSupplyMainEndpoint = ethers.utils.parseEther("1000000000")
- name = CONFIG.stargateToken.name
- symbol = CONFIG.stargateToken.name
- mainEndpointId = 0 // endpoint id that controls the token
- numEndpoints = 3 // increase this number to iterate more endpoints
- })
- beforeEach(async function () {
- oft = {}
- lzEndpoints = {}
- for (let i = 0; i < numEndpoints; ++i) {
- lzEndpoints[i] = await deployNew("LZEndpointMock", [i])
- oft[i] = await deployNew("StargateToken", [name, symbol, lzEndpoints[i].address, mainEndpointId, initSupplyMainEndpoint])
- }
- // wire them together
- for (const i in oft) {
- for (const j in lzEndpoints) {
- // if (i === j) continue;
- const oftSrc = oft[i]
- const oftDst = oft[j]
- const lzSrc = lzEndpoints[i]
- const lzDst = lzEndpoints[j]
- // set
- await oftSrc.setDestination(j, oftDst.address)
- await oftDst.setDestination(i, oftSrc.address)
- await lzSrc.setDestLzEndpoint(oftDst.address, lzDst.address)
- await lzDst.setDestLzEndpoint(oftSrc.address, lzSrc.address)
- }
- }
- })
- it("send() - transfers to last chain", async function () {
- const fromUserId = 0
- const toUserId = 1
- const qty = ethers.utils.parseEther("1")
- const fromEndpointId = mainEndpointId
- const dstEndpointId = numEndpoints - 1
- await sendTokens(fromUserId, toUserId, qty, fromEndpointId, dstEndpointId)
- })
- it("send() - transfer to next chain", async function () {
- const fromUserId = 0
- const toUserId = 1
- const qty = ethers.utils.parseEther("1")
- const fromEndpointId = mainEndpointId
- const dstEndpointId = fromEndpointId + 1
- await sendTokens(fromUserId, toUserId, qty, fromEndpointId, dstEndpointId)
- })
- it("send() - send tokens to themselves", async function () {
- const user0 = 0
- await sendTokens(user0, user0, 100, mainEndpointId, mainEndpointId)
- })
- it("send() - everyone gets tokens, then everyone sends to everyone", async function () {
- // send everyone a balance on every endpoint from the source owner and source chain
- const originalOwnnerId = 0
- const originalMainEndpointId = mainEndpointId
- const largeQty = 1000000
- for (let toUserId = 0; toUserId < users.length; ++toUserId) {
- for (let endpointId = 0; endpointId < numEndpoints; ++endpointId) {
- await sendTokens(originalOwnnerId, toUserId, largeQty, originalMainEndpointId, endpointId)
- }
- }
- // have them all send to each other
- const qty = 100
- for (let fromUserId = 0; fromUserId < users.length; ++fromUserId) {
- for (let toUserId = 0; toUserId < users.length; ++toUserId) {
- for (let endpointId = 0; endpointId < numEndpoints; ++endpointId) {
- for (let endpointId_B = 0; endpointId_B < numEndpoints; ++endpointId_B) {
- await sendTokens(fromUserId, toUserId, qty, endpointId, endpointId_B)
- }
- }
- }
- }
- })
- it("balanceOf() - initial balances of main and children (token contract)", async function () {
- // assert token balance. only chain 1 would mint
- for (let i = 0; i < numEndpoints; ++i) {
- expect(await getChainBalance(i)).to.equal("0")
- }
- })
- it("balanceOf() - initial balances of main and children (users)", async function () {
- //assert token balance. only chain 1 would mint
- for (let i = 0; i < numEndpoints; ++i) {
- for (let j = 0; j < users.length; ++j) {
- const balanceOft = await getUserBalance(i, users[j].address)
- if (i === mainEndpointId && j === 0) {
- // the owner/deployer of the token on the main chain gets the initial supply
- expect(balanceOft).to.equal("1000000000000000000000000000")
- } else {
- expect(balanceOft).to.equal("0")
- }
- }
- }
- })
- it("sendTokens() - tokens get moved accross chains", async function () {
- // owner send some from oft_0 to alice oft_1
- // alice has no money to begin with
- expect(await oft[1].balanceOf(alice.address)).to.equal("0")
- const money1 = ethers.utils.parseEther("99")
- await oft[0].connect(owner).sendTokens(1, alice.address, money1, ZERO_ADDRESS, "0x", {
- value: ethers.utils.parseEther("0.1"),
- })
- // alice should have some money now
- expect(await oft[1].balanceOf(alice.address)).to.equal(money1)
- //assert token balance. only chain 1 would mint
- expect(await oft[0].totalSupply()).to.equal("1000000000000000000000000000")
- expect(await oft[1].totalSupply()).to.equal("99000000000000000000")
- // alice send some to bob from oft_1 to oft_2
- expect(await oft[2].balanceOf(bob.address)).to.equal("0")
- const money2 = ethers.utils.parseEther("15")
- await oft[1].connect(alice).sendTokens(2, bob.address, money2, ZERO_ADDRESS, "0x", {
- value: ethers.utils.parseEther("0.1"),
- })
- // alice should have some money now
- expect(await oft[2].balanceOf(bob.address)).to.equal(money2)
- // assert the total supply
- expect(await oft[0].totalSupply()).to.equal("1000000000000000000000000000")
- expect(await oft[1].totalSupply()).to.equal("84000000000000000000")
- expect(await oft[2].totalSupply()).to.equal("15000000000000000000")
- // bob send some to alice from oft_2 to oft_0
- const money3 = ethers.utils.parseEther("8")
- await oft[2].connect(bob).sendTokens(0, alice.address, money3, ZERO_ADDRESS, "0x", {
- value: ethers.utils.parseEther("0.1"),
- })
- // alice should have some money on oft[0]
- expect(await oft[0].balanceOf(alice.address)).to.equal(money3)
- // assert the total supply
- expect(await oft[0].totalSupply()).to.equal("1000000000000000000000000000")
- expect(await oft[1].totalSupply()).to.equal("84000000000000000000")
- // 15 - 8
- expect(await oft[2].totalSupply()).to.equal("7000000000000000000")
- })
- it("lzReceive() - reverts for non owner", async function () {
- // 42 is the arbitrary dummy return value in our mocks
- await expect(oft[0].lzReceive(chainId, "0x", 1, "0x")).to.revertedWith("")
- })
- it("estimateSendTokensFee()", async function () {
- // 42 is the arbitrary dummy return value in our mocks
- expect((await oft[0].estimateSendTokensFee(1, "0x", false, "0x"))[0]).to.equal(42)
- })
- it("setSendVersion()", async function () {
- const version = 22
- await oft[0].setSendVersion(version)
- expect(await lzEndpoints[0].mockSendVersion()).to.equal(version)
- })
- it("setReceiveVersion()", async function () {
- const version = 23
- await oft[0].setReceiveVersion(version)
- expect(await lzEndpoints[0].mockReceiveVersion()).to.equal(version)
- })
- it("setSendVersion() - reverts when non owner", async function () {
- const version = 22
- await expect(oft[0].connect(badUser1).setSendVersion(version)).to.revertedWith("Ownable: caller is not the owner")
- })
- it("setReceiveVersion() - reverts when non owner", async function () {
- const version = 23
- await expect(oft[0].connect(badUser1).setReceiveVersion(version)).to.revertedWith("Ownable: caller is not the owner")
- })
- it("setConfig()", async function () {
- const version = 22
- const configType = 0
- const config = "0x1234"
- await expect(oft[0].setConfig(version, chainId, configType, config))
- .to.emit(lzEndpoints[0], "SetConfig")
- .withArgs(version, chainId, configType, config)
- })
- it("setConfig() - reverts when non owner", async function () {
- const version = 22
- const configType = 0
- const config = "0x1234"
- await expect(oft[0].connect(badUser1).setConfig(version, chainId, configType, config)).to.revertedWith(
- "Ownable: caller is not the owner"
- )
- })
- it("forceResumeReceive()", async function () {
- const bytesAddr = "0x1234"
- await expect(oft[0].forceResumeReceive(chainId, bytesAddr)).to.emit(lzEndpoints[0], "ForceResumeReceive").withArgs(chainId, bytesAddr)
- })
- it("forceResumeReceive() - reverts when non owner", async function () {
- const bytesAddr = "0x1234"
- await expect(oft[0].connect(badUser1).forceResumeReceive(chainId, bytesAddr)).to.revertedWith("Ownable: caller is not the owner")
- })
- })
|