Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add account recovery functionality #424

Merged
merged 21 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
fa014a5
chore: Add .idea/ to .gitignore
keyvankhademi Mar 22, 2024
4e2972a
feat: Add RecoverAccount structure to staking context
keyvankhademi Mar 22, 2024
397a329
feat: Add RecoverAccount function in staking program
keyvankhademi Mar 22, 2024
68f47a4
chore: generate staking.json
keyvankhademi Mar 22, 2024
4640c43
feat: Export StakeTarget type in staking tests utils
keyvankhademi Mar 22, 2024
aac4e11
feat: generate staking.ts
keyvankhademi Mar 22, 2024
1a8a1db
feat: Add buildRecoverAccountInstruction function to StakeConnection
keyvankhademi Mar 22, 2024
3c8c92d
feat: Implement account recovery test in staking application
keyvankhademi Mar 22, 2024
3a0d137
feat: add failed account recovery test
keyvankhademi Mar 22, 2024
87d3872
fix: refactor recover account test to send the transaction to chain a…
keyvankhademi Mar 25, 2024
1cfdd15
fix: corrected typo in file name for 'recover_account.ts'
keyvankhademi Mar 25, 2024
5bcb2ac
fix: add assertion for stake account metadata owner in recover_accoun…
keyvankhademi Mar 25, 2024
438ac47
Fix: remove mutability from config account
keyvankhademi Mar 25, 2024
f6b8887
Fix: refine documentation and add documentation for account recovery …
keyvankhademi Mar 25, 2024
cfbda18
Update version in staking package.json file
keyvankhademi Mar 25, 2024
b37c519
Update version in staking Cargo.toml file
keyvankhademi Mar 25, 2024
ce95db1
fix: update version in staking program
keyvankhademi Mar 26, 2024
a0e924f
fix: update test description in recover_account.ts
keyvankhademi Mar 26, 2024
85db434
fix: update staking version and improve documentation
keyvankhademi Mar 26, 2024
be59f75
fix: add tests for stake account ownership
keyvankhademi Mar 26, 2024
58906a9
fix: add check for staked tokens in recover account function
keyvankhademi Mar 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.DS_Store
node_modules
.idea/
2 changes: 1 addition & 1 deletion staking/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions staking/app/StakeConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1178,6 +1178,21 @@ export class StakeConnection {

await this.provider.sendAndConfirm(tx);
}

public async buildRecoverAccountInstruction(
stakeAccountAddress: PublicKey,
governanceAuthorityAddress: PublicKey
): Promise<TransactionInstruction> {
const stakeAccount = await this.loadStakeAccount(stakeAccountAddress);
return await this.program.methods
.recoverAccount()
.accounts({
payer: governanceAuthorityAddress,
payerTokenAccount: stakeAccount.stakeAccountPositionsJs.owner,
stakeAccountPositions: stakeAccountAddress,
})
.instruction();
}
}

export interface BalanceSummary {
Expand Down
2 changes: 1 addition & 1 deletion staking/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pythnetwork/staking",
"version": "2.1.0",
"version": "2.2.0",
"description": "Pyth Network Staking SDK",
"main": "lib/app/index.js",
"types": "lib/app/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion staking/programs/staking/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pyth-staking-program"
version = "1.0.0"
version = "1.2.0"
description = "Created with Anchor"
edition = "2018"

Expand Down
35 changes: 35 additions & 0 deletions staking/programs/staking/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -405,3 +405,38 @@ pub struct AdvanceClock<'info> {
#[account(mut, seeds = [CONFIG_SEED.as_bytes()], bump = config.bump)]
pub config: Account<'info, global_config::GlobalConfig>,
}

#[derive(Accounts)]
pub struct RecoverAccount<'info> {
// Native payer:
#[account(address = config.governance_authority)]
pub payer: Signer<'info>,

// Token account:
#[account(address = stake_account_metadata.owner)]
pub payer_token_account: Account<'info, TokenAccount>,

// Stake program accounts:
#[account(mut)]
pub stake_account_positions: AccountLoader<'info, positions::PositionData>,

#[account(
mut,
seeds = [
STAKE_ACCOUNT_METADATA_SEED.as_bytes(),
stake_account_positions.key().as_ref()
],
bump = stake_account_metadata.metadata_bump
)]
pub stake_account_metadata: Account<'info, stake_account::StakeAccountMetadataV2>,

#[account(
mut,
seeds = [VOTER_RECORD_SEED.as_bytes(), stake_account_positions.key().as_ref()],
bump = stake_account_metadata.voter_bump
)]
pub voter_record: Account<'info, voter_weight_record::VoterWeightRecord>,

