From 1406d29ff6d8b08a70ff6c55650b1822bccdf1f2 Mon Sep 17 00:00:00 2001 From: ckeun Date: Wed, 23 Nov 2022 10:24:06 -0600 Subject: [PATCH] sdk/js: added vaa repair script to utils (#1935) * sdk/js: Added repairVaa & test * fixed unnecessary comments * Separated rpc call from base repairVaa function. removed console logs and added throws * removed unncessary else statement * removed unnecessary async * Skipping rpc call test for current guardian set * Clean up minor formatting --- sdk/js/src/utils/repairVaa.test.ts | 82 ++++++++++++++++++++ sdk/js/src/utils/repairVaa.ts | 115 +++++++++++++++++++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 sdk/js/src/utils/repairVaa.test.ts create mode 100644 sdk/js/src/utils/repairVaa.ts diff --git a/sdk/js/src/utils/repairVaa.test.ts b/sdk/js/src/utils/repairVaa.test.ts new file mode 100644 index 000000000..ad92393ea --- /dev/null +++ b/sdk/js/src/utils/repairVaa.test.ts @@ -0,0 +1,82 @@ +import { expect, test } from "@jest/globals"; +import { ethers } from "ethers"; +import { repairVaa, repairVaaWithCurrentGuardianSet } from "./repairVaa"; + +const guardianSetData = { + index: 2, + keys: [ + "0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5", + "0xfF6CB952589BDE862c25Ef4392132fb9D4A42157", + "0x114De8460193bdf3A2fCf81f86a09765F4762fD1", + "0x107A0086b32d7A0977926A205131d8731D39cbEB", + "0x8C82B2fd82FaeD2711d59AF0F2499D16e726f6b2", + "0x11b39756C042441BE6D8650b69b54EbE715E2343", + "0x54Ce5B4D348fb74B958e8966e2ec3dBd4958a7cd", + "0x66B9590e1c41e0B226937bf9217D1d67Fd4E91F5", + "0x74a3bf913953D695260D88BC1aA25A4eeE363ef0", + "0x000aC0076727b35FBea2dAc28fEE5cCB0fEA768e", + "0xAF45Ced136b9D9e24903464AE889F5C8a723FC14", + "0xf93124b7c738843CBB89E864c862c38cddCccF95", + "0xD2CC37A4dc036a8D232b48f62cDD4731412f4890", + "0xDA798F6896A3331F64b48c12D1D57Fd9cbe70811", + "0x71AA1BE1D36CaFE3867910F99C09e347899C19C3", + "0x8192b6E7387CCd768277c17DAb1b7a5027c0b3Cf", + "0x178e21ad2E77AE06711549CFBB1f9c7a9d8096e8", + "0x5E1487F35515d02A92753504a8D75471b9f49EdB", + "0x6FbEBc898F403E4773E95feB15E80C9A99c8348d", + ], + expiry: 0, +}; + +test("vaa has enough signatures to repair", () => { + // has 14 signatures, Signature at index #1 has been altered + const vaa = + "01000000010e00489871e73fc73a19ed47d9d6c39551b1b2e92f5fc76546b4c2d790845563b3aa6b413553d633fb2ede0b6491d6b8b55738bb89a648e01077eb29ad452bc32de6000181123e985106659001cd9edb9e5db954443fc532e4cabf4f1c3b215e2a935cbd123ce1ee267618d685dc7c4379892327d0fddb729eb1e0f0611f825bfe871b68010295f8bfb0394d23826fecba81f73af18278dac42b665efb148e0a8b380532f2403a6e776851d6f4d2c0f6ae61f8efa699c856802f707a64b4f9e320f4483017cc0003397afeaba4e9c064fd99c79caac2bff7c9c147cde9286b26b242afe0367bd9fe227b345ad0f7d51cbcfd63b5d8593ce65918bfe8c1794b6316869638fc73cf530104df5411869d2e7c5de5de5f1e199db371ac40e7e8adb00cc8a2ed999fe2d02b75278fe8442306203206ec45efdffa5208fe70a3eeaa8125b4fb435aac103037860106106e85c3fcb8ebf231e176e8854f9b04a6ae777cbbbda3f0f1bcd1e08cecc9da420c4af21145972d7d538e28cdd957dfe6ff048d6a403393ed5ca44dd9f1180b000730c77ea4586080203329cda5b74022f1f53bc56fad600cb89f73c75457fd963271d9ff0425b7cdff2e013598a58ac413163b0e878bf01979104d67d9a4e85e0a010948f3dd5a01023936384410fd31c3e58c6b808dfe0826b7eb6af695884d20e95e47bbe093af574ed2640cfe32b6171a7957cede3bbf9d8e5374547f49ca00cbc8010c1b194773d701095798252c356ee224e8ba188b8f8d09975687efc3b376b2cf496e07c267c6b54f2ce98cc262c4c3bc28229ff1e257afe7d78cc9569a660eb04c000d61e3e135c605ba4b3d39b178f0dfc0db6497291b29c97afed6f6feedcd7fbe052795861e4ef05f7d715f313c4cafca443ad1ca69d61aecde7b1aee9e3cf520f2000e617900cb13db3eb68bdbbc159bcced7a064cdbcc7253d10a1a6ea5cd6f5d9fa87b2b1f7d474180da2534db5f478607ad3c82d0b7cc30734f3a480e77a80d13e6010fb84790f4637d4f78612f7b734daa1a085fc21ebcca4f89279a26a12e8836c6a7437342392a034dda85d3a0330f425207132df39d49688a05e0f316d8cc4c721e0010c77c0979a9034a129ed211e5c720a1df2d024cc7d45ae174f779127a089900142b144b5ce6513d19df1e1528d574a528300c06229abb1ec50fc58c0fac7dc7400012090fcaf1f83cee46756e3a9c370fe2a6c7c421bc7cfa5920c044d36b6c2130204e819edd895249c2686d3330565c583f53b89cfdc4275fd56baa570bb442fc4701637431d7a33b000000020000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585000000000001685e010100000000000000000000000000000000000000000000000000000001d5a977820000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f984000200000000000000000000000027ec3715bc5e419df98689bd301c17661c73c2c300040000000000000000000000000000000000000000000000000000000000000000"; + const repairedVaa = repairVaa(vaa, guardianSetData); + expect(repairedVaa).toBe( + "01000000020d00489871e73fc73a19ed47d9d6c39551b1b2e92f5fc76546b4c2d790845563b3aa6b413553d633fb2ede0b6491d6b8b55738bb89a648e01077eb29ad452bc32de6000295f8bfb0394d23826fecba81f73af18278dac42b665efb148e0a8b380532f2403a6e776851d6f4d2c0f6ae61f8efa699c856802f707a64b4f9e320f4483017cc0003397afeaba4e9c064fd99c79caac2bff7c9c147cde9286b26b242afe0367bd9fe227b345ad0f7d51cbcfd63b5d8593ce65918bfe8c1794b6316869638fc73cf530104df5411869d2e7c5de5de5f1e199db371ac40e7e8adb00cc8a2ed999fe2d02b75278fe8442306203206ec45efdffa5208fe70a3eeaa8125b4fb435aac103037860106106e85c3fcb8ebf231e176e8854f9b04a6ae777cbbbda3f0f1bcd1e08cecc9da420c4af21145972d7d538e28cdd957dfe6ff048d6a403393ed5ca44dd9f1180b000730c77ea4586080203329cda5b74022f1f53bc56fad600cb89f73c75457fd963271d9ff0425b7cdff2e013598a58ac413163b0e878bf01979104d67d9a4e85e0a010948f3dd5a01023936384410fd31c3e58c6b808dfe0826b7eb6af695884d20e95e47bbe093af574ed2640cfe32b6171a7957cede3bbf9d8e5374547f49ca00cbc8010c1b194773d701095798252c356ee224e8ba188b8f8d09975687efc3b376b2cf496e07c267c6b54f2ce98cc262c4c3bc28229ff1e257afe7d78cc9569a660eb04c000d61e3e135c605ba4b3d39b178f0dfc0db6497291b29c97afed6f6feedcd7fbe052795861e4ef05f7d715f313c4cafca443ad1ca69d61aecde7b1aee9e3cf520f2000e617900cb13db3eb68bdbbc159bcced7a064cdbcc7253d10a1a6ea5cd6f5d9fa87b2b1f7d474180da2534db5f478607ad3c82d0b7cc30734f3a480e77a80d13e6010fb84790f4637d4f78612f7b734daa1a085fc21ebcca4f89279a26a12e8836c6a7437342392a034dda85d3a0330f425207132df39d49688a05e0f316d8cc4c721e0010c77c0979a9034a129ed211e5c720a1df2d024cc7d45ae174f779127a089900142b144b5ce6513d19df1e1528d574a528300c06229abb1ec50fc58c0fac7dc7400012090fcaf1f83cee46756e3a9c370fe2a6c7c421bc7cfa5920c044d36b6c2130204e819edd895249c2686d3330565c583f53b89cfdc4275fd56baa570bb442fc4701637431d7a33b000000020000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585000000000001685e010100000000000000000000000000000000000000000000000000000001d5a977820000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f984000200000000000000000000000027ec3715bc5e419df98689bd301c17661c73c2c300040000000000000000000000000000000000000000000000000000000000000000" + ); +}); + +test("vaa does not have enough signatures to repair", () => { + // has 13 signatures. Signature at index #0 has been altered + const vaa = + "01000000010d00249871e73fc73a19ed47d9d6c39551b1b2e92f5fc76546b4c2d790845563b3aa6b413553d633fb2ede0b6491d6b8b55738bb89a648e01077eb29ad452bc32de6000295f8bfb0394d23826fecba81f73af18278dac42b665efb148e0a8b380532f2403a6e776851d6f4d2c0f6ae61f8efa699c856802f707a64b4f9e320f4483017cc0003397afeaba4e9c064fd99c79caac2bff7c9c147cde9286b26b242afe0367bd9fe227b345ad0f7d51cbcfd63b5d8593ce65918bfe8c1794b6316869638fc73cf530104df5411869d2e7c5de5de5f1e199db371ac40e7e8adb00cc8a2ed999fe2d02b75278fe8442306203206ec45efdffa5208fe70a3eeaa8125b4fb435aac103037860106106e85c3fcb8ebf231e176e8854f9b04a6ae777cbbbda3f0f1bcd1e08cecc9da420c4af21145972d7d538e28cdd957dfe6ff048d6a403393ed5ca44dd9f1180b000730c77ea4586080203329cda5b74022f1f53bc56fad600cb89f73c75457fd963271d9ff0425b7cdff2e013598a58ac413163b0e878bf01979104d67d9a4e85e0a010948f3dd5a01023936384410fd31c3e58c6b808dfe0826b7eb6af695884d20e95e47bbe093af574ed2640cfe32b6171a7957cede3bbf9d8e5374547f49ca00cbc8010c1b194773d701095798252c356ee224e8ba188b8f8d09975687efc3b376b2cf496e07c267c6b54f2ce98cc262c4c3bc28229ff1e257afe7d78cc9569a660eb04c000d61e3e135c605ba4b3d39b178f0dfc0db6497291b29c97afed6f6feedcd7fbe052795861e4ef05f7d715f313c4cafca443ad1ca69d61aecde7b1aee9e3cf520f2000e617900cb13db3eb68bdbbc159bcced7a064cdbcc7253d10a1a6ea5cd6f5d9fa87b2b1f7d474180da2534db5f478607ad3c82d0b7cc30734f3a480e77a80d13e6010fb84790f4637d4f78612f7b734daa1a085fc21ebcca4f89279a26a12e8836c6a7437342392a034dda85d3a0330f425207132df39d49688a05e0f316d8cc4c721e0010c77c0979a9034a129ed211e5c720a1df2d024cc7d45ae174f779127a089900142b144b5ce6513d19df1e1528d574a528300c06229abb1ec50fc58c0fac7dc7400012090fcaf1f83cee46756e3a9c370fe2a6c7c421bc7cfa5920c044d36b6c2130204e819edd895249c2686d3330565c583f53b89cfdc4275fd56baa570bb442fc4701637431d7a33b000000020000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585000000000001685e010100000000000000000000000000000000000000000000000000000001d5a977820000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f984000200000000000000000000000027ec3715bc5e419df98689bd301c17661c73c2c300040000000000000000000000000000000000000000000000000000000000000000"; + expect(() => { + repairVaa(vaa, guardianSetData); + }).toThrow("There are not enough valid signatures to repair."); +}); + +test("number of vaa signatures does not match parse signatures", () => { + // Attempting to parse vaa with fake # of signatures. error thrown by parseVaa function + const vaa = + "01000000011100249871e73fc73a19ed47d9d6c39551b1b2e92f5fc76546b4c2d790845563b3aa6b413553d633fb2ede0b6491d6b8b55738bb89a648e01077eb29ad452bc32de6000295f8bfb0394d23826fecba81f73af18278dac42b665efb148e0a8b380532f2403a6e776851d6f4d2c0f6ae61f8efa699c856802f707a64b4f9e320f4483017cc0003397afeaba4e9c064fd99c79caac2bff7c9c147cde9286b26b242afe0367bd9fe227b345ad0f7d51cbcfd63b5d8593ce65918bfe8c1794b6316869638fc73cf530104df5411869d2e7c5de5de5f1e199db371ac40e7e8adb00cc8a2ed999fe2d02b75278fe8442306203206ec45efdffa5208fe70a3eeaa8125b4fb435aac103037860106106e85c3fcb8ebf231e176e8854f9b04a6ae777cbbbda3f0f1bcd1e08cecc9da420c4af21145972d7d538e28cdd957dfe6ff048d6a403393ed5ca44dd9f1180b000730c77ea4586080203329cda5b74022f1f53bc56fad600cb89f73c75457fd963271d9ff0425b7cdff2e013598a58ac413163b0e878bf01979104d67d9a4e85e0a010948f3dd5a01023936384410fd31c3e58c6b808dfe0826b7eb6af695884d20e95e47bbe093af574ed2640cfe32b6171a7957cede3bbf9d8e5374547f49ca00cbc8010c1b194773d701095798252c356ee224e8ba188b8f8d09975687efc3b376b2cf496e07c267c6b54f2ce98cc262c4c3bc28229ff1e257afe7d78cc9569a660eb04c000d61e3e135c605ba4b3d39b178f0dfc0db6497291b29c97afed6f6feedcd7fbe052795861e4ef05f7d715f313c4cafca443ad1ca69d61aecde7b1aee9e3cf520f2000e617900cb13db3eb68bdbbc159bcced7a064cdbcc7253d10a1a6ea5cd6f5d9fa87b2b1f7d474180da2534db5f478607ad3c82d0b7cc30734f3a480e77a80d13e6010fb84790f4637d4f78612f7b734daa1a085fc21ebcca4f89279a26a12e8836c6a7437342392a034dda85d3a0330f425207132df39d49688a05e0f316d8cc4c721e0010c77c0979a9034a129ed211e5c720a1df2d024cc7d45ae174f779127a089900142b144b5ce6513d19df1e1528d574a528300c06229abb1ec50fc58c0fac7dc7400012090fcaf1f83cee46756e3a9c370fe2a6c7c421bc7cfa5920c044d36b6c2130204e819edd895249c2686d3330565c583f53b89cfdc4275fd56baa570bb442fc4701637431d7a33b000000020000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585000000000001685e010100000000000000000000000000000000000000000000000000000001d5a977820000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f984000200000000000000000000000027ec3715bc5e419df98689bd301c17661c73c2c300040000000000000000000000000000000000000000000000000000000000000000"; + expect(() => { + repairVaa(vaa, guardianSetData); + }).toThrow("Attempt to access memory outside buffer bounds"); +}); + +test.skip("Use current guardian set", async () => { + const rpcUrl = "https://rpc.ankr.com/eth"; + const provider = new ethers.providers.JsonRpcProvider(rpcUrl); + // Grab current guardian set and successfully repair. + const vaa = + "01000000010e00489871e73fc73a19ed47d9d6c39551b1b2e92f5fc76546b4c2d790845563b3aa6b413553d633fb2ede0b6491d6b8b55738bb89a648e01077eb29ad452bc32de6000181123e985106659001cd9edb9e5db954443fc532e4cabf4f1c3b215e2a935cbd123ce1ee267618d685dc7c4379892327d0fddb729eb1e0f0611f825bfe871b68010295f8bfb0394d23826fecba81f73af18278dac42b665efb148e0a8b380532f2403a6e776851d6f4d2c0f6ae61f8efa699c856802f707a64b4f9e320f4483017cc0003397afeaba4e9c064fd99c79caac2bff7c9c147cde9286b26b242afe0367bd9fe227b345ad0f7d51cbcfd63b5d8593ce65918bfe8c1794b6316869638fc73cf530104df5411869d2e7c5de5de5f1e199db371ac40e7e8adb00cc8a2ed999fe2d02b75278fe8442306203206ec45efdffa5208fe70a3eeaa8125b4fb435aac103037860106106e85c3fcb8ebf231e176e8854f9b04a6ae777cbbbda3f0f1bcd1e08cecc9da420c4af21145972d7d538e28cdd957dfe6ff048d6a403393ed5ca44dd9f1180b000730c77ea4586080203329cda5b74022f1f53bc56fad600cb89f73c75457fd963271d9ff0425b7cdff2e013598a58ac413163b0e878bf01979104d67d9a4e85e0a010948f3dd5a01023936384410fd31c3e58c6b808dfe0826b7eb6af695884d20e95e47bbe093af574ed2640cfe32b6171a7957cede3bbf9d8e5374547f49ca00cbc8010c1b194773d701095798252c356ee224e8ba188b8f8d09975687efc3b376b2cf496e07c267c6b54f2ce98cc262c4c3bc28229ff1e257afe7d78cc9569a660eb04c000d61e3e135c605ba4b3d39b178f0dfc0db6497291b29c97afed6f6feedcd7fbe052795861e4ef05f7d715f313c4cafca443ad1ca69d61aecde7b1aee9e3cf520f2000e617900cb13db3eb68bdbbc159bcced7a064cdbcc7253d10a1a6ea5cd6f5d9fa87b2b1f7d474180da2534db5f478607ad3c82d0b7cc30734f3a480e77a80d13e6010fb84790f4637d4f78612f7b734daa1a085fc21ebcca4f89279a26a12e8836c6a7437342392a034dda85d3a0330f425207132df39d49688a05e0f316d8cc4c721e0010c77c0979a9034a129ed211e5c720a1df2d024cc7d45ae174f779127a089900142b144b5ce6513d19df1e1528d574a528300c06229abb1ec50fc58c0fac7dc7400012090fcaf1f83cee46756e3a9c370fe2a6c7c421bc7cfa5920c044d36b6c2130204e819edd895249c2686d3330565c583f53b89cfdc4275fd56baa570bb442fc4701637431d7a33b000000020000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585000000000001685e010100000000000000000000000000000000000000000000000000000001d5a977820000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f984000200000000000000000000000027ec3715bc5e419df98689bd301c17661c73c2c300040000000000000000000000000000000000000000000000000000000000000000"; + + const repairedVaa = await repairVaaWithCurrentGuardianSet(vaa, provider); + expect(repairedVaa).toBe( + "01000000020d00489871e73fc73a19ed47d9d6c39551b1b2e92f5fc76546b4c2d790845563b3aa6b413553d633fb2ede0b6491d6b8b55738bb89a648e01077eb29ad452bc32de6000295f8bfb0394d23826fecba81f73af18278dac42b665efb148e0a8b380532f2403a6e776851d6f4d2c0f6ae61f8efa699c856802f707a64b4f9e320f4483017cc0003397afeaba4e9c064fd99c79caac2bff7c9c147cde9286b26b242afe0367bd9fe227b345ad0f7d51cbcfd63b5d8593ce65918bfe8c1794b6316869638fc73cf530104df5411869d2e7c5de5de5f1e199db371ac40e7e8adb00cc8a2ed999fe2d02b75278fe8442306203206ec45efdffa5208fe70a3eeaa8125b4fb435aac103037860106106e85c3fcb8ebf231e176e8854f9b04a6ae777cbbbda3f0f1bcd1e08cecc9da420c4af21145972d7d538e28cdd957dfe6ff048d6a403393ed5ca44dd9f1180b000730c77ea4586080203329cda5b74022f1f53bc56fad600cb89f73c75457fd963271d9ff0425b7cdff2e013598a58ac413163b0e878bf01979104d67d9a4e85e0a010948f3dd5a01023936384410fd31c3e58c6b808dfe0826b7eb6af695884d20e95e47bbe093af574ed2640cfe32b6171a7957cede3bbf9d8e5374547f49ca00cbc8010c1b194773d701095798252c356ee224e8ba188b8f8d09975687efc3b376b2cf496e07c267c6b54f2ce98cc262c4c3bc28229ff1e257afe7d78cc9569a660eb04c000d61e3e135c605ba4b3d39b178f0dfc0db6497291b29c97afed6f6feedcd7fbe052795861e4ef05f7d715f313c4cafca443ad1ca69d61aecde7b1aee9e3cf520f2000e617900cb13db3eb68bdbbc159bcced7a064cdbcc7253d10a1a6ea5cd6f5d9fa87b2b1f7d474180da2534db5f478607ad3c82d0b7cc30734f3a480e77a80d13e6010fb84790f4637d4f78612f7b734daa1a085fc21ebcca4f89279a26a12e8836c6a7437342392a034dda85d3a0330f425207132df39d49688a05e0f316d8cc4c721e0010c77c0979a9034a129ed211e5c720a1df2d024cc7d45ae174f779127a089900142b144b5ce6513d19df1e1528d574a528300c06229abb1ec50fc58c0fac7dc7400012090fcaf1f83cee46756e3a9c370fe2a6c7c421bc7cfa5920c044d36b6c2130204e819edd895249c2686d3330565c583f53b89cfdc4275fd56baa570bb442fc4701637431d7a33b000000020000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585000000000001685e010100000000000000000000000000000000000000000000000000000001d5a977820000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f984000200000000000000000000000027ec3715bc5e419df98689bd301c17661c73c2c300040000000000000000000000000000000000000000000000000000000000000000" + ); +}); + +test.skip("Grab current guardian set with bad rpc", async () => { + const rpcUrl = "https://rkc.ankr.com/eth"; + const provider = new ethers.providers.JsonRpcProvider(rpcUrl); + // Try to grab current guardian set with bad rpc. Should throw error + const vaa = + "01000000010e00489871e73fc73a19ed47d9d6c39551b1b2e92f5fc76546b4c2d790845563b3aa6b413553d633fb2ede0b6491d6b8b55738bb89a648e01077eb29ad452bc32de6000181123e985106659001cd9edb9e5db954443fc532e4cabf4f1c3b215e2a935cbd123ce1ee267618d685dc7c4379892327d0fddb729eb1e0f0611f825bfe871b68010295f8bfb0394d23826fecba81f73af18278dac42b665efb148e0a8b380532f2403a6e776851d6f4d2c0f6ae61f8efa699c856802f707a64b4f9e320f4483017cc0003397afeaba4e9c064fd99c79caac2bff7c9c147cde9286b26b242afe0367bd9fe227b345ad0f7d51cbcfd63b5d8593ce65918bfe8c1794b6316869638fc73cf530104df5411869d2e7c5de5de5f1e199db371ac40e7e8adb00cc8a2ed999fe2d02b75278fe8442306203206ec45efdffa5208fe70a3eeaa8125b4fb435aac103037860106106e85c3fcb8ebf231e176e8854f9b04a6ae777cbbbda3f0f1bcd1e08cecc9da420c4af21145972d7d538e28cdd957dfe6ff048d6a403393ed5ca44dd9f1180b000730c77ea4586080203329cda5b74022f1f53bc56fad600cb89f73c75457fd963271d9ff0425b7cdff2e013598a58ac413163b0e878bf01979104d67d9a4e85e0a010948f3dd5a01023936384410fd31c3e58c6b808dfe0826b7eb6af695884d20e95e47bbe093af574ed2640cfe32b6171a7957cede3bbf9d8e5374547f49ca00cbc8010c1b194773d701095798252c356ee224e8ba188b8f8d09975687efc3b376b2cf496e07c267c6b54f2ce98cc262c4c3bc28229ff1e257afe7d78cc9569a660eb04c000d61e3e135c605ba4b3d39b178f0dfc0db6497291b29c97afed6f6feedcd7fbe052795861e4ef05f7d715f313c4cafca443ad1ca69d61aecde7b1aee9e3cf520f2000e617900cb13db3eb68bdbbc159bcced7a064cdbcc7253d10a1a6ea5cd6f5d9fa87b2b1f7d474180da2534db5f478607ad3c82d0b7cc30734f3a480e77a80d13e6010fb84790f4637d4f78612f7b734daa1a085fc21ebcca4f89279a26a12e8836c6a7437342392a034dda85d3a0330f425207132df39d49688a05e0f316d8cc4c721e0010c77c0979a9034a129ed211e5c720a1df2d024cc7d45ae174f779127a089900142b144b5ce6513d19df1e1528d574a528300c06229abb1ec50fc58c0fac7dc7400012090fcaf1f83cee46756e3a9c370fe2a6c7c421bc7cfa5920c044d36b6c2130204e819edd895249c2686d3330565c583f53b89cfdc4275fd56baa570bb442fc4701637431d7a33b000000020000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585000000000001685e010100000000000000000000000000000000000000000000000000000001d5a977820000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f984000200000000000000000000000027ec3715bc5e419df98689bd301c17661c73c2c300040000000000000000000000000000000000000000000000000000000000000000"; + + await expect( + repairVaaWithCurrentGuardianSet(vaa, provider) + ).rejects.toThrow(); +}); diff --git a/sdk/js/src/utils/repairVaa.ts b/sdk/js/src/utils/repairVaa.ts new file mode 100644 index 000000000..6e1bce90a --- /dev/null +++ b/sdk/js/src/utils/repairVaa.ts @@ -0,0 +1,115 @@ +import { ethers } from "ethers"; +import { CONTRACTS } from "./consts"; +import { Implementation__factory } from "../ethers-contracts"; +import { parseVaa, GuardianSignature } from "../vaa"; +import { hexToUint8Array } from "./array"; +import { keccak256 } from "../utils"; + +const ETHEREUM_CORE_BRIDGE = CONTRACTS["MAINNET"].ethereum.core; + +function hex(x: string): string { + return ethers.utils.hexlify(x, { allowMissingPrefix: true }); +} +interface GuardianSetData { + index: number; + keys: string[]; + expiry: number; +} + +export async function getCurrentGuardianSet( + provider: ethers.providers.JsonRpcProvider +): Promise { + let result: GuardianSetData = { + index: 0, + keys: [], + expiry: 0, + }; + const core = Implementation__factory.connect(ETHEREUM_CORE_BRIDGE, provider); + const index = await core.getCurrentGuardianSetIndex(); + const guardianSet = await core.getGuardianSet(index); + result.index = index; + result.keys = guardianSet[0]; + result.expiry = guardianSet[1]; + return result; +} + +/** + * + * Takes in a hexstring representation of a signed vaa and a guardian set. + * Attempts to remove invalid guardian signatures, update total remaining + * valid signatures, and update the guardian set index + * @throws if not enough valid signatures remain + **/ + +export function repairVaa( + vaaHex: string, + guardianSetData: GuardianSetData +): string { + const guardianSetIndex = guardianSetData.index; + const currentGuardianSet = guardianSetData.keys; + const minNumSignatures = + Math.floor((2.0 * currentGuardianSet.length) / 3.0) + 1; + const version = vaaHex.slice(0, 2); + const parsedVaa = parseVaa(hexToUint8Array(vaaHex)); + const numSignatures = parsedVaa.guardianSignatures.length; + const digest = keccak256(parsedVaa.hash).toString("hex"); + + var validSignatures: GuardianSignature[] = []; + + // take each signature, check if valid against hash & current guardian set + parsedVaa.guardianSignatures.forEach((signature) => { + try { + const vaaGuardianPublicKey = ethers.utils.recoverAddress( + hex(digest), + hex(signature.signature.toString("hex")) + ); + const currentIndex = signature.index; + const currentGuardianPublicKey = currentGuardianSet[currentIndex]; + + if (currentGuardianPublicKey === vaaGuardianPublicKey) { + validSignatures.push(signature); + } + } catch (_) {} + }); + + // re-construct vaa with signatures that remain + const numRepairedSignatures = validSignatures.length; + if (numRepairedSignatures < minNumSignatures) { + throw new Error(`There are not enough valid signatures to repair.`); + } + const repairedSignatures = validSignatures + .sort(function (a, b) { + return a.index - b.index; + }) + .map((signature) => { + return `${signature.index + .toString(16) + .padStart(2, "0")}${signature.signature.toString("hex")}`; + }) + .join(""); + const newSignatureBody = `${version}${guardianSetIndex + .toString(16) + .padStart(8, "0")}${numRepairedSignatures + .toString(16) + .padStart(2, "0")}${repairedSignatures}`; + + const repairedVaa = `${newSignatureBody}${vaaHex.slice( + 12 + numSignatures * 132 + )}`; + return repairedVaa; +} + +/** + * + * Takes in a hexstring representation of a signed vaa and an eth provider. + * Attempts to query eth core contract and retrieve current guardian set. + * Then attempts to repair the vaa. + **/ + +export async function repairVaaWithCurrentGuardianSet( + vaaHex: string, + provider: ethers.providers.JsonRpcProvider +): Promise { + const guardianSetData = await getCurrentGuardianSet(provider); + return repairVaa(vaaHex, guardianSetData); +}