diff --git a/staking/app/StakeConnection.ts b/staking/app/StakeConnection.ts index 6d83d800..98476efd 100644 --- a/staking/app/StakeConnection.ts +++ b/staking/app/StakeConnection.ts @@ -1,5 +1,4 @@ import { - Provider, Program, Wallet, utils, @@ -27,6 +26,7 @@ import { import BN from "bn.js"; import * as idljs from "@project-serum/anchor/dist/cjs/coder/borsh/idl"; import { Staking } from "../target/types/staking"; +import IDL from "../target/idl/staking.json"; import { batchInstructions } from "./transaction"; import { PythBalance } from "./pythBalance"; import { @@ -36,7 +36,7 @@ import { } from "@solana/spl-governance"; import { GOVERNANCE_ADDRESS } from "./constants"; import assert from "assert"; -import { PositionAccountJs, Position } from "./PositionAccountJs"; +import { PositionAccountJs } from "./PositionAccountJs"; let wasm = wasm2; export { wasm }; @@ -83,9 +83,8 @@ export class StakeConnection { stakingProgramAddress: PublicKey ): Promise { const provider = new AnchorProvider(connection, wallet, {}); - const idl = (await Program.fetchIdl(stakingProgramAddress, provider))!; const program = new Program( - idl, + IDL as Idl, stakingProgramAddress, provider ) as unknown as Program; diff --git a/staking/app/deploy/4_transfer_authorities_to_multisig.ts b/staking/app/deploy/4_transfer_authorities_to_multisig.ts index 316cf279..189ec554 100644 --- a/staking/app/deploy/4_transfer_authorities_to_multisig.ts +++ b/staking/app/deploy/4_transfer_authorities_to_multisig.ts @@ -12,7 +12,9 @@ import { } from "./mainnet_beta"; import { GOVERNANCE_ADDRESS, REALM_ID, STAKING_ADDRESS } from "../constants"; -import { AnchorProvider, Program, Wallet } from "@project-serum/anchor"; +import { AnchorProvider, Idl, Program, Wallet } from "@project-serum/anchor"; +import IDL from "../../target/idl/staking.json"; + // Actual transaction hash : // mainnet-beta : 3FDjeBC946SZ6ZgSiDiNzFHKS5hs9bAXYrJKGZrGw1tuVcwi4BxXB1qvqsVmvtcnG5mzYvLM4hmPLjUTiCiY6Tfe // devnet : 54WrJp6FDXvJCVzaGojUtWz4brm8wJHx3ZTYCpSTF2EwmeswySYsQY335XhJ1A7KL2N4mhYW7NtAGJpMA2fM9M6W @@ -24,8 +26,8 @@ async function main() { new Wallet(AUTHORITY_KEYPAIR), {} ); - const idl = (await Program.fetchIdl(STAKING_ADDRESS, provider))!; - const program = new Program(idl, STAKING_ADDRESS, provider); + + const program = new Program(IDL as Idl, STAKING_ADDRESS, provider); const tx = new Transaction(); withSetRealmAuthority( diff --git a/staking/programs/staking/src/context.rs b/staking/programs/staking/src/context.rs index c31d1c16..33f9599f 100644 --- a/staking/programs/staking/src/context.rs +++ b/staking/programs/staking/src/context.rs @@ -67,6 +67,16 @@ pub struct UpdateGovernanceAuthority<'info> { pub config: Account<'info, global_config::GlobalConfig>, } +#[derive(Accounts)] +#[instruction(new_authority : Pubkey)] +pub struct UpdatePdaAuthority<'info> { + #[account(address = config.pda_authority)] + pub governance_signer: Signer<'info>, + #[account(mut, seeds = [CONFIG_SEED.as_bytes()], bump = config.bump)] + pub config: Account<'info, global_config::GlobalConfig>, +} + + #[derive(Accounts)] #[instruction(freeze : bool)] pub struct UpdateFreeze<'info> { diff --git a/staking/programs/staking/src/lib.rs b/staking/programs/staking/src/lib.rs index 7a407888..44b55b0a 100644 --- a/staking/programs/staking/src/lib.rs +++ b/staking/programs/staking/src/lib.rs @@ -87,6 +87,15 @@ pub mod staking { Ok(()) } + pub fn update_pda_authority( + ctx: Context, + new_authority: Pubkey, + ) -> Result<()> { + let config = &mut ctx.accounts.config; + config.pda_authority = new_authority; + Ok(()) + } + pub fn update_freeze(ctx: Context, freeze: bool) -> Result<()> { let config = &mut ctx.accounts.config; config.freeze = freeze; diff --git a/staking/target/idl/staking.json b/staking/target/idl/staking.json index 3d83c968..716d63a8 100644 --- a/staking/target/idl/staking.json +++ b/staking/target/idl/staking.json @@ -74,6 +74,36 @@ } ] }, + { + "name": "updatePdaAuthority", + "accounts": [ + { + "name": "governanceSigner", + "isMut": false, + "isSigner": true + }, + { + "name": "config", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "config" + } + ] + } + } + ], + "args": [ + { + "name": "newAuthority", + "type": "publicKey" + } + ] + }, { "name": "updateFreeze", "accounts": [ diff --git a/staking/target/types/staking.ts b/staking/target/types/staking.ts index be475a00..8afd5133 100644 --- a/staking/target/types/staking.ts +++ b/staking/target/types/staking.ts @@ -74,6 +74,36 @@ export type Staking = { } ] }, + { + "name": "updatePdaAuthority", + "accounts": [ + { + "name": "governanceSigner", + "isMut": false, + "isSigner": true + }, + { + "name": "config", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "config" + } + ] + } + } + ], + "args": [ + { + "name": "newAuthority", + "type": "publicKey" + } + ] + }, { "name": "updateFreeze", "accounts": [ @@ -1981,6 +2011,36 @@ export const IDL: Staking = { } ] }, + { + "name": "updatePdaAuthority", + "accounts": [ + { + "name": "governanceSigner", + "isMut": false, + "isSigner": true + }, + { + "name": "config", + "isMut": true, + "isSigner": false, + "pda": { + "seeds": [ + { + "kind": "const", + "type": "string", + "value": "config" + } + ] + } + } + ], + "args": [ + { + "name": "newAuthority", + "type": "publicKey" + } + ] + }, { "name": "updateFreeze", "accounts": [ diff --git a/staking/tests/config.ts b/staking/tests/config.ts index 3448f42a..2260d4a2 100644 --- a/staking/tests/config.ts +++ b/staking/tests/config.ts @@ -31,8 +31,9 @@ describe("config", async () => { const pythMintAuthority = new Keypair(); const zeroPubkey = new PublicKey(0); + const pdaAuthorityKeypair = new Keypair(); const config = readAnchorConfig(ANCHOR_CONFIG_PATH); - const pdaAuthority = PublicKey.unique(); + const pdaAuthority = pdaAuthorityKeypair.publicKey; const governanceProgram = new PublicKey(config.programs.localnet.governance); let errMap: Map; @@ -416,4 +417,74 @@ describe("config", async () => { errMap ); }); + + it("updates pda authority", async () => { + await expectFail( + program.methods.updatePdaAuthority(program.provider.wallet.publicKey), + "An address constraint was violated", + errMap + ); + + const pdaConnection = await StakeConnection.createStakeConnection( + program.provider.connection, + new Wallet(pdaAuthorityKeypair), + program.programId + ); + + await pdaConnection.program.provider.connection.requestAirdrop( + pdaAuthorityKeypair.publicKey, + 1_000_000_000_000 + ); + + // Airdrops are not instant unfortunately, wait + await new Promise((resolve) => setTimeout(resolve, 2000)); + + await pdaConnection.program.methods + .updatePdaAuthority(program.provider.wallet.publicKey) + .rpc(); + + let configAccountData = await program.account.globalConfig.fetch( + configAccount + ); + + assert.equal( + JSON.stringify(configAccountData), + JSON.stringify({ + bump, + governanceAuthority: program.provider.wallet.publicKey, + pythTokenMint: pythMintAccount.publicKey, + pythGovernanceRealm: zeroPubkey, + unlockingDuration: 2, + epochDuration: new BN(3600), + freeze: true, + pdaAuthority: program.provider.wallet.publicKey, + governanceProgram, + pythTokenListTime: null, + agreementHash: getDummyAgreementHash(), + mockClockTime: new BN(30), + }) + ); + + await program.methods.updatePdaAuthority(pdaAuthority).rpc(); + + configAccountData = await program.account.globalConfig.fetch(configAccount); + + assert.equal( + JSON.stringify(configAccountData), + JSON.stringify({ + bump, + governanceAuthority: program.provider.wallet.publicKey, + pythTokenMint: pythMintAccount.publicKey, + pythGovernanceRealm: zeroPubkey, + unlockingDuration: 2, + epochDuration: new BN(3600), + freeze: true, + pdaAuthority: pdaAuthority, + governanceProgram, + pythTokenListTime: null, + agreementHash: getDummyAgreementHash(), + mockClockTime: new BN(30), + }) + ); + }); }); diff --git a/staking/tsconfig.api.json b/staking/tsconfig.api.json index b54b81d5..12f416e6 100644 --- a/staking/tsconfig.api.json +++ b/staking/tsconfig.api.json @@ -7,7 +7,8 @@ "esModuleInterop": true, "skipLibCheck": true, "outDir": "lib", - "declaration": true + "declaration": true, + "resolveJsonModule": true }, "include": ["./app/*.ts"], "exclude": ["./tests", "./docker", "./migrations"] diff --git a/staking/tsconfig.json b/staking/tsconfig.json index d6f8a23b..61511615 100644 --- a/staking/tsconfig.json +++ b/staking/tsconfig.json @@ -5,7 +5,8 @@ "module": "commonjs", "target": "es6", "esModuleInterop": true, - "skipLibCheck": true + "skipLibCheck": true, + "resolveJsonModule": true }, "include": ["./app/*.ts", "./tests"], "exclude": ["./docker", "./migrations"]