Skip to content

Commit 77083cf

Browse files
ali-behjatiStanisław Drozd
andauthored
Attestation: Add ops owner and set-is-active ix (#295)
* Attestation: Add ops owner and set-is-active ix * Update solana/pyth2wormhole/client/src/cli.rs Co-authored-by: Stanisław Drozd <stan@nexantic.com> * Fix typos * Add a test without owner Co-authored-by: Stanisław Drozd <stan@nexantic.com>
1 parent bf032f0 commit 77083cf

File tree

9 files changed

+392
-8
lines changed

9 files changed

+392
-8
lines changed

solana/pyth2wormhole/client/src/cli.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ pub enum Action {
5858
/// Option<> makes sure not specifying this flag does not imply "false"
5959
#[clap(long = "is-active")]
6060
is_active: Option<bool>,
61+
#[clap(long = "ops-owner")]
62+
ops_owner_addr: Option<Pubkey>,
6163
},
6264
#[clap(
6365
about = "Use an existing pyth2wormhole program to attest product price information to another chain"
@@ -115,6 +117,10 @@ pub enum Action {
115117
new_pyth_owner_addr: Option<Pubkey>,
116118
#[clap(long = "is-active")]
117119
is_active: Option<bool>,
120+
#[clap(long = "ops-owner")]
121+
ops_owner_addr: Option<Pubkey>,
122+
#[clap(long = "remove-ops-owner", conflicts_with = "ops_owner_addr")]
123+
remove_ops_owner: bool,
118124
},
119125
#[clap(
120126
about = "Migrate existing pyth2wormhole program settings to a newer format version. Client version must match the deployed contract."
@@ -130,4 +136,21 @@ pub enum Action {
130136
},
131137
#[clap(about = "Print out emitter address for the specified pyth2wormhole contract")]
132138
GetEmitter,
139+
#[clap(
140+
about = "Set the value of is_active config as ops_owner"
141+
)]
142+
SetIsActive {
143+
/// Current ops owner keypair path
144+
#[clap(
145+
long,
146+
default_value = "~/.config/solana/id.json",
147+
help = "Keypair file for the current ops owner"
148+
)]
149+
ops_owner: String,
150+
#[clap(
151+
index = 1,
152+
possible_values = ["true", "false"],
153+
)]
154+
new_is_active: String,
155+
}
133156
}

solana/pyth2wormhole/client/src/lib.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,45 @@ pub fn gen_set_config_tx(
163163
Ok(tx_signed)
164164
}
165165

