testlib.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. /**
  2. *
  3. * Copyright 2022 Wormhole Project Contributors
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. import {
  19. ChainId,
  20. CHAIN_ID_AVAX,
  21. CHAIN_ID_BSC,
  22. CHAIN_ID_ETH,
  23. CHAIN_ID_FANTOM,
  24. CHAIN_ID_OASIS,
  25. CHAIN_ID_POLYGON,
  26. CHAIN_ID_SOLANA,
  27. CHAIN_ID_TERRA,
  28. } from "@certusone/wormhole-sdk";
  29. const web3EthAbi = require("web3-eth-abi");
  30. const web3Utils = require("web3-utils");
  31. const elliptic = require("elliptic");
  32. export class TestLib {
  33. zeroBytes: string;
  34. singleGuardianKey: string[] = ["beFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe"];
  35. singleGuardianPrivKey: string[] = [
  36. "cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0",
  37. ];
  38. constructor() {
  39. this.zeroBytes =
  40. "0000000000000000000000000000000000000000000000000000000000000000";
  41. }
  42. hexStringToUint8Array(hs: string): Uint8Array {
  43. if (hs.length % 2 === 1) {
  44. // prepend a 0
  45. hs = "0" + hs;
  46. }
  47. const buf = Buffer.from(hs, "hex");
  48. const retval = Uint8Array.from(buf);
  49. return retval;
  50. }
  51. uint8ArrayToHexString(arr: Uint8Array, add0x: boolean) {
  52. const ret: string = Buffer.from(arr).toString("hex");
  53. if (!add0x) {
  54. return ret;
  55. }
  56. return "0x" + ret;
  57. }
  58. guardianKeys: string[] = [
  59. "52A26Ce40F8CAa8D36155d37ef0D5D783fc614d2",
  60. "389A74E8FFa224aeAD0778c786163a7A2150768C",
  61. "B4459EA6482D4aE574305B239B4f2264239e7599",
  62. "072491bd66F63356090C11Aae8114F5372aBf12B",
  63. "51280eA1fd2B0A1c76Ae29a7d54dda68860A2bfF",
  64. "fa9Aa60CfF05e20E2CcAA784eE89A0A16C2057CB",
  65. "e42d59F8FCd86a1c5c4bA351bD251A5c5B05DF6A",
  66. "4B07fF9D5cE1A6ed58b6e9e7d6974d1baBEc087e",
  67. "c8306B84235D7b0478c61783C50F990bfC44cFc0",
  68. "C8C1035110a13fe788259A4148F871b52bAbcb1B",
  69. "58A2508A20A7198E131503ce26bBE119aA8c62b2",
  70. "8390820f04ddA22AFe03be1c3bb10f4ba6CF94A0",
  71. "1FD6e97387C34a1F36DE0f8341E9D409E06ec45b",
  72. "255a41fC2792209CB998A8287204D40996df9E54",
  73. "bA663B12DD23fbF4FbAC618Be140727986B3BBd0",
  74. "79040E577aC50486d0F6930e160A5C75FD1203C6",
  75. "3580D2F00309A9A85efFAf02564Fc183C0183A96",
  76. "3869795913D3B6dBF3B24a1C7654672c69A23c35",
  77. "1c0Cc52D7673c52DE99785741344662F5b2308a0",
  78. ];
  79. guardianPrivKeys: string[] = [
  80. "563d8d2fd4e701901d3846dee7ae7a92c18f1975195264d676f8407ac5976757",
  81. "8d97f25916a755df1d9ef74eb4dbebc5f868cb07830527731e94478cdc2b9d5f",
  82. "9bd728ad7617c05c31382053b57658d4a8125684c0098f740a054d87ddc0e93b",
  83. "5a02c4cd110d20a83a7ce8d1a2b2ae5df252b4e5f6781c7855db5cc28ed2d1b4",
  84. "93d4e3b443bf11f99a00901222c032bd5f63cf73fc1bcfa40829824d121be9b2",
  85. "ea40e40c63c6ff155230da64a2c44fcd1f1c9e50cacb752c230f77771ce1d856",
  86. "87eaabe9c27a82198e618bca20f48f9679c0f239948dbd094005e262da33fe6a",
  87. "61ffed2bff38648a6d36d6ed560b741b1ca53d45391441124f27e1e48ca04770",
  88. "bd12a242c6da318fef8f98002efb98efbf434218a78730a197d981bebaee826e",
  89. "20d3597bb16525b6d09e5fb56feb91b053d961ab156f4807e37d980f50e71aff",
  90. "344b313ffbc0199ff6ca08cacdaf5dc1d85221e2f2dc156a84245bd49b981673",
  91. "848b93264edd3f1a521274ca4da4632989eb5303fd15b14e5ec6bcaa91172b05",
  92. "c6f2046c1e6c172497fc23bd362104e2f4460d0f61984938fa16ef43f27d93f6",
  93. "693b256b1ee6b6fb353ba23274280e7166ab3be8c23c203cc76d716ba4bc32bf",
  94. "13c41508c0da03018d61427910b9922345ced25e2bbce50652e939ee6e5ea56d",
  95. "460ee0ee403be7a4f1eb1c63dd1edaa815fbaa6cf0cf2344dcba4a8acf9aca74",
  96. "b25148579b99b18c8994b0b86e4dd586975a78fa6e7ad6ec89478d7fbafd2683",
  97. "90d7ac6a82166c908b8cf1b352f3c9340a8d1f2907d7146fb7cd6354a5436cca",
  98. "b71d23908e4cf5d6cd973394f3a4b6b164eb1065785feee612efdfd8d30005ed",
  99. ];
  100. encoder(type: string, val: any) {
  101. if (type == "uint8")
  102. return web3EthAbi.encodeParameter("uint8", val).substring(2 + (64 - 2));
  103. if (type == "uint16")
  104. return web3EthAbi.encodeParameter("uint16", val).substring(2 + (64 - 4));
  105. if (type == "uint32")
  106. return web3EthAbi.encodeParameter("uint32", val).substring(2 + (64 - 8));
  107. if (type == "uint64")
  108. return web3EthAbi.encodeParameter("uint64", val).substring(2 + (64 - 16));
  109. if (type == "uint128")
  110. return web3EthAbi
  111. .encodeParameter("uint128", val)
  112. .substring(2 + (64 - 32));
  113. if (type == "uint256" || type == "bytes32")
  114. return web3EthAbi.encodeParameter(type, val).substring(2 + (64 - 64));
  115. }
  116. ord(c: any) {
  117. return c.charCodeAt(0);
  118. }
  119. genGuardianSetUpgrade(
  120. signers: any,
  121. guardianSet: number,
  122. targetSet: number,
  123. nonce: number,
  124. seq: number,
  125. guardianKeys: string[]
  126. ): string {
  127. const b = [
  128. "0x",
  129. this.zeroBytes.slice(0, 28 * 2),
  130. this.encoder("uint8", this.ord("C")),
  131. this.encoder("uint8", this.ord("o")),
  132. this.encoder("uint8", this.ord("r")),
  133. this.encoder("uint8", this.ord("e")),
  134. this.encoder("uint8", 2),
  135. this.encoder("uint16", 0),
  136. this.encoder("uint32", targetSet),
  137. this.encoder("uint8", guardianKeys.length),
  138. ];
  139. guardianKeys.forEach((x) => {
  140. b.push(x);
  141. });
  142. let emitter = "0x" + this.zeroBytes.slice(0, 31 * 2) + "04";
  143. let seconds = Math.floor(new Date().getTime() / 1000.0);
  144. return this.createSignedVAA(
  145. guardianSet,
  146. signers,
  147. seconds,
  148. nonce,
  149. 1,
  150. emitter,
  151. seq,
  152. 32,
  153. b.join("")
  154. );
  155. }
  156. genGSetFee(
  157. signers: any,
  158. guardianSet: number,
  159. nonce: number,
  160. seq: number,
  161. amt: number
  162. ) {
  163. const b = [
  164. "0x",
  165. this.zeroBytes.slice(0, 28 * 2),
  166. this.encoder("uint8", this.ord("C")),
  167. this.encoder("uint8", this.ord("o")),
  168. this.encoder("uint8", this.ord("r")),
  169. this.encoder("uint8", this.ord("e")),
  170. this.encoder("uint8", 3),
  171. this.encoder("uint16", 8),
  172. this.encoder("uint256", Math.floor(amt)),
  173. ];
  174. let emitter = "0x" + this.zeroBytes.slice(0, 31 * 2) + "04";
  175. var seconds = Math.floor(new Date().getTime() / 1000.0);
  176. return this.createSignedVAA(
  177. guardianSet,
  178. signers,
  179. seconds,
  180. nonce,
  181. 1,
  182. emitter,
  183. seq,
  184. 32,
  185. b.join("")
  186. );
  187. }
  188. genGFeePayout(
  189. signers: any,
  190. guardianSet: number,
  191. nonce: number,
  192. seq: number,
  193. amt: number,
  194. dest: Uint8Array
  195. ) {
  196. const b = [
  197. "0x",
  198. this.zeroBytes.slice(0, 28 * 2),
  199. this.encoder("uint8", this.ord("C")),
  200. this.encoder("uint8", this.ord("o")),
  201. this.encoder("uint8", this.ord("r")),
  202. this.encoder("uint8", this.ord("e")),
  203. this.encoder("uint8", 4),
  204. this.encoder("uint16", 8),
  205. this.encoder("uint256", Math.floor(amt)),
  206. this.uint8ArrayToHexString(dest, false),
  207. ];
  208. let emitter = "0x" + this.zeroBytes.slice(0, 31 * 2) + "04";
  209. var seconds = Math.floor(new Date().getTime() / 1000.0);
  210. return this.createSignedVAA(
  211. guardianSet,
  212. signers,
  213. seconds,
  214. nonce,
  215. 1,
  216. emitter,
  217. seq,
  218. 32,
  219. b.join("")
  220. );
  221. }
  222. getTokenEmitter(chain: number): string {
  223. if (chain === CHAIN_ID_SOLANA) {
  224. return "c69a1b1a65dd336bf1df6a77afb501fc25db7fc0938cb08595a9ef473265cb4f";
  225. }
  226. if (chain === CHAIN_ID_ETH) {
  227. return "0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16";
  228. }
  229. if (chain === CHAIN_ID_TERRA) {
  230. return "000000000000000000000000784999135aaa8a3ca5914468852fdddbddd8789d";
  231. }
  232. if (chain === CHAIN_ID_BSC) {
  233. return "0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16";
  234. }
  235. if (chain === CHAIN_ID_POLYGON) {
  236. return "0000000000000000000000005a58505a96d1dbf8df91cb21b54419fc36e93fde";
  237. }
  238. if (chain === CHAIN_ID_AVAX) {
  239. return "0000000000000000000000000e082f06ff657d94310cb8ce8b0d9a04541d8052";
  240. }
  241. if (chain === CHAIN_ID_OASIS) {
  242. return "0000000000000000000000005848c791e09901b40a9ef749f2a6735b418d7564";
  243. }
  244. if (chain === CHAIN_ID_FANTOM) {
  245. return "0000000000000000000000007C9Fc5741288cDFdD83CeB07f3ea7e22618D79D2";
  246. }
  247. return "";
  248. }
  249. getNftEmitter(chain: ChainId): string {
  250. if (chain === CHAIN_ID_SOLANA) {
  251. return "0def15a24423e1edd1a5ab16f557b9060303ddbab8c803d2ee48f4b78a1cfd6b";
  252. }
  253. if (chain === CHAIN_ID_ETH) {
  254. return "0000000000000000000000006ffd7ede62328b3af38fcd61461bbfc52f5651fe";
  255. }
  256. if (chain === CHAIN_ID_BSC) {
  257. return "0000000000000000000000005a58505a96d1dbf8df91cb21b54419fc36e93fde";
  258. }
  259. if (chain === CHAIN_ID_POLYGON) {
  260. return "00000000000000000000000090bbd86a6fe93d3bc3ed6335935447e75fab7fcf";
  261. }
  262. if (chain === CHAIN_ID_AVAX) {
  263. return "000000000000000000000000f7b6737ca9c4e08ae573f75a97b73d7a813f5de5";
  264. }
  265. if (chain === CHAIN_ID_OASIS) {
  266. return "00000000000000000000000004952D522Ff217f40B5Ef3cbF659EcA7b952a6c1";
  267. }
  268. if (chain === CHAIN_ID_FANTOM) {
  269. return "000000000000000000000000A9c7119aBDa80d4a4E0C06C8F4d8cF5893234535";
  270. }
  271. return "";
  272. }
  273. genRegisterChain(
  274. signers: any,
  275. guardianSet: number,
  276. nonce: number,
  277. seq: number,
  278. chain: string
  279. ) {
  280. const b = [
  281. "0x",
  282. this.zeroBytes.slice(0, (32 - 11) * 2),
  283. this.encoder("uint8", this.ord("T")),
  284. this.encoder("uint8", this.ord("o")),
  285. this.encoder("uint8", this.ord("k")),
  286. this.encoder("uint8", this.ord("e")),
  287. this.encoder("uint8", this.ord("n")),
  288. this.encoder("uint8", this.ord("B")),
  289. this.encoder("uint8", this.ord("r")),
  290. this.encoder("uint8", this.ord("i")),
  291. this.encoder("uint8", this.ord("d")),
  292. this.encoder("uint8", this.ord("g")),
  293. this.encoder("uint8", this.ord("e")),
  294. this.encoder("uint8", 1),
  295. this.encoder("uint16", 0),
  296. this.encoder("uint16", chain),
  297. this.getTokenEmitter(parseInt(chain)),
  298. ];
  299. let emitter = "0x" + this.zeroBytes.slice(0, 31 * 2) + "04";
  300. var seconds = Math.floor(new Date().getTime() / 1000.0);
  301. return this.createSignedVAA(
  302. guardianSet,
  303. signers,
  304. seconds,
  305. nonce,
  306. 1,
  307. emitter,
  308. seq,
  309. 32,
  310. b.join("")
  311. );
  312. }
  313. genAssetMeta(
  314. signers: any,
  315. guardianSet: number,
  316. nonce: number,
  317. seq: number,
  318. tokenAddress: string,
  319. chain: number,
  320. decimals: number,
  321. symbol: string,
  322. name: string
  323. ) {
  324. const b = [
  325. "0x",
  326. this.encoder("uint8", 2),
  327. this.zeroBytes.slice(0, 64 - tokenAddress.length),
  328. tokenAddress,
  329. this.encoder("uint16", chain),
  330. this.encoder("uint8", decimals),
  331. Buffer.from(symbol).toString("hex"),
  332. this.zeroBytes.slice(0, (32 - symbol.length) * 2),
  333. Buffer.from(name).toString("hex"),
  334. this.zeroBytes.slice(0, (32 - name.length) * 2),
  335. ];
  336. // console.log(b.join())
  337. // console.log(b.join('').length)
  338. let emitter = "0x" + this.getTokenEmitter(chain);
  339. let seconds = Math.floor(new Date().getTime() / 1000.0);
  340. return this.createSignedVAA(
  341. guardianSet,
  342. signers,
  343. seconds,
  344. nonce,
  345. chain,
  346. emitter,
  347. seq,
  348. 32,
  349. b.join("")
  350. );
  351. }
  352. genTransfer(
  353. signers: any,
  354. guardianSet: number,
  355. nonce: number,
  356. seq: number,
  357. amount: number,
  358. tokenAddress: string,
  359. tokenChain: number,
  360. toAddress: string,
  361. toChain: number,
  362. fee: number
  363. ) {
  364. const b = [
  365. "0x",
  366. this.encoder("uint8", 1),
  367. this.encoder("uint256", Math.floor(amount * 100000000)),
  368. this.zeroBytes.slice(0, 64 - tokenAddress.length),
  369. tokenAddress,
  370. this.encoder("uint16", tokenChain),
  371. this.zeroBytes.slice(0, 64 - toAddress.length),
  372. toAddress,
  373. this.encoder("uint16", toChain),
  374. this.encoder("uint256", Math.floor(fee * 100000000)),
  375. ];
  376. let emitter = "0x" + this.getTokenEmitter(tokenChain);
  377. let seconds = Math.floor(new Date().getTime() / 1000.0);
  378. return this.createSignedVAA(
  379. guardianSet,
  380. signers,
  381. seconds,
  382. nonce,
  383. tokenChain,
  384. emitter,
  385. seq,
  386. 32,
  387. b.join("")
  388. );
  389. }
  390. /**
  391. * Create a packed and signed VAA for testing.
  392. * See https://github.com/wormhole-foundation/wormhole/blob/main/design/0001_generic_message_passing.md
  393. *
  394. * @param {} guardianSetIndex The guardian set index
  395. * @param {*} signers The list of private keys for signing the VAA
  396. * @param {*} timestamp The timestamp of VAA
  397. * @param {*} nonce The nonce.
  398. * @param {*} emitterChainId The emitter chain identifier
  399. * @param {*} emitterAddress The emitter chain address, prefixed with 0x
  400. * @param {*} sequence The sequence.
  401. * @param {*} consistencyLevel The reported consistency level
  402. * @param {*} payload This VAA Payload hex string, prefixed with 0x
  403. */
  404. createSignedVAA(
  405. guardianSetIndex: number,
  406. signers: any,
  407. timestamp: number,
  408. nonce: number,
  409. emitterChainId: number,
  410. emitterAddress: string,
  411. sequence: number,
  412. consistencyLevel: number,
  413. payload: string
  414. ) {
  415. console.log(typeof payload);
  416. const body = [
  417. this.encoder("uint32", timestamp),
  418. this.encoder("uint32", nonce),
  419. this.encoder("uint16", emitterChainId),
  420. this.encoder("bytes32", emitterAddress),
  421. this.encoder("uint64", sequence),
  422. this.encoder("uint8", consistencyLevel),
  423. payload.substring(2),
  424. ];
  425. const hash = web3Utils.keccak256(web3Utils.keccak256("0x" + body.join("")));
  426. let signatures = "";
  427. for (const i in signers) {
  428. // eslint-disable-next-line new-cap
  429. const ec = new elliptic.ec("secp256k1");
  430. const key = ec.keyFromPrivate(signers[i]);
  431. const signature = key.sign(hash.substr(2), { canonical: true });
  432. const packSig = [
  433. this.encoder("uint8", i),
  434. this.zeroPadBytes(signature.r.toString(16), 32),
  435. this.zeroPadBytes(signature.s.toString(16), 32),
  436. this.encoder("uint8", signature.recoveryParam),
  437. ];
  438. signatures += packSig.join("");
  439. }
  440. const vm = [
  441. this.encoder("uint8", 1),
  442. this.encoder("uint32", guardianSetIndex),
  443. this.encoder("uint8", signers.length),
  444. signatures,
  445. body.join(""),
  446. ].join("");
  447. return vm;
  448. }
  449. zeroPadBytes(value: string, length: number) {
  450. while (value.length < 2 * length) {
  451. value = "0" + value;
  452. }
  453. return value;
  454. }
  455. }
  456. module.exports = {
  457. TestLib,
  458. };