Explorar el Código

Xc admin/add executor (#466)

* Add encoder

* Update test

* Cleanup

* More cleanup

* Add executor

* Update comment

* Update package lock

* Cleanup

* Fix bug and error handling
guibescos hace 2 años
padre
commit
80fe230563

+ 1 - 0
.pre-commit-config.yaml

@@ -5,6 +5,7 @@ repos:
       - id: trailing-whitespace
       - id: end-of-file-fixer
       - id: check-added-large-files
+        exclude: package-lock.json
   # Hook to format many type of files in the repo
   # including solidity contracts.
   - repo: https://github.com/pre-commit/mirrors-prettier

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 113 - 182
xc-admin/package-lock.json


+ 27 - 0
xc-admin/packages/crank-executor/package.json

@@ -0,0 +1,27 @@
+{
+  "name": "crank-executor",
+  "version": "0.0.0",
+  "description": "A crank to executed all executeReady multisig transaction",
+  "author": "",
+  "homepage": "https://github.com/pyth-network/pyth-crosschain",
+  "license": "ISC",
+  "main": "src/index.ts",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/pyth-network/pyth-crosschain.git"
+  },
+  "bugs": {
+    "url": "https://github.com/pyth-network/pyth-crosschain/issues"
+  },
+  "scripts": {
+    "build": "tsc",
+    "format": "prettier --write \"src/**/*.ts\""
+  },
+  "dependencies": {
+    "@coral-xyz/anchor": "^0.26.0",
+    "@pythnetwork/client": "^2.9.0",
+    "@solana/web3.js": "^1.73.0",
+    "@sqds/mesh": "^1.0.6",
+    "ts-node": "^10.9.1"
+  }
+}

+ 80 - 0
xc-admin/packages/crank-executor/src/index.ts

@@ -0,0 +1,80 @@
+import {
+  Commitment,
+  Connection,
+  Keypair,
+  PublicKey,
+  SendTransactionError,
+  Transaction,
+} from "@solana/web3.js";
+import SquadsMesh, { DEFAULT_MULTISIG_PROGRAM_ID, getIxPDA } from "@sqds/mesh";
+import * as fs from "fs";
+import NodeWallet from "@project-serum/anchor/dist/cjs/nodewallet";
+import { getProposals } from "xc-admin-common";
+import BN from "bn.js";
+import { AnchorProvider } from "@project-serum/anchor";
+import {
+  getPythClusterApiUrl,
+  PythCluster,
+} from "@pythnetwork/client/lib/cluster";
+
+export function envOrErr(env: string): string {
+  const val = process.env[env];
+  if (!val) {
+    throw new Error(`environment variable "${env}" must be set`);
+  }
+  return String(process.env[env]);
+}
+
+const CLUSTER: string = envOrErr("CLUSTER");
+const COMMITMENT: Commitment =
+  (process.env.COMMITMENT as Commitment) ?? "confirmed";
+const VAULT: PublicKey = new PublicKey(envOrErr("VAULT"));
+const KEYPAIR: Keypair = Keypair.fromSecretKey(
+  Uint8Array.from(JSON.parse(fs.readFileSync(envOrErr("WALLET"), "ascii")))
+);
+
+async function run() {
+  const squad = new SquadsMesh({
+    connection: new Connection(
+      getPythClusterApiUrl(CLUSTER as PythCluster),
+      COMMITMENT
+    ),
+    wallet: new NodeWallet(KEYPAIR),
+    multisigProgramId: DEFAULT_MULTISIG_PROGRAM_ID,
+  });
+  const proposals = await getProposals(squad, VAULT, undefined, "executeReady");
+  for (const proposal of proposals) {
+    // If we have previously cancelled because the proposal was failing, don't attempt
+    if (proposal.cancelled.length == 0) {
+      for (
+        let i = proposal.executedIndex + 1;
+        i <= proposal.instructionIndex;
+        i++
+      ) {
+        const transaction = new Transaction().add(
+          await squad.buildExecuteInstruction(
+            proposal.publicKey,
+            getIxPDA(proposal.publicKey, new BN(i), squad.multisigProgramId)[0]
+          )
+        );
+
+        try {
+          await new AnchorProvider(squad.connection, squad.wallet, {
+            commitment: COMMITMENT,
+            preflightCommitment: COMMITMENT,
+          }).sendAndConfirm(transaction, []);
+        } catch (error) {
+          // Mark the transaction as cancelled if we failed to run it
+          if (error instanceof SendTransactionError) {
+            await squad.cancelTransaction(proposal.publicKey);
+          }
+          break;
+        }
+      }
+    }
+  }
+}
+
+(async () => {
+  await run();
+})();

+ 16 - 0
xc-admin/packages/crank-executor/tsconfig.json

@@ -0,0 +1,16 @@
+{
+  "compilerOptions": {
+    "declaration": true,
+    "target": "es2016",
+    "module": "commonjs",
+    "outDir": "lib",
+    "esModuleInterop": true,
+    "forceConsistentCasingInFileNames": true,
+    "strict": true,
+    "skipLibCheck": true,
+    "resolveJsonModule": true,
+    "noErrorTruncation": true
+  },
+  "include": ["src/**/*.ts"],
+  "exclude": ["src/__tests__/"]
+}

+ 8 - 4
xc-admin/packages/xc-admin-common/src/multisig.ts

@@ -9,16 +9,18 @@ import BN from "bn.js";
 import lodash from "lodash";
 
 /**
- * Find all active proposals for vault `vault` using Squads client `squad`
+ * Find all proposals for vault `vault` using Squads client `squad`
  * @param squad Squads client
  * @param vault vault public key. It needs to exist in the instance of squads that `squad` is targeting
  * @param offset (optional) ignore all proposals with `proposal_index < offset`
+ * @param state filter by status
  * @returns All the proposal accounts as `TransactionAccount`
  */
-export async function getActiveProposals(
+export async function getProposals(
   squad: Squads,
   vault: PublicKey,
-  offset: number = 1
+  offset: number = 1,
+  state: "active" | "executeReady" | "executed" | "all" = "all"
 ): Promise<TransactionAccount[]> {
   const msAccount = await squad.getMultisig(vault);
   let txKeys = lodash
@@ -29,7 +31,9 @@ export async function getActiveProposals(
     .filter(
       (x: TransactionAccount | null): x is TransactionAccount => x != null
     )
-    .filter((x) => lodash.isEqual(x.status, { active: {} }));
+    .filter((x) =>
+      state === "all" ? true : lodash.isEqual(x.status, { [state]: {} })
+    );
 }
 
 /**

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio