Skip to content

Commit

Permalink
feat(staking): add create staking account
Browse files Browse the repository at this point in the history
  • Loading branch information
keyvankhademi committed Sep 11, 2024
1 parent b4fcc32 commit 340a7f3
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 153 deletions.
7 changes: 3 additions & 4 deletions apps/staking/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -339,11 +339,10 @@ export const loadAccountHistory = async (
};

export const createStakeAccountAndDeposit = async (
_client: PythStakingClient,
_amount: bigint,
client: PythStakingClient,
amount: bigint,
): Promise<StakeAccountPositions> => {
await new Promise((resolve) => setTimeout(resolve, MOCK_DELAY));
throw new NotImplementedError();
return client.createStakeAccountAndDeposit(amount);
};

export const deposit = async (
Expand Down
1 change: 1 addition & 0 deletions governance/pyth_staking_sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"dependencies": {
"@coral-xyz/anchor": "^0.30.1",
"@pythnetwork/solana-utils": "workspace:*",
"@solana/spl-governance": "^0.3.28",
"@solana/spl-token": "^0.3.7",
"@solana/web3.js": "^1.95.3"
}
Expand Down
5 changes: 5 additions & 0 deletions governance/pyth_staking_sdk/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const EPOCH_DURATION = ONE_WEEK_IN_SECONDS;

export const POSITION_BUFFER_SIZE = 200;
export const POSITIONS_ACCOUNT_HEADER_SIZE = DISCRIMINATOR_SIZE + 32;
export const POSITIONS_ACCOUNT_SIZE = DISCRIMINATOR_SIZE + 32;

export const STAKING_PROGRAM_ADDRESS = new PublicKey(
"pytS9TjG1qyAZypk7n8rw8gfW9sUaqqYyMhJQ4E7JCQ",
Expand All @@ -22,3 +23,7 @@ export const INTEGRITY_POOL_PROGRAM_ADDRESS = new PublicKey(
export const PUBLISHER_CAPS_PROGRAM_ADDRESS = new PublicKey(
"pytcD8uUjPxSLMsNqoVnm9dXQw9tKJJf3CQnGwa8oL7",
);

export const GOVERNANCE_ADDRESS = new PublicKey(
"pytGY6tWRgGinSCvRLnSv4fHfBTMoiDGiCsesmHWM6U",
);
102 changes: 102 additions & 0 deletions governance/pyth_staking_sdk/src/pyth-staking-client.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import * as crypto from "crypto";

import { AnchorProvider, BN, Program } from "@coral-xyz/anchor";
import {
getTokenOwnerRecordAddress,
PROGRAM_VERSION_V2,
withCreateTokenOwnerRecord,
} from "@solana/spl-governance";
import {
type Account,
createTransferInstruction,
Expand All @@ -9,10 +16,12 @@ import type { AnchorWallet } from "@solana/wallet-adapter-react";
import {
Connection,
PublicKey,
SystemProgram,
Transaction,
TransactionInstruction,
} from "@solana/web3.js";

import { GOVERNANCE_ADDRESS, POSITIONS_ACCOUNT_SIZE } from "./constants";
import {
getConfigAddress,
getPoolConfigAddress,
Expand Down Expand Up @@ -340,6 +349,99 @@ export class PythStakingClient {
return sendTransaction(instructions, this.connection, this.wallet);
}

public async hasGovernanceRecord(config: GlobalConfig): Promise<boolean> {
const tokenOwnerRecordAddress = await getTokenOwnerRecordAddress(
GOVERNANCE_ADDRESS,
config.pythGovernanceRealm,
config.pythTokenMint,
this.wallet.publicKey,
);
const voterAccountInfo =
await this.stakingProgram.provider.connection.getAccountInfo(
tokenOwnerRecordAddress,
);

return Boolean(voterAccountInfo);
}

public async createStakeAccountAndDeposit(amount: bigint) {
const globalConfig = await this.getGlobalConfig();

const senderTokenAccount = await getAssociatedTokenAddress(
globalConfig.pythTokenMint,
this.wallet.publicKey,
);

const nonce = crypto.randomBytes(16).toString("hex");
const stakeAccountPositions = await PublicKey.createWithSeed(
this.wallet.publicKey,
nonce,
this.stakingProgram.programId,
);

const minimumBalance =
await this.stakingProgram.provider.connection.getMinimumBalanceForRentExemption(
POSITIONS_ACCOUNT_SIZE,
);

const instructions = [];

instructions.push(
SystemProgram.createAccountWithSeed({
fromPubkey: this.wallet.publicKey,
newAccountPubkey: stakeAccountPositions,
basePubkey: this.wallet.publicKey,
seed: nonce,
lamports: minimumBalance,
space: POSITIONS_ACCOUNT_SIZE,
programId: this.stakingProgram.programId,
}),
await this.stakingProgram.methods
.createStakeAccount(this.wallet.publicKey, { fullyVested: {} })
.accounts({
stakeAccountPositions,
})
.instruction(),
await this.stakingProgram.methods
.createVoterRecord()
.accounts({
stakeAccountPositions,
})
.instruction(),
);

if (!(await this.hasGovernanceRecord(globalConfig))) {
await withCreateTokenOwnerRecord(
instructions,
GOVERNANCE_ADDRESS,
PROGRAM_VERSION_V2,
globalConfig.pythGovernanceRealm,
this.wallet.publicKey,
globalConfig.pythTokenMint,
this.wallet.publicKey,
);
}

instructions.push(
await this.stakingProgram.methods
.joinDaoLlc(globalConfig.agreementHash)
.accounts({
stakeAccountPositions,
})
.instruction(),
createTransferInstruction(
senderTokenAccount,
getStakeAccountCustodyAddress(stakeAccountPositions),
this.wallet.publicKey,
amount,
),
);

await sendTransaction(instructions, this.connection, this.wallet);

return this.getStakeAccountPositions(stakeAccountPositions);
}

public async depositTokensToStakeAccountCustody(
stakeAccountPositions: PublicKey,
amount: bigint,
Expand Down
Loading

0 comments on commit 340a7f3

Please sign in to comment.