From 6c9a24d6895c160b926fddc3999a31ff1cf53a48 Mon Sep 17 00:00:00 2001 From: Daniel Chew Date: Tue, 14 Jan 2025 13:50:50 +0900 Subject: [PATCH 1/8] export lazer program id --- lazer/sdk/js/src/constants.ts | 5 +++++ lazer/sdk/js/src/index.ts | 1 + 2 files changed, 6 insertions(+) create mode 100644 lazer/sdk/js/src/constants.ts diff --git a/lazer/sdk/js/src/constants.ts b/lazer/sdk/js/src/constants.ts new file mode 100644 index 000000000..28a1c1ede --- /dev/null +++ b/lazer/sdk/js/src/constants.ts @@ -0,0 +1,5 @@ +import { PublicKey } from "@solana/web3.js"; + +export const LAZER_PROGRAM_ID = new PublicKey( + "pytd2yyk641x7ak7mkaasSJVXh6YYZnC7wTmtgAyxPt" +); diff --git a/lazer/sdk/js/src/index.ts b/lazer/sdk/js/src/index.ts index 22ea1d2ab..15504200d 100644 --- a/lazer/sdk/js/src/index.ts +++ b/lazer/sdk/js/src/index.ts @@ -1,3 +1,4 @@ export * from "./client.js"; export * from "./protocol.js"; export * from "./ed25519.js"; +export * from "./constants.js"; From 230f73cbc973ea37902a2ae4ec959cf9f1c71bfc Mon Sep 17 00:00:00 2001 From: Daniel Chew Date: Tue, 14 Jan 2025 13:51:40 +0900 Subject: [PATCH 2/8] bump --- lazer/sdk/js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lazer/sdk/js/package.json b/lazer/sdk/js/package.json index 2b975af96..29a76a74c 100644 --- a/lazer/sdk/js/package.json +++ b/lazer/sdk/js/package.json @@ -1,6 +1,6 @@ { "name": "@pythnetwork/pyth-lazer-sdk", - "version": "0.2.0", + "version": "0.2.1", "description": "Pyth Lazer SDK", "publishConfig": { "access": "public" From 9d08d79aed48bc727610139d0be50f0fbf70e80b Mon Sep 17 00:00:00 2001 From: Daniel Chew Date: Tue, 14 Jan 2025 14:16:45 +0900 Subject: [PATCH 3/8] export storage id --- lazer/sdk/js/src/constants.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lazer/sdk/js/src/constants.ts b/lazer/sdk/js/src/constants.ts index 28a1c1ede..d69dbc814 100644 --- a/lazer/sdk/js/src/constants.ts +++ b/lazer/sdk/js/src/constants.ts @@ -3,3 +3,6 @@ import { PublicKey } from "@solana/web3.js"; export const LAZER_PROGRAM_ID = new PublicKey( "pytd2yyk641x7ak7mkaasSJVXh6YYZnC7wTmtgAyxPt" ); +export const STORAGE_ID = new PublicKey( + "3rdJbqfnagQ4yx9HXJViD4zc4xpiSqmFsKpPuSCQVyQL" +); From 5e08204a341041c44d8497a418d1d552de4c8c45 Mon Sep 17 00:00:00 2001 From: Daniel Chew Date: Tue, 14 Jan 2025 14:22:45 +0900 Subject: [PATCH 4/8] add set-trusted-signer proposal instruction --- .../packages/xc_admin_cli/package.json | 1 + .../packages/xc_admin_cli/src/index.ts | 54 ++++++++++++++++++- .../packages/xc_admin_common/package.json | 1 + .../LazerMultisigInstruction.ts | 4 -- .../src/multisig_transaction/index.ts | 6 +-- pnpm-lock.yaml | 6 +++ 6 files changed, 63 insertions(+), 9 deletions(-) diff --git a/governance/xc_admin/packages/xc_admin_cli/package.json b/governance/xc_admin/packages/xc_admin_cli/package.json index 11b1dd125..f6df93ad8 100644 --- a/governance/xc_admin/packages/xc_admin_cli/package.json +++ b/governance/xc_admin/packages/xc_admin_cli/package.json @@ -27,6 +27,7 @@ "@pythnetwork/pyth-solana-receiver": "workspace:*", "@pythnetwork/solana-utils": "workspace:^", "@pythnetwork/xc-admin-common": "workspace:*", + "@pythnetwork/pyth-lazer-sdk": "workspace:*", "@solana/spl-token": "^0.3.7", "@solana/web3.js": "^1.73.0", "@sqds/mesh": "^1.0.6", diff --git a/governance/xc_admin/packages/xc_admin_cli/src/index.ts b/governance/xc_admin/packages/xc_admin_cli/src/index.ts index cc1efbd2f..c304ae071 100644 --- a/governance/xc_admin/packages/xc_admin_cli/src/index.ts +++ b/governance/xc_admin/packages/xc_admin_cli/src/index.ts @@ -1,4 +1,4 @@ -import { Program } from "@coral-xyz/anchor"; +import { Program, BN } from "@coral-xyz/anchor"; import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet"; import { Wallet } from "@coral-xyz/anchor/dist/cjs/provider"; import { TOKEN_PROGRAM_ID } from "@coral-xyz/anchor/dist/cjs/utils/token"; @@ -54,6 +54,7 @@ import { getConfigPda, DEFAULT_RECEIVER_PROGRAM_ID, } from "@pythnetwork/pyth-solana-receiver"; +import { LAZER_PROGRAM_ID, STORAGE_ID } from "@pythnetwork/pyth-lazer-sdk"; import { LedgerNodeWallet } from "./ledger"; import { @@ -924,4 +925,55 @@ multisigCommand("execute-add-and-delete", "Execute a roster change proposal") await vault.squad.executeTransaction(proposal); }); +multisigCommand( + "set-trusted-signer", + "Set a trusted signer for the Lazer program" +) + .requiredOption( + "-s, --signer ", + "public key of the trusted signer to add/update" + ) + .requiredOption( + "-e, --expiry-time ", + "expiry time in seconds since Unix epoch. Set to 0 to remove the signer." + ) + .action(async (options: any) => { + const vault = await loadVaultFromOptions(options); + const targetCluster: PythCluster = options.cluster; + + const trustedSigner = new PublicKey(options.signer); + const expiryTime = new BN(options.expiryTime); + + // Create the update instruction + const updateInstruction = new TransactionInstruction({ + programId: LAZER_PROGRAM_ID, + keys: [ + { + pubkey: await vault.getVaultAuthorityPDA(targetCluster), + isSigner: false, + isWritable: false, + }, + { + pubkey: STORAGE_ID, + isSigner: false, + isWritable: true, + }, + ], + data: Buffer.concat([ + // Anchor discriminator for "update" + Buffer.from([219, 200, 88, 176, 158, 63, 253, 127]), + // Trusted signer pubkey + trustedSigner.toBuffer(), + // Expiry time (i64) + Buffer.from(expiryTime.toArray("le", 8)), + ]), + }); + + await vault.proposeInstructions( + [updateInstruction], + targetCluster, + DEFAULT_PRIORITY_FEE_CONFIG + ); + }); + program.parse(); diff --git a/governance/xc_admin/packages/xc_admin_common/package.json b/governance/xc_admin/packages/xc_admin_common/package.json index faf5458fd..ae53311ba 100644 --- a/governance/xc_admin/packages/xc_admin_common/package.json +++ b/governance/xc_admin/packages/xc_admin_common/package.json @@ -40,6 +40,7 @@ "ethers": "^5.7.2", "lodash": "^4.17.21", "message_buffer": "workspace:^", + "@pythnetwork/pyth-lazer-sdk": "workspace:*", "typescript": "^4.9.4" }, "devDependencies": { diff --git a/governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/LazerMultisigInstruction.ts b/governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/LazerMultisigInstruction.ts index 29a2758d4..7787c3fd4 100644 --- a/governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/LazerMultisigInstruction.ts +++ b/governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/LazerMultisigInstruction.ts @@ -8,10 +8,6 @@ import { PublicKey, TransactionInstruction } from "@solana/web3.js"; import { Idl, BorshInstructionCoder } from "@coral-xyz/anchor"; import lazerIdl from "./idl/lazer.json"; -export const LAZER_PROGRAM_ID = new PublicKey( - "pytd2yyk641x7ak7mkaasSJVXh6YYZnC7wTmtgAyxPt" -); - export class LazerMultisigInstruction implements MultisigInstruction { readonly program = MultisigInstructionProgram.Lazer; readonly name: string; diff --git a/governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/index.ts b/governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/index.ts index 52fc7287d..1e3efb1b9 100644 --- a/governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/index.ts +++ b/governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/index.ts @@ -27,10 +27,8 @@ import { PRICE_STORE_PROGRAM_ID, PriceStoreMultisigInstruction, } from "../price_store"; -import { - LazerMultisigInstruction, - LAZER_PROGRAM_ID, -} from "./LazerMultisigInstruction"; +import { LazerMultisigInstruction } from "./LazerMultisigInstruction"; +import { LAZER_PROGRAM_ID } from "@pythnetwork/pyth-lazer-sdk"; export const UNRECOGNIZED_INSTRUCTION = "unrecognizedInstruction"; export enum MultisigInstructionProgram { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 83abc8106..33c7cd337 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1249,6 +1249,9 @@ importers: '@pythnetwork/client': specifier: ^2.22.0 version: 2.22.0(@solana/web3.js@1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10) + '@pythnetwork/pyth-lazer-sdk': + specifier: workspace:* + version: link:../../../../lazer/sdk/js '@pythnetwork/pyth-solana-receiver': specifier: workspace:* version: link:../../../../target_chains/solana/sdk/js/pyth_solana_receiver @@ -1291,6 +1294,9 @@ importers: '@pythnetwork/client': specifier: ^2.22.0 version: 2.22.0(@solana/web3.js@1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10) + '@pythnetwork/pyth-lazer-sdk': + specifier: workspace:* + version: link:../../../../lazer/sdk/js '@pythnetwork/pyth-solana-receiver': specifier: workspace:* version: link:../../../../target_chains/solana/sdk/js/pyth_solana_receiver From 288268ae5518402dd63926a09d31c48f760c208f Mon Sep 17 00:00:00 2001 From: Daniel Chew Date: Tue, 14 Jan 2025 21:35:44 +0900 Subject: [PATCH 5/8] add script to check trusted signer --- lazer/contracts/solana/package.json | 3 +- .../solana/scripts/check_trusted_signer.ts | 68 +++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 lazer/contracts/solana/scripts/check_trusted_signer.ts diff --git a/lazer/contracts/solana/package.json b/lazer/contracts/solana/package.json index cb52148d7..095e0619b 100644 --- a/lazer/contracts/solana/package.json +++ b/lazer/contracts/solana/package.json @@ -8,7 +8,8 @@ "test:anchor": "CARGO_TARGET_DIR=\"$PWD/target\" anchor test", "test": "pnpm run test:format && pnpm run test:anchor", "setup": "anchor build && pnpm ts-node scripts/setup.ts", - "migrate_from_0_1_0": "pnpm ts-node scripts/migrate_from_0_1_0.ts" + "migrate_from_0_1_0": "pnpm ts-node scripts/migrate_from_0_1_0.ts", + "check_trusted_signer": "pnpm ts-node scripts/check_trusted_signer.ts" }, "dependencies": { "@coral-xyz/anchor": "^0.30.1" diff --git a/lazer/contracts/solana/scripts/check_trusted_signer.ts b/lazer/contracts/solana/scripts/check_trusted_signer.ts new file mode 100644 index 000000000..8dac4ed2c --- /dev/null +++ b/lazer/contracts/solana/scripts/check_trusted_signer.ts @@ -0,0 +1,68 @@ +import * as anchor from "@coral-xyz/anchor"; +import { PythLazerSolanaContract } from "../target/types/pyth_lazer_solana_contract"; +import * as pythLazerSolanaContractIdl from "../target/idl/pyth_lazer_solana_contract.json"; +import yargs from "yargs/yargs"; +import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet"; + +const parser = yargs(process.argv.slice(2)).options({ + url: { + type: "string", + demandOption: true, + desc: "RPC URL to use", + }, + "storage-id": { + type: "string", + demandOption: true, + desc: "Storage account ID to check", + }, +}); + +async function main() { + const argv = await parser.argv; + + // Setup anchor provider + const connection = new anchor.web3.Connection(argv.url); + const provider = new anchor.AnchorProvider( + connection, + new NodeWallet(anchor.web3.Keypair.generate()), // Dummy wallet since we're only reading + { commitment: "confirmed" } + ); + anchor.setProvider(provider); + + const program: anchor.Program = new anchor.Program( + pythLazerSolanaContractIdl as PythLazerSolanaContract, + provider + ); + + // Fetch and decode storage account + const storageId = new anchor.web3.PublicKey(argv["storage-id"]); + const storage = await program.account.storage.fetch(storageId); + + // Print storage info + console.log("Storage Account Info:"); + console.log("--------------------"); + console.log("Top Authority:", storage.topAuthority.toBase58()); + console.log("Treasury:", storage.treasury.toBase58()); + console.log("\nTrusted Signers:"); + console.log("----------------"); + + for (const signer of storage.trustedSigners) { + if (signer.pubkey.equals(anchor.web3.PublicKey.default)) continue; + console.log(`\nPublic Key: ${signer.pubkey.toBase58()}`); + console.log( + `Expires At: ${new Date( + signer.expiresAt.toNumber() * 1000 + ).toISOString()}` + ); + console.log( + `Active: ${ + signer.expiresAt.toNumber() > Date.now() / 1000 ? "Yes" : "No" + }` + ); + } +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); From 71de85d921df7db48d8a2b4c5c3c82d9bdaa5e1c Mon Sep 17 00:00:00 2001 From: Daniel Chew Date: Tue, 14 Jan 2025 22:18:08 +0900 Subject: [PATCH 6/8] fix constants --- governance/xc_admin/packages/xc_admin_cli/src/index.ts | 9 ++++++--- .../xc_admin_common/src/multisig_transaction/index.ts | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/governance/xc_admin/packages/xc_admin_cli/src/index.ts b/governance/xc_admin/packages/xc_admin_cli/src/index.ts index c304ae071..c4feeb765 100644 --- a/governance/xc_admin/packages/xc_admin_cli/src/index.ts +++ b/governance/xc_admin/packages/xc_admin_cli/src/index.ts @@ -54,7 +54,10 @@ import { getConfigPda, DEFAULT_RECEIVER_PROGRAM_ID, } from "@pythnetwork/pyth-solana-receiver"; -import { LAZER_PROGRAM_ID, STORAGE_ID } from "@pythnetwork/pyth-lazer-sdk"; +import { + SOLANA_LAZER_PROGRAM_ID, + SOLANA_STORAGE_ID, +} from "@pythnetwork/pyth-lazer-sdk"; import { LedgerNodeWallet } from "./ledger"; import { @@ -946,7 +949,7 @@ multisigCommand( // Create the update instruction const updateInstruction = new TransactionInstruction({ - programId: LAZER_PROGRAM_ID, + programId: SOLANA_LAZER_PROGRAM_ID, keys: [ { pubkey: await vault.getVaultAuthorityPDA(targetCluster), @@ -954,7 +957,7 @@ multisigCommand( isWritable: false, }, { - pubkey: STORAGE_ID, + pubkey: SOLANA_STORAGE_ID, isSigner: false, isWritable: true, }, diff --git a/governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/index.ts b/governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/index.ts index 1e3efb1b9..4b7159ea2 100644 --- a/governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/index.ts +++ b/governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/index.ts @@ -28,7 +28,7 @@ import { PriceStoreMultisigInstruction, } from "../price_store"; import { LazerMultisigInstruction } from "./LazerMultisigInstruction"; -import { LAZER_PROGRAM_ID } from "@pythnetwork/pyth-lazer-sdk"; +import { SOLANA_LAZER_PROGRAM_ID } from "@pythnetwork/pyth-lazer-sdk"; export const UNRECOGNIZED_INSTRUCTION = "unrecognizedInstruction"; export enum MultisigInstructionProgram { @@ -166,7 +166,7 @@ export class MultisigParser { return SolanaStakingMultisigInstruction.fromTransactionInstruction( instruction ); - } else if (instruction.programId.equals(LAZER_PROGRAM_ID)) { + } else if (instruction.programId.equals(SOLANA_LAZER_PROGRAM_ID)) { return LazerMultisigInstruction.fromInstruction(instruction); } else { return UnrecognizedProgram.fromTransactionInstruction(instruction); From 6edb6b6933ed0839390847a65190bed5b9e6c7ed Mon Sep 17 00:00:00 2001 From: Daniel Chew Date: Tue, 14 Jan 2025 22:22:37 +0900 Subject: [PATCH 7/8] use anchor --- .../packages/xc_admin_cli/src/index.ts | 42 ++++++++----------- .../packages/xc_admin_common/src/index.ts | 1 + 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/governance/xc_admin/packages/xc_admin_cli/src/index.ts b/governance/xc_admin/packages/xc_admin_cli/src/index.ts index c4feeb765..69a4768e0 100644 --- a/governance/xc_admin/packages/xc_admin_cli/src/index.ts +++ b/governance/xc_admin/packages/xc_admin_cli/src/index.ts @@ -1,4 +1,4 @@ -import { Program, BN } from "@coral-xyz/anchor"; +import { Program, BN, Idl } from "@coral-xyz/anchor"; import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet"; import { Wallet } from "@coral-xyz/anchor/dist/cjs/provider"; import { TOKEN_PROGRAM_ID } from "@coral-xyz/anchor/dist/cjs/utils/token"; @@ -47,6 +47,7 @@ import { getProposalInstructions, idlSetBuffer, isPriceStorePublisherInitialized, + lazerIdl, } from "@pythnetwork/xc-admin-common"; import { @@ -947,30 +948,21 @@ multisigCommand( const trustedSigner = new PublicKey(options.signer); const expiryTime = new BN(options.expiryTime); - // Create the update instruction - const updateInstruction = new TransactionInstruction({ - programId: SOLANA_LAZER_PROGRAM_ID, - keys: [ - { - pubkey: await vault.getVaultAuthorityPDA(targetCluster), - isSigner: false, - isWritable: false, - }, - { - pubkey: SOLANA_STORAGE_ID, - isSigner: false, - isWritable: true, - }, - ], - data: Buffer.concat([ - // Anchor discriminator for "update" - Buffer.from([219, 200, 88, 176, 158, 63, 253, 127]), - // Trusted signer pubkey - trustedSigner.toBuffer(), - // Expiry time (i64) - Buffer.from(expiryTime.toArray("le", 8)), - ]), - }); + // Create Anchor program instance + const lazerProgram = new Program( + lazerIdl as Idl, + SOLANA_LAZER_PROGRAM_ID, + vault.getAnchorProvider() + ); + + // Use Anchor to create the instruction + const updateInstruction = await lazerProgram.methods + .update(trustedSigner, expiryTime) + .accounts({ + authority: await vault.getVaultAuthorityPDA(targetCluster), + storage: SOLANA_STORAGE_ID, + }) + .instruction(); await vault.proposeInstructions( [updateInstruction], diff --git a/governance/xc_admin/packages/xc_admin_common/src/index.ts b/governance/xc_admin/packages/xc_admin_common/src/index.ts index 3ffc5923f..24c55fbe2 100644 --- a/governance/xc_admin/packages/xc_admin_common/src/index.ts +++ b/governance/xc_admin/packages/xc_admin_common/src/index.ts @@ -13,3 +13,4 @@ export * from "./executor"; export * from "./chains"; export * from "./deterministic_stake_accounts"; export * from "./price_store"; +export { default as lazerIdl } from "./multisig_transaction/idl/lazer.json"; From 9aabfa2bcea9a5db42550efada82f687515d0950 Mon Sep 17 00:00:00 2001 From: Daniel Chew Date: Tue, 14 Jan 2025 22:40:53 +0900 Subject: [PATCH 8/8] precommit --- lazer/sdk/js/src/constants.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lazer/sdk/js/src/constants.ts b/lazer/sdk/js/src/constants.ts index 13e447995..f672d6040 100644 --- a/lazer/sdk/js/src/constants.ts +++ b/lazer/sdk/js/src/constants.ts @@ -1,6 +1,5 @@ import { PublicKey } from "@solana/web3.js"; - export const SOLANA_LAZER_PROGRAM_ID = new PublicKey( "pytd2yyk641x7ak7mkaasSJVXh6YYZnC7wTmtgAyxPt" );