Oft.test.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. const { expect } = require("chai")
  2. const { ethers } = require("hardhat")
  3. const CONFIG = require("../constants/config.json")
  4. const { getAddr, deployNew } = require("./util/helpers")
  5. const { ZERO_ADDRESS } = require("./util/constants")
  6. describe("Oft:", function () {
  7. this.timeout(300000)
  8. let owner, alice, bob, user3, user4, badUser1, fakeContract, router, mockToken, lzEndpoint, bridge
  9. let chainId, decimals, oft, lzEndpoints, users, mainEndpointId, numEndpoints, initSupplyMainEndpoint, name, symbol
  10. const getChainBalance = async (endpointId) => {
  11. return await oft[endpointId].balanceOf(oft[endpointId].address)
  12. }
  13. const getUserBalance = async (endpointId, userAddress) => {
  14. return await oft[endpointId].balanceOf(userAddress)
  15. }
  16. const auditGlobalTokenSupply = async function () {
  17. // make sure the total amount of tokens locked int the mainEndpoint token contract
  18. // is equal to the total tokens owned by all addresses on all non-mainEndpoint chains
  19. const mainLockedTokens = await getChainBalance(mainEndpointId)
  20. let childrenCumulativeTokens = ethers.BigNumber.from(0)
  21. for (let childEndpointId = 1; childEndpointId < numEndpoints; ++childEndpointId) {
  22. for (let userId = 0; userId < users.length; ++userId) {
  23. let childUserBalance = await getUserBalance(childEndpointId, users[userId].address)
  24. childrenCumulativeTokens = childrenCumulativeTokens.add(childUserBalance)
  25. }
  26. }
  27. expect(mainLockedTokens).to.equal(childrenCumulativeTokens)
  28. }
  29. const sendTokens = async (fromUserId, toUserId, qty, fromEndpointId, toEndpointId) => {
  30. const fromSigner = users[fromUserId]
  31. const toSigner = users[toUserId]
  32. const preFromBalance = await getUserBalance(fromEndpointId, fromSigner.address)
  33. const preToBalance = await getUserBalance(toEndpointId, toSigner.address)
  34. const localOft = oft[fromEndpointId]
  35. // send the tokens across chains
  36. await localOft.connect(fromSigner).sendTokens(toEndpointId, toSigner.address, qty, ZERO_ADDRESS, "0x", {
  37. value: ethers.utils.parseEther("0.1"),
  38. })
  39. const postFromBalance = await getUserBalance(fromEndpointId, fromSigner.address)
  40. const postToBalance = await getUserBalance(toEndpointId, toSigner.address)
  41. if (fromUserId === toUserId && fromEndpointId === toEndpointId) {
  42. // user sends to themselves on the same endpoint
  43. expect(postFromBalance).to.equal(preFromBalance)
  44. expect(postToBalance).to.equal(preToBalance)
  45. } else {
  46. // final balance check for a user send to a different user,
  47. // or a user sending to their address on another chain
  48. expect(postFromBalance).to.equal(preFromBalance.sub(qty))
  49. expect(postToBalance).to.equal(preToBalance.add(qty))
  50. }
  51. // audit the global token supply by comparing the locked tokens on mainendpoint to
  52. // the cumulative qty of tokens in user wallets on NON main endpoints
  53. await auditGlobalTokenSupply()
  54. }
  55. before(async function () {
  56. ;({ owner, alice, bob, user3, user4, badUser1, fakeContract } = await getAddr(ethers))
  57. users = [owner, alice, bob, user3, user4]
  58. chainId = 1
  59. decimals = 18
  60. initSupplyMainEndpoint = ethers.utils.parseEther("1000000000")
  61. name = CONFIG.stargateToken.name
  62. symbol = CONFIG.stargateToken.name
  63. mainEndpointId = 0 // endpoint id that controls the token
  64. numEndpoints = 3 // increase this number to iterate more endpoints
  65. })
  66. beforeEach(async function () {
  67. oft = {}
  68. lzEndpoints = {}
  69. for (let i = 0; i < numEndpoints; ++i) {
  70. lzEndpoints[i] = await deployNew("LZEndpointMock", [i])
  71. oft[i] = await deployNew("StargateToken", [name, symbol, lzEndpoints[i].address, mainEndpointId, initSupplyMainEndpoint])
  72. }
  73. // wire them together
  74. for (const i in oft) {
  75. for (const j in lzEndpoints) {
  76. // if (i === j) continue;
  77. const oftSrc = oft[i]
  78. const oftDst = oft[j]
  79. const lzSrc = lzEndpoints[i]
  80. const lzDst = lzEndpoints[j]
  81. // set
  82. await oftSrc.setDestination(j, oftDst.address)
  83. await oftDst.setDestination(i, oftSrc.address)
  84. await lzSrc.setDestLzEndpoint(oftDst.address, lzDst.address)
  85. await lzDst.setDestLzEndpoint(oftSrc.address, lzSrc.address)
  86. }
  87. }
  88. })
  89. it("send() - transfers to last chain", async function () {
  90. const fromUserId = 0
  91. const toUserId = 1
  92. const qty = ethers.utils.parseEther("1")
  93. const fromEndpointId = mainEndpointId
  94. const dstEndpointId = numEndpoints - 1
  95. await sendTokens(fromUserId, toUserId, qty, fromEndpointId, dstEndpointId)
  96. })
  97. it("send() - transfer to next chain", async function () {
  98. const fromUserId = 0
  99. const toUserId = 1
  100. const qty = ethers.utils.parseEther("1")
  101. const fromEndpointId = mainEndpointId
  102. const dstEndpointId = fromEndpointId + 1
  103. await sendTokens(fromUserId, toUserId, qty, fromEndpointId, dstEndpointId)
  104. })
  105. it("send() - send tokens to themselves", async function () {
  106. const user0 = 0
  107. await sendTokens(user0, user0, 100, mainEndpointId, mainEndpointId)
  108. })
  109. it("send() - everyone gets tokens, then everyone sends to everyone", async function () {
  110. // send everyone a balance on every endpoint from the source owner and source chain
  111. const originalOwnnerId = 0
  112. const originalMainEndpointId = mainEndpointId
  113. const largeQty = 1000000
  114. for (let toUserId = 0; toUserId < users.length; ++toUserId) {
  115. for (let endpointId = 0; endpointId < numEndpoints; ++endpointId) {
  116. await sendTokens(originalOwnnerId, toUserId, largeQty, originalMainEndpointId, endpointId)
  117. }
  118. }
  119. // have them all send to each other
  120. const qty = 100
  121. for (let fromUserId = 0; fromUserId < users.length; ++fromUserId) {
  122. for (let toUserId = 0; toUserId < users.length; ++toUserId) {
  123. for (let endpointId = 0; endpointId < numEndpoints; ++endpointId) {
  124. for (let endpointId_B = 0; endpointId_B < numEndpoints; ++endpointId_B) {
  125. await sendTokens(fromUserId, toUserId, qty, endpointId, endpointId_B)
  126. }
  127. }
  128. }
  129. }
  130. })
  131. it("balanceOf() - initial balances of main and children (token contract)", async function () {
  132. // assert token balance. only chain 1 would mint
  133. for (let i = 0; i < numEndpoints; ++i) {
  134. expect(await getChainBalance(i)).to.equal("0")
  135. }
  136. })
  137. it("balanceOf() - initial balances of main and children (users)", async function () {
  138. //assert token balance. only chain 1 would mint
  139. for (let i = 0; i < numEndpoints; ++i) {
  140. for (let j = 0; j < users.length; ++j) {
  141. const balanceOft = await getUserBalance(i, users[j].address)
  142. if (i === mainEndpointId && j === 0) {
  143. // the owner/deployer of the token on the main chain gets the initial supply
  144. expect(balanceOft).to.equal("1000000000000000000000000000")
  145. } else {
  146. expect(balanceOft).to.equal("0")
  147. }
  148. }
  149. }
  150. })
  151. it("sendTokens() - tokens get moved accross chains", async function () {
  152. // owner send some from oft_0 to alice oft_1
  153. // alice has no money to begin with
  154. expect(await oft[1].balanceOf(alice.address)).to.equal("0")
  155. const money1 = ethers.utils.parseEther("99")
  156. await oft[0].connect(owner).sendTokens(1, alice.address, money1, ZERO_ADDRESS, "0x", {
  157. value: ethers.utils.parseEther("0.1"),
  158. })
  159. // alice should have some money now
  160. expect(await oft[1].balanceOf(alice.address)).to.equal(money1)
  161. //assert token balance. only chain 1 would mint
  162. expect(await oft[0].totalSupply()).to.equal("1000000000000000000000000000")
  163. expect(await oft[1].totalSupply()).to.equal("99000000000000000000")
  164. // alice send some to bob from oft_1 to oft_2
  165. expect(await oft[2].balanceOf(bob.address)).to.equal("0")
  166. const money2 = ethers.utils.parseEther("15")
  167. await oft[1].connect(alice).sendTokens(2, bob.address, money2, ZERO_ADDRESS, "0x", {
  168. value: ethers.utils.parseEther("0.1"),
  169. })
  170. // alice should have some money now
  171. expect(await oft[2].balanceOf(bob.address)).to.equal(money2)
  172. // assert the total supply
  173. expect(await oft[0].totalSupply()).to.equal("1000000000000000000000000000")
  174. expect(await oft[1].totalSupply()).to.equal("84000000000000000000")
  175. expect(await oft[2].totalSupply()).to.equal("15000000000000000000")
  176. // bob send some to alice from oft_2 to oft_0
  177. const money3 = ethers.utils.parseEther("8")
  178. await oft[2].connect(bob).sendTokens(0, alice.address, money3, ZERO_ADDRESS, "0x", {
  179. value: ethers.utils.parseEther("0.1"),
  180. })
  181. // alice should have some money on oft[0]
  182. expect(await oft[0].balanceOf(alice.address)).to.equal(money3)
  183. // assert the total supply
  184. expect(await oft[0].totalSupply()).to.equal("1000000000000000000000000000")
  185. expect(await oft[1].totalSupply()).to.equal("84000000000000000000")
  186. // 15 - 8
  187. expect(await oft[2].totalSupply()).to.equal("7000000000000000000")
  188. })
  189. it("lzReceive() - reverts for non owner", async function () {
  190. // 42 is the arbitrary dummy return value in our mocks
  191. await expect(oft[0].lzReceive(chainId, "0x", 1, "0x")).to.revertedWith("")
  192. })
  193. it("estimateSendTokensFee()", async function () {
  194. // 42 is the arbitrary dummy return value in our mocks
  195. expect((await oft[0].estimateSendTokensFee(1, "0x", false, "0x"))[0]).to.equal(42)
  196. })
  197. it("setSendVersion()", async function () {
  198. const version = 22
  199. await oft[0].setSendVersion(version)
  200. expect(await lzEndpoints[0].mockSendVersion()).to.equal(version)
  201. })
  202. it("setReceiveVersion()", async function () {
  203. const version = 23
  204. await oft[0].setReceiveVersion(version)
  205. expect(await lzEndpoints[0].mockReceiveVersion()).to.equal(version)
  206. })
  207. it("setSendVersion() - reverts when non owner", async function () {
  208. const version = 22
  209. await expect(oft[0].connect(badUser1).setSendVersion(version)).to.revertedWith("Ownable: caller is not the owner")
  210. })
  211. it("setReceiveVersion() - reverts when non owner", async function () {
  212. const version = 23
  213. await expect(oft[0].connect(badUser1).setReceiveVersion(version)).to.revertedWith("Ownable: caller is not the owner")
  214. })
  215. it("setConfig()", async function () {
  216. const version = 22
  217. const configType = 0
  218. const config = "0x1234"
  219. await expect(oft[0].setConfig(version, chainId, configType, config))
  220. .to.emit(lzEndpoints[0], "SetConfig")
  221. .withArgs(version, chainId, configType, config)
  222. })
  223. it("setConfig() - reverts when non owner", async function () {
  224. const version = 22
  225. const configType = 0
  226. const config = "0x1234"
  227. await expect(oft[0].connect(badUser1).setConfig(version, chainId, configType, config)).to.revertedWith(
  228. "Ownable: caller is not the owner"
  229. )
  230. })
  231. it("forceResumeReceive()", async function () {
  232. const bytesAddr = "0x1234"
  233. await expect(oft[0].forceResumeReceive(chainId, bytesAddr)).to.emit(lzEndpoints[0], "ForceResumeReceive").withArgs(chainId, bytesAddr)
  234. })
  235. it("forceResumeReceive() - reverts when non owner", async function () {
  236. const bytesAddr = "0x1234"
  237. await expect(oft[0].connect(badUser1).forceResumeReceive(chainId, bytesAddr)).to.revertedWith("Ownable: caller is not the owner")
  238. })
  239. })