166+
167+
pub fn gen_set_is_active_tx(
168+
payer: Keypair,
169+
p2w_addr: Pubkey,
170+
ops_owner: Keypair,
171+
new_is_active: bool,
172+
latest_blockhash: Hash,
173+
) -> Result<Transaction, ErrBox> {
174+
let payer_pubkey = payer.pubkey();
175+
176+
let acc_metas = vec![
177+
// config
178+
AccountMeta::new(
179+
P2WConfigAccount::<{ AccountState::Initialized }>::key(None, &p2w_addr),
180+
false,
181+
),
182+
// ops_owner
183+
AccountMeta::new(ops_owner.pubkey(), true),
184+
// payer
185+
AccountMeta::new(payer.pubkey(), true),
186+
];
187+
188+
let ix_data = (
189+
pyth2wormhole::instruction::Instruction::SetIsActive,
190+
new_is_active,
191+
);
192+
193+
let ix = Instruction::new_with_bytes(p2w_addr, ix_data.try_to_vec()?.as_slice(), acc_metas);
194+
195+
let signers = vec![&ops_owner, &payer];
196+
let tx_signed = Transaction::new_signed_with_payer::<Vec<&Keypair>>(
197+
&[ix],
198+
Some(&payer_pubkey),
199+
&signers,
200+
latest_blockhash,
201+
);
202+
Ok(tx_signed)
203+
}
204+
166205
pub fn gen_migrate_tx(
167206
payer: Keypair,
168207
p2w_addr: Pubkey,

solana/pyth2wormhole/client/src/main.rs

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ async fn main() -> Result<(), ErrBox> {
9797
pyth_owner_addr,
9898
wh_prog,
9999
is_active,
100+
ops_owner_addr,
100101
} => {
101102
let tx = gen_init_tx(
102103
payer,
@@ -107,14 +108,15 @@ async fn main() -> Result<(), ErrBox> {
107108
pyth_owner: pyth_owner_addr,
108109
is_active: is_active.unwrap_or(true),
109110
max_batch_size: P2W_MAX_BATCH_SIZE,
111+
ops_owner: ops_owner_addr,
110112
},
111113
latest_blockhash,
112114
)?;
113115
rpc_client
114116
.send_and_confirm_transaction_with_spinner(&tx)
115117
.await?;
116118
println!(
117-
"Initialized with conifg:\n{:?}",
119+
"Initialized with config:\n{:?}",
118120
get_config_account(&rpc_client, &p2w_addr).await?
119121
);
120122
}
@@ -127,8 +129,17 @@ async fn main() -> Result<(), ErrBox> {
127129
new_wh_prog,
128130
new_pyth_owner_addr,
129131
is_active,
132+
ops_owner_addr,
133+
remove_ops_owner,
130134
} => {
131135
let old_config = get_config_account(&rpc_client, &p2w_addr).await?;
136+
137+
let new_ops_owner = if remove_ops_owner {
138+
None
139+
} else {
140+
ops_owner_addr
141+
};
142+
132143
let tx = gen_set_config_tx(
133144
payer,
134145
p2w_addr,
@@ -139,14 +150,15 @@ async fn main() -> Result<(), ErrBox> {
139150
pyth_owner: new_pyth_owner_addr.unwrap_or(old_config.pyth_owner),
140151
is_active: is_active.unwrap_or(old_config.is_active),
141152
max_batch_size: P2W_MAX_BATCH_SIZE,
153+
ops_owner: new_ops_owner,
142154
},
143155
latest_blockhash,
144156
)?;
145157
rpc_client
146158
.send_and_confirm_transaction_with_spinner(&tx)
147159
.await?;
148160
println!(
149-
"Applied conifg:\n{:?}",
161+
"Applied config:\n{:?}",
150162
get_config_account(&rpc_client, &p2w_addr).await?
151163
);
152164
}
@@ -161,7 +173,7 @@ async fn main() -> Result<(), ErrBox> {
161173
.send_and_confirm_transaction_with_spinner(&tx)
162174
.await?;
163175
println!(
164-
"Applied conifg:\n{:?}",
176+
"Applied config:\n{:?}",
165177
get_config_account(&rpc_client, &p2w_addr).await?
166178
);
167179
}
@@ -196,7 +208,23 @@ async fn main() -> Result<(), ErrBox> {
196208
)
197209
.await?;
198210
}
199-
Action::GetEmitter => unreachable! {},
211+
Action::GetEmitter => unreachable! {}, // It is handled early in this function.
212+
Action::SetIsActive { ops_owner, new_is_active } => {
213+
let tx = gen_set_is_active_tx(
214+
payer,
215+
p2w_addr,
216+
read_keypair_file(&*shellexpand::tilde(&ops_owner))?,
217+
new_is_active.eq_ignore_ascii_case("true"),
218+
latest_blockhash,
219+
)?;
220+
rpc_client
221+
.send_and_confirm_transaction_with_spinner(&tx)
222+
.await?;
223+
println!(
224+
"Applied config:\n{:?}",
225+
get_config_account(&rpc_client, &p2w_addr).await?
226+
);
227+
},
200228
}
201229

202230
Ok(())

solana/pyth2wormhole/client/tests/test_attest.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ async fn test_happy_path() -> Result<(), p2wc::ErrBoxSend> {
4747
// Authorities
4848
let p2w_owner = Pubkey::new_unique();
4949
let pyth_owner = Pubkey::new_unique();
50+
let ops_owner = Pubkey::new_unique();
5051

5152
// On-chain state
5253
let p2w_config = Pyth2WormholeConfig {
@@ -55,6 +56,7 @@ async fn test_happy_path() -> Result<(), p2wc::ErrBoxSend> {
5556
max_batch_size: pyth2wormhole::attest::P2W_MAX_BATCH_SIZE,
5657
pyth_owner,
5758
is_active: true,
59+
ops_owner: Some(ops_owner),
5860
};
5961

6062
let bridge_config = BridgeData {

solana/pyth2wormhole/client/tests/test_migrate.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ async fn test_migrate_works() -> Result<(), solitaire::ErrBox> {
6060
wh_prog: wh_fixture_program_id,
6161
max_batch_size: pyth2wormhole::attest::P2W_MAX_BATCH_SIZE,
6262
pyth_owner,
63+
is_active: true,
6364
};
6465

6566
info!("Before ProgramTest::new()");
@@ -114,13 +115,15 @@ async fn test_migrate_already_migrated() -> Result<(), solitaire::ErrBox> {
114115
// Authorities
115116
let p2w_owner = Keypair::new();
116117
let pyth_owner = Pubkey::new_unique();
118+
let ops_owner = Keypair::new();
117119

118120
// On-chain state
119121
let old_p2w_config = OldPyth2WormholeConfig {
120122
owner: p2w_owner.pubkey(),
121123
wh_prog: wh_fixture_program_id,
122124
max_batch_size: pyth2wormhole::attest::P2W_MAX_BATCH_SIZE,
123125
pyth_owner,
126+
is_active: true,
124127
};
125128

126129
let new_p2w_config = Pyth2WormholeConfig {
@@ -129,6 +132,7 @@ async fn test_migrate_already_migrated() -> Result<(), solitaire::ErrBox> {
129132
max_batch_size: pyth2wormhole::attest::P2W_MAX_BATCH_SIZE,
130133
pyth_owner,
131134
is_active: true,
135+
ops_owner: Some(ops_owner.pubkey()),
132136
};
133137

134138
info!("Before ProgramTest::new()");

0 commit comments

Comments
 (0)