#[account(seeds = [CONFIG_SEED.as_bytes()], bump = config.bump)]
pub config: Account<'info, global_config::GlobalConfig>,
}
4 changes: 3 additions & 1 deletion staking/programs/staking/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ pub enum ErrorCode {
SplitWithStake,
#[msg("The approval arguments do not match the split request.")] // 6034
InvalidApproval,
#[msg("Other")] //6035
#[msg("Can't recover account with staking positions. Unstake your tokens first.")] // 6035
RecoverWithStake,
#[msg("Other")] //6036
Other,
}
26 changes: 25 additions & 1 deletion staking/programs/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ pub mod staking {


/**
* A split request can only be accepted by the `pda_authority`` from
* A split request can only be accepted by the `pda_authority` from
* the config account. If accepted, `amount` tokens are transferred to a new stake account
* owned by the `recipient` and the split request is reset (by setting `amount` to 0).
* The recipient of a transfer can't vote during the epoch of the transfer.
Expand Down Expand Up @@ -706,4 +706,28 @@ pub mod staking {
Some(ctx.accounts.config.agreement_hash);
Ok(())
}

/** Recovers a user's `stake account` ownership by transferring ownership
* from a token account to the `owner` of that token account.
*
* This functionality addresses the scenario where a user mistakenly
* created a stake account using their token account address as the owner.
*/
pub fn recover_account(ctx: Context<RecoverAccount>) -> Result<()> {
guibescos marked this conversation as resolved.
Show resolved Hide resolved
// Check that there aren't any positions (i.e., staked tokens) in the account.
// Transferring accounts with staked tokens might lead to double voting
require!(
ctx.accounts.stake_account_metadata.next_index == 0,
ErrorCode::SplitWithStake
keyvankhademi marked this conversation as resolved.
Show resolved Hide resolved
);

let new_owner = ctx.accounts.payer_token_account.owner;
keyvankhademi marked this conversation as resolved.
Show resolved Hide resolved

ctx.accounts.stake_account_metadata.owner = new_owner;
let stake_account_positions = &mut ctx.accounts.stake_account_positions.load_mut()?;
stake_account_positions.owner = new_owner;
ctx.accounts.voter_record.governing_token_owner = new_owner;

Ok(())
}
}
85 changes: 83 additions & 2 deletions staking/target/idl/staking.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "1.0.0",
"version": "1.2.0",
"name": "staking",
"instructions": [
{
Expand Down Expand Up @@ -915,7 +915,7 @@
{
"name": "acceptSplit",
"docs": [
"* A split request can only be accepted by the `pda_authority`` from\n * the config account. If accepted, `amount` tokens are transferred to a new stake account\n * owned by the `recipient` and the split request is reset (by setting `amount` to 0).\n * The recipient of a transfer can't vote during the epoch of the transfer.\n *\n * The `pda_authority` must explicitly approve both the amount of tokens and recipient, and\n * these parameters must match the request (in the `split_request` account)."
"* A split request can only be accepted by the `pda_authority` from\n * the config account. If accepted, `amount` tokens are transferred to a new stake account\n * owned by the `recipient` and the split request is reset (by setting `amount` to 0).\n * The recipient of a transfer can't vote during the epoch of the transfer.\n *\n * The `pda_authority` must explicitly approve both the amount of tokens and recipient, and\n * these parameters must match the request (in the `split_request` account)."
],
"accounts": [
{
Expand Down Expand Up @@ -1198,6 +1198,82 @@
}
}
]
},
{
keyvankhademi marked this conversation as resolved.
Show resolved Hide resolved
"name": "recoverAccount",
"docs": [
"Recovers a user's `stake account` ownership by transferring ownership\n * from a token account to the `owner` of that token account.\n *\n * This functionality addresses the scenario where a user mistakenly\n * created a stake account using their token account address as the owner."
],
"accounts": [
{
"name": "payer",
"isMut": false,
"isSigner": true
},
{
"name": "payerTokenAccount",
"isMut": false,
"isSigner": false
},
{
"name": "stakeAccountPositions",
"isMut": true,
"isSigner": false
},
{
"name": "stakeAccountMetadata",
"isMut": true,
"isSigner": false,
"pda": {
"seeds": [
{
"kind": "const",
"type": "string",
"value": "stake_metadata"
},
{
"kind": "account",
"type": "publicKey",
"path": "stake_account_positions"
}
]
}
},
{
"name": "voterRecord",
"isMut": true,
"isSigner": false,
"pda": {
"seeds": [
{
"kind": "const",
"type": "string",
"value": "voter_weight"
},
{
"kind": "account",
"type": "publicKey",
"path": "stake_account_positions"
}
]
}
},
{
"name": "config",
"isMut": false,
"isSigner": false,
"pda": {
"seeds": [
{
"kind": "const",
"type": "string",
"value": "config"
}
]
}
}
],
"args": []
}
],
"accounts": [
Expand Down Expand Up @@ -1963,6 +2039,11 @@
},
{
"code": 6035,
"name": "RecoverWithStake",
"msg": "Can't recover account with staking positions. Unstake your tokens first."
},
{
"code": 6036,
"name": "Other",
"msg": "Other"
}
Expand Down
Loading
Loading