Skip to content

Commit

Permalink
Started adding HeartToken API
Browse files Browse the repository at this point in the history
  • Loading branch information
GabeDottl committed Apr 20, 2021
1 parent 2f4d59b commit 1e87916
Show file tree
Hide file tree
Showing 5 changed files with 246 additions and 2 deletions.
16 changes: 16 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@ use thiserror::Error;

use solana_program::program_error::ProgramError;


#[derive(Error, Debug, Copy, Clone)]
pub enum HeartTokenError {
/// Invalid instruction
#[error("Invalid Instruction")]
InvalidInstruction,
#[error("Not Rent Exempt")]
NotRentExempt,
}

impl From<HeartTokenError> for ProgramError {
fn from(e: HeartTokenError) -> Self {
ProgramError::Custom(e as u32)
}
}

#[derive(Error, Debug, Copy, Clone)]
pub enum EscrowError {
/// Invalid instruction
Expand Down
103 changes: 103 additions & 0 deletions src/heart_token.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// use crate::{error::TokenError, processor::Processor};
use solana_program::{
account_info::AccountInfo, entrypoint, entrypoint::ProgramResult,
program_error::PrintProgramError, pubkey::Pubkey,
};

// TODO: Do I need this?
entrypoint!(process_instruction);
fn process_instruction(
program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult {
if let Err(error) = process(program_id, accounts, instruction_data) {
// catch the error so we can print it
error.print::<TokenError>();
return Err(error);
}
Ok(())
}


/// Processes an [Instruction](enum.Instruction.html).
pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult {
let instruction = TokenInstruction::unpack(input)?;

match instruction {
TokenInstruction::InitializeMint {
decimals,
mint_authority,
freeze_authority,
} => {
msg!("Instruction: InitializeMint");
Self::process_initialize_mint(accounts, decimals, mint_authority, freeze_authority)
}
}
}

// Creates a new HeartToken with the specified account.
fn create_heart_token(
program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult {
// TODO: Fees - portion to verifier.
// TODO: Uniqueness check - verifier incentitivzed to ensure uniqueness?
// TODO: Incentivize user to make their unencrypted data public?

// Input: User wallet/account signature, verifier signature, verified credential proving identity.
// Side-effects:
// 1) Account checked if it has any other HeartTokens associated with it (Bloom filter?)
// 2) If account already has HeartToken, return Error & point to claim_heart_token
// 3) Else, create HeartToken

// Check if account has existing HeartToken - return Error if so.
// HeartToken
solana_program::declare_id!("So11111111111111111111111111111111111111112");
}

HeartToken data:
HeartToken ID, current account (pub/priv key)
Public data (e.g. profile)
Public, verify-only data (e.g. phone number encrypted with public key)
Public claims/credentials - e.g. Google indicating employment


// HeartToken provides auth & access log?

CRUD(auth, heart_token_target, data_key, data_filter)
// CRUD profile data; only

// HeartToken.com functionality
Query(SQL over-data?)


get_data(hearttoken, type) {
// Input: HeartToken ID (or username)


}

fn sign_contract(addr*, contract, addr_ht_requirements) {
for addr in addrs:

}

fn attest_identity(self, target_account, {name, heart_token_id}, verify_cost) {

transfer(target_account, self, verify_cost)
}

fn get_data(heart_token, schema, access_token) {

}

fn get_heart_token(self, addr) {

}


// heart_token_id is account_id. If account_id changes, you can transfer the name
// to it and it would disable the old account's heart_token access

76 changes: 75 additions & 1 deletion src/instruction.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::error::EscrowError::InvalidInstruction;
use crate::error::{HeartTokenError, EscrowError::InvalidInstruction};
use crate::state::{CredentialType, HeartToken, VerifiedCredential};
use solana_program::program_error::ProgramError;
use solana_program::{
instruction::{AccountMeta, Instruction},
Expand All @@ -8,6 +9,79 @@ use solana_program::{
use std::convert::TryInto;
use std::mem::size_of;

pub enum HeartTokenInstruction {
/// Creates a
CreateHeartToken {
heart_token_owner: Pubkey, // Wallet of holder.
// verified_credentials: Vec<VerifiedCredential>
},
// RecoverHeartToken {
// heart_token_account: Pubkey, // The account/ID of the HeartToken
// heart_token_owner: Pubkey, // Wallet of holder.
// verified_credentials: Vec<VerifiedCredential>
// },
// AddCredentialsToHeartToken {
// heart_token_owner: Pubkey,
// verified_credentials: Vec<VerifiedCredential>
// },
// SignWithHeartTokens {
// instructions: Vec<Instruction>,
// // constraints: Vec<Constraint>
// },
}

impl HeartTokenInstruction {
/// Unpacks a byte buffer into a [EscrowInstruction](enum.EscrowInstruction.html).
pub fn unpack(input: &[u8]) -> Result<Self, ProgramError> {
let (tag, rest) = input.split_first().ok_or(InvalidInstruction)?;

Ok(match tag {
0 => {
let (pubkey, _rest) = Self::unpack_pubkey(rest)?;
Self::CreateHeartToken {
heart_token_owner: pubkey,
}
}
_ => return Err(HeartTokenError::InvalidInstruction.into()),
})
}
fn unpack_pubkey(input: &[u8]) -> Result<(Pubkey, &[u8]), ProgramError> {
if input.len() >= 32 {
let (key, rest) = input.split_at(32);
let pk = Pubkey::new(key);
Ok((pk, rest))
} else {
Err(HeartTokenError::InvalidInstruction.into())
}
}

fn pack(&self) -> Vec<u8> {
let mut buf = Vec::with_capacity(size_of::<Self>());
match self {
&Self::CreateHeartToken { heart_token_owner } => {
buf.push(0);
buf.extend_from_slice(heart_token_owner.as_ref());
}
}
buf
}

pub fn create_heart_token(
heart_token_program_id: &Pubkey,
heart_token_owner: &Pubkey
) -> Result<Instruction, ProgramError> {
let accounts = vec![
AccountMeta::new(*heart_token_owner, true),
];
let data = HeartTokenInstruction::CreateHeartToken { heart_token_owner: *heart_token_owner }.pack();
Ok(Instruction {
program_id: *heart_token_program_id,
accounts,
data,
})
}
}

pub enum EscrowInstruction {
/// Starts the trade by creating and populating an escrow account and transferring ownership of the given temp token account to the PDA
///
Expand Down
33 changes: 32 additions & 1 deletion src/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,41 @@ use solana_program::{
sysvar::{rent::Rent, Sysvar},
};

use crate::{error::EscrowError, instruction::EscrowInstruction, state::Escrow};
use crate::{error::EscrowError, instruction::{EscrowInstruction, HeartTokenInstruction}, state::{HeartToken, Escrow}};

pub struct Processor;
impl Processor {
// HeartToken Process
pub fn process_heart_token(
program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult {
let instruction = HeartTokenInstruction::unpack(instruction_data)?;

match instruction {
HeartTokenInstruction::CreateHeartToken { heart_token_owner } => {
msg!("Instruction: CreateHeartToken");
Self::process_create_heart_token(accounts, heart_token_owner, program_id)
}
}
}

fn process_create_heart_token(
accounts: &[AccountInfo],
heart_token_owner: Pubkey,
program_id: &Pubkey,
) -> ProgramResult {
let account_info_iter = &mut accounts.iter();

let initializer = next_account_info(account_info_iter)?;
if !initializer.is_signer {
return Err(ProgramError::MissingRequiredSignature);
}
Ok(())
}

// Escrow Process
pub fn process(
program_id: &Pubkey,
accounts: &[AccountInfo],
Expand Down
20 changes: 20 additions & 0 deletions src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,26 @@ use solana_program::{

use arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs};

pub enum CredentialType {
DriversLicense
// TODO:
// is_uniquely_identifying
}

pub struct VerifiedCredential {
pub type_: CredentialType,
pub verifier: Pubkey,
pub timestamp_nanos: u64,
pub data: Vec<u8>
// TODO: Data location & hash.
}

pub struct HeartToken {
// ID is account ID.
pub owner: Pubkey,
pub verifiedCredential: Vec<VerifiedCredential>
}

pub struct Escrow {
pub is_initialized: bool,
pub initializer_pubkey: Pubkey,
Expand Down

0 comments on commit 1e87916

Please sign in to comment.