-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
644 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
[package] | ||
name = "solana-vest-api" | ||
version = "0.20.0-pre0" | ||
description = "Solana Vest program API" | ||
authors = ["Solana Maintainers <maintainers@solana.com>"] | ||
repository = "https://github.com/solana-labs/solana" | ||
license = "Apache-2.0" | ||
homepage = "https://solana.com/" | ||
edition = "2018" | ||
|
||
[dependencies] | ||
bincode = "1.1.4" | ||
chrono = { version = "0.4.9", features = ["serde"] } | ||
log = "0.4.8" | ||
num-derive = "0.2" | ||
num-traits = "0.2" | ||
serde = "1.0.100" | ||
serde_derive = "1.0.100" | ||
solana-sdk = { path = "../../sdk", version = "0.20.0-pre0" } | ||
solana-config-api = { path = "../config_api", version = "0.20.0-pre0" } | ||
|
||
[dev-dependencies] | ||
solana-runtime = { path = "../../runtime", version = "0.20.0-pre0" } | ||
|
||
[lib] | ||
crate-type = ["lib"] | ||
name = "solana_budget_api" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/// | ||
/// A library for creating a trusted date oracle. | ||
/// | ||
use bincode::{deserialize, serialized_size}; | ||
use chrono::{ | ||
prelude::{DateTime, TimeZone, Utc}, | ||
serde::ts_seconds, | ||
}; | ||
use serde_derive::{Deserialize, Serialize}; | ||
use solana_config_api::{config_instruction, ConfigState}; | ||
use solana_sdk::{instruction::Instruction, pubkey::Pubkey}; | ||
|
||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] | ||
pub struct DateConfig { | ||
#[serde(with = "ts_seconds")] | ||
pub dt: DateTime<Utc>, | ||
} | ||
|
||
impl Default for DateConfig { | ||
fn default() -> Self { | ||
Self { | ||
dt: Utc.timestamp(0, 0), | ||
} | ||
} | ||
} | ||
impl DateConfig { | ||
pub fn new(dt: DateTime<Utc>) -> Self { | ||
Self { dt } | ||
} | ||
|
||
pub fn deserialize(input: &[u8]) -> Option<Self> { | ||
deserialize(input).ok() | ||
} | ||
} | ||
|
||
impl ConfigState for DateConfig { | ||
fn max_space() -> u64 { | ||
serialized_size(&Self::default()).unwrap() | ||
} | ||
} | ||
|
||
/// Create a date account. The date is set to the Unix epoch. | ||
pub fn create_account( | ||
from_account_pubkey: &Pubkey, | ||
date_account_pubkey: &Pubkey, | ||
lamports: u64, | ||
) -> Vec<Instruction> { | ||
config_instruction::create_account::<DateConfig>( | ||
from_account_pubkey, | ||
date_account_pubkey, | ||
lamports, | ||
vec![], | ||
) | ||
} | ||
|
||
/// Set the date in the date account. The account pubkey must be signed in the | ||
/// transaction containing this instruction. | ||
pub fn store(date_account_pubkey: &Pubkey, dt: DateTime<Utc>) -> Instruction { | ||
let date_config = DateConfig::new(dt); | ||
config_instruction::store(&date_account_pubkey, true, vec![], &date_config) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
pub mod date_instruction; | ||
pub mod vest_instruction; | ||
pub mod vest_processor; | ||
pub mod vest_state; | ||
|
||
const VEST_PROGRAM_ID: [u8; 32] = [ | ||
7, 87, 23, 47, 219, 236, 238, 33, 137, 188, 215, 141, 32, 229, 155, 195, 133, 124, 23, 232, | ||
113, 153, 252, 252, 111, 5, 187, 128, 0, 0, 0, 0, | ||
]; | ||
|
||
solana_sdk::solana_name_id!( | ||
VEST_PROGRAM_ID, | ||
"Vest111111111111111111111111111111111111111" | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
use crate::{id, vest_state::VestState}; | ||
use bincode::serialized_size; | ||
use chrono::prelude::{DateTime, Utc}; | ||
use num_derive::FromPrimitive; | ||
use serde_derive::{Deserialize, Serialize}; | ||
use solana_sdk::{ | ||
instruction::{AccountMeta, Instruction}, | ||
instruction_processor_utils::DecodeError, | ||
pubkey::Pubkey, | ||
system_instruction, | ||
}; | ||
|
||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, FromPrimitive)] | ||
pub enum VestError { | ||
DestinationMissing, | ||
Unauthorized, | ||
} | ||
|
||
impl<T> DecodeError<T> for VestError { | ||
fn type_of() -> &'static str { | ||
"VestError" | ||
} | ||
} | ||
|
||
impl std::fmt::Display for VestError { | ||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | ||
write!( | ||
f, | ||
"{}", | ||
match self { | ||
VestError::DestinationMissing => "destination missing", | ||
VestError::Unauthorized => "unauthorized", | ||
} | ||
) | ||
} | ||
} | ||
impl std::error::Error for VestError {} | ||
|
||
/// An instruction to progress the smart contract. | ||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] | ||
pub enum VestInstruction { | ||
/// Declare and instantiate a vesting schedule | ||
InitializeAccount { | ||
terminator_pubkey: Pubkey, // The address authorized to terminate this contract with a signed Terminate instruction | ||
payee_pubkey: Pubkey, // The address authorized to redeem vested tokens | ||
start_dt: DateTime<Utc>, // The day from which the vesting contract begins | ||
oracle_pubkey: Pubkey, // Address of an account containing a trusted date, used to drive the vesting schedule | ||
lamports: u64, // The number of lamports to send the payee if the schedule completes | ||
}, | ||
|
||
/// Load an account and pass its data to the contract for inspection. | ||
RedeemTokens, | ||
|
||
/// Tell the contract that the `InitializeAccount` with `Signature` has been | ||
/// signed by the containing transaction's `Pubkey`. | ||
Terminate, | ||
} | ||
|
||
fn initialize_account( | ||
terminator_pubkey: &Pubkey, | ||
payee_pubkey: &Pubkey, | ||
contract_pubkey: &Pubkey, | ||
start_dt: DateTime<Utc>, | ||
oracle_pubkey: &Pubkey, | ||
lamports: u64, | ||
) -> Instruction { | ||
let keys = vec![AccountMeta::new(*contract_pubkey, false)]; | ||
Instruction::new( | ||
id(), | ||
&VestInstruction::InitializeAccount { | ||
terminator_pubkey: *terminator_pubkey, | ||
payee_pubkey: *payee_pubkey, | ||
start_dt, | ||
oracle_pubkey: *oracle_pubkey, | ||
lamports, | ||
}, | ||
keys, | ||
) | ||
} | ||
|
||
pub fn create_account( | ||
terminator_pubkey: &Pubkey, | ||
payee_pubkey: &Pubkey, | ||
contract_pubkey: &Pubkey, | ||
start_dt: DateTime<Utc>, | ||
oracle_pubkey: &Pubkey, | ||
lamports: u64, | ||
) -> Vec<Instruction> { | ||
let space = serialized_size(&VestState::default()).unwrap(); | ||
vec![ | ||
system_instruction::create_account( | ||
&terminator_pubkey, | ||
contract_pubkey, | ||
lamports, | ||
space, | ||
&id(), | ||
), | ||
initialize_account( | ||
terminator_pubkey, | ||
payee_pubkey, | ||
contract_pubkey, | ||
start_dt, | ||
oracle_pubkey, | ||
lamports, | ||
), | ||
] | ||
} | ||
|
||
pub fn terminate(from: &Pubkey, contract: &Pubkey, to: &Pubkey) -> Instruction { | ||
let mut account_metas = vec![ | ||
AccountMeta::new(*from, true), | ||
AccountMeta::new(*contract, false), | ||
]; | ||
if from != to { | ||
account_metas.push(AccountMeta::new_credit_only(*to, false)); | ||
} | ||
Instruction::new(id(), &VestInstruction::Terminate, account_metas) | ||
} | ||
|
||
/// Apply account data to a contract waiting on an AccountData witness. | ||
pub fn redeem_tokens(witness_pubkey: &Pubkey, contract: &Pubkey, to: &Pubkey) -> Instruction { | ||
let account_metas = vec![ | ||
AccountMeta::new_credit_only(*witness_pubkey, false), | ||
AccountMeta::new(*contract, false), | ||
AccountMeta::new_credit_only(*to, false), | ||
]; | ||
Instruction::new(id(), &VestInstruction::RedeemTokens, account_metas) | ||
} |
Oops, something went wrong.