streamflow_timelock/
utils.rs

1// Copyright (c) 2021 Ivan Jelincic <parazyd@dyne.org>
2//
3// This file is part of streamflow-finance/timelock-crate
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU Affero General Public License version 3
7// as published by the Free Software Foundation.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU Affero General Public License for more details.
13//
14// You should have received a copy of the GNU Affero General Public License
15// along with this program. If not, see <https://www.gnu.org/licenses/>.
16use std::iter::FromIterator;
17
18use solana_program::{account_info::AccountInfo, program_error::ProgramError, program_pack::Pack};
19
20/// Do a sanity check with given Unix timestamps.
21pub fn duration_sanity(now: u64, start: u64, end: u64, cliff: u64) -> bool {
22    let cliff_cond = if cliff == 0 {
23        true
24    } else {
25        start <= cliff && cliff <= end
26    };
27
28    now < start && start < end && cliff_cond
29}
30
31/// Unpack token account from `account_info`
32pub fn unpack_token_account(
33    account_info: &AccountInfo,
34) -> Result<spl_token::state::Account, ProgramError> {
35    if account_info.owner != &spl_token::id() {
36        return Err(ProgramError::InvalidAccountData);
37    }
38
39    spl_token::state::Account::unpack(&account_info.data.borrow())
40}
41
42/// Unpack mint account from `account_info`
43pub fn unpack_mint_account(
44    account_info: &AccountInfo,
45) -> Result<spl_token::state::Mint, ProgramError> {
46    spl_token::state::Mint::unpack(&account_info.data.borrow())
47}
48
49/// Returns a days/hours/minutes/seconds string from given `t` seconds.
50pub fn pretty_time(t: u64) -> String {
51    let seconds = t % 60;
52    let minutes = (t / 60) % 60;
53    let hours = (t / (60 * 60)) % 24;
54    let days = t / (60 * 60 * 24);
55
56    format!(
57        "{} days, {} hours, {} minutes, {} seconds",
58        days, hours, minutes, seconds
59    )
60}
61
62/// Encode given amount to a string with given decimal places.
63pub fn encode_base10(amount: u64, decimal_places: usize) -> String {
64    let mut s: Vec<char> = format!("{:0width$}", amount, width = 1 + decimal_places)
65        .chars()
66        .collect();
67    s.insert(s.len() - decimal_places, '.');
68
69    String::from_iter(&s)
70        .trim_end_matches('0')
71        .trim_end_matches('.')
72        .to_string()
73}
74
75#[allow(unused_imports)]
76mod tests {
77    use crate::utils::duration_sanity;
78
79    #[test]
80    fn test_duration_sanity() {
81        // now, start, end, cliff
82        assert_eq!(true, duration_sanity(100, 110, 130, 120));
83        assert_eq!(true, duration_sanity(100, 110, 130, 0));
84        assert_eq!(false, duration_sanity(100, 140, 130, 130));
85        assert_eq!(false, duration_sanity(100, 130, 130, 130));
86        assert_eq!(false, duration_sanity(130, 130, 130, 130));
87        assert_eq!(false, duration_sanity(100, 110, 130, 140));
88    }
89}