Minor cleanup
This commit is contained in:
parent
e1c0425c2b
commit
b61aed7250
|
@ -32,7 +32,7 @@ pub enum BudgetInstruction {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BudgetInstruction {
|
impl BudgetInstruction {
|
||||||
pub fn new_initialize_account(contract: &Pubkey, expr: BudgetExpr) -> Instruction {
|
fn new_initialize_account(contract: &Pubkey, expr: BudgetExpr) -> Instruction {
|
||||||
let mut keys = vec![];
|
let mut keys = vec![];
|
||||||
if let BudgetExpr::Pay(payment) = &expr {
|
if let BudgetExpr::Pay(payment) = &expr {
|
||||||
keys.push(AccountMeta::new(payment.to, false));
|
keys.push(AccountMeta::new(payment.to, false));
|
||||||
|
@ -41,33 +41,6 @@ impl BudgetInstruction {
|
||||||
Instruction::new(id(), &BudgetInstruction::InitializeAccount(expr), keys)
|
Instruction::new(id(), &BudgetInstruction::InitializeAccount(expr), keys)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_apply_timestamp(
|
|
||||||
from: &Pubkey,
|
|
||||||
contract: &Pubkey,
|
|
||||||
to: &Pubkey,
|
|
||||||
dt: DateTime<Utc>,
|
|
||||||
) -> Instruction {
|
|
||||||
let mut account_metas = vec![
|
|
||||||
AccountMeta::new(*from, true),
|
|
||||||
AccountMeta::new(*contract, false),
|
|
||||||
];
|
|
||||||
if from != to {
|
|
||||||
account_metas.push(AccountMeta::new(*to, false));
|
|
||||||
}
|
|
||||||
Instruction::new(id(), &BudgetInstruction::ApplyTimestamp(dt), account_metas)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_apply_signature(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(*to, false));
|
|
||||||
}
|
|
||||||
Instruction::new(id(), &BudgetInstruction::ApplySignature, account_metas)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_account(
|
pub fn new_account(
|
||||||
from: &Pubkey,
|
from: &Pubkey,
|
||||||
contract: &Pubkey,
|
contract: &Pubkey,
|
||||||
|
@ -118,6 +91,33 @@ impl BudgetInstruction {
|
||||||
let expr = BudgetExpr::new_cancelable_authorized_payment(witness, lamports, to, cancelable);
|
let expr = BudgetExpr::new_cancelable_authorized_payment(witness, lamports, to, cancelable);
|
||||||
Self::new_account(from, contract, lamports, expr)
|
Self::new_account(from, contract, lamports, expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_apply_timestamp(
|
||||||
|
from: &Pubkey,
|
||||||
|
contract: &Pubkey,
|
||||||
|
to: &Pubkey,
|
||||||
|
dt: DateTime<Utc>,
|
||||||
|
) -> Instruction {
|
||||||
|
let mut account_metas = vec![
|
||||||
|
AccountMeta::new(*from, true),
|
||||||
|
AccountMeta::new(*contract, false),
|
||||||
|
];
|
||||||
|
if from != to {
|
||||||
|
account_metas.push(AccountMeta::new(*to, false));
|
||||||
|
}
|
||||||
|
Instruction::new(id(), &BudgetInstruction::ApplyTimestamp(dt), account_metas)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_apply_signature(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(*to, false));
|
||||||
|
}
|
||||||
|
Instruction::new(id(), &BudgetInstruction::ApplySignature, account_metas)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -10,13 +10,17 @@ use solana_sdk::pubkey::Pubkey;
|
||||||
pub struct TradeRequestInfo {
|
pub struct TradeRequestInfo {
|
||||||
/// Direction of trade
|
/// Direction of trade
|
||||||
pub direction: Direction,
|
pub direction: Direction,
|
||||||
|
|
||||||
/// Token pair to trade
|
/// Token pair to trade
|
||||||
pub pair: TokenPair,
|
pub pair: TokenPair,
|
||||||
|
|
||||||
/// Number of tokens to exchange; refers to the primary or the secondary depending on the direction
|
/// Number of tokens to exchange; refers to the primary or the secondary depending on the direction
|
||||||
pub tokens: u64,
|
pub tokens: u64,
|
||||||
|
|
||||||
/// The price ratio the primary price over the secondary price. The primary price is fixed
|
/// The price ratio the primary price over the secondary price. The primary price is fixed
|
||||||
/// and equal to the variable `SCALER`.
|
/// and equal to the variable `SCALER`.
|
||||||
pub price: u64,
|
pub price: u64,
|
||||||
|
|
||||||
/// Token account to deposit tokens on successful swap
|
/// Token account to deposit tokens on successful swap
|
||||||
pub dst_account: Pubkey,
|
pub dst_account: Pubkey,
|
||||||
}
|
}
|
||||||
|
@ -27,20 +31,24 @@ pub enum ExchangeInstruction {
|
||||||
/// key 0 - Signer
|
/// key 0 - Signer
|
||||||
/// key 1 - New token account
|
/// key 1 - New token account
|
||||||
AccountRequest,
|
AccountRequest,
|
||||||
|
|
||||||
/// Transfer tokens between two accounts
|
/// Transfer tokens between two accounts
|
||||||
/// key 0 - Account to transfer tokens to
|
/// key 0 - Account to transfer tokens to
|
||||||
/// key 1 - Account to transfer tokens from. This can be the exchange program itself,
|
/// key 1 - Account to transfer tokens from. This can be the exchange program itself,
|
||||||
/// the exchange has a limitless number of tokens it can transfer.
|
/// the exchange has a limitless number of tokens it can transfer.
|
||||||
TransferRequest(Token, u64),
|
TransferRequest(Token, u64),
|
||||||
|
|
||||||
/// Trade request
|
/// Trade request
|
||||||
/// key 0 - Signer
|
/// key 0 - Signer
|
||||||
/// key 1 - Account in which to record the swap
|
/// key 1 - Account in which to record the swap
|
||||||
/// key 2 - Token account associated with this trade
|
/// key 2 - Token account associated with this trade
|
||||||
TradeRequest(TradeRequestInfo),
|
TradeRequest(TradeRequestInfo),
|
||||||
|
|
||||||
/// Trade cancellation
|
/// Trade cancellation
|
||||||
/// key 0 - Signer
|
/// key 0 - Signer
|
||||||
/// key 1 -Ttrade order to cancel
|
/// key 1 -Ttrade order to cancel
|
||||||
TradeCancellation,
|
TradeCancellation,
|
||||||
|
|
||||||
/// Trade swap request
|
/// Trade swap request
|
||||||
/// key 0 - Signer
|
/// key 0 - Signer
|
||||||
/// key 1 - Account in which to record the swap
|
/// key 1 - Account in which to record the swap
|
||||||
|
|
|
@ -1,89 +1,67 @@
|
||||||
use bincode;
|
|
||||||
use log::*;
|
use log::*;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use solana_sdk::account::KeyedAccount;
|
use solana_sdk::account::KeyedAccount;
|
||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use std;
|
|
||||||
|
|
||||||
#[derive(Serialize, Debug, PartialEq)]
|
#[derive(Serialize, Debug, PartialEq)]
|
||||||
pub enum Error {
|
pub enum TokenError {
|
||||||
InvalidArgument,
|
InvalidArgument,
|
||||||
InsufficentFunds,
|
InsufficentFunds,
|
||||||
NotOwner,
|
NotOwner,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for Error {
|
impl std::fmt::Display for TokenError {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
write!(f, "error")
|
write!(f, "error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl std::error::Error for Error {}
|
impl std::error::Error for TokenError {}
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, TokenError>;
|
||||||
|
|
||||||
#[derive(Debug, Default, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Default, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct TokenInfo {
|
pub struct TokenInfo {
|
||||||
/**
|
/// Total supply of tokens
|
||||||
* Total supply of tokens
|
|
||||||
*/
|
|
||||||
supply: u64,
|
supply: u64,
|
||||||
|
|
||||||
/**
|
/// Number of base 10 digits to the right of the decimal place in the total supply
|
||||||
* Number of base 10 digits to the right of the decimal place in the total supply
|
|
||||||
*/
|
|
||||||
decimals: u8,
|
decimals: u8,
|
||||||
|
|
||||||
/**
|
/// Descriptive name of this token
|
||||||
* Descriptive name of this token
|
|
||||||
*/
|
|
||||||
name: String,
|
name: String,
|
||||||
|
|
||||||
/**
|
/// Symbol for this token
|
||||||
* Symbol for this token
|
|
||||||
*/
|
|
||||||
symbol: String,
|
symbol: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct TokenAccountDelegateInfo {
|
pub struct TokenAccountDelegateInfo {
|
||||||
/**
|
/// The source account for the tokens
|
||||||
* The source account for the tokens
|
|
||||||
*/
|
|
||||||
source: Pubkey,
|
source: Pubkey,
|
||||||
|
|
||||||
/**
|
/// The original amount that this delegate account was authorized to spend up to
|
||||||
* The original amount that this delegate account was authorized to spend up to
|
|
||||||
*/
|
|
||||||
original_amount: u64,
|
original_amount: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct TokenAccountInfo {
|
pub struct TokenAccountInfo {
|
||||||
/**
|
/// The kind of token this account holds
|
||||||
* The kind of token this account holds
|
|
||||||
*/
|
|
||||||
token: Pubkey,
|
token: Pubkey,
|
||||||
|
|
||||||
/**
|
/// Owner of this account
|
||||||
* Owner of this account
|
|
||||||
*/
|
|
||||||
owner: Pubkey,
|
owner: Pubkey,
|
||||||
|
|
||||||
/**
|
/// Amount of tokens this account holds
|
||||||
* Amount of tokens this account holds
|
|
||||||
*/
|
|
||||||
amount: u64,
|
amount: u64,
|
||||||
|
|
||||||
/**
|
/// If `delegate` None, `amount` belongs to this account.
|
||||||
* If `delegate` None, `amount` belongs to this account.
|
/// If `delegate` is Option<_>, `amount` represents the remaining allowance
|
||||||
* If `delegate` is Option<_>, `amount` represents the remaining allowance
|
/// of tokens that may be transferred from the `source` account.
|
||||||
* of tokens that may be transferred from the `source` account.
|
|
||||||
*/
|
|
||||||
delegate: Option<TokenAccountDelegateInfo>,
|
delegate: Option<TokenAccountDelegateInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
enum Command {
|
enum TokenInstruction {
|
||||||
NewToken(TokenInfo),
|
NewToken(TokenInfo),
|
||||||
NewTokenAccount,
|
NewTokenAccount,
|
||||||
Transfer(u64),
|
Transfer(u64),
|
||||||
|
@ -106,14 +84,14 @@ impl Default for TokenState {
|
||||||
|
|
||||||
impl TokenState {
|
impl TokenState {
|
||||||
#[allow(clippy::needless_pass_by_value)]
|
#[allow(clippy::needless_pass_by_value)]
|
||||||
fn map_to_invalid_args(err: std::boxed::Box<bincode::ErrorKind>) -> Error {
|
fn map_to_invalid_args(err: std::boxed::Box<bincode::ErrorKind>) -> TokenError {
|
||||||
warn!("invalid argument: {:?}", err);
|
warn!("invalid argument: {:?}", err);
|
||||||
Error::InvalidArgument
|
TokenError::InvalidArgument
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deserialize(input: &[u8]) -> Result<TokenState> {
|
pub fn deserialize(input: &[u8]) -> Result<TokenState> {
|
||||||
if input.is_empty() {
|
if input.is_empty() {
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
match input[0] {
|
match input[0] {
|
||||||
0 => Ok(TokenState::Unallocated),
|
0 => Ok(TokenState::Unallocated),
|
||||||
|
@ -123,17 +101,17 @@ impl TokenState {
|
||||||
2 => Ok(TokenState::Account(
|
2 => Ok(TokenState::Account(
|
||||||
bincode::deserialize(&input[1..]).map_err(Self::map_to_invalid_args)?,
|
bincode::deserialize(&input[1..]).map_err(Self::map_to_invalid_args)?,
|
||||||
)),
|
)),
|
||||||
_ => Err(Error::InvalidArgument),
|
_ => Err(TokenError::InvalidArgument),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize(self: &TokenState, output: &mut [u8]) -> Result<()> {
|
fn serialize(self: &TokenState, output: &mut [u8]) -> Result<()> {
|
||||||
if output.is_empty() {
|
if output.is_empty() {
|
||||||
warn!("serialize fail: ouput.len is 0");
|
warn!("serialize fail: ouput.len is 0");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
match self {
|
match self {
|
||||||
TokenState::Unallocated | TokenState::Invalid => Err(Error::InvalidArgument),
|
TokenState::Unallocated | TokenState::Invalid => Err(TokenError::InvalidArgument),
|
||||||
TokenState::Token(token_info) => {
|
TokenState::Token(token_info) => {
|
||||||
output[0] = 1;
|
output[0] = 1;
|
||||||
let writer = std::io::BufWriter::new(&mut output[1..]);
|
let writer = std::io::BufWriter::new(&mut output[1..]);
|
||||||
|
@ -152,7 +130,7 @@ impl TokenState {
|
||||||
if let TokenState::Account(account_info) = self {
|
if let TokenState::Account(account_info) = self {
|
||||||
Ok(account_info.amount)
|
Ok(account_info.amount)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::InvalidArgument)
|
Err(TokenError::InvalidArgument)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,63 +144,63 @@ impl TokenState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
warn!("TokenState: non-owner rejected");
|
warn!("TokenState: non-owner rejected");
|
||||||
Err(Error::NotOwner)
|
Err(TokenError::NotOwner)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_command_newtoken(
|
pub fn process_newtoken(
|
||||||
info: &mut [KeyedAccount],
|
info: &mut [KeyedAccount],
|
||||||
token_info: TokenInfo,
|
token_info: TokenInfo,
|
||||||
input_program_accounts: &[TokenState],
|
input_accounts: &[TokenState],
|
||||||
output_program_accounts: &mut Vec<(usize, TokenState)>,
|
output_accounts: &mut Vec<(usize, TokenState)>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if input_program_accounts.len() != 2 {
|
if input_accounts.len() != 2 {
|
||||||
error!("Expected 2 accounts");
|
error!("Expected 2 accounts");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let TokenState::Account(dest_account) = &input_program_accounts[1] {
|
if let TokenState::Account(dest_account) = &input_accounts[1] {
|
||||||
if info[0].signer_key().unwrap() != &dest_account.token {
|
if info[0].signer_key().unwrap() != &dest_account.token {
|
||||||
error!("account 1 token mismatch");
|
error!("account 1 token mismatch");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if dest_account.delegate.is_some() {
|
if dest_account.delegate.is_some() {
|
||||||
error!("account 1 is a delegate and cannot accept tokens");
|
error!("account 1 is a delegate and cannot accept tokens");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut output_dest_account = dest_account.clone();
|
let mut output_dest_account = dest_account.clone();
|
||||||
output_dest_account.amount = token_info.supply;
|
output_dest_account.amount = token_info.supply;
|
||||||
output_program_accounts.push((1, TokenState::Account(output_dest_account)));
|
output_accounts.push((1, TokenState::Account(output_dest_account)));
|
||||||
} else {
|
} else {
|
||||||
error!("account 1 invalid");
|
error!("account 1 invalid");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if input_program_accounts[0] != TokenState::Unallocated {
|
if input_accounts[0] != TokenState::Unallocated {
|
||||||
error!("account 0 not available");
|
error!("account 0 not available");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
output_program_accounts.push((0, TokenState::Token(token_info)));
|
output_accounts.push((0, TokenState::Token(token_info)));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_command_newaccount(
|
pub fn process_newaccount(
|
||||||
info: &mut [KeyedAccount],
|
info: &mut [KeyedAccount],
|
||||||
input_program_accounts: &[TokenState],
|
input_accounts: &[TokenState],
|
||||||
output_program_accounts: &mut Vec<(usize, TokenState)>,
|
output_accounts: &mut Vec<(usize, TokenState)>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
// key 0 - Destination new token account
|
// key 0 - Destination new token account
|
||||||
// key 1 - Owner of the account
|
// key 1 - Owner of the account
|
||||||
// key 2 - Token this account is associated with
|
// key 2 - Token this account is associated with
|
||||||
// key 3 - Source account that this account is a delegate for (optional)
|
// key 3 - Source account that this account is a delegate for (optional)
|
||||||
if input_program_accounts.len() < 3 {
|
if input_accounts.len() < 3 {
|
||||||
error!("Expected 3 accounts");
|
error!("Expected 3 accounts");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
if input_program_accounts[0] != TokenState::Unallocated {
|
if input_accounts[0] != TokenState::Unallocated {
|
||||||
error!("account 0 is already allocated");
|
error!("account 0 is already allocated");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
let mut token_account_info = TokenAccountInfo {
|
let mut token_account_info = TokenAccountInfo {
|
||||||
token: *info[2].unsigned_key(),
|
token: *info[2].unsigned_key(),
|
||||||
|
@ -230,131 +208,131 @@ impl TokenState {
|
||||||
amount: 0,
|
amount: 0,
|
||||||
delegate: None,
|
delegate: None,
|
||||||
};
|
};
|
||||||
if input_program_accounts.len() >= 4 {
|
if input_accounts.len() >= 4 {
|
||||||
token_account_info.delegate = Some(TokenAccountDelegateInfo {
|
token_account_info.delegate = Some(TokenAccountDelegateInfo {
|
||||||
source: *info[3].unsigned_key(),
|
source: *info[3].unsigned_key(),
|
||||||
original_amount: 0,
|
original_amount: 0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
output_program_accounts.push((0, TokenState::Account(token_account_info)));
|
output_accounts.push((0, TokenState::Account(token_account_info)));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_command_transfer(
|
pub fn process_transfer(
|
||||||
info: &mut [KeyedAccount],
|
info: &mut [KeyedAccount],
|
||||||
amount: u64,
|
amount: u64,
|
||||||
input_program_accounts: &[TokenState],
|
input_accounts: &[TokenState],
|
||||||
output_program_accounts: &mut Vec<(usize, TokenState)>,
|
output_accounts: &mut Vec<(usize, TokenState)>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if input_program_accounts.len() < 3 {
|
if input_accounts.len() < 3 {
|
||||||
error!("Expected 3 accounts");
|
error!("Expected 3 accounts");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let (TokenState::Account(source_account), TokenState::Account(dest_account)) =
|
if let (TokenState::Account(source_account), TokenState::Account(dest_account)) =
|
||||||
(&input_program_accounts[1], &input_program_accounts[2])
|
(&input_accounts[1], &input_accounts[2])
|
||||||
{
|
{
|
||||||
if source_account.token != dest_account.token {
|
if source_account.token != dest_account.token {
|
||||||
error!("account 1/2 token mismatch");
|
error!("account 1/2 token mismatch");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if dest_account.delegate.is_some() {
|
if dest_account.delegate.is_some() {
|
||||||
error!("account 2 is a delegate and cannot accept tokens");
|
error!("account 2 is a delegate and cannot accept tokens");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if info[0].signer_key().unwrap() != &source_account.owner {
|
if info[0].signer_key().unwrap() != &source_account.owner {
|
||||||
error!("owner of account 1 not present");
|
error!("owner of account 1 not present");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if source_account.amount < amount {
|
if source_account.amount < amount {
|
||||||
Err(Error::InsufficentFunds)?;
|
Err(TokenError::InsufficentFunds)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut output_source_account = source_account.clone();
|
let mut output_source_account = source_account.clone();
|
||||||
output_source_account.amount -= amount;
|
output_source_account.amount -= amount;
|
||||||
output_program_accounts.push((1, TokenState::Account(output_source_account)));
|
output_accounts.push((1, TokenState::Account(output_source_account)));
|
||||||
|
|
||||||
if let Some(ref delegate_info) = source_account.delegate {
|
if let Some(ref delegate_info) = source_account.delegate {
|
||||||
if input_program_accounts.len() != 4 {
|
if input_accounts.len() != 4 {
|
||||||
error!("Expected 4 accounts");
|
error!("Expected 4 accounts");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let delegate_account = source_account;
|
let delegate_account = source_account;
|
||||||
if let TokenState::Account(source_account) = &input_program_accounts[3] {
|
if let TokenState::Account(source_account) = &input_accounts[3] {
|
||||||
if source_account.token != delegate_account.token {
|
if source_account.token != delegate_account.token {
|
||||||
error!("account 1/3 token mismatch");
|
error!("account 1/3 token mismatch");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
if info[3].unsigned_key() != &delegate_info.source {
|
if info[3].unsigned_key() != &delegate_info.source {
|
||||||
error!("Account 1 is not a delegate of account 3");
|
error!("Account 1 is not a delegate of account 3");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if source_account.amount < amount {
|
if source_account.amount < amount {
|
||||||
Err(Error::InsufficentFunds)?;
|
Err(TokenError::InsufficentFunds)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut output_source_account = source_account.clone();
|
let mut output_source_account = source_account.clone();
|
||||||
output_source_account.amount -= amount;
|
output_source_account.amount -= amount;
|
||||||
output_program_accounts.push((3, TokenState::Account(output_source_account)));
|
output_accounts.push((3, TokenState::Account(output_source_account)));
|
||||||
} else {
|
} else {
|
||||||
error!("account 3 is an invalid account");
|
error!("account 3 is an invalid account");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut output_dest_account = dest_account.clone();
|
let mut output_dest_account = dest_account.clone();
|
||||||
output_dest_account.amount += amount;
|
output_dest_account.amount += amount;
|
||||||
output_program_accounts.push((2, TokenState::Account(output_dest_account)));
|
output_accounts.push((2, TokenState::Account(output_dest_account)));
|
||||||
} else {
|
} else {
|
||||||
error!("account 1 and/or 2 are invalid accounts");
|
error!("account 1 and/or 2 are invalid accounts");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_command_approve(
|
pub fn process_approve(
|
||||||
info: &mut [KeyedAccount],
|
info: &mut [KeyedAccount],
|
||||||
amount: u64,
|
amount: u64,
|
||||||
input_program_accounts: &[TokenState],
|
input_accounts: &[TokenState],
|
||||||
output_program_accounts: &mut Vec<(usize, TokenState)>,
|
output_accounts: &mut Vec<(usize, TokenState)>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if input_program_accounts.len() != 3 {
|
if input_accounts.len() != 3 {
|
||||||
error!("Expected 3 accounts");
|
error!("Expected 3 accounts");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let (TokenState::Account(source_account), TokenState::Account(delegate_account)) =
|
if let (TokenState::Account(source_account), TokenState::Account(delegate_account)) =
|
||||||
(&input_program_accounts[1], &input_program_accounts[2])
|
(&input_accounts[1], &input_accounts[2])
|
||||||
{
|
{
|
||||||
if source_account.token != delegate_account.token {
|
if source_account.token != delegate_account.token {
|
||||||
error!("account 1/2 token mismatch");
|
error!("account 1/2 token mismatch");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if info[0].signer_key().unwrap() != &source_account.owner {
|
if info[0].signer_key().unwrap() != &source_account.owner {
|
||||||
error!("owner of account 1 not present");
|
error!("owner of account 1 not present");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if source_account.delegate.is_some() {
|
if source_account.delegate.is_some() {
|
||||||
error!("account 1 is a delegate");
|
error!("account 1 is a delegate");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
match &delegate_account.delegate {
|
match &delegate_account.delegate {
|
||||||
None => {
|
None => {
|
||||||
error!("account 2 is not a delegate");
|
error!("account 2 is not a delegate");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
Some(delegate_info) => {
|
Some(delegate_info) => {
|
||||||
if info[1].unsigned_key() != &delegate_info.source {
|
if info[1].unsigned_key() != &delegate_info.source {
|
||||||
error!("account 2 is not a delegate of account 1");
|
error!("account 2 is not a delegate of account 1");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut output_delegate_account = delegate_account.clone();
|
let mut output_delegate_account = delegate_account.clone();
|
||||||
|
@ -363,57 +341,58 @@ impl TokenState {
|
||||||
source: delegate_info.source,
|
source: delegate_info.source,
|
||||||
original_amount: amount,
|
original_amount: amount,
|
||||||
});
|
});
|
||||||
output_program_accounts.push((2, TokenState::Account(output_delegate_account)));
|
output_accounts.push((2, TokenState::Account(output_delegate_account)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error!("account 1 and/or 2 are invalid accounts");
|
error!("account 1 and/or 2 are invalid accounts");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_command_setowner(
|
pub fn process_setowner(
|
||||||
info: &mut [KeyedAccount],
|
info: &mut [KeyedAccount],
|
||||||
input_program_accounts: &[TokenState],
|
input_accounts: &[TokenState],
|
||||||
output_program_accounts: &mut Vec<(usize, TokenState)>,
|
output_accounts: &mut Vec<(usize, TokenState)>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if input_program_accounts.len() < 3 {
|
if input_accounts.len() < 3 {
|
||||||
error!("Expected 3 accounts");
|
error!("Expected 3 accounts");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let TokenState::Account(source_account) = &input_program_accounts[1] {
|
if let TokenState::Account(source_account) = &input_accounts[1] {
|
||||||
if info[0].signer_key().unwrap() != &source_account.owner {
|
if info[0].signer_key().unwrap() != &source_account.owner {
|
||||||
info!("owner of account 1 not present");
|
info!("owner of account 1 not present");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut output_source_account = source_account.clone();
|
let mut output_source_account = source_account.clone();
|
||||||
output_source_account.owner = *info[2].unsigned_key();
|
output_source_account.owner = *info[2].unsigned_key();
|
||||||
output_program_accounts.push((1, TokenState::Account(output_source_account)));
|
output_accounts.push((1, TokenState::Account(output_source_account)));
|
||||||
} else {
|
} else {
|
||||||
info!("account 1 is invalid");
|
info!("account 1 is invalid");
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process(program_id: &Pubkey, info: &mut [KeyedAccount], input: &[u8]) -> Result<()> {
|
pub fn process(program_id: &Pubkey, info: &mut [KeyedAccount], input: &[u8]) -> Result<()> {
|
||||||
let command = bincode::deserialize::<Command>(input).map_err(Self::map_to_invalid_args)?;
|
let command =
|
||||||
|
bincode::deserialize::<TokenInstruction>(input).map_err(Self::map_to_invalid_args)?;
|
||||||
info!("process_transaction: command={:?}", command);
|
info!("process_transaction: command={:?}", command);
|
||||||
|
|
||||||
if info[0].signer_key().is_none() {
|
if info[0].signer_key().is_none() {
|
||||||
Err(Error::InvalidArgument)?;
|
Err(TokenError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let input_program_accounts: Vec<TokenState> = info
|
let input_accounts: Vec<TokenState> = info
|
||||||
.iter()
|
.iter()
|
||||||
.map(|keyed_account| {
|
.map(|keyed_account| {
|
||||||
let account = &keyed_account.account;
|
let account = &keyed_account.account;
|
||||||
if account.owner == *program_id {
|
if account.owner == *program_id {
|
||||||
match Self::deserialize(&account.data) {
|
match Self::deserialize(&account.data) {
|
||||||
Ok(token_program) => token_program,
|
Ok(token_state) => token_state,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("deserialize failed: {:?}", err);
|
error!("deserialize failed: {:?}", err);
|
||||||
TokenState::Invalid
|
TokenState::Invalid
|
||||||
|
@ -425,52 +404,36 @@ impl TokenState {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
for program_account in &input_program_accounts {
|
for account in &input_accounts {
|
||||||
info!("input_program_account: data={:?}", program_account);
|
info!("input_account: data={:?}", account);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut output_program_accounts: Vec<(_, _)> = vec![];
|
let mut output_accounts: Vec<(_, _)> = vec![];
|
||||||
|
|
||||||
match command {
|
match command {
|
||||||
Command::NewToken(token_info) => Self::process_command_newtoken(
|
TokenInstruction::NewToken(token_info) => {
|
||||||
info,
|
Self::process_newtoken(info, token_info, &input_accounts, &mut output_accounts)?
|
||||||
token_info,
|
}
|
||||||
&input_program_accounts,
|
TokenInstruction::NewTokenAccount => {
|
||||||
&mut output_program_accounts,
|
Self::process_newaccount(info, &input_accounts, &mut output_accounts)?
|
||||||
)?,
|
|
||||||
Command::NewTokenAccount => Self::process_command_newaccount(
|
|
||||||
info,
|
|
||||||
&input_program_accounts,
|
|
||||||
&mut output_program_accounts,
|
|
||||||
)?,
|
|
||||||
|
|
||||||
Command::Transfer(amount) => Self::process_command_transfer(
|
|
||||||
info,
|
|
||||||
amount,
|
|
||||||
&input_program_accounts,
|
|
||||||
&mut output_program_accounts,
|
|
||||||
)?,
|
|
||||||
|
|
||||||
Command::Approve(amount) => Self::process_command_approve(
|
|
||||||
info,
|
|
||||||
amount,
|
|
||||||
&input_program_accounts,
|
|
||||||
&mut output_program_accounts,
|
|
||||||
)?,
|
|
||||||
|
|
||||||
Command::SetOwner => Self::process_command_setowner(
|
|
||||||
info,
|
|
||||||
&input_program_accounts,
|
|
||||||
&mut output_program_accounts,
|
|
||||||
)?,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (index, program_account) in &output_program_accounts {
|
TokenInstruction::Transfer(amount) => {
|
||||||
info!(
|
Self::process_transfer(info, amount, &input_accounts, &mut output_accounts)?
|
||||||
"output_program_account: index={} data={:?}",
|
}
|
||||||
index, program_account
|
|
||||||
);
|
TokenInstruction::Approve(amount) => {
|
||||||
Self::serialize(program_account, &mut info[*index].account.data)?;
|
Self::process_approve(info, amount, &input_accounts, &mut output_accounts)?
|
||||||
|
}
|
||||||
|
|
||||||
|
TokenInstruction::SetOwner => {
|
||||||
|
Self::process_setowner(info, &input_accounts, &mut output_accounts)?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (index, account) in &output_accounts {
|
||||||
|
info!("output_account: index={} data={:?}", index, account);
|
||||||
|
Self::serialize(account, &mut info[*index].account.data)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,17 +23,26 @@ pub enum VoteInstruction {
|
||||||
/// Initialize the VoteState for this `vote account`
|
/// Initialize the VoteState for this `vote account`
|
||||||
/// * Instruction::keys[0] - the new "vote account" to be associated with the delegate
|
/// * Instruction::keys[0] - the new "vote account" to be associated with the delegate
|
||||||
InitializeAccount,
|
InitializeAccount,
|
||||||
|
|
||||||
/// `Delegate` or `Assign` a vote account to a particular node
|
/// `Delegate` or `Assign` a vote account to a particular node
|
||||||
DelegateStake(Pubkey),
|
DelegateStake(Pubkey),
|
||||||
|
|
||||||
/// Authorize a voter to send signed votes.
|
/// Authorize a voter to send signed votes.
|
||||||
AuthorizeVoter(Pubkey),
|
AuthorizeVoter(Pubkey),
|
||||||
|
|
||||||
Vote(Vote),
|
Vote(Vote),
|
||||||
|
|
||||||
/// Clear the credits in the vote account
|
/// Clear the credits in the vote account
|
||||||
/// * Transaction::keys[0] - the "vote account"
|
/// * Transaction::keys[0] - the "vote account"
|
||||||
ClearCredits,
|
ClearCredits,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VoteInstruction {
|
impl VoteInstruction {
|
||||||
|
fn new_initialize_account(vote_id: &Pubkey) -> Instruction {
|
||||||
|
let account_metas = vec![AccountMeta::new(*vote_id, false)];
|
||||||
|
Instruction::new(id(), &VoteInstruction::InitializeAccount, account_metas)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new_account(from_id: &Pubkey, staker_id: &Pubkey, lamports: u64) -> Vec<Instruction> {
|
pub fn new_account(from_id: &Pubkey, staker_id: &Pubkey, lamports: u64) -> Vec<Instruction> {
|
||||||
let space = VoteState::max_size() as u64;
|
let space = VoteState::max_size() as u64;
|
||||||
let create_ix =
|
let create_ix =
|
||||||
|
@ -41,10 +50,12 @@ impl VoteInstruction {
|
||||||
let init_ix = VoteInstruction::new_initialize_account(staker_id);
|
let init_ix = VoteInstruction::new_initialize_account(staker_id);
|
||||||
vec![create_ix, init_ix]
|
vec![create_ix, init_ix]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_clear_credits(vote_id: &Pubkey) -> Instruction {
|
pub fn new_clear_credits(vote_id: &Pubkey) -> Instruction {
|
||||||
let account_metas = vec![AccountMeta::new(*vote_id, true)];
|
let account_metas = vec![AccountMeta::new(*vote_id, true)];
|
||||||
Instruction::new(id(), &VoteInstruction::ClearCredits, account_metas)
|
Instruction::new(id(), &VoteInstruction::ClearCredits, account_metas)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_delegate_stake(vote_id: &Pubkey, delegate_id: &Pubkey) -> Instruction {
|
pub fn new_delegate_stake(vote_id: &Pubkey, delegate_id: &Pubkey) -> Instruction {
|
||||||
let account_metas = vec![AccountMeta::new(*vote_id, true)];
|
let account_metas = vec![AccountMeta::new(*vote_id, true)];
|
||||||
Instruction::new(
|
Instruction::new(
|
||||||
|
@ -53,6 +64,7 @@ impl VoteInstruction {
|
||||||
account_metas,
|
account_metas,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_authorize_voter(vote_id: &Pubkey, authorized_voter_id: &Pubkey) -> Instruction {
|
pub fn new_authorize_voter(vote_id: &Pubkey, authorized_voter_id: &Pubkey) -> Instruction {
|
||||||
let account_metas = vec![AccountMeta::new(*vote_id, true)];
|
let account_metas = vec![AccountMeta::new(*vote_id, true)];
|
||||||
Instruction::new(
|
Instruction::new(
|
||||||
|
@ -61,10 +73,7 @@ impl VoteInstruction {
|
||||||
account_metas,
|
account_metas,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
pub fn new_initialize_account(vote_id: &Pubkey) -> Instruction {
|
|
||||||
let account_metas = vec![AccountMeta::new(*vote_id, false)];
|
|
||||||
Instruction::new(id(), &VoteInstruction::InitializeAccount, account_metas)
|
|
||||||
}
|
|
||||||
pub fn new_vote(vote_id: &Pubkey, vote: Vote) -> Instruction {
|
pub fn new_vote(vote_id: &Pubkey, vote: Vote) -> Instruction {
|
||||||
let account_metas = vec![AccountMeta::new(*vote_id, true)];
|
let account_metas = vec![AccountMeta::new(*vote_id, true)];
|
||||||
Instruction::new(id(), &VoteInstruction::Vote(vote), account_metas)
|
Instruction::new(id(), &VoteInstruction::Vote(vote), account_metas)
|
||||||
|
|
|
@ -54,6 +54,12 @@ impl SystemInstruction {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create and sign a transaction to create a system account
|
||||||
|
pub fn new_account(from_id: &Pubkey, to_id: &Pubkey, lamports: u64) -> Instruction {
|
||||||
|
let program_id = system_program::id();
|
||||||
|
Self::new_program_account(from_id, to_id, lamports, 0, &program_id)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new_assign(from_id: &Pubkey, program_id: &Pubkey) -> Instruction {
|
pub fn new_assign(from_id: &Pubkey, program_id: &Pubkey) -> Instruction {
|
||||||
let account_metas = vec![AccountMeta::new(*from_id, true)];
|
let account_metas = vec![AccountMeta::new(*from_id, true)];
|
||||||
Instruction::new(
|
Instruction::new(
|
||||||
|
|
Loading…
Reference in New Issue