mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-03 13:53:12 +00:00
add token program
This commit is contained in:
parent
29914b3220
commit
b9e0ff230f
@ -2,7 +2,7 @@ use crate::program::ProgramId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub type Nonce = u128;
|
||||
type Data = Vec<u8>;
|
||||
pub type Data = Vec<u8>;
|
||||
|
||||
/// Account to be used both in public and private contexts
|
||||
#[derive(Serialize, Deserialize, Clone, Default, PartialEq, Eq)]
|
||||
@ -18,7 +18,7 @@ pub struct Account {
|
||||
/// is public, or a `NullifierPublicKey` in case the account is private.
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(any(feature = "host", test), derive(Debug))]
|
||||
pub struct AccountId([u8; 32]);
|
||||
pub struct AccountId(pub(super) [u8; 32]);
|
||||
impl AccountId {
|
||||
pub fn new(value: [u8; 32]) -> Self {
|
||||
Self(value)
|
||||
|
||||
@ -7,6 +7,7 @@ use std::io::Read;
|
||||
|
||||
use crate::account::Account;
|
||||
|
||||
use crate::account::AccountId;
|
||||
#[cfg(feature = "host")]
|
||||
use crate::encryption::shared_key_derivation::Secp256k1Point;
|
||||
|
||||
@ -137,6 +138,12 @@ impl Secp256k1Point {
|
||||
}
|
||||
}
|
||||
|
||||
impl AccountId {
|
||||
pub fn to_bytes(&self) -> [u8; 32] {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
1
nssa/program_methods/guest/Cargo.lock
generated
1
nssa/program_methods/guest/Cargo.lock
generated
@ -1817,6 +1817,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"nssa-core",
|
||||
"risc0-zkvm",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@ -8,3 +8,4 @@ edition = "2024"
|
||||
[dependencies]
|
||||
risc0-zkvm = { version = "3.0.3", default-features = false, features = ['std'] }
|
||||
nssa-core = { path = "../../core" }
|
||||
serde = { version = "1.0.219", default-features = false }
|
||||
|
||||
166
nssa/program_methods/guest/src/bin/token.rs
Normal file
166
nssa/program_methods/guest/src/bin/token.rs
Normal file
@ -0,0 +1,166 @@
|
||||
use nssa_core::{
|
||||
account::{Account, AccountId, AccountWithMetadata, Data},
|
||||
program::{ProgramInput, read_nssa_inputs, write_nssa_outputs},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
enum Instruction {
|
||||
Transfer(u128),
|
||||
NewDefinition([u8; 6], u128),
|
||||
}
|
||||
|
||||
const TOKEN_DEFINITION_TYPE: u8 = 0;
|
||||
const TOKEN_DEFINITION_SIZE: usize = 23;
|
||||
|
||||
const TOKEN_HOLDING_TYPE: u8 = 1;
|
||||
const TOKEN_HOLDING_SIZE: usize = 49;
|
||||
|
||||
struct TokenDefinition {
|
||||
account_type: u8,
|
||||
name: [u8; 6],
|
||||
total_supply: u128,
|
||||
}
|
||||
|
||||
struct TokenHolding {
|
||||
account_type: u8,
|
||||
definition_id: AccountId,
|
||||
balance: u128,
|
||||
}
|
||||
|
||||
impl TokenDefinition {
|
||||
fn into_data(self) -> Vec<u8> {
|
||||
let mut bytes = [0; TOKEN_DEFINITION_SIZE];
|
||||
bytes[0] = self.account_type;
|
||||
bytes[1..7].copy_from_slice(&self.name);
|
||||
bytes[7..].copy_from_slice(&self.total_supply.to_le_bytes());
|
||||
bytes.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl TokenHolding {
|
||||
fn new(definition_id: &AccountId) -> Self {
|
||||
Self {
|
||||
account_type: TOKEN_HOLDING_TYPE,
|
||||
definition_id: definition_id.clone(),
|
||||
balance: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn parse(data: &[u8]) -> Option<Self> {
|
||||
if data.len() != TOKEN_HOLDING_SIZE && data[0] != TOKEN_HOLDING_TYPE {
|
||||
None
|
||||
} else {
|
||||
let account_type = data[0];
|
||||
let definition_id = AccountId::new(data[33..65].try_into().unwrap());
|
||||
let balance = u128::from_le_bytes(data[65..].try_into().unwrap());
|
||||
Some(Self {
|
||||
definition_id,
|
||||
balance,
|
||||
account_type,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn into_data(self) -> Data {
|
||||
let mut bytes = [0; TOKEN_HOLDING_SIZE];
|
||||
bytes[0] = self.account_type;
|
||||
bytes[1..33].copy_from_slice(&self.definition_id.to_bytes());
|
||||
bytes[33..].copy_from_slice(&self.balance.to_le_bytes());
|
||||
bytes.into()
|
||||
}
|
||||
}
|
||||
|
||||
fn transfer(pre_states: Vec<AccountWithMetadata>, balance_to_move: u128) {
|
||||
let [sender, recipient] = match pre_states.try_into() {
|
||||
Ok(array) => array,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
let mut sender_holding = TokenHolding::parse(&sender.account.data).unwrap();
|
||||
let mut recipient_holding = if recipient.account == Account::default() {
|
||||
TokenHolding::new(&sender_holding.definition_id)
|
||||
} else {
|
||||
TokenHolding::parse(&recipient.account.data).unwrap()
|
||||
};
|
||||
|
||||
if sender_holding.definition_id != recipient_holding.definition_id {
|
||||
panic!("Sender and recipient definition id mismatch");
|
||||
}
|
||||
|
||||
if sender_holding.balance < balance_to_move {
|
||||
panic!("Insufficient balance");
|
||||
}
|
||||
|
||||
if !sender.is_authorized {
|
||||
panic!("Sender authorization is missing");
|
||||
}
|
||||
|
||||
sender_holding.balance -= balance_to_move;
|
||||
recipient_holding.balance += balance_to_move;
|
||||
|
||||
let sender_post = {
|
||||
let mut this = sender.account.clone();
|
||||
this.data = sender_holding.into_data();
|
||||
this
|
||||
};
|
||||
let recipient_post = {
|
||||
let mut this = recipient.account.clone();
|
||||
this.data = recipient_holding.into_data();
|
||||
this
|
||||
};
|
||||
|
||||
write_nssa_outputs(vec![sender, recipient], vec![sender_post, recipient_post]);
|
||||
}
|
||||
|
||||
fn new_definition(pre_states: Vec<AccountWithMetadata>, name: [u8; 6], total_supply: u128) {
|
||||
let [definition_target_account, holding_target_account] = match pre_states.try_into() {
|
||||
Ok(array) => array,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
if definition_target_account.account != Account::default() {
|
||||
panic!("Definition target account must have default values.");
|
||||
}
|
||||
|
||||
if holding_target_account.account != Account::default() {
|
||||
panic!("Holding target account must have default values.");
|
||||
}
|
||||
|
||||
let token_definition = TokenDefinition {
|
||||
account_type: TOKEN_DEFINITION_TYPE,
|
||||
name,
|
||||
total_supply,
|
||||
};
|
||||
|
||||
let token_holding = TokenHolding {
|
||||
account_type: TOKEN_HOLDING_TYPE,
|
||||
definition_id: definition_target_account.account_id.clone(),
|
||||
balance: total_supply,
|
||||
};
|
||||
|
||||
let mut definition_target_account_post = definition_target_account.account.clone();
|
||||
definition_target_account_post.data = token_definition.into_data();
|
||||
|
||||
let mut holding_target_account_post = holding_target_account.account.clone();
|
||||
holding_target_account_post.data = token_holding.into_data();
|
||||
|
||||
write_nssa_outputs(
|
||||
vec![definition_target_account, holding_target_account],
|
||||
vec![definition_target_account_post, holding_target_account_post],
|
||||
);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let ProgramInput {
|
||||
pre_states,
|
||||
instruction,
|
||||
} = read_nssa_inputs::<Instruction>();
|
||||
|
||||
match instruction {
|
||||
Instruction::Transfer(balance_to_move) => transfer(pre_states, balance_to_move),
|
||||
Instruction::NewDefinition(name, total_supply) => {
|
||||
new_definition(pre_states, name, total_supply)
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -2,7 +2,7 @@ use nssa_core::{
|
||||
account::{Account, AccountWithMetadata},
|
||||
program::{InstructionData, ProgramId, ProgramOutput},
|
||||
};
|
||||
use program_methods::{AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID};
|
||||
use program_methods::{AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID, TOKEN_ELF, TOKEN_ID};
|
||||
use risc0_zkvm::{ExecutorEnv, ExecutorEnvBuilder, default_executor, serde::to_vec};
|
||||
use serde::Serialize;
|
||||
|
||||
@ -73,6 +73,13 @@ impl Program {
|
||||
elf: AUTHENTICATED_TRANSFER_ELF,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn token() -> Self {
|
||||
Self {
|
||||
id: TOKEN_ID,
|
||||
elf: TOKEN_ELF,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@ -86,6 +86,7 @@ impl V01State {
|
||||
};
|
||||
|
||||
this.insert_program(Program::authenticated_transfer_program());
|
||||
this.insert_program(Program::token());
|
||||
|
||||
this
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user