bridge.js 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375
  1. const jsonfile = require('jsonfile');
  2. const elliptic = require('elliptic');
  3. const BigNumber = require('bignumber.js');
  4. const Wormhole = artifacts.require("Wormhole");
  5. const TokenBridge = artifacts.require("TokenBridge");
  6. const BridgeImplementation = artifacts.require("BridgeImplementation");
  7. const TokenImplementation = artifacts.require("TokenImplementation");
  8. const FeeToken = artifacts.require("FeeToken");
  9. const MockBridgeImplementation = artifacts.require("MockBridgeImplementation");
  10. const MockTokenBridgeIntegration = artifacts.require("MockTokenBridgeIntegration");
  11. const MockWETH9 = artifacts.require("MockWETH9");
  12. const testSigner1PK = "cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0";
  13. const testSigner2PK = "892330666a850761e7370376430bb8c2aa1494072d3bfeaed0c4fa3d5a9135fe";
  14. const WormholeImplementationFullABI = jsonfile.readFileSync("build/contracts/Implementation.json").abi
  15. const BridgeImplementationFullABI = jsonfile.readFileSync("build/contracts/BridgeImplementation.json").abi
  16. const TokenImplementationFullABI = jsonfile.readFileSync("build/contracts/TokenImplementation.json").abi
  17. contract("Bridge", function () {
  18. const testSigner1 = web3.eth.accounts.privateKeyToAccount(testSigner1PK);
  19. const testSigner2 = web3.eth.accounts.privateKeyToAccount(testSigner2PK);
  20. const testChainId = "2";
  21. const testFinality = "1";
  22. const testGovernanceChainId = "1";
  23. const testGovernanceContract = "0x0000000000000000000000000000000000000000000000000000000000000004";
  24. let WETH = process.env.BRIDGE_INIT_WETH;
  25. const testForeignChainId = "1";
  26. const testForeignBridgeContract = "0x000000000000000000000000000000000000000000000000000000000000ffff";
  27. const testBridgedAssetChain = "0001";
  28. const testBridgedAssetAddress = "000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e";
  29. it("should be initialized with the correct signers and values", async function () {
  30. const initialized = new web3.eth.Contract(BridgeImplementationFullABI, TokenBridge.address);
  31. const weth = await initialized.methods.WETH().call();
  32. assert.equal(weth, WETH);
  33. const tokenImplentation = await initialized.methods.tokenImplementation().call();
  34. assert.equal(tokenImplentation, TokenImplementation.address);
  35. // test beacon functionality
  36. const beaconImplementation = await initialized.methods.implementation().call();
  37. assert.equal(beaconImplementation, TokenImplementation.address);
  38. // chain id
  39. const chainId = await initialized.methods.chainId().call();
  40. assert.equal(chainId, testChainId);
  41. // finality
  42. const finality = await initialized.methods.finality().call();
  43. assert.equal(finality, testFinality);
  44. // governance
  45. const governanceChainId = await initialized.methods.governanceChainId().call();
  46. assert.equal(governanceChainId, testGovernanceChainId);
  47. const governanceContract = await initialized.methods.governanceContract().call();
  48. assert.equal(governanceContract, testGovernanceContract);
  49. })
  50. it("should register a foreign bridge implementation correctly", async function () {
  51. const initialized = new web3.eth.Contract(BridgeImplementationFullABI, TokenBridge.address);
  52. const accounts = await web3.eth.getAccounts();
  53. let data = [
  54. "0x",
  55. "000000000000000000000000000000000000000000546f6b656e427269646765",
  56. "01",
  57. "0000",
  58. web3.eth.abi.encodeParameter("uint16", testForeignChainId).substring(2 + (64 - 4)),
  59. web3.eth.abi.encodeParameter("bytes32", testForeignBridgeContract).substring(2),
  60. ].join('')
  61. const vm = await signAndEncodeVM(
  62. 1,
  63. 1,
  64. testGovernanceChainId,
  65. testGovernanceContract,
  66. 0,
  67. data,
  68. [
  69. testSigner1PK
  70. ],
  71. 0,
  72. 0
  73. );
  74. let before = await initialized.methods.bridgeContracts(testForeignChainId).call();
  75. assert.equal(before, "0x0000000000000000000000000000000000000000000000000000000000000000");
  76. await initialized.methods.registerChain("0x" + vm).send({
  77. value: 0,
  78. from: accounts[0],
  79. gasLimit: 2000000
  80. });
  81. let after = await initialized.methods.bridgeContracts(testForeignChainId).call();
  82. assert.equal(after, testForeignBridgeContract);
  83. })
  84. it("should accept a valid upgrade", async function () {
  85. const initialized = new web3.eth.Contract(BridgeImplementationFullABI, TokenBridge.address);
  86. const accounts = await web3.eth.getAccounts();
  87. const mock = await MockBridgeImplementation.new();
  88. let data = [
  89. "0x",
  90. "000000000000000000000000000000000000000000546f6b656e427269646765",
  91. "02",
  92. web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + (64 - 4)),
  93. web3.eth.abi.encodeParameter("address", mock.address).substring(2),
  94. ].join('')
  95. const vm = await signAndEncodeVM(
  96. 1,
  97. 1,
  98. testGovernanceChainId,
  99. testGovernanceContract,
  100. 0,
  101. data,
  102. [
  103. testSigner1PK
  104. ],
  105. 0,
  106. 0
  107. );
  108. let before = await web3.eth.getStorageAt(TokenBridge.address, "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc");
  109. assert.equal(before.toLowerCase(), BridgeImplementation.address.toLowerCase());
  110. await initialized.methods.upgrade("0x" + vm).send({
  111. value: 0,
  112. from: accounts[0],
  113. gasLimit: 2000000
  114. });
  115. let after = await web3.eth.getStorageAt(TokenBridge.address, "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc");
  116. assert.equal(after.toLowerCase(), mock.address.toLowerCase());
  117. const mockImpl = new web3.eth.Contract(MockBridgeImplementation.abi, TokenBridge.address);
  118. let isUpgraded = await mockImpl.methods.testNewImplementationActive().call();
  119. assert.ok(isUpgraded);
  120. })
  121. it("bridged tokens should only be mint- and burn-able by owner", async function () {
  122. const accounts = await web3.eth.getAccounts();
  123. // initialize our template token contract
  124. const token = new web3.eth.Contract(TokenImplementation.abi, TokenImplementation.address);
  125. await token.methods.initialize(
  126. "TestToken",
  127. "TT",
  128. 18,
  129. 0,
  130. accounts[0],
  131. 0,
  132. "0x0"
  133. ).send({
  134. value: 0,
  135. from: accounts[0],
  136. gasLimit: 2000000
  137. });
  138. await token.methods.mint(accounts[0], 10).send({
  139. from: accounts[0],
  140. gasLimit: 2000000
  141. });
  142. await token.methods.burn(accounts[0], 5).send({
  143. from: accounts[0],
  144. gasLimit: 2000000
  145. });
  146. let failed = false
  147. try {
  148. await token.methods.mint(accounts[0], 10).send({
  149. from: accounts[1],
  150. gasLimit: 2000000
  151. });
  152. } catch (e) {
  153. failed = true
  154. }
  155. assert.ok(failed)
  156. failed = false
  157. try {
  158. await token.methods.burn(accounts[0], 5).send({
  159. from: accounts[1],
  160. gasLimit: 2000000
  161. });
  162. } catch (e) {
  163. failed = true
  164. }
  165. assert.ok(failed)
  166. await token.methods.burn(accounts[0], 5).send({
  167. from: accounts[0],
  168. gasLimit: 2000000
  169. });
  170. })
  171. it("should attest a token correctly", async function () {
  172. const accounts = await web3.eth.getAccounts();
  173. const initialized = new web3.eth.Contract(BridgeImplementationFullABI, TokenBridge.address);
  174. await initialized.methods.attestToken(TokenImplementation.address, "234").send({
  175. value: 0,
  176. from: accounts[0],
  177. gasLimit: 2000000
  178. });
  179. const wormhole = new web3.eth.Contract(WormholeImplementationFullABI, Wormhole.address);
  180. const log = (await wormhole.getPastEvents('LogMessagePublished', {
  181. fromBlock: 'latest'
  182. }))[0].returnValues
  183. assert.equal(log.sender, TokenBridge.address)
  184. assert.equal(log.payload.length - 2, 200);
  185. // payload id
  186. assert.equal(log.payload.substr(2, 2), "02");
  187. // token address
  188. assert.equal(log.payload.substr(4, 64), web3.eth.abi.encodeParameter("address", TokenImplementation.address).substring(2));
  189. // chain id
  190. assert.equal(log.payload.substr(68, 4), web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + 64 - 4))
  191. // decimals
  192. assert.equal(log.payload.substr(72, 2), web3.eth.abi.encodeParameter("uint8", 18).substring(2 + 64 - 2))
  193. // symbol (TT)
  194. assert.equal(log.payload.substr(74, 64), "5454000000000000000000000000000000000000000000000000000000000000")
  195. // name (TestToken)
  196. assert.equal(log.payload.substr(138, 64), "54657374546f6b656e0000000000000000000000000000000000000000000000")
  197. })
  198. it("should correctly deploy a wrapped asset for a token attestation", async function () {
  199. const initialized = new web3.eth.Contract(BridgeImplementationFullABI, TokenBridge.address);
  200. const accounts = await web3.eth.getAccounts();
  201. const data = "0x02" +
  202. // tokenAddress
  203. testBridgedAssetAddress +
  204. // tokenchain
  205. testBridgedAssetChain +
  206. // decimals
  207. "12" +
  208. // symbol
  209. "5454000000000000000000000000000000000000000000000000000000000000" +
  210. // name
  211. "54657374546f6b656e0000000000000000000000000000000000000000000000";
  212. const vm = await signAndEncodeVM(
  213. 0,
  214. 0,
  215. testForeignChainId,
  216. testForeignBridgeContract,
  217. 0,
  218. data,
  219. [
  220. testSigner1PK
  221. ],
  222. 0,
  223. 0
  224. );
  225. await initialized.methods.createWrapped("0x" + vm).send({
  226. value: 0,
  227. from: accounts[0],
  228. gasLimit: 2000000
  229. });
  230. const wrappedAddress = await initialized.methods.wrappedAsset("0x0001", "0x000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e").call();
  231. assert.ok(await initialized.methods.isWrappedAsset(wrappedAddress).call())
  232. const initializedWrappedAsset = new web3.eth.Contract(TokenImplementation.abi, wrappedAddress);
  233. const symbol = await initializedWrappedAsset.methods.symbol().call();
  234. assert.equal(symbol, "TT");
  235. const name = await initializedWrappedAsset.methods.name().call();
  236. assert.equal(name, "TestToken");
  237. const decimals = await initializedWrappedAsset.methods.decimals().call();
  238. assert.equal(decimals, 18);
  239. const chainId = await initializedWrappedAsset.methods.chainId().call();
  240. assert.equal(chainId, 1);
  241. const nativeContract = await initializedWrappedAsset.methods.nativeContract().call();
  242. assert.equal(nativeContract, "0x000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e");
  243. })
  244. it("should correctly update a wrapped asset for a token attestation", async function () {
  245. const initialized = new web3.eth.Contract(BridgeImplementationFullABI, TokenBridge.address);
  246. const accounts = await web3.eth.getAccounts();
  247. const data = "0x02" +
  248. // tokenAddress
  249. testBridgedAssetAddress +
  250. // tokenchain
  251. testBridgedAssetChain +
  252. // decimals
  253. "12" +
  254. // symbol
  255. "5555000000000000000000000000000000000000000000000000000000000000" +
  256. // name
  257. "5472656500000000000000000000000000000000000000000000000000000000";
  258. let vm = await signAndEncodeVM(
  259. 0,
  260. 0,
  261. testForeignChainId,
  262. testForeignBridgeContract,
  263. 0,
  264. data,
  265. [
  266. testSigner1PK
  267. ],
  268. 0,
  269. 0
  270. );
  271. let failed = false;
  272. try {
  273. await initialized.methods.updateWrapped("0x" + vm).send({
  274. value: 0,
  275. from: accounts[0],
  276. gasLimit: 2000000
  277. });
  278. } catch (error) {
  279. assert.equal(error.message, "Returned error: VM Exception while processing transaction: revert current metadata is up to date")
  280. failed = true
  281. }
  282. assert.ok(failed)
  283. vm = await signAndEncodeVM(
  284. 0,
  285. 0,
  286. testForeignChainId,
  287. testForeignBridgeContract,
  288. 1,
  289. data,
  290. [
  291. testSigner1PK
  292. ],
  293. 0,
  294. 0
  295. );
  296. await initialized.methods.updateWrapped("0x" + vm).send({
  297. value: 0,
  298. from: accounts[0],
  299. gasLimit: 2000000
  300. });
  301. const wrappedAddress = await initialized.methods.wrappedAsset("0x0001", "0x000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e").call();
  302. assert.ok(await initialized.methods.isWrappedAsset(wrappedAddress).call())
  303. const initializedWrappedAsset = new web3.eth.Contract(TokenImplementation.abi, wrappedAddress);
  304. const symbol = await initializedWrappedAsset.methods.symbol().call();
  305. assert.equal(symbol, "UU");
  306. const name = await initializedWrappedAsset.methods.name().call();
  307. assert.equal(name, "Tree");
  308. const decimals = await initializedWrappedAsset.methods.decimals().call();
  309. assert.equal(decimals, 18);
  310. const chainId = await initializedWrappedAsset.methods.chainId().call();
  311. assert.equal(chainId, 1);
  312. const nativeContract = await initializedWrappedAsset.methods.nativeContract().call();
  313. assert.equal(nativeContract, "0x000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e");
  314. })
  315. it("should deposit and log transfers correctly", async function () {
  316. const accounts = await web3.eth.getAccounts();
  317. const amount = "1000000000000000000";
  318. const fee = "100000000000000000";
  319. // mint and approve tokens
  320. const token = new web3.eth.Contract(TokenImplementation.abi, TokenImplementation.address);
  321. await token.methods.mint(accounts[0], amount).send({
  322. value: 0,
  323. from: accounts[0],
  324. gasLimit: 2000000
  325. });
  326. await token.methods.approve(TokenBridge.address, amount).send({
  327. value: 0,
  328. from: accounts[0],
  329. gasLimit: 2000000
  330. });
  331. // deposit tokens
  332. const initialized = new web3.eth.Contract(BridgeImplementationFullABI, TokenBridge.address);
  333. const accountBalanceBefore = await token.methods.balanceOf(accounts[0]).call();
  334. const bridgeBalanceBefore = await token.methods.balanceOf(TokenBridge.address).call();
  335. assert.equal(accountBalanceBefore.toString(10), amount);
  336. assert.equal(bridgeBalanceBefore.toString(10), "0");
  337. await initialized.methods.transferTokens(
  338. TokenImplementation.address,
  339. amount,
  340. "10",
  341. "0x000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e",
  342. fee,
  343. "234"
  344. ).send({
  345. value: 0,
  346. from: accounts[0],
  347. gasLimit: 2000000
  348. });
  349. const accountBalanceAfter = await token.methods.balanceOf(accounts[0]).call();
  350. const bridgeBalanceAfter = await token.methods.balanceOf(TokenBridge.address).call();
  351. assert.equal(accountBalanceAfter.toString(10), "0");
  352. assert.equal(bridgeBalanceAfter.toString(10), amount);
  353. // check transfer log
  354. const wormhole = new web3.eth.Contract(WormholeImplementationFullABI, Wormhole.address);
  355. const log = (await wormhole.getPastEvents('LogMessagePublished', {
  356. fromBlock: 'latest'
  357. }))[0].returnValues
  358. assert.equal(log.sender, TokenBridge.address)
  359. assert.equal(log.payload.length - 2, 266);
  360. // payload id
  361. assert.equal(log.payload.substr(2, 2), "01");
  362. // amount
  363. assert.equal(log.payload.substr(4, 64), web3.eth.abi.encodeParameter("uint256", new BigNumber(amount).div(1e10).toString()).substring(2));
  364. // token
  365. assert.equal(log.payload.substr(68, 64), web3.eth.abi.encodeParameter("address", TokenImplementation.address).substring(2));
  366. // chain id
  367. assert.equal(log.payload.substr(132, 4), web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + 64 - 4))
  368. // to
  369. assert.equal(log.payload.substr(136, 64), "000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e");
  370. // to chain id
  371. assert.equal(log.payload.substr(200, 4), web3.eth.abi.encodeParameter("uint16", 10).substring(2 + 64 - 4))
  372. // fee
  373. assert.equal(log.payload.substr(204, 64), web3.eth.abi.encodeParameter("uint256", new BigNumber(fee).div(1e10).toString()).substring(2))
  374. })
  375. it("should deposit and log fee token transfers correctly", async function () {
  376. const accounts = await web3.eth.getAccounts();
  377. const mintAmount = "10000000000000000000";
  378. const amount = "1000000000000000000";
  379. const fee = "100000000000000000";
  380. // mint and approve tokens
  381. const deployFeeToken = await FeeToken.new();
  382. const token = new web3.eth.Contract(FeeToken.abi, deployFeeToken.address);
  383. await token.methods.initialize(
  384. "Test",
  385. "TST",
  386. "18",
  387. "123",
  388. accounts[0],
  389. "0",
  390. "0x0000000000000000000000000000000000000000000000000000000000000000"
  391. ).send({
  392. value: 0,
  393. from: accounts[0],
  394. gasLimit: 2000000
  395. });
  396. await token.methods.mint(accounts[0], mintAmount).send({
  397. value: 0,
  398. from: accounts[0],
  399. gasLimit: 2000000
  400. });
  401. await token.methods.approve(TokenBridge.address, mintAmount).send({
  402. value: 0,
  403. from: accounts[0],
  404. gasLimit: 2000000
  405. });
  406. // deposit tokens
  407. const initialized = new web3.eth.Contract(BridgeImplementationFullABI, TokenBridge.address);
  408. const bridgeBalanceBefore = await token.methods.balanceOf(TokenBridge.address).call();
  409. assert.equal(bridgeBalanceBefore.toString(10), "0");
  410. await initialized.methods.transferTokens(
  411. deployFeeToken.address,
  412. amount,
  413. "10",
  414. "0x000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e",
  415. fee,
  416. "234"
  417. ).send({
  418. value: 0,
  419. from: accounts[0],
  420. gasLimit: 2000000
  421. });
  422. const bridgeBalanceAfter = await token.methods.balanceOf(TokenBridge.address).call();
  423. let feeAmount = new BigNumber(amount).times(9).div(10)
  424. assert.equal(bridgeBalanceAfter.toString(10), feeAmount);
  425. // check transfer log
  426. const wormhole = new web3.eth.Contract(WormholeImplementationFullABI, Wormhole.address);
  427. const log = (await wormhole.getPastEvents('LogMessagePublished', {
  428. fromBlock: 'latest'
  429. }))[0].returnValues
  430. assert.equal(log.sender, TokenBridge.address)
  431. assert.equal(log.payload.length - 2, 266);
  432. // payload id
  433. assert.equal(log.payload.substr(2, 2), "01");
  434. // amount
  435. assert.equal(log.payload.substr(4, 64), web3.eth.abi.encodeParameter("uint256", feeAmount.div(1e10).toString()).substring(2));
  436. // token
  437. assert.equal(log.payload.substr(68, 64), web3.eth.abi.encodeParameter("address", deployFeeToken.address).substring(2));
  438. // chain id
  439. assert.equal(log.payload.substr(132, 4), web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + 64 - 4))
  440. // to
  441. assert.equal(log.payload.substr(136, 64), "000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e");
  442. // to chain id
  443. assert.equal(log.payload.substr(200, 4), web3.eth.abi.encodeParameter("uint16", 10).substring(2 + 64 - 4))
  444. // fee
  445. assert.equal(log.payload.substr(204, 64), web3.eth.abi.encodeParameter("uint256", new BigNumber(fee).div(1e10).toString()).substring(2))
  446. })
  447. it("should transfer out locked assets for a valid transfer vm", async function () {
  448. const accounts = await web3.eth.getAccounts();
  449. const amount = "1000000000000000000";
  450. const token = new web3.eth.Contract(TokenImplementation.abi, TokenImplementation.address);
  451. const initialized = new web3.eth.Contract(BridgeImplementationFullABI, TokenBridge.address);
  452. const accountBalanceBefore = await token.methods.balanceOf(accounts[0]).call();
  453. const bridgeBalanceBefore = await token.methods.balanceOf(TokenBridge.address).call();
  454. assert.equal(accountBalanceBefore.toString(10), "0");
  455. assert.equal(bridgeBalanceBefore.toString(10), amount);
  456. const data = "0x" +
  457. "01" +
  458. // amount
  459. web3.eth.abi.encodeParameter("uint256", new BigNumber(amount).div(1e10).toString()).substring(2) +
  460. // tokenaddress
  461. web3.eth.abi.encodeParameter("address", TokenImplementation.address).substr(2) +
  462. // tokenchain
  463. web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + (64 - 4)) +
  464. // receiver
  465. web3.eth.abi.encodeParameter("address", accounts[0]).substr(2) +
  466. // receiving chain
  467. web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + (64 - 4)) +
  468. // fee
  469. "0000000000000000000000000000000000000000000000000000000000000000";
  470. const vm = await signAndEncodeVM(
  471. 0,
  472. 0,
  473. testForeignChainId,
  474. testForeignBridgeContract,
  475. 0,
  476. data,
  477. [
  478. testSigner1PK
  479. ],
  480. 0,
  481. 0
  482. );
  483. await initialized.methods.completeTransfer("0x" + vm).send({
  484. value: 0,
  485. from: accounts[0],
  486. gasLimit: 2000000
  487. });
  488. const accountBalanceAfter = await token.methods.balanceOf(accounts[0]).call();
  489. const bridgeBalanceAfter = await token.methods.balanceOf(TokenBridge.address).call();
  490. assert.equal(accountBalanceAfter.toString(10), amount);
  491. assert.equal(bridgeBalanceAfter.toString(10), "0");
  492. })
  493. it("should deposit and log transfer with payload correctly", async function () {
  494. const accounts = await web3.eth.getAccounts();
  495. const amount = "1000000000000000000";
  496. // mint and approve tokens
  497. const token = new web3.eth.Contract(TokenImplementation.abi, TokenImplementation.address);
  498. await token.methods.mint(accounts[0], amount).send({
  499. value: 0,
  500. from: accounts[0],
  501. gasLimit: 2000000
  502. });
  503. await token.methods.approve(TokenBridge.address, amount).send({
  504. value: 0,
  505. from: accounts[0],
  506. gasLimit: 2000000
  507. });
  508. // deposit tokens
  509. const initialized = new web3.eth.Contract(BridgeImplementationFullABI, TokenBridge.address);
  510. const accountBalanceBefore = await token.methods.balanceOf(accounts[0]).call();
  511. const bridgeBalanceBefore = await token.methods.balanceOf(TokenBridge.address).call();
  512. assert.equal(bridgeBalanceBefore.toString(10), "0");
  513. const additionalPayload = "abc123"
  514. await initialized.methods.transferTokensWithPayload(
  515. TokenImplementation.address,
  516. amount,
  517. "10",
  518. "0x000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e",
  519. "234",
  520. "0x"+additionalPayload
  521. ).send({
  522. value: 0,
  523. from: accounts[0],
  524. gasLimit: 2000000
  525. });
  526. const accountBalanceAfter = await token.methods.balanceOf(accounts[0]).call();
  527. const bridgeBalanceAfter = await token.methods.balanceOf(TokenBridge.address).call();
  528. assert.equal(accountBalanceAfter.toString(10), new BigNumber(accountBalanceBefore).minus(amount).toString(10));
  529. assert.equal(bridgeBalanceAfter.toString(10), amount);
  530. // check transfer log
  531. const wormhole = new web3.eth.Contract(WormholeImplementationFullABI, Wormhole.address);
  532. const log = (await wormhole.getPastEvents('LogMessagePublished', {
  533. fromBlock: 'latest'
  534. }))[0].returnValues
  535. assert.equal(log.sender, TokenBridge.address)
  536. assert.equal(log.payload.length - 2 - additionalPayload.length, 266);
  537. // payload id
  538. assert.equal(log.payload.substr(2, 2), "03");
  539. // amount
  540. assert.equal(log.payload.substr(4, 64), web3.eth.abi.encodeParameter("uint256", new BigNumber(amount).div(1e10).toString()).substring(2));
  541. // token
  542. assert.equal(log.payload.substr(68, 64), web3.eth.abi.encodeParameter("address", TokenImplementation.address).substring(2));
  543. // chain id
  544. assert.equal(log.payload.substr(132, 4), web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + 64 - 4))
  545. // to
  546. assert.equal(log.payload.substr(136, 64), "000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e");
  547. // to chain id
  548. assert.equal(log.payload.substr(200, 4), web3.eth.abi.encodeParameter("uint16", 10).substring(2 + 64 - 4))
  549. // from address
  550. // the actual type is bytes32, but here we use 'address' encoding so that it gets left-padded as expected
  551. assert.equal(log.payload.substr(204, 64), web3.eth.abi.encodeParameter("address", accounts[0]).substring(2))
  552. // payload
  553. assert.equal(log.payload.substr(268), additionalPayload)
  554. })
  555. it("should transfer out locked assets for a valid transfer with payload vm", async function () {
  556. const accounts = await web3.eth.getAccounts();
  557. const amount = "1000000000000000000";
  558. const token = new web3.eth.Contract(TokenImplementation.abi, TokenImplementation.address);
  559. const initialized = new web3.eth.Contract(BridgeImplementationFullABI, TokenBridge.address);
  560. const accountBalanceBefore = await token.methods.balanceOf(accounts[0]).call();
  561. const bridgeBalanceBefore = await token.methods.balanceOf(TokenBridge.address).call();
  562. assert.equal(bridgeBalanceBefore.toString(10), amount);
  563. const data = "0x" +
  564. "03" +
  565. // amount
  566. web3.eth.abi.encodeParameter("uint256", new BigNumber(amount).div(1e10).toString()).substring(2) +
  567. // tokenaddress
  568. web3.eth.abi.encodeParameter("address", TokenImplementation.address).substr(2) +
  569. // tokenchain
  570. web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + (64 - 4)) +
  571. // receiver
  572. web3.eth.abi.encodeParameter("address", accounts[0]).substr(2) +
  573. // receiving chain
  574. web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + (64 - 4)) +
  575. // fee
  576. "0000000000000000000000000000000000000000000000000000000000000000" +
  577. // additional payload
  578. "abc123";
  579. const vm = await signAndEncodeVM(
  580. 0,
  581. 0,
  582. testForeignChainId,
  583. testForeignBridgeContract,
  584. 0,
  585. data,
  586. [
  587. testSigner1PK
  588. ],
  589. 0,
  590. 0
  591. );
  592. await initialized.methods.completeTransferWithPayload("0x" + vm).send({
  593. value: 0,
  594. from: accounts[0],
  595. gasLimit: 2000000
  596. });
  597. const accountBalanceAfter = await token.methods.balanceOf(accounts[0]).call();
  598. const bridgeBalanceAfter = await token.methods.balanceOf(TokenBridge.address).call();
  599. assert.equal(accountBalanceAfter.toString(10), new BigNumber(accountBalanceBefore).plus(amount).toString(10));
  600. assert.equal(bridgeBalanceAfter.toString(10), "0");
  601. })
  602. it("should mint bridged assets wrappers on transfer from another chain and handle fees correctly", async function () {
  603. const accounts = await web3.eth.getAccounts();
  604. const amount = "1000000000000000000";
  605. const fee = "1000000000000000";
  606. const initialized = new web3.eth.Contract(BridgeImplementationFullABI, TokenBridge.address);
  607. const wrappedAddress = await initialized.methods.wrappedAsset("0x" + testBridgedAssetChain, "0x" + testBridgedAssetAddress).call();
  608. const wrappedAsset = new web3.eth.Contract(TokenImplementation.abi, wrappedAddress);
  609. const totalSupply = await wrappedAsset.methods.totalSupply().call();
  610. assert.equal(totalSupply.toString(10), "0");
  611. // we are using the asset where we created a wrapper in the previous test
  612. const data = "0x" +
  613. "01" +
  614. // amount
  615. web3.eth.abi.encodeParameter("uint256", new BigNumber(amount).div(1e10).toString()).substring(2) +
  616. // tokenaddress
  617. testBridgedAssetAddress +
  618. // tokenchain
  619. testBridgedAssetChain +
  620. // receiver
  621. web3.eth.abi.encodeParameter("address", accounts[0]).substr(2) +
  622. // receiving chain
  623. web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + (64 - 4)) +
  624. // fee
  625. web3.eth.abi.encodeParameter("uint256", new BigNumber(fee).div(1e10).toString()).substring(2);
  626. const vm = await signAndEncodeVM(
  627. 0,
  628. 0,
  629. testForeignChainId,
  630. testForeignBridgeContract,
  631. 0,
  632. data,
  633. [
  634. testSigner1PK
  635. ],
  636. 0,
  637. 0
  638. );
  639. await initialized.methods.completeTransfer("0x" + vm).send({
  640. value: 0,
  641. from: accounts[1],
  642. gasLimit: 2000000
  643. });
  644. const accountBalanceAfter = await wrappedAsset.methods.balanceOf(accounts[0]).call();
  645. const senderBalanceAfter = await wrappedAsset.methods.balanceOf(accounts[1]).call();
  646. const totalSupplyAfter = await wrappedAsset.methods.totalSupply().call();
  647. assert.equal(accountBalanceAfter.toString(10), new BigNumber(amount).minus(fee).toString(10));
  648. assert.equal(senderBalanceAfter.toString(10), fee);
  649. assert.equal(totalSupplyAfter.toString(10), amount);
  650. await wrappedAsset.methods.transfer(accounts[0], fee).send({
  651. value: 0,
  652. from: accounts[1],
  653. gasLimit: 2000000
  654. });
  655. })
  656. it("should not allow a redemption from msg.sender other than 'to' on token bridge transfer with payload", async function () {
  657. const accounts = await web3.eth.getAccounts();
  658. const amount = "1000000000000000000";
  659. const initialized = new web3.eth.Contract(BridgeImplementationFullABI, TokenBridge.address);
  660. const wrappedAddress = await initialized.methods.wrappedAsset("0x" + testBridgedAssetChain, "0x" + testBridgedAssetAddress).call();
  661. const wrappedAsset = new web3.eth.Contract(TokenImplementation.abi, wrappedAddress);
  662. // we are using the asset where we created a wrapper in the previous test
  663. const data = "0x" +
  664. "03" +
  665. // amount
  666. web3.eth.abi.encodeParameter("uint256", new BigNumber(amount).div(1e10).toString()).substring(2) +
  667. // tokenaddress
  668. testBridgedAssetAddress +
  669. // tokenchain
  670. testBridgedAssetChain +
  671. // receiver (must be self msg.sender)
  672. web3.eth.abi.encodeParameter("address", accounts[0]).substr(2) +
  673. // receiving chain
  674. web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + (64 - 4)) +
  675. // from address
  676. web3.eth.abi.encodeParameter("address", accounts[2]).substring(2) +
  677. // additional payload
  678. web3.eth.abi.encodeParameter("address", accounts[1]).substr(2);
  679. const vm = await signAndEncodeVM(
  680. 0,
  681. 0,
  682. testForeignChainId,
  683. testForeignBridgeContract,
  684. 1,
  685. data,
  686. [
  687. testSigner1PK
  688. ],
  689. 0,
  690. 0
  691. );
  692. let hadSenderError = false
  693. try {
  694. await initialized.methods.completeTransferWithPayload("0x" + vm).send({
  695. value: 0,
  696. from: accounts[1],
  697. gasLimit: 2000000
  698. });
  699. } catch(e) {
  700. hadSenderError = e.message.includes('revert invalid sender')
  701. }
  702. assert.equal(hadSenderError, true)
  703. })
  704. it("should allow a redemption from msg.sender == 'to' on token bridge transfer with payload and check that sender recieves fee", async function () {
  705. const accounts = await web3.eth.getAccounts();
  706. const amount = "1000000000000000000";
  707. const initialized = new web3.eth.Contract(BridgeImplementationFullABI, TokenBridge.address);
  708. mock = (await MockTokenBridgeIntegration.new()).address;
  709. const MockIntegration = new web3.eth.Contract(MockTokenBridgeIntegration.abi, mock);
  710. await MockIntegration.methods.setup(TokenBridge.address).send({
  711. value: 0,
  712. from: accounts[1],
  713. gasLimit: 2000000
  714. });
  715. const wrappedAddress = await initialized.methods.wrappedAsset("0x" + testBridgedAssetChain, "0x" + testBridgedAssetAddress).call();
  716. const wrappedAsset = new web3.eth.Contract(TokenImplementation.abi, wrappedAddress);
  717. const accountBalanceBefore = await wrappedAsset.methods.balanceOf(accounts[0]).call();
  718. const senderBalanceBefore = await wrappedAsset.methods.balanceOf(accounts[1]).call();
  719. const totalSupplyBefore = await wrappedAsset.methods.totalSupply().call();
  720. // we are using the asset where we created a wrapper in the previous test
  721. const data = "0x" +
  722. "03" +
  723. // amount
  724. web3.eth.abi.encodeParameter("uint256", new BigNumber(amount).div(1e10).toString()).substring(2) +
  725. // tokenaddress
  726. testBridgedAssetAddress +
  727. // tokenchain
  728. testBridgedAssetChain +
  729. // receiver
  730. web3.eth.abi.encodeParameter("address", mock).substr(2) +
  731. // receiving chain
  732. web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + (64 - 4)) +
  733. // from address
  734. web3.eth.abi.encodeParameter("address", accounts[1]).substring(2) +
  735. // additional payload
  736. web3.eth.abi.encodeParameter("address", accounts[0]).substr(2);
  737. const vm = await signAndEncodeVM(
  738. 0,
  739. 0,
  740. testForeignChainId,
  741. testForeignBridgeContract,
  742. 2,
  743. data,
  744. [
  745. testSigner1PK
  746. ],
  747. 0,
  748. 0
  749. );
  750. await MockIntegration.methods.completeTransferAndSwap("0x" + vm).send({
  751. value: 0,
  752. from: accounts[1],
  753. gasLimit: 2000000
  754. });
  755. const accountBalanceAfter = await wrappedAsset.methods.balanceOf(accounts[0]).call();
  756. const totalSupplyAfter = await wrappedAsset.methods.totalSupply().call();
  757. assert.equal(accountBalanceAfter.toString(10), new BigNumber(accountBalanceBefore).plus(amount).toString(10));
  758. assert.equal(totalSupplyAfter.toString(10), new BigNumber(totalSupplyBefore).plus(amount).toString(10));
  759. })
  760. it("should burn bridged assets wrappers on transfer to another chain", async function () {
  761. const accounts = await web3.eth.getAccounts();
  762. const initialized = new web3.eth.Contract(BridgeImplementationFullABI, TokenBridge.address);
  763. const amount = "2000000000000000000";
  764. const wrappedFeesPaid = "0";
  765. const wrappedAddress = await initialized.methods.wrappedAsset("0x" + testBridgedAssetChain, "0x" + testBridgedAssetAddress).call();
  766. const wrappedAsset = new web3.eth.Contract(TokenImplementation.abi, wrappedAddress);
  767. await wrappedAsset.methods.approve(TokenBridge.address, amount).send({
  768. value: 0,
  769. from: accounts[0],
  770. gasLimit: 2000000
  771. });
  772. // deposit tokens
  773. const accountBalanceBefore = await wrappedAsset.methods.balanceOf(accounts[0]).call();
  774. assert.equal(accountBalanceBefore.toString(10), amount);
  775. await initialized.methods.transferTokens(
  776. wrappedAddress,
  777. amount,
  778. "11",
  779. "0x000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e",
  780. "0",
  781. "234"
  782. ).send({
  783. value: 0,
  784. from: accounts[0],
  785. gasLimit: 2000000
  786. });
  787. const accountBalanceAfter = await wrappedAsset.methods.balanceOf(accounts[0]).call();
  788. assert.equal(accountBalanceAfter.toString(10), "0");
  789. const bridgeBalanceAfter = await wrappedAsset.methods.balanceOf(TokenBridge.address).call();
  790. assert.equal(bridgeBalanceAfter.toString(10), "0");
  791. const totalSupplyAfter = await wrappedAsset.methods.totalSupply().call();
  792. assert.equal(totalSupplyAfter.toString(10), wrappedFeesPaid);
  793. })
  794. it("should handle ETH deposits correctly", async function () {
  795. const accounts = await web3.eth.getAccounts();
  796. const amount = "100000000000000000";
  797. const fee = "10000000000000000";
  798. // mint and approve tokens
  799. WETH = (await MockWETH9.new()).address;
  800. const token = new web3.eth.Contract(MockWETH9.abi, WETH);
  801. // set WETH contract
  802. const mock = new web3.eth.Contract(MockBridgeImplementation.abi, TokenBridge.address);
  803. mock.methods.testUpdateWETHAddress(WETH).send({
  804. from: accounts[0],
  805. gasLimit: 2000000
  806. });
  807. // deposit tokens
  808. const initialized = new web3.eth.Contract(BridgeImplementationFullABI, TokenBridge.address);
  809. const totalWETHSupply = await token.methods.totalSupply().call();
  810. const bridgeBalanceBefore = await token.methods.balanceOf(TokenBridge.address).call();
  811. assert.equal(totalWETHSupply.toString(10), "0");
  812. assert.equal(bridgeBalanceBefore.toString(10), "0");
  813. await initialized.methods.wrapAndTransferETH(
  814. "10",
  815. "0x000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e",
  816. fee,
  817. "234"
  818. ).send({
  819. value: amount,
  820. from: accounts[0],
  821. gasLimit: 2000000
  822. });
  823. const totalWETHSupplyAfter = await token.methods.totalSupply().call();
  824. const bridgeBalanceAfter = await token.methods.balanceOf(TokenBridge.address).call();
  825. assert.equal(totalWETHSupplyAfter.toString(10), amount);
  826. assert.equal(bridgeBalanceAfter.toString(10), amount);
  827. // check transfer log
  828. const wormhole = new web3.eth.Contract(WormholeImplementationFullABI, Wormhole.address);
  829. const log = (await wormhole.getPastEvents('LogMessagePublished', {
  830. fromBlock: 'latest'
  831. }))[0].returnValues
  832. assert.equal(log.sender, TokenBridge.address)
  833. assert.equal(log.payload.length - 2, 266);
  834. // payload id
  835. assert.equal(log.payload.substr(2, 2), "01");
  836. // amount
  837. assert.equal(log.payload.substr(4, 64), web3.eth.abi.encodeParameter("uint256", new BigNumber(amount).div(1e10).toString()).substring(2));
  838. // token
  839. assert.equal(log.payload.substr(68, 64), web3.eth.abi.encodeParameter("address", WETH).substring(2));
  840. // chain id
  841. assert.equal(log.payload.substr(132, 4), web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + 64 - 4))
  842. // to
  843. assert.equal(log.payload.substr(136, 64), "000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e");
  844. // to chain id
  845. assert.equal(log.payload.substr(200, 4), web3.eth.abi.encodeParameter("uint16", 10).substring(2 + 64 - 4))
  846. // fee
  847. assert.equal(log.payload.substr(204, 64), web3.eth.abi.encodeParameter("uint256", new BigNumber(fee).div(1e10).toString()).substring(2))
  848. })
  849. it("should handle ETH withdrawals and fees correctly", async function () {
  850. const accounts = await web3.eth.getAccounts();
  851. const amount = "100000000000000000";
  852. const fee = "50000000000000000";
  853. const initialized = new web3.eth.Contract(BridgeImplementationFullABI, TokenBridge.address);
  854. const token = new web3.eth.Contract(MockWETH9.abi, WETH);
  855. const totalSupply = await token.methods.totalSupply().call();
  856. assert.equal(totalSupply.toString(10), amount);
  857. const feeRecipientBalanceBefore = await web3.eth.getBalance(accounts[0]);
  858. const accountBalanceBefore = await web3.eth.getBalance(accounts[1]);
  859. // we are using the asset where we created a wrapper in the previous test
  860. const data = "0x" +
  861. "01" +
  862. // amount
  863. web3.eth.abi.encodeParameter("uint256", new BigNumber(amount).div(1e10).toString()).substring(2) +
  864. // tokenaddress
  865. web3.eth.abi.encodeParameter("address", WETH).substr(2) +
  866. // tokenchain
  867. web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + (64 - 4)) +
  868. // receiver
  869. web3.eth.abi.encodeParameter("address", accounts[1]).substr(2) +
  870. // receiving chain
  871. web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + (64 - 4)) +
  872. // fee
  873. web3.eth.abi.encodeParameter("uint256", new BigNumber(fee).div(1e10).toString()).substring(2);
  874. const vm = await signAndEncodeVM(
  875. 0,
  876. 0,
  877. testForeignChainId,
  878. testForeignBridgeContract,
  879. 0,
  880. data,
  881. [
  882. testSigner1PK
  883. ],
  884. 0,
  885. 0
  886. );
  887. const transferTX = await initialized.methods.completeTransferAndUnwrapETH("0x" + vm).send({
  888. from: accounts[0],
  889. gasLimit: 2000000
  890. });
  891. const totalSupplyAfter = await token.methods.totalSupply().call();
  892. assert.equal(totalSupplyAfter.toString(10), "0");
  893. const accountBalanceAfter = await web3.eth.getBalance(accounts[1]);
  894. const feeRecipientBalanceAfter = await web3.eth.getBalance(accounts[0]);
  895. assert.equal((new BigNumber(accountBalanceAfter)).minus(accountBalanceBefore).toString(10), (new BigNumber(amount)).minus(fee).toString(10))
  896. assert.ok((new BigNumber(feeRecipientBalanceAfter)).gt(feeRecipientBalanceBefore))
  897. })
  898. it("should handle ETH deposits with payload correctly", async function () {
  899. const accounts = await web3.eth.getAccounts();
  900. const amount = "100000000000000000";
  901. // mint and approve tokens
  902. WETH = (await MockWETH9.new()).address;
  903. const token = new web3.eth.Contract(MockWETH9.abi, WETH);
  904. // set WETH contract
  905. const mock = new web3.eth.Contract(MockBridgeImplementation.abi, TokenBridge.address);
  906. mock.methods.testUpdateWETHAddress(WETH).send({
  907. from: accounts[0],
  908. gasLimit: 2000000
  909. });
  910. // deposit tokens
  911. const initialized = new web3.eth.Contract(BridgeImplementationFullABI, TokenBridge.address);
  912. const totalWETHSupply = await token.methods.totalSupply().call();
  913. const bridgeBalanceBefore = await token.methods.balanceOf(TokenBridge.address).call();
  914. assert.equal(totalWETHSupply.toString(10), "0");
  915. assert.equal(bridgeBalanceBefore.toString(10), "0");
  916. const additionalPayload = "abc123"
  917. await initialized.methods.wrapAndTransferETHWithPayload(
  918. "10",
  919. "0x000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e",
  920. "234",
  921. "0x"+additionalPayload
  922. ).send({
  923. value: amount,
  924. from: accounts[0],
  925. gasLimit: 2000000
  926. });
  927. const totalWETHSupplyAfter = await token.methods.totalSupply().call();
  928. const bridgeBalanceAfter = await token.methods.balanceOf(TokenBridge.address).call();
  929. assert.equal(totalWETHSupplyAfter.toString(10), amount);
  930. assert.equal(bridgeBalanceAfter.toString(10), amount);
  931. // check transfer log
  932. const wormhole = new web3.eth.Contract(WormholeImplementationFullABI, Wormhole.address);
  933. const log = (await wormhole.getPastEvents('LogMessagePublished', {
  934. fromBlock: 'latest'
  935. }))[0].returnValues
  936. assert.equal(log.sender, TokenBridge.address)
  937. assert.equal(log.payload.length - 2 - additionalPayload.length, 266);
  938. // payload id
  939. assert.equal(log.payload.substr(2, 2), "03");
  940. // amount
  941. assert.equal(log.payload.substr(4, 64), web3.eth.abi.encodeParameter("uint256", new BigNumber(amount).div(1e10).toString()).substring(2));
  942. // token
  943. assert.equal(log.payload.substr(68, 64), web3.eth.abi.encodeParameter("address", WETH).substring(2));
  944. // chain id
  945. assert.equal(log.payload.substr(132, 4), web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + 64 - 4))
  946. // to
  947. assert.equal(log.payload.substr(136, 64), "000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e");
  948. // to chain id
  949. assert.equal(log.payload.substr(200, 4), web3.eth.abi.encodeParameter("uint16", 10).substring(2 + 64 - 4))
  950. // from address
  951. assert.equal(log.payload.substr(204, 64), web3.eth.abi.encodeParameter("address", accounts[0]).substring(2))
  952. // payload
  953. assert.equal(log.payload.substr(268), additionalPayload)
  954. })
  955. it("should handle ETH withdrawals with payload correctly", async function () {
  956. const accounts = await web3.eth.getAccounts();
  957. const amount = "100000000000000000";
  958. const fee = "0";
  959. const initialized = new web3.eth.Contract(BridgeImplementationFullABI, TokenBridge.address);
  960. const token = new web3.eth.Contract(MockWETH9.abi, WETH);
  961. const totalSupply = await token.methods.totalSupply().call();
  962. assert.equal(totalSupply.toString(10), amount);
  963. const accountBalanceBefore = await web3.eth.getBalance(accounts[0]);
  964. // we are using the asset where we created a wrapper in the previous test
  965. const data = "0x" +
  966. "03" +
  967. // amount
  968. web3.eth.abi.encodeParameter("uint256", new BigNumber(amount).div(1e10).toString()).substring(2) +
  969. // tokenaddress
  970. web3.eth.abi.encodeParameter("address", WETH).substr(2) +
  971. // tokenchain
  972. web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + (64 - 4)) +
  973. // receiver
  974. web3.eth.abi.encodeParameter("address", accounts[0]).substr(2) +
  975. // receiving chain
  976. web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + (64 - 4)) +
  977. // fee
  978. web3.eth.abi.encodeParameter("uint256", new BigNumber(fee).toString()).substring(2) +
  979. // additional payload
  980. "abc123"
  981. const vm = await signAndEncodeVM(
  982. 0,
  983. 0,
  984. testForeignChainId,
  985. testForeignBridgeContract,
  986. 0,
  987. data,
  988. [
  989. testSigner1PK
  990. ],
  991. 0,
  992. 0
  993. );
  994. const transferTX = await initialized.methods.completeTransferAndUnwrapETHWithPayload("0x" + vm).send({
  995. from: accounts[0], //must be same as receiver
  996. gasLimit: 2000000
  997. });
  998. const totalSupplyAfter = await token.methods.totalSupply().call();
  999. assert.equal(totalSupplyAfter.toString(10), "0");
  1000. const accountBalanceAfter = await web3.eth.getBalance(accounts[0]);
  1001. assert.ok((new BigNumber(accountBalanceAfter)).gt(accountBalanceBefore))
  1002. })
  1003. it("should revert on transfer out of a total of > max(uint64) tokens", async function () {
  1004. const accounts = await web3.eth.getAccounts();
  1005. const supply = "184467440737095516160000000000";
  1006. const firstTransfer = "1000000000000";
  1007. // mint and approve tokens
  1008. const token = new web3.eth.Contract(TokenImplementation.abi, TokenImplementation.address);
  1009. await token.methods.mint(accounts[0], supply).send({
  1010. value: 0,
  1011. from: accounts[0],
  1012. gasLimit: 2000000
  1013. });
  1014. await token.methods.approve(TokenBridge.address, supply).send({
  1015. value: 0,
  1016. from: accounts[0],
  1017. gasLimit: 2000000
  1018. });
  1019. // deposit tokens
  1020. const initialized = new web3.eth.Contract(BridgeImplementationFullABI, TokenBridge.address);
  1021. await initialized.methods.transferTokens(
  1022. TokenImplementation.address,
  1023. firstTransfer,
  1024. "10",
  1025. "0x000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e",
  1026. "0",
  1027. "0"
  1028. ).send({
  1029. value: 0,
  1030. from: accounts[0],
  1031. gasLimit: 2000000
  1032. });
  1033. let failed = false;
  1034. try {
  1035. await initialized.methods.transferTokens(
  1036. TokenImplementation.address,
  1037. new BigNumber(supply).minus(firstTransfer).toString(10),
  1038. "10",
  1039. "0x000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e",
  1040. "0",
  1041. "0"
  1042. ).send({
  1043. value: 0,
  1044. from: accounts[0],
  1045. gasLimit: 2000000
  1046. });
  1047. } catch (error) {
  1048. assert.equal(error.message, "Returned error: VM Exception while processing transaction: revert transfer exceeds max outstanding bridged token amount")
  1049. failed = true
  1050. }
  1051. assert.ok(failed)
  1052. })
  1053. });
  1054. const signAndEncodeVM = async function (
  1055. timestamp,
  1056. nonce,
  1057. emitterChainId,
  1058. emitterAddress,
  1059. sequence,
  1060. data,
  1061. signers,
  1062. guardianSetIndex,
  1063. consistencyLevel
  1064. ) {
  1065. const body = [
  1066. web3.eth.abi.encodeParameter("uint32", timestamp).substring(2 + (64 - 8)),
  1067. web3.eth.abi.encodeParameter("uint32", nonce).substring(2 + (64 - 8)),
  1068. web3.eth.abi.encodeParameter("uint16", emitterChainId).substring(2 + (64 - 4)),
  1069. web3.eth.abi.encodeParameter("bytes32", emitterAddress).substring(2),
  1070. web3.eth.abi.encodeParameter("uint64", sequence).substring(2 + (64 - 16)),
  1071. web3.eth.abi.encodeParameter("uint8", consistencyLevel).substring(2 + (64 - 2)),
  1072. data.substr(2)
  1073. ]
  1074. const hash = web3.utils.soliditySha3(web3.utils.soliditySha3("0x" + body.join("")))
  1075. let signatures = "";
  1076. for (let i in signers) {
  1077. const ec = new elliptic.ec("secp256k1");
  1078. const key = ec.keyFromPrivate(signers[i]);
  1079. const signature = key.sign(hash.substr(2), {canonical: true});
  1080. const packSig = [
  1081. web3.eth.abi.encodeParameter("uint8", i).substring(2 + (64 - 2)),
  1082. zeroPadBytes(signature.r.toString(16), 32),
  1083. zeroPadBytes(signature.s.toString(16), 32),
  1084. web3.eth.abi.encodeParameter("uint8", signature.recoveryParam).substr(2 + (64 - 2)),
  1085. ]
  1086. signatures += packSig.join("")
  1087. }
  1088. const vm = [
  1089. web3.eth.abi.encodeParameter("uint8", 1).substring(2 + (64 - 2)),
  1090. web3.eth.abi.encodeParameter("uint32", guardianSetIndex).substring(2 + (64 - 8)),
  1091. web3.eth.abi.encodeParameter("uint8", signers.length).substring(2 + (64 - 2)),
  1092. signatures,
  1093. body.join("")
  1094. ].join("");
  1095. return vm
  1096. }
  1097. function zeroPadBytes(value, length) {
  1098. while (value.length < 2 * length) {
  1099. value = "0" + value;
  1100. }
  1101. return value;
  1102. }