-
Notifications
You must be signed in to change notification settings - Fork 731
/
Copy pathrepairVaa.ts
115 lines (103 loc) · 3.56 KB
/
repairVaa.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
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<GuardianSetData> {
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<string> {
const guardianSetData = await getCurrentGuardianSet(provider);
return repairVaa(vaaHex, guardianSetData);
}