Bridge.test.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. const { expect } = require("chai")
  2. const { ethers } = require("hardhat")
  3. const { TYPE_SWAP_REMOTE, TYPE_ADD_LIQUIDITY, TYPE_REDEEM_LOCAL_CALL_BACK, TYPE_WITHDRAW_REMOTE, ZERO_ADDRESS } = require("./util/constants")
  4. const { callAsContract, getAddr, deployNew, encodeParams } = require("./util/helpers")
  5. describe("Bridge:", function () {
  6. let owner, alice, badUser1, fakeContract, router, mockToken, lzEndpoint, bridge
  7. let chainId, nonce, defaultGasAmount, transferAndCallPayload, defaultCreditObj, defaulSwapObject, defaultLzTxObj
  8. before(async function () {
  9. ;({ owner, alice, badUser1, fakeContract } = await getAddr(ethers))
  10. chainId = 1
  11. nonce = 1
  12. defaultGasAmount = 123
  13. transferAndCallPayload = "0x"
  14. defaultCreditObj = { credits: 0, idealBalance: 0 }
  15. defaulSwapObject = { amount: 0, eqFee: 0, eqReward: 0, lpFee: 0, protocolFee: 0, lkbRemove: 0 }
  16. defaultLzTxObj = { dstGasForCall: 0, dstNativeAmount: 0, dstNativeAddr: "0x" }
  17. })
  18. beforeEach(async function () {
  19. router = await deployNew("Router")
  20. mockToken = await deployNew("MockToken", ["Token", "TKN", 18])
  21. lzEndpoint = await deployNew("LZEndpointMock", [chainId])
  22. bridge = await deployNew("Bridge", [lzEndpoint.address, router.address])
  23. })
  24. it("constructor() - reverts for 0x0 LZ endpoint", async function () {
  25. await expect(deployNew("Bridge", [ZERO_ADDRESS, ZERO_ADDRESS])).to.be.revertedWith("Stargate: _layerZeroEndpoint cannot be 0x0")
  26. })
  27. it("constructor() - reverts for 0x0 router endpoint", async function () {
  28. await expect(deployNew("Bridge", [fakeContract.address, ZERO_ADDRESS])).to.be.revertedWith("Stargate: _router cannot be 0x0")
  29. })
  30. it("renounceOwnership() - does not affect ownership", async function () {
  31. expect(await bridge.owner()).to.equal(owner.address)
  32. await bridge.renounceOwnership()
  33. expect(await bridge.owner()).to.equal(owner.address)
  34. })
  35. it("swap() - reverts when non owner", async function () {
  36. await expect(bridge.swap(1, 1, 1, ZERO_ADDRESS, defaultCreditObj, defaulSwapObject, defaultLzTxObj, "0x", "0x")).to.revertedWith(
  37. "Stargate: caller must be Router."
  38. )
  39. })
  40. it("redeemLocalCallback() - reverts when non owner", async function () {
  41. await expect(bridge.redeemLocalCallback(1, ZERO_ADDRESS, defaultCreditObj, defaultLzTxObj, "0x")).to.revertedWith(
  42. "Stargate: caller must be Router."
  43. )
  44. })
  45. it("lzReceive() - reverts for non LZ endpoint", async function () {
  46. await expect(bridge.lzReceive(chainId, alice.address, nonce, alice.address)).to.be.revertedWith(
  47. "Stargate: only LayerZero endpoint can call lzReceive"
  48. )
  49. })
  50. it("lzReceive() - does NOT revert if invalid function type passed", async function () {
  51. const payload = encodeParams(["uint256", "uint8"], [123, 123])
  52. await expect(
  53. callAsContract(bridge, lzEndpoint.address, "lzReceive(uint16,bytes,uint64,bytes)", [chainId, "0x", nonce, payload])
  54. ).to.not.be.revertedWith()
  55. })
  56. it("lzReceive() - reverts for mismatched bridgeLookup", async function () {
  57. await bridge.setBridge(chainId, fakeContract.address)
  58. await expect(
  59. callAsContract(bridge, lzEndpoint.address, "lzReceive(uint16,bytes,uint64,bytes)", [chainId, alice.address, nonce, alice.address])
  60. ).to.be.revertedWith("Stargate: bridge does not match")
  61. })
  62. it("setBridge()", async function () {
  63. expect(await bridge.bridgeLookup(chainId)).to.equal("0x")
  64. await bridge.setBridge(chainId, fakeContract.address)
  65. expect(await bridge.bridgeLookup(chainId)).to.equal(fakeContract.address.toLowerCase()) // lowerCase because it returns bytes
  66. })
  67. it("setBridge() - reverts when bridge already set ", async function () {
  68. await bridge.setBridge(chainId, fakeContract.address) // set it first
  69. await expect(bridge.setBridge(chainId, fakeContract.address)).to.be.revertedWith("Stargate: Bridge already set!")
  70. })
  71. it("setBridge() - reverts for non owner", async function () {
  72. await expect(bridge.connect(badUser1).setBridge(chainId, fakeContract.address)).to.be.revertedWith("Ownable: caller is not the owner")
  73. })
  74. it("setGasAmount() - reverts for non owner", async function () {
  75. await expect(bridge.connect(badUser1).setGasAmount(chainId, TYPE_SWAP_REMOTE, defaultGasAmount)).to.be.revertedWith(
  76. "Ownable: caller is not the owner"
  77. )
  78. })
  79. it("setGasAmount() - reverts for invalid function type", async function () {
  80. const invalidFunctionType = 0
  81. await expect(bridge.setGasAmount(chainId, invalidFunctionType, defaultGasAmount)).to.be.revertedWith("Stargate: invalid _functionType")
  82. })
  83. it("setGasAmount()", async function () {
  84. await expect(bridge.setGasAmount(chainId, TYPE_SWAP_REMOTE, defaultGasAmount)).to.not.be.revertedWith("Stargate: invalid _functionType")
  85. expect(await bridge.gasLookup(chainId, TYPE_SWAP_REMOTE)).to.equal(defaultGasAmount)
  86. })
  87. it("approveTokenSpender() - reverts for non owner", async function () {
  88. await expect(bridge.connect(badUser1).approveTokenSpender(alice.address, badUser1.address, 0)).to.be.revertedWith(
  89. "Ownable: caller is not the owner"
  90. )
  91. })
  92. it("approveTokenSpender() - approves amount", async function () {
  93. expect(await mockToken.allowance(bridge.address, alice.address)).to.equal(0)
  94. const approveAmount = 1
  95. await bridge.approveTokenSpender(mockToken.address, alice.address, approveAmount)
  96. expect(await mockToken.allowance(bridge.address, alice.address)).to.equal(approveAmount)
  97. })
  98. it("setUseLayerZeroToken() - reverts for non owner", async function () {
  99. await expect(bridge.connect(badUser1).setUseLayerZeroToken(true)).to.be.revertedWith("Ownable: caller is not the owner")
  100. })
  101. it("setUseLayerZeroToken()", async function () {
  102. expect(await bridge.useLayerZeroToken()).to.equal(false)
  103. await bridge.setUseLayerZeroToken(true)
  104. expect(await bridge.useLayerZeroToken()).to.equal(true)
  105. })
  106. it("quoteLayerZeroFee() - TYPE_SWAP_REMOTE returns valid fee", async function () {
  107. expect(
  108. await bridge.quoteLayerZeroFee(chainId, TYPE_SWAP_REMOTE, fakeContract.address, transferAndCallPayload, {
  109. dstGasForCall: 0,
  110. dstNativeAmount: 0,
  111. dstNativeAddr: "0x",
  112. })
  113. ).to.deep.equal(await lzEndpoint.estimateFees(chainId, fakeContract.address, transferAndCallPayload, true, "0x"))
  114. })
  115. it("quoteLayerZeroFee() - TYPE_ADD_LIQUIDITY returns valid fee", async function () {
  116. expect(
  117. await bridge.quoteLayerZeroFee(chainId, TYPE_ADD_LIQUIDITY, fakeContract.address, transferAndCallPayload, {
  118. dstGasForCall: 0,
  119. dstNativeAmount: 0,
  120. dstNativeAddr: "0x",
  121. })
  122. ).to.deep.equal(await lzEndpoint.estimateFees(chainId, fakeContract.address, transferAndCallPayload, true, "0x"))
  123. })
  124. it("quoteLayerZeroFee() - TYPE_REDEEM_LOCAL_CALL_BACK returns valid fee", async function () {
  125. expect(
  126. await bridge.quoteLayerZeroFee(chainId, TYPE_REDEEM_LOCAL_CALL_BACK, fakeContract.address, transferAndCallPayload, {
  127. dstGasForCall: 0,
  128. dstNativeAmount: 0,
  129. dstNativeAddr: "0x",
  130. })
  131. ).to.deep.equal(await lzEndpoint.estimateFees(chainId, fakeContract.address, "0x", true, "0x"))
  132. })
  133. it("quoteLayerZeroFee() - TYPE_WITHDRAW_REMOTE returns valid fee", async function () {
  134. expect(
  135. await bridge.quoteLayerZeroFee(chainId, TYPE_WITHDRAW_REMOTE, fakeContract.address, transferAndCallPayload, {
  136. dstGasForCall: 0,
  137. dstNativeAmount: 0,
  138. dstNativeAddr: "0x",
  139. })
  140. ).to.deep.equal(await lzEndpoint.estimateFees(chainId, fakeContract.address, transferAndCallPayload, true, "0x"))
  141. })
  142. it("quoteLayerZeroFee() - reverts with unsupported tx type is sent", async function () {
  143. await expect(
  144. bridge.quoteLayerZeroFee(chainId, TYPE_WITHDRAW_REMOTE + 1, fakeContract.address, transferAndCallPayload, {
  145. dstGasForCall: 0,
  146. dstNativeAmount: 0,
  147. dstNativeAddr: "0x",
  148. })
  149. ).to.revertedWith("Stargate: unsupported function type")
  150. })
  151. it("setSendVersion()", async function () {
  152. const version = 22
  153. await bridge.setSendVersion(version)
  154. expect(await lzEndpoint.mockSendVersion()).to.equal(version)
  155. })
  156. it("setReceiveVersion()", async function () {
  157. const version = 23
  158. await bridge.setReceiveVersion(version)
  159. expect(await lzEndpoint.mockReceiveVersion()).to.equal(version)
  160. })
  161. it("setSendVersion() - reverts when non owner", async function () {
  162. const version = 22
  163. await expect(bridge.connect(badUser1).setSendVersion(version)).to.revertedWith("Ownable: caller is not the owner")
  164. })
  165. it("setReceiveVersion() - reverts when non owner", async function () {
  166. const version = 23
  167. await expect(bridge.connect(badUser1).setReceiveVersion(version)).to.revertedWith("Ownable: caller is not the owner")
  168. })
  169. it("setConfig()", async function () {
  170. const version = 22
  171. const configType = 0
  172. const config = "0x1234"
  173. await expect(bridge.setConfig(version, chainId, configType, config))
  174. .to.emit(lzEndpoint, "SetConfig")
  175. .withArgs(version, chainId, configType, config)
  176. })
  177. it("setConfig() - reverts when non owner", async function () {
  178. const version = 22
  179. const configType = 0
  180. const config = "0x1234"
  181. await expect(bridge.connect(badUser1).setConfig(version, chainId, configType, config)).to.revertedWith(
  182. "Ownable: caller is not the owner"
  183. )
  184. })
  185. it("forceResumeReceive()", async function () {
  186. const bytesAddr = "0x1234"
  187. await expect(bridge.forceResumeReceive(chainId, bytesAddr)).to.emit(lzEndpoint, "ForceResumeReceive").withArgs(chainId, bytesAddr)
  188. })
  189. it("forceResumeReceive() - reverts when non owner", async function () {
  190. const bytesAddr = "0x1234"
  191. await expect(bridge.connect(badUser1).forceResumeReceive(chainId, bytesAddr)).to.revertedWith("Ownable: caller is not the owner")
  192. })
  193. })