|
1 | 1 | use {
|
| 2 | + chrono::{DateTime, NaiveDateTime, SecondsFormat, Utc}, |
2 | 3 | clap::{
|
3 | 4 | crate_description, crate_name, crate_version, value_t_or_exit, App, AppSettings, Arg,
|
4 | 5 | SubCommand,
|
|
9 | 10 | },
|
10 | 11 | solana_client::rpc_client::RpcClient,
|
11 | 12 | solana_sdk::{
|
| 13 | + clock::UnixTimestamp, |
12 | 14 | commitment_config::CommitmentConfig,
|
13 | 15 | program_pack::Pack,
|
14 | 16 | pubkey::Pubkey,
|
15 | 17 | signature::{read_keypair_file, Keypair, Signer},
|
16 | 18 | transaction::Transaction,
|
17 | 19 | },
|
18 | 20 | spl_feature_proposal::state::{AcceptanceCriteria, FeatureProposal},
|
19 |
| - std::{fs::File, io::Write}, |
| 21 | + std::{ |
| 22 | + fs::File, |
| 23 | + io::Write, |
| 24 | + time::{Duration, SystemTime, UNIX_EPOCH}, |
| 25 | + }, |
20 | 26 | };
|
21 | 27 |
|
22 | 28 | struct Config {
|
@@ -183,12 +189,23 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
183 | 189 | let distribution_file = value_t_or_exit!(arg_matches, "distribution_file", String);
|
184 | 190 | let percent_stake_required =
|
185 | 191 | value_t_or_exit!(arg_matches, "percent_stake_required", u8);
|
| 192 | + |
| 193 | + // Hard code deadline for now... |
| 194 | + let fortnight = Duration::from_secs(60 * 60 * 24 * 14); |
| 195 | + let deadline = SystemTime::now() |
| 196 | + .duration_since(UNIX_EPOCH) |
| 197 | + .unwrap() |
| 198 | + .checked_add(fortnight) |
| 199 | + .unwrap() |
| 200 | + .as_secs() as UnixTimestamp; |
| 201 | + |
186 | 202 | process_propose(
|
187 | 203 | &rpc_client,
|
188 | 204 | &config,
|
189 | 205 | &feature_proposal_keypair,
|
190 | 206 | distribution_file,
|
191 | 207 | percent_stake_required,
|
| 208 | + deadline, |
192 | 209 | arg_matches.is_present("confirm"),
|
193 | 210 | )
|
194 | 211 | }
|
@@ -229,12 +246,25 @@ fn get_feature_proposal(
|
229 | 246 | }
|
230 | 247 | }
|
231 | 248 |
|
| 249 | +fn unix_timestamp_to_string(unix_timestamp: UnixTimestamp) -> String { |
| 250 | + format!( |
| 251 | + "{} (UnixTimestamp: {})", |
| 252 | + match NaiveDateTime::from_timestamp_opt(unix_timestamp, 0) { |
| 253 | + Some(ndt) => |
| 254 | + DateTime::<Utc>::from_utc(ndt, Utc).to_rfc3339_opts(SecondsFormat::Secs, true), |
| 255 | + None => "unknown".to_string(), |
| 256 | + }, |
| 257 | + unix_timestamp, |
| 258 | + ) |
| 259 | +} |
| 260 | + |
232 | 261 | fn process_propose(
|
233 | 262 | rpc_client: &RpcClient,
|
234 | 263 | config: &Config,
|
235 | 264 | feature_proposal_keypair: &Keypair,
|
236 | 265 | distribution_file: String,
|
237 | 266 | percent_stake_required: u8,
|
| 267 | + deadline: UnixTimestamp, |
238 | 268 | confirm: bool,
|
239 | 269 | ) -> Result<(), Box<dyn std::error::Error>> {
|
240 | 270 | let distributor_token_address =
|
@@ -295,7 +325,7 @@ fn process_propose(
|
295 | 325 | tokens_to_mint,
|
296 | 326 | AcceptanceCriteria {
|
297 | 327 | tokens_required,
|
298 |
| - deadline: None, |
| 328 | + deadline, |
299 | 329 | },
|
300 | 330 | )],
|
301 | 331 | Some(&config.keypair.pubkey()),
|
@@ -347,6 +377,11 @@ fn process_propose(
|
347 | 377 | println!("Tallying is permissionless and may be run by anybody.");
|
348 | 378 | println!("Once this feature proposal is accepted, the {} feature will be activated at the next epoch.", feature_id_address);
|
349 | 379 |
|
| 380 | + println!(); |
| 381 | + println!( |
| 382 | + "Proposal will expire at {}", |
| 383 | + unix_timestamp_to_string(deadline) |
| 384 | + ); |
350 | 385 | println!();
|
351 | 386 | if !confirm {
|
352 | 387 | println!("Add --confirm flag to initiate the feature proposal");
|
@@ -396,19 +431,22 @@ fn process_tally(
|
396 | 431 | "{} tokens have been received",
|
397 | 432 | spl_feature_proposal::amount_to_ui_amount(acceptance_token_balance)
|
398 | 433 | );
|
| 434 | + println!( |
| 435 | + "Proposal will expire at {}", |
| 436 | + unix_timestamp_to_string(acceptance_criteria.deadline) |
| 437 | + ); |
399 | 438 | println!();
|
400 | 439 |
|
401 |
| - match acceptance_criteria.deadline { |
402 |
| - None => { |
403 |
| - // Don't bother issuing a transaction if it's clear the Tally won't succeed |
404 |
| - if acceptance_token_balance < acceptance_criteria.tokens_required { |
405 |
| - println!("Feature proposal pending"); |
406 |
| - return Ok(()); |
407 |
| - } |
408 |
| - } |
409 |
| - Some(deadline) => { |
410 |
| - println!("Deadline: {}", deadline); // TODO: format deadline nicely |
411 |
| - } |
| 440 | + // Don't bother issuing a transaction if it's clear the Tally won't succeed |
| 441 | + if acceptance_token_balance < acceptance_criteria.tokens_required |
| 442 | + && (SystemTime::now() |
| 443 | + .duration_since(UNIX_EPOCH) |
| 444 | + .unwrap() |
| 445 | + .as_secs() as UnixTimestamp) |
| 446 | + < acceptance_criteria.deadline |
| 447 | + { |
| 448 | + println!("Feature proposal pending"); |
| 449 | + return Ok(()); |
412 | 450 | }
|
413 | 451 | }
|
414 | 452 | FeatureProposal::Accepted { .. } => {
|
|
0 commit comments