mirror of
https://github.com/logos-blockchain/logos-execution-zone.git
synced 2026-05-25 17:39:27 +00:00
Merge bc6ba30f6620b8eb938142202983cbfe7385bf86 into 694e48422847771b9d3d1948dc796830986003f2
This commit is contained in:
commit
c529d1ed57
@ -16,7 +16,6 @@ ignore = [
|
||||
{ id = "RUSTSEC-2026-0097", reason = "`rand` v0.8.5 is present transitively from logos crates, modification may break integration" },
|
||||
{ id = "RUSTSEC-2026-0118", reason = "`hickory-proto` v0.25.0-alpha.5 is present transitively from logos crates, modification may break integration" },
|
||||
{ id = "RUSTSEC-2026-0119", reason = "`hickory-proto` v0.25.0-alpha.5 is present transitively from logos crates, modification may break integration" },
|
||||
{ id = "RUSTSEC-2026-0145", reason = "`astral-tokio-tar` v0.6.1 is pulled transitively via testcontainers (integration_tests dev/test path); waiting on upstream fix" },
|
||||
]
|
||||
yanked = "deny"
|
||||
unused-ignored-advisory = "deny"
|
||||
|
||||
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -10203,6 +10203,7 @@ dependencies = [
|
||||
"key_protocol",
|
||||
"nssa",
|
||||
"nssa_core",
|
||||
"risc0-zkvm",
|
||||
"sequencer_service_rpc",
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use nssa::{AccountId, program::Program};
|
||||
use wallet::{PrivacyPreservingAccount, WalletCore};
|
||||
use wallet::{AccountIdentity, WalletCore};
|
||||
|
||||
// Before running this example, compile the `hello_world.rs` guest program with:
|
||||
//
|
||||
@ -44,7 +44,7 @@ async fn main() {
|
||||
// Define the desired greeting in ASCII
|
||||
let greeting: Vec<u8> = vec![72, 111, 108, 97, 32, 109, 117, 110, 100, 111, 33];
|
||||
|
||||
let accounts = vec![PrivacyPreservingAccount::PrivateOwned(account_id)];
|
||||
let accounts = vec![AccountIdentity::PrivateOwned(account_id)];
|
||||
|
||||
// Construct and submit the privacy-preserving transaction
|
||||
wallet_core
|
||||
|
||||
@ -4,7 +4,7 @@ use nssa::{
|
||||
AccountId, ProgramId, privacy_preserving_transaction::circuit::ProgramWithDependencies,
|
||||
program::Program,
|
||||
};
|
||||
use wallet::{PrivacyPreservingAccount, WalletCore};
|
||||
use wallet::{AccountIdentity, WalletCore};
|
||||
|
||||
// Before running this example, compile the `simple_tail_call.rs` guest program with:
|
||||
//
|
||||
@ -51,7 +51,7 @@ async fn main() {
|
||||
std::iter::once((hello_world.id(), hello_world)).collect();
|
||||
let program_with_dependencies = ProgramWithDependencies::new(simple_tail_call, dependencies);
|
||||
|
||||
let accounts = vec![PrivacyPreservingAccount::PrivateOwned(account_id)];
|
||||
let accounts = vec![AccountIdentity::PrivateOwned(account_id)];
|
||||
|
||||
// Construct and submit the privacy-preserving transaction
|
||||
let instruction = ();
|
||||
|
||||
@ -2,7 +2,7 @@ use clap::{Parser, Subcommand};
|
||||
use common::transaction::NSSATransaction;
|
||||
use nssa::{PublicTransaction, program::Program, public_transaction};
|
||||
use sequencer_service_rpc::RpcClient as _;
|
||||
use wallet::{PrivacyPreservingAccount, WalletCore};
|
||||
use wallet::{AccountIdentity, WalletCore};
|
||||
|
||||
// Before running this example, compile the `hello_world_with_move_function.rs` guest program with:
|
||||
//
|
||||
@ -99,7 +99,7 @@ async fn main() {
|
||||
} => {
|
||||
let instruction: Instruction = (WRITE_FUNCTION_ID, greeting.into_bytes());
|
||||
let account_id = account_id.parse().unwrap();
|
||||
let accounts = vec![PrivacyPreservingAccount::PrivateOwned(account_id)];
|
||||
let accounts = vec![AccountIdentity::PrivateOwned(account_id)];
|
||||
|
||||
wallet_core
|
||||
.send_privacy_preserving_tx(
|
||||
@ -138,8 +138,8 @@ async fn main() {
|
||||
let to = to.parse().unwrap();
|
||||
|
||||
let accounts = vec![
|
||||
PrivacyPreservingAccount::Public(from),
|
||||
PrivacyPreservingAccount::PrivateOwned(to),
|
||||
AccountIdentity::Public(from),
|
||||
AccountIdentity::PrivateOwned(to),
|
||||
];
|
||||
|
||||
wallet_core
|
||||
|
||||
@ -18,7 +18,7 @@ use nssa::{
|
||||
use nssa_core::{NullifierPublicKey, encryption::ViewingPublicKey, program::PdaSeed};
|
||||
use tokio::test;
|
||||
use wallet::{
|
||||
PrivacyPreservingAccount, WalletCore,
|
||||
AccountIdentity, WalletCore,
|
||||
cli::{Command, account::AccountSubcommand},
|
||||
};
|
||||
|
||||
@ -46,8 +46,8 @@ async fn fund_private_pda(
|
||||
wallet
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::Public(sender),
|
||||
PrivacyPreservingAccount::PrivatePdaForeign {
|
||||
AccountIdentity::Public(sender),
|
||||
AccountIdentity::PrivatePdaForeign {
|
||||
account_id: pda_account_id,
|
||||
npk,
|
||||
vpk,
|
||||
@ -83,8 +83,8 @@ async fn spend_private_pda(
|
||||
wallet
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::PrivatePdaOwned(pda_account_id),
|
||||
PrivacyPreservingAccount::PrivateForeign {
|
||||
AccountIdentity::PrivatePdaOwned(pda_account_id),
|
||||
AccountIdentity::PrivateForeign {
|
||||
npk: recipient_npk,
|
||||
vpk: recipient_vpk,
|
||||
identifier: 0,
|
||||
|
||||
@ -9,9 +9,7 @@ use sequencer_service::{GenesisAction, SequencerHandle};
|
||||
use sequencer_service_rpc::RpcClient as _;
|
||||
use tempfile::TempDir;
|
||||
use testcontainers::compose::DockerCompose;
|
||||
use wallet::{
|
||||
AccDecodeData::Decode, PrivacyPreservingAccount, WalletCore, config::WalletConfigOverrides,
|
||||
};
|
||||
use wallet::{AccDecodeData::Decode, AccountIdentity, WalletCore, config::WalletConfigOverrides};
|
||||
|
||||
use crate::{
|
||||
BEDROCK_SERVICE_PORT, BEDROCK_SERVICE_WITH_OPEN_PORT,
|
||||
@ -293,8 +291,8 @@ async fn claim_funds_from_vault_to_private(
|
||||
let (tx_hash, mut secrets) = wallet
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::PrivateOwned(owner_id),
|
||||
PrivacyPreservingAccount::Public(owner_vault_id),
|
||||
AccountIdentity::PrivateOwned(owner_id),
|
||||
AccountIdentity::Public(owner_vault_id),
|
||||
],
|
||||
instruction_data,
|
||||
&program_with_dependencies,
|
||||
|
||||
@ -19,6 +19,7 @@ sequencer_service_rpc = { workspace = true, features = ["client"] }
|
||||
tokio.workspace = true
|
||||
key_protocol.workspace = true
|
||||
serde_json.workspace = true
|
||||
risc0-zkvm.workspace = true
|
||||
|
||||
[build-dependencies]
|
||||
cbindgen = "0.29"
|
||||
|
||||
@ -14,7 +14,7 @@ use crate::{
|
||||
WalletHandle,
|
||||
},
|
||||
wallet::get_wallet,
|
||||
FfiU128,
|
||||
FfiAccountIdentity, FfiU128,
|
||||
};
|
||||
|
||||
/// Create a new public account.
|
||||
@ -653,3 +653,29 @@ pub unsafe extern "C" fn wallet_ffi_import_private_account(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Free account identity returned by `wallet_ffi_resolve_private_account` or
|
||||
/// `wallet_ffi_resolve_public_account`.
|
||||
///
|
||||
/// # Safety
|
||||
/// The account must be either null or a valid account returned by
|
||||
/// `wallet_ffi_resolve_private_account` or `wallet_ffi_resolve_public_account`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wallet_ffi_free_account_identity(
|
||||
account_identity: *mut FfiAccountIdentity,
|
||||
) {
|
||||
if account_identity.is_null() {
|
||||
return;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let account_identity = &*account_identity;
|
||||
if !account_identity.viewing_public_key.is_null() {
|
||||
let slice = std::slice::from_raw_parts_mut(
|
||||
account_identity.viewing_public_key.cast_mut(),
|
||||
account_identity.viewing_public_key_len,
|
||||
);
|
||||
drop(Box::from_raw(std::ptr::from_mut::<[u8]>(slice)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,6 +41,8 @@ pub enum WalletFfiError {
|
||||
InvalidTypeConversion = 15,
|
||||
/// Invalid Key value.
|
||||
InvalidKeyValue = 16,
|
||||
/// Invalid program bytecode
|
||||
InvalidBytecode = 17,
|
||||
/// Internal error (catch-all).
|
||||
InternalError = 99,
|
||||
}
|
||||
|
||||
247
wallet-ffi/src/generic_transaction.rs
Normal file
247
wallet-ffi/src/generic_transaction.rs
Normal file
@ -0,0 +1,247 @@
|
||||
use std::{collections::HashMap, ffi::CString};
|
||||
|
||||
use nssa::{privacy_preserving_transaction::circuit::ProgramWithDependencies, program::Program};
|
||||
|
||||
use crate::{
|
||||
block_on,
|
||||
error::{print_error, WalletFfiError},
|
||||
map_execution_error,
|
||||
wallet::get_wallet,
|
||||
FfiAccountIdentity, FfiTransferResult, WalletHandle,
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct SerializationHelperResult {
|
||||
pub instruction_words: *mut u32,
|
||||
pub instruction_words_size: usize,
|
||||
pub error: WalletFfiError,
|
||||
}
|
||||
|
||||
impl SerializationHelperResult {
|
||||
fn from_err(error: WalletFfiError) -> Self {
|
||||
Self {
|
||||
instruction_words: std::ptr::null_mut(),
|
||||
instruction_words_size: 0,
|
||||
error,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialize sequence of bytes into RISC0 readable words
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `input_instruction_data`: Valid pointer to a sequence of bytes
|
||||
/// - `input_instruction_data_size`: Size of `input_instruction_data`
|
||||
///
|
||||
/// # Returns
|
||||
/// - `Success` on successful creation
|
||||
/// - Error code on failure
|
||||
///
|
||||
/// # Safety
|
||||
/// - `input_instruction_data` must be a valid pointer
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wallet_ffi_serialization_helper(
|
||||
input_instruction_data: *const u8,
|
||||
input_instruction_data_size: usize,
|
||||
) -> SerializationHelperResult {
|
||||
if input_instruction_data.is_null() {
|
||||
print_error("Null input pointer for instruction_data");
|
||||
return SerializationHelperResult::from_err(WalletFfiError::NullPointer);
|
||||
}
|
||||
|
||||
let input_slice =
|
||||
unsafe { std::slice::from_raw_parts(input_instruction_data, input_instruction_data_size) };
|
||||
let res_vec_u32 = match risc0_zkvm::serde::to_vec(input_slice).map_err(|err| {
|
||||
print_error(format!(
|
||||
"Failed to serialize input into words with err {err}"
|
||||
));
|
||||
WalletFfiError::SerializationError
|
||||
}) {
|
||||
Ok(res) => res,
|
||||
Err(err) => return SerializationHelperResult::from_err(err),
|
||||
};
|
||||
let res_len = res_vec_u32.len();
|
||||
let res_boxed = res_vec_u32.into_boxed_slice();
|
||||
let res_ptr = Box::into_raw(res_boxed).cast::<u32>();
|
||||
|
||||
SerializationHelperResult {
|
||||
instruction_words: res_ptr,
|
||||
instruction_words_size: res_len,
|
||||
error: WalletFfiError::Success,
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
/// Intended to be created manually
|
||||
pub struct FfiProgram {
|
||||
pub elf_data: *const u8,
|
||||
pub elf_size: usize,
|
||||
}
|
||||
|
||||
impl TryFrom<&FfiProgram> for Program {
|
||||
type Error = WalletFfiError;
|
||||
|
||||
fn try_from(value: &FfiProgram) -> Result<Self, Self::Error> {
|
||||
let mut elf = Vec::with_capacity(value.elf_size);
|
||||
|
||||
// Alignment will be different, we need to read elements one-by-one
|
||||
for i in 0..value.elf_size {
|
||||
elf.push(unsafe { *value.elf_data.add(i) });
|
||||
}
|
||||
|
||||
Self::new(elf).map_err(|err| {
|
||||
print_error(format!("Invalid program bytecode, err: {err}"));
|
||||
WalletFfiError::InvalidBytecode
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
/// Intended to be created manually
|
||||
pub struct FfiProgramWithDependencies {
|
||||
pub program: FfiProgram,
|
||||
pub deps: *const FfiProgram,
|
||||
pub deps_size: usize,
|
||||
}
|
||||
|
||||
impl TryFrom<FfiProgramWithDependencies> for ProgramWithDependencies {
|
||||
type Error = WalletFfiError;
|
||||
|
||||
fn try_from(value: FfiProgramWithDependencies) -> Result<Self, Self::Error> {
|
||||
let mut program_map = HashMap::new();
|
||||
|
||||
let orig_program = (&value.program).try_into()?;
|
||||
|
||||
// Alignment will be different, we need to read elements one-by-one
|
||||
for i in 0..value.deps_size {
|
||||
let program_dep: Program = unsafe { value.deps.add(i).as_ref() }
|
||||
.ok_or(WalletFfiError::NullPointer)?
|
||||
.try_into()?;
|
||||
|
||||
program_map.insert(program_dep.id(), program_dep);
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
program: orig_program,
|
||||
dependencies: program_map,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub enum FfiExecutionFlow {
|
||||
Public = 0,
|
||||
PrivacyPreserving = 1,
|
||||
}
|
||||
|
||||
/// Send generic transaction
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `handle`: Valid pointer to wallet handle
|
||||
/// - `account_identities`: Valid pointer to list of `FfiAccountIdentity`
|
||||
/// - `instruction_words`: Valid pointer to instruction words
|
||||
/// - `out_result`: Valid pointer to `FfiTransferResult`
|
||||
///
|
||||
/// # Returns
|
||||
/// - `Success` on successful creation
|
||||
/// - Error code on failure
|
||||
///
|
||||
/// # Safety
|
||||
/// - `handle` must be a valid pointer
|
||||
/// - `account_identities` must be a valid pointer
|
||||
/// - `instruction_words` must be a valid pointer
|
||||
/// - `out_result` must be a valid pointer
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wallet_ffi_send_generic_transaction(
|
||||
handle: *mut WalletHandle,
|
||||
account_identities: *const FfiAccountIdentity,
|
||||
account_identities_size: usize,
|
||||
instruction_words: *const u32,
|
||||
instruction_words_size: usize,
|
||||
program_with_dependencies: FfiProgramWithDependencies,
|
||||
out_result: *mut FfiTransferResult,
|
||||
) -> WalletFfiError {
|
||||
let wrapper = match get_wallet(handle) {
|
||||
Ok(w) => w,
|
||||
Err(e) => return e,
|
||||
};
|
||||
|
||||
if account_identities.is_null() {
|
||||
print_error("Null output pointer for account identities list");
|
||||
return WalletFfiError::NullPointer;
|
||||
}
|
||||
|
||||
if instruction_words.is_null() {
|
||||
print_error("Null output pointer for instruction data");
|
||||
return WalletFfiError::NullPointer;
|
||||
}
|
||||
|
||||
if out_result.is_null() {
|
||||
print_error("Null output pointer return hash");
|
||||
return WalletFfiError::NullPointer;
|
||||
}
|
||||
|
||||
let wallet = match wrapper.core.lock() {
|
||||
Ok(w) => w,
|
||||
Err(e) => {
|
||||
print_error(format!("Failed to lock wallet: {e}"));
|
||||
return WalletFfiError::InternalError;
|
||||
}
|
||||
};
|
||||
|
||||
let mut accounts = Vec::with_capacity(account_identities_size);
|
||||
let mut instruction_data = Vec::with_capacity(instruction_words_size);
|
||||
|
||||
// Alignment will be different, we need to read elements one-by-one
|
||||
for i in 0..account_identities_size {
|
||||
accounts.push(
|
||||
match match unsafe { account_identities.add(i).as_ref() }
|
||||
.ok_or(WalletFfiError::NullPointer)
|
||||
{
|
||||
Ok(v) => v,
|
||||
Err(err) => {
|
||||
print_error(format!(
|
||||
"account_identities_size does not match actual size of account_identities"
|
||||
));
|
||||
return err;
|
||||
}
|
||||
}
|
||||
.try_into()
|
||||
{
|
||||
Ok(v) => v,
|
||||
Err(err) => return err,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Alignment will be different, we need to read elements one-by-one
|
||||
for i in 0..instruction_words_size {
|
||||
instruction_data.push(unsafe { *instruction_words.add(i) });
|
||||
}
|
||||
|
||||
let program = match program_with_dependencies.try_into() {
|
||||
Ok(v) => v,
|
||||
Err(err) => return err,
|
||||
};
|
||||
|
||||
match block_on(wallet.send_pub_tx(accounts, instruction_data, &program)) {
|
||||
Ok(tx_hash) => {
|
||||
let tx_hash = CString::new(tx_hash.to_string())
|
||||
.map_or(std::ptr::null_mut(), std::ffi::CString::into_raw);
|
||||
|
||||
unsafe {
|
||||
(*out_result).tx_hash = tx_hash;
|
||||
(*out_result).success = true;
|
||||
}
|
||||
WalletFfiError::Success
|
||||
}
|
||||
Err(e) => {
|
||||
print_error(format!("Public send failed: {e:?}"));
|
||||
unsafe {
|
||||
(*out_result).tx_hash = std::ptr::null_mut();
|
||||
(*out_result).success = false;
|
||||
}
|
||||
map_execution_error(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3,11 +3,13 @@
|
||||
use std::ptr;
|
||||
|
||||
use nssa::{AccountId, PublicKey};
|
||||
use wallet::AccountIdentity;
|
||||
|
||||
use crate::{
|
||||
error::{print_error, WalletFfiError},
|
||||
types::{FfiBytes32, FfiPrivateAccountKeys, FfiPublicAccountKey, WalletHandle},
|
||||
wallet::get_wallet,
|
||||
FfiAccountIdentity,
|
||||
};
|
||||
|
||||
/// Get the public key for a public account.
|
||||
@ -250,3 +252,85 @@ pub unsafe extern "C" fn wallet_ffi_account_id_from_base58(
|
||||
|
||||
WalletFfiError::Success
|
||||
}
|
||||
|
||||
/// Resolve public account.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `account_id`: 32 bytes of the public account ID
|
||||
/// - `needs_sign`: does account needs signing
|
||||
/// - `out_account_identity`: valid pointer, where output will be written
|
||||
///
|
||||
/// # Returns
|
||||
/// - `Success` on successful retrieval
|
||||
///
|
||||
/// # Safety
|
||||
/// - `out_account_identity` must be a valid pointer to a `FfiAccountManagerAccountIdentity` struct
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wallet_ffi_resolve_public_account(
|
||||
account_id: FfiBytes32,
|
||||
needs_sign: bool,
|
||||
out_account_identity: *mut FfiAccountIdentity,
|
||||
) -> WalletFfiError {
|
||||
let resolved_account = if needs_sign {
|
||||
AccountIdentity::Public(account_id.into())
|
||||
} else {
|
||||
AccountIdentity::PublicNoSign(account_id.into())
|
||||
};
|
||||
|
||||
unsafe {
|
||||
*out_account_identity = resolved_account.into();
|
||||
}
|
||||
|
||||
WalletFfiError::Success
|
||||
}
|
||||
|
||||
/// Resolve private account.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `handle`: Valid wallet handle
|
||||
/// - `account_id`: 32 bytes of the public account ID
|
||||
/// - `out_account_identity`: valid pointer, where output will be written
|
||||
///
|
||||
/// # Returns
|
||||
/// - `Success` on successful retrieval
|
||||
/// - `InternalError` if wailed to lock wallet
|
||||
/// - `AccountNotFound` if failed to found account
|
||||
///
|
||||
/// # Safety
|
||||
/// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
|
||||
/// - `out_account_identity` must be a valid pointer to a `FfiAccountManagerAccountIdentity` struct
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wallet_ffi_resolve_private_account(
|
||||
handle: *mut WalletHandle,
|
||||
account_id: FfiBytes32,
|
||||
out_account_identity: *mut FfiAccountIdentity,
|
||||
) -> WalletFfiError {
|
||||
let wrapper = match get_wallet(handle) {
|
||||
Ok(w) => w,
|
||||
Err(e) => return e,
|
||||
};
|
||||
|
||||
let wallet = match wrapper.core.lock() {
|
||||
Ok(w) => w,
|
||||
Err(e) => {
|
||||
print_error(format!("Failed to lock wallet: {e}"));
|
||||
return WalletFfiError::InternalError;
|
||||
}
|
||||
};
|
||||
|
||||
let account_id = account_id.into();
|
||||
|
||||
let resolved_account = match wallet.resolve_private_account(account_id) {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
print_error(format!("Account not found"));
|
||||
return WalletFfiError::AccountNotFound;
|
||||
}
|
||||
};
|
||||
|
||||
unsafe {
|
||||
*out_account_identity = resolved_account.into();
|
||||
}
|
||||
|
||||
WalletFfiError::Success
|
||||
}
|
||||
|
||||
@ -42,6 +42,7 @@ use crate::error::print_error;
|
||||
|
||||
pub mod account;
|
||||
pub mod error;
|
||||
pub mod generic_transaction;
|
||||
pub mod keys;
|
||||
pub mod pinata;
|
||||
pub mod sync;
|
||||
|
||||
@ -4,7 +4,8 @@ use core::slice;
|
||||
use std::{ffi::c_char, ptr};
|
||||
|
||||
use nssa::Data;
|
||||
use nssa_core::encryption::shared_key_derivation::Secp256k1Point;
|
||||
use nssa_core::{encryption::shared_key_derivation::Secp256k1Point, NullifierPublicKey};
|
||||
use wallet::AccountIdentity;
|
||||
|
||||
use crate::error::WalletFfiError;
|
||||
|
||||
@ -172,6 +173,45 @@ impl FfiPrivateAccountKeys {
|
||||
}
|
||||
}
|
||||
|
||||
/// Enumeration to represent kinds of FfiAccountManagerAccountIdentity
|
||||
#[repr(C)]
|
||||
pub enum FfiAccountIdentityKind {
|
||||
Public = 0,
|
||||
PublicNoSign = 1,
|
||||
PrivateOwned = 2,
|
||||
PrivateForeign = 3,
|
||||
PrivatePdaOwned = 4,
|
||||
PrivatePdaForeign = 5,
|
||||
PrivateShared = 6,
|
||||
PrivatePdaShared = 7,
|
||||
}
|
||||
|
||||
/// Struct representing of account identity, given to `AccountManager` at intialization
|
||||
#[repr(C)]
|
||||
pub struct FfiAccountIdentity {
|
||||
kind: FfiAccountIdentityKind,
|
||||
pub account_id: FfiBytes32,
|
||||
pub nullifier_secret_key: FfiBytes32,
|
||||
pub nullifier_public_key: FfiBytes32,
|
||||
pub viewing_public_key: *const u8,
|
||||
pub viewing_public_key_len: usize,
|
||||
pub identifier: FfiU128,
|
||||
}
|
||||
|
||||
impl Default for FfiAccountIdentity {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
kind: FfiAccountIdentityKind::Public,
|
||||
account_id: FfiBytes32::default(),
|
||||
nullifier_secret_key: FfiBytes32::default(),
|
||||
nullifier_public_key: FfiBytes32::default(),
|
||||
viewing_public_key: std::ptr::null(),
|
||||
viewing_public_key_len: 0,
|
||||
identifier: FfiU128::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u128> for FfiU128 {
|
||||
fn from(value: u128) -> Self {
|
||||
Self {
|
||||
@ -192,6 +232,12 @@ impl From<nssa::AccountId> for FfiBytes32 {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[u8; 32]> for FfiBytes32 {
|
||||
fn from(value: [u8; 32]) -> Self {
|
||||
Self { data: value }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FfiBytes32> for nssa::AccountId {
|
||||
fn from(bytes: FfiBytes32) -> Self {
|
||||
Self::new(bytes.data)
|
||||
@ -266,3 +312,228 @@ impl TryFrom<&FfiPublicAccountKey> for nssa::PublicKey {
|
||||
Ok(public_key)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AccountIdentity> for FfiAccountIdentity {
|
||||
fn from(value: AccountIdentity) -> Self {
|
||||
match value {
|
||||
AccountIdentity::Public(account_id) => Self {
|
||||
kind: FfiAccountIdentityKind::Public,
|
||||
account_id: account_id.into(),
|
||||
..Default::default()
|
||||
},
|
||||
AccountIdentity::PublicNoSign(account_id) => Self {
|
||||
kind: FfiAccountIdentityKind::PublicNoSign,
|
||||
account_id: account_id.into(),
|
||||
..Default::default()
|
||||
},
|
||||
AccountIdentity::PrivateOwned(account_id) => Self {
|
||||
kind: FfiAccountIdentityKind::PrivateOwned,
|
||||
account_id: account_id.into(),
|
||||
..Default::default()
|
||||
},
|
||||
AccountIdentity::PrivateForeign {
|
||||
npk,
|
||||
vpk,
|
||||
identifier,
|
||||
} => {
|
||||
let vpk_vec = vpk.0;
|
||||
let vpk_len = vpk_vec.len();
|
||||
let vpk_data = if vpk_len > 0 {
|
||||
let vpk_data_boxed = vpk_vec.into_boxed_slice();
|
||||
Box::into_raw(vpk_data_boxed) as *const u8
|
||||
} else {
|
||||
ptr::null()
|
||||
};
|
||||
|
||||
Self {
|
||||
kind: FfiAccountIdentityKind::PrivateForeign,
|
||||
nullifier_public_key: npk.0.into(),
|
||||
viewing_public_key: vpk_data,
|
||||
viewing_public_key_len: vpk_len,
|
||||
identifier: identifier.into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
AccountIdentity::PrivatePdaOwned(account_id) => Self {
|
||||
kind: FfiAccountIdentityKind::PrivatePdaOwned,
|
||||
account_id: account_id.into(),
|
||||
..Default::default()
|
||||
},
|
||||
AccountIdentity::PrivatePdaForeign {
|
||||
account_id,
|
||||
npk,
|
||||
vpk,
|
||||
identifier,
|
||||
} => {
|
||||
let vpk_vec = vpk.0;
|
||||
let vpk_len = vpk_vec.len();
|
||||
let vpk_data = if vpk_len > 0 {
|
||||
let vpk_data_boxed = vpk_vec.into_boxed_slice();
|
||||
Box::into_raw(vpk_data_boxed) as *const u8
|
||||
} else {
|
||||
ptr::null()
|
||||
};
|
||||
|
||||
Self {
|
||||
kind: FfiAccountIdentityKind::PrivatePdaForeign,
|
||||
account_id: account_id.into(),
|
||||
nullifier_public_key: npk.0.into(),
|
||||
viewing_public_key: vpk_data,
|
||||
viewing_public_key_len: vpk_len,
|
||||
identifier: identifier.into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
AccountIdentity::PrivateShared {
|
||||
nsk,
|
||||
npk,
|
||||
vpk,
|
||||
identifier,
|
||||
} => {
|
||||
let vpk_vec = vpk.0;
|
||||
let vpk_len = vpk_vec.len();
|
||||
let vpk_data = if vpk_len > 0 {
|
||||
let vpk_data_boxed = vpk_vec.into_boxed_slice();
|
||||
Box::into_raw(vpk_data_boxed) as *const u8
|
||||
} else {
|
||||
ptr::null()
|
||||
};
|
||||
|
||||
Self {
|
||||
kind: FfiAccountIdentityKind::PrivateShared,
|
||||
nullifier_secret_key: nsk.into(),
|
||||
nullifier_public_key: npk.0.into(),
|
||||
viewing_public_key: vpk_data,
|
||||
viewing_public_key_len: vpk_len,
|
||||
identifier: identifier.into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
AccountIdentity::PrivatePdaShared {
|
||||
account_id,
|
||||
nsk,
|
||||
npk,
|
||||
vpk,
|
||||
identifier,
|
||||
} => {
|
||||
let vpk_vec = vpk.0;
|
||||
let vpk_len = vpk_vec.len();
|
||||
let vpk_data = if vpk_len > 0 {
|
||||
let vpk_data_boxed = vpk_vec.into_boxed_slice();
|
||||
Box::into_raw(vpk_data_boxed) as *const u8
|
||||
} else {
|
||||
ptr::null()
|
||||
};
|
||||
|
||||
Self {
|
||||
kind: FfiAccountIdentityKind::PrivateShared,
|
||||
account_id: account_id.into(),
|
||||
nullifier_secret_key: nsk.into(),
|
||||
nullifier_public_key: npk.0.into(),
|
||||
viewing_public_key: vpk_data,
|
||||
viewing_public_key_len: vpk_len,
|
||||
identifier: identifier.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&FfiAccountIdentity> for AccountIdentity {
|
||||
type Error = WalletFfiError;
|
||||
|
||||
fn try_from(value: &FfiAccountIdentity) -> Result<Self, Self::Error> {
|
||||
match value.kind {
|
||||
FfiAccountIdentityKind::Public => Ok(AccountIdentity::Public(value.account_id.into())),
|
||||
FfiAccountIdentityKind::PublicNoSign => {
|
||||
Ok(AccountIdentity::PublicNoSign(value.account_id.into()))
|
||||
}
|
||||
FfiAccountIdentityKind::PrivateOwned => {
|
||||
Ok(AccountIdentity::PrivateOwned(value.account_id.into()))
|
||||
}
|
||||
FfiAccountIdentityKind::PrivateForeign => {
|
||||
let vpk = if value.viewing_public_key_len == 33 {
|
||||
let slice = unsafe {
|
||||
slice::from_raw_parts(
|
||||
value.viewing_public_key,
|
||||
value.viewing_public_key_len,
|
||||
)
|
||||
};
|
||||
Ok(Secp256k1Point(slice.to_vec()))
|
||||
} else {
|
||||
Err(WalletFfiError::InvalidKeyValue)
|
||||
}?;
|
||||
|
||||
Ok(AccountIdentity::PrivateForeign {
|
||||
npk: NullifierPublicKey(value.nullifier_public_key.data),
|
||||
vpk,
|
||||
identifier: value.identifier.into(),
|
||||
})
|
||||
}
|
||||
FfiAccountIdentityKind::PrivatePdaOwned => {
|
||||
Ok(AccountIdentity::PrivatePdaOwned(value.account_id.into()))
|
||||
}
|
||||
FfiAccountIdentityKind::PrivatePdaForeign => {
|
||||
let vpk = if value.viewing_public_key_len == 33 {
|
||||
let slice = unsafe {
|
||||
slice::from_raw_parts(
|
||||
value.viewing_public_key,
|
||||
value.viewing_public_key_len,
|
||||
)
|
||||
};
|
||||
Ok(Secp256k1Point(slice.to_vec()))
|
||||
} else {
|
||||
Err(WalletFfiError::InvalidKeyValue)
|
||||
}?;
|
||||
|
||||
Ok(AccountIdentity::PrivatePdaForeign {
|
||||
account_id: value.account_id.into(),
|
||||
npk: NullifierPublicKey(value.nullifier_public_key.data),
|
||||
vpk,
|
||||
identifier: value.identifier.into(),
|
||||
})
|
||||
}
|
||||
FfiAccountIdentityKind::PrivateShared => {
|
||||
let vpk = if value.viewing_public_key_len == 33 {
|
||||
let slice = unsafe {
|
||||
slice::from_raw_parts(
|
||||
value.viewing_public_key,
|
||||
value.viewing_public_key_len,
|
||||
)
|
||||
};
|
||||
Ok(Secp256k1Point(slice.to_vec()))
|
||||
} else {
|
||||
Err(WalletFfiError::InvalidKeyValue)
|
||||
}?;
|
||||
|
||||
Ok(AccountIdentity::PrivateShared {
|
||||
nsk: value.nullifier_secret_key.data,
|
||||
npk: NullifierPublicKey(value.nullifier_public_key.data),
|
||||
vpk,
|
||||
identifier: value.identifier.into(),
|
||||
})
|
||||
}
|
||||
FfiAccountIdentityKind::PrivatePdaShared => {
|
||||
let vpk = if value.viewing_public_key_len == 33 {
|
||||
let slice = unsafe {
|
||||
slice::from_raw_parts(
|
||||
value.viewing_public_key,
|
||||
value.viewing_public_key_len,
|
||||
)
|
||||
};
|
||||
Ok(Secp256k1Point(slice.to_vec()))
|
||||
} else {
|
||||
Err(WalletFfiError::InvalidKeyValue)
|
||||
}?;
|
||||
|
||||
Ok(AccountIdentity::PrivatePdaShared {
|
||||
account_id: value.account_id.into(),
|
||||
nsk: value.nullifier_secret_key.data,
|
||||
npk: NullifierPublicKey(value.nullifier_public_key.data),
|
||||
vpk,
|
||||
identifier: value.identifier.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,12 +103,30 @@ typedef enum WalletFfiError {
|
||||
* Invalid Key value.
|
||||
*/
|
||||
INVALID_KEY_VALUE = 16,
|
||||
/**
|
||||
* Invalid program bytecode
|
||||
*/
|
||||
INVALID_BYTECODE = 17,
|
||||
/**
|
||||
* Internal error (catch-all).
|
||||
*/
|
||||
INTERNAL_ERROR = 99,
|
||||
} WalletFfiError;
|
||||
|
||||
/**
|
||||
* Enumeration to represent kinds of FfiAccountManagerAccountIdentity
|
||||
*/
|
||||
typedef enum FfiAccountIdentityKind {
|
||||
PUBLIC = 0,
|
||||
PUBLIC_NO_SIGN = 1,
|
||||
PRIVATE_OWNED = 2,
|
||||
PRIVATE_FOREIGN = 3,
|
||||
PRIVATE_PDA_OWNED = 4,
|
||||
PRIVATE_PDA_FOREIGN = 5,
|
||||
PRIVATE_SHARED = 6,
|
||||
PRIVATE_PDA_SHARED = 7,
|
||||
} FfiAccountIdentityKind;
|
||||
|
||||
/**
|
||||
* Opaque pointer to the Wallet instance.
|
||||
*
|
||||
@ -201,11 +219,40 @@ typedef struct FfiAccount {
|
||||
} FfiAccount;
|
||||
|
||||
/**
|
||||
* Public key info for a public account.
|
||||
* Struct representing of account identity, given to `AccountManager` at intialization
|
||||
*/
|
||||
typedef struct FfiPublicAccountKey {
|
||||
struct FfiBytes32 public_key;
|
||||
} FfiPublicAccountKey;
|
||||
typedef struct FfiAccountIdentity {
|
||||
enum FfiAccountIdentityKind kind;
|
||||
struct FfiBytes32 account_id;
|
||||
struct FfiBytes32 nullifier_secret_key;
|
||||
struct FfiBytes32 nullifier_public_key;
|
||||
const uint8_t *viewing_public_key;
|
||||
uintptr_t viewing_public_key_len;
|
||||
struct FfiU128 identifier;
|
||||
} FfiAccountIdentity;
|
||||
|
||||
typedef struct SerializationHelperResult {
|
||||
uint32_t *instruction_words;
|
||||
uintptr_t instruction_words_size;
|
||||
enum WalletFfiError error;
|
||||
} SerializationHelperResult;
|
||||
|
||||
/**
|
||||
* Intended to be created manually
|
||||
*/
|
||||
typedef struct FfiProgram {
|
||||
const uint8_t *elf_data;
|
||||
uintptr_t elf_size;
|
||||
} FfiProgram;
|
||||
|
||||
/**
|
||||
* Intended to be created manually
|
||||
*/
|
||||
typedef struct FfiProgramWithDependencies {
|
||||
struct FfiProgram program;
|
||||
const struct FfiProgram *deps;
|
||||
uintptr_t deps_size;
|
||||
} FfiProgramWithDependencies;
|
||||
|
||||
/**
|
||||
* Result of a transfer operation.
|
||||
@ -221,6 +268,13 @@ typedef struct FfiTransferResult {
|
||||
bool success;
|
||||
} FfiTransferResult;
|
||||
|
||||
/**
|
||||
* Public key info for a public account.
|
||||
*/
|
||||
typedef struct FfiPublicAccountKey {
|
||||
struct FfiBytes32 public_key;
|
||||
} FfiPublicAccountKey;
|
||||
|
||||
/**
|
||||
* Create a new public account.
|
||||
*
|
||||
@ -454,6 +508,60 @@ enum WalletFfiError wallet_ffi_import_private_account(struct WalletHandle *handl
|
||||
const struct FfiU128 *identifier,
|
||||
const char *account_state_json);
|
||||
|
||||
/**
|
||||
* Free account identity returned by `wallet_ffi_resolve_private_account` or
|
||||
* `wallet_ffi_resolve_public_account`.
|
||||
*
|
||||
* # Safety
|
||||
* The account must be either null or a valid account returned by
|
||||
* `wallet_ffi_resolve_private_account` or `wallet_ffi_resolve_public_account`.
|
||||
*/
|
||||
void wallet_ffi_free_account_identity(struct FfiAccountIdentity *account_identity);
|
||||
|
||||
/**
|
||||
* Serialize sequence of bytes into RISC0 readable words
|
||||
*
|
||||
* # Parameters
|
||||
* - `input_instruction_data`: Valid pointer to a sequence of bytes
|
||||
* - `input_instruction_data_size`: Size of `input_instruction_data`
|
||||
*
|
||||
* # Returns
|
||||
* - `Success` on successful creation
|
||||
* - Error code on failure
|
||||
*
|
||||
* # Safety
|
||||
* - `input_instruction_data` must be a valid pointer
|
||||
*/
|
||||
struct SerializationHelperResult wallet_ffi_serialization_helper(const uint8_t *input_instruction_data,
|
||||
uintptr_t input_instruction_data_size);
|
||||
|
||||
/**
|
||||
* Send generic transaction
|
||||
*
|
||||
* # Parameters
|
||||
* - `handle`: Valid pointer to wallet handle
|
||||
* - `account_identities`: Valid pointer to list of `FfiAccountIdentity`
|
||||
* - `instruction_words`: Valid pointer to instruction words
|
||||
* - `out_result`: Valid pointer to `FfiTransferResult`
|
||||
*
|
||||
* # Returns
|
||||
* - `Success` on successful creation
|
||||
* - Error code on failure
|
||||
*
|
||||
* # Safety
|
||||
* - `handle` must be a valid pointer
|
||||
* - `account_identities` must be a valid pointer
|
||||
* - `instruction_words` must be a valid pointer
|
||||
* - `out_result` must be a valid pointer
|
||||
*/
|
||||
enum WalletFfiError wallet_ffi_send_generic_transaction(struct WalletHandle *handle,
|
||||
const struct FfiAccountIdentity *account_identities,
|
||||
uintptr_t account_identities_size,
|
||||
const uint32_t *instruction_words,
|
||||
uintptr_t instruction_words_size,
|
||||
struct FfiProgramWithDependencies program_with_dependencies,
|
||||
struct FfiTransferResult *out_result);
|
||||
|
||||
/**
|
||||
* Get the public key for a public account.
|
||||
*
|
||||
@ -552,6 +660,45 @@ char *wallet_ffi_account_id_to_base58(const struct FfiBytes32 *account_id);
|
||||
enum WalletFfiError wallet_ffi_account_id_from_base58(const char *base58_str,
|
||||
struct FfiBytes32 *out_account_id);
|
||||
|
||||
/**
|
||||
* Resolve public account.
|
||||
*
|
||||
* # Parameters
|
||||
* - `account_id`: 32 bytes of the public account ID
|
||||
* - `needs_sign`: does account needs signing
|
||||
* - `out_account_identity`: valid pointer, where output will be written
|
||||
*
|
||||
* # Returns
|
||||
* - `Success` on successful retrieval
|
||||
*
|
||||
* # Safety
|
||||
* - `out_account_identity` must be a valid pointer to a `FfiAccountManagerAccountIdentity` struct
|
||||
*/
|
||||
enum WalletFfiError wallet_ffi_resolve_public_account(struct FfiBytes32 account_id,
|
||||
bool needs_sign,
|
||||
struct FfiAccountIdentity *out_account_identity);
|
||||
|
||||
/**
|
||||
* Resolve private account.
|
||||
*
|
||||
* # Parameters
|
||||
* - `handle`: Valid wallet handle
|
||||
* - `account_id`: 32 bytes of the public account ID
|
||||
* - `out_account_identity`: valid pointer, where output will be written
|
||||
*
|
||||
* # Returns
|
||||
* - `Success` on successful retrieval
|
||||
* - `InternalError` if wailed to lock wallet
|
||||
* - `AccountNotFound` if failed to found account
|
||||
*
|
||||
* # Safety
|
||||
* - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
|
||||
* - `out_account_identity` must be a valid pointer to a `FfiAccountManagerAccountIdentity` struct
|
||||
*/
|
||||
enum WalletFfiError wallet_ffi_resolve_private_account(struct WalletHandle *handle,
|
||||
struct FfiBytes32 account_id,
|
||||
struct FfiAccountIdentity *out_account_identity);
|
||||
|
||||
/**
|
||||
* Claim a pinata reward using a public transaction.
|
||||
*
|
||||
|
||||
@ -11,8 +11,10 @@ use nssa_core::{
|
||||
use crate::{ExecutionFailureKind, WalletCore};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum PrivacyPreservingAccount {
|
||||
pub enum AccountIdentity {
|
||||
Public(AccountId),
|
||||
/// A public account without signing. Would not try to sign, even if account is owned.
|
||||
PublicNoSign(AccountId),
|
||||
PrivateOwned(AccountId),
|
||||
PrivateForeign {
|
||||
npk: NullifierPublicKey,
|
||||
@ -50,10 +52,10 @@ pub enum PrivacyPreservingAccount {
|
||||
},
|
||||
}
|
||||
|
||||
impl PrivacyPreservingAccount {
|
||||
impl AccountIdentity {
|
||||
#[must_use]
|
||||
pub const fn is_public(&self) -> bool {
|
||||
matches!(&self, Self::Public(_))
|
||||
matches!(&self, Self::Public(_) | Self::PublicNoSign(_))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
@ -92,13 +94,13 @@ pub struct AccountManager {
|
||||
impl AccountManager {
|
||||
pub async fn new(
|
||||
wallet: &WalletCore,
|
||||
accounts: Vec<PrivacyPreservingAccount>,
|
||||
accounts: Vec<AccountIdentity>,
|
||||
) -> Result<Self, ExecutionFailureKind> {
|
||||
let mut states = Vec::with_capacity(accounts.len());
|
||||
|
||||
for account in accounts {
|
||||
let state = match account {
|
||||
PrivacyPreservingAccount::Public(account_id) => {
|
||||
AccountIdentity::Public(account_id) => {
|
||||
let acc = wallet
|
||||
.get_account_public(account_id)
|
||||
.await
|
||||
@ -109,12 +111,23 @@ impl AccountManager {
|
||||
|
||||
State::Public { account, sk }
|
||||
}
|
||||
PrivacyPreservingAccount::PrivateOwned(account_id) => {
|
||||
AccountIdentity::PublicNoSign(account_id) => {
|
||||
let acc = wallet
|
||||
.get_account_public(account_id)
|
||||
.await
|
||||
.map_err(ExecutionFailureKind::SequencerError)?;
|
||||
|
||||
let sk = None;
|
||||
let account = AccountWithMetadata::new(acc.clone(), sk.is_some(), account_id);
|
||||
|
||||
State::Public { account, sk }
|
||||
}
|
||||
AccountIdentity::PrivateOwned(account_id) => {
|
||||
let pre = private_key_tree_acc_preparation(wallet, account_id, false).await?;
|
||||
|
||||
State::Private(pre)
|
||||
}
|
||||
PrivacyPreservingAccount::PrivateForeign {
|
||||
AccountIdentity::PrivateForeign {
|
||||
npk,
|
||||
vpk,
|
||||
identifier,
|
||||
@ -138,11 +151,11 @@ impl AccountManager {
|
||||
|
||||
State::Private(pre)
|
||||
}
|
||||
PrivacyPreservingAccount::PrivatePdaOwned(account_id) => {
|
||||
AccountIdentity::PrivatePdaOwned(account_id) => {
|
||||
let pre = private_key_tree_acc_preparation(wallet, account_id, true).await?;
|
||||
State::Private(pre)
|
||||
}
|
||||
PrivacyPreservingAccount::PrivatePdaForeign {
|
||||
AccountIdentity::PrivatePdaForeign {
|
||||
account_id,
|
||||
npk,
|
||||
vpk,
|
||||
@ -166,7 +179,7 @@ impl AccountManager {
|
||||
};
|
||||
State::Private(pre)
|
||||
}
|
||||
PrivacyPreservingAccount::PrivateShared {
|
||||
AccountIdentity::PrivateShared {
|
||||
nsk,
|
||||
npk,
|
||||
vpk,
|
||||
@ -180,7 +193,7 @@ impl AccountManager {
|
||||
|
||||
State::Private(pre)
|
||||
}
|
||||
PrivacyPreservingAccount::PrivatePdaShared {
|
||||
AccountIdentity::PrivatePdaShared {
|
||||
account_id,
|
||||
nsk,
|
||||
npk,
|
||||
@ -410,7 +423,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn private_shared_is_private() {
|
||||
let acc = PrivacyPreservingAccount::PrivateShared {
|
||||
let acc = AccountIdentity::PrivateShared {
|
||||
nsk: [0; 32],
|
||||
npk: NullifierPublicKey([1; 32]),
|
||||
vpk: ViewingPublicKey::from_scalar([2; 32]),
|
||||
@ -9,6 +9,7 @@
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub use account_manager::AccountIdentity;
|
||||
use anyhow::{Context as _, Result};
|
||||
use bip39::Mnemonic;
|
||||
use common::{HashType, transaction::NSSATransaction};
|
||||
@ -24,7 +25,6 @@ use nssa::{
|
||||
use nssa_core::{
|
||||
Commitment, MembershipProof, SharedSecretKey, account::Nonce, program::InstructionData,
|
||||
};
|
||||
pub use privacy_preserving_tx::PrivacyPreservingAccount;
|
||||
use sequencer_service_rpc::{RpcClient as _, SequencerClient, SequencerClientBuilder};
|
||||
use storage::Storage;
|
||||
use tokio::io::AsyncWriteExt as _;
|
||||
@ -37,11 +37,11 @@ use crate::{
|
||||
};
|
||||
|
||||
pub mod account;
|
||||
mod account_manager;
|
||||
pub mod cli;
|
||||
pub mod config;
|
||||
pub mod helperfunctions;
|
||||
pub mod poller;
|
||||
mod privacy_preserving_tx;
|
||||
pub mod program_facades;
|
||||
pub mod storage;
|
||||
|
||||
@ -273,10 +273,7 @@ impl WalletCore {
|
||||
/// Resolve an `AccountId` to the appropriate `PrivacyPreservingAccount` variant.
|
||||
/// Checks the key tree first, then shared private accounts.
|
||||
#[must_use]
|
||||
pub fn resolve_private_account(
|
||||
&self,
|
||||
account_id: nssa::AccountId,
|
||||
) -> Option<PrivacyPreservingAccount> {
|
||||
pub fn resolve_private_account(&self, account_id: nssa::AccountId) -> Option<AccountIdentity> {
|
||||
// Check key tree first
|
||||
if self
|
||||
.storage
|
||||
@ -284,7 +281,7 @@ impl WalletCore {
|
||||
.private_account(account_id)
|
||||
.is_some()
|
||||
{
|
||||
return Some(PrivacyPreservingAccount::PrivateOwned(account_id));
|
||||
return Some(AccountIdentity::PrivateOwned(account_id));
|
||||
}
|
||||
|
||||
// Check shared private accounts
|
||||
@ -299,7 +296,7 @@ impl WalletCore {
|
||||
|
||||
if let (Some(pda_seed), Some(program_id)) = (entry.pda_seed, entry.pda_program_id) {
|
||||
let keys = holder.derive_keys_for_pda(&program_id, &pda_seed);
|
||||
Some(PrivacyPreservingAccount::PrivatePdaShared {
|
||||
Some(AccountIdentity::PrivatePdaShared {
|
||||
account_id,
|
||||
nsk: keys.nullifier_secret_key,
|
||||
npk: keys.generate_nullifier_public_key(),
|
||||
@ -316,7 +313,7 @@ impl WalletCore {
|
||||
result
|
||||
};
|
||||
let keys = holder.derive_keys_for_shared_account(&derivation_seed);
|
||||
Some(PrivacyPreservingAccount::PrivateShared {
|
||||
Some(AccountIdentity::PrivateShared {
|
||||
nsk: keys.nullifier_secret_key,
|
||||
npk: keys.generate_nullifier_public_key(),
|
||||
vpk: keys.generate_viewing_public_key(),
|
||||
@ -541,7 +538,7 @@ impl WalletCore {
|
||||
|
||||
pub async fn send_privacy_preserving_tx(
|
||||
&self,
|
||||
accounts: Vec<PrivacyPreservingAccount>,
|
||||
accounts: Vec<AccountIdentity>,
|
||||
instruction_data: InstructionData,
|
||||
program: &ProgramWithDependencies,
|
||||
) -> Result<(HashType, Vec<SharedSecretKey>), ExecutionFailureKind> {
|
||||
@ -553,12 +550,12 @@ impl WalletCore {
|
||||
|
||||
pub async fn send_privacy_preserving_tx_with_pre_check(
|
||||
&self,
|
||||
accounts: Vec<PrivacyPreservingAccount>,
|
||||
accounts: Vec<AccountIdentity>,
|
||||
instruction_data: InstructionData,
|
||||
program: &ProgramWithDependencies,
|
||||
tx_pre_check: impl FnOnce(&[&Account]) -> Result<(), ExecutionFailureKind>,
|
||||
) -> Result<(HashType, Vec<SharedSecretKey>), ExecutionFailureKind> {
|
||||
let acc_manager = privacy_preserving_tx::AccountManager::new(self, accounts).await?;
|
||||
let acc_manager = account_manager::AccountManager::new(self, accounts).await?;
|
||||
|
||||
let pre_states = acc_manager.pre_states();
|
||||
tx_pre_check(
|
||||
@ -610,6 +607,65 @@ impl WalletCore {
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn send_pub_tx(
|
||||
&self,
|
||||
accounts: Vec<AccountIdentity>,
|
||||
instruction_data: InstructionData,
|
||||
program: &ProgramWithDependencies,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
self.send_pub_tx_with_pre_check(accounts, instruction_data, program, |_| Ok(()))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn send_pub_tx_with_pre_check(
|
||||
&self,
|
||||
accounts: Vec<AccountIdentity>,
|
||||
instruction_data: InstructionData,
|
||||
program: &ProgramWithDependencies,
|
||||
tx_pre_check: impl FnOnce(&[&Account]) -> Result<(), ExecutionFailureKind>,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
// Public transaction, all accounts must be public
|
||||
if accounts.iter().any(AccountIdentity::is_private) {
|
||||
return Err(ExecutionFailureKind::TransactionBuildError(
|
||||
nssa::error::NssaError::InvalidInput(
|
||||
"Private accounts are not allowed in public transactions".to_owned(),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
let acc_manager = account_manager::AccountManager::new(self, accounts).await?;
|
||||
|
||||
let pre_states = acc_manager.pre_states();
|
||||
tx_pre_check(
|
||||
&pre_states
|
||||
.iter()
|
||||
.map(|pre| &pre.account)
|
||||
.collect::<Vec<_>>(),
|
||||
)?;
|
||||
|
||||
let account_ids = acc_manager.public_account_ids();
|
||||
let program_id = program.program.id();
|
||||
let nonces = acc_manager.public_account_nonces();
|
||||
let private_keys = acc_manager.public_account_auth();
|
||||
|
||||
let message = nssa::public_transaction::Message::new_preserialized(
|
||||
program_id,
|
||||
account_ids,
|
||||
nonces,
|
||||
instruction_data,
|
||||
);
|
||||
|
||||
let witness_set =
|
||||
nssa::public_transaction::WitnessSet::for_message(&message, &private_keys);
|
||||
|
||||
let tx = nssa::public_transaction::PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self
|
||||
.sequencer_client
|
||||
.send_transaction(NSSATransaction::Public(tx))
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn sync_to_latest_block(&mut self) -> Result<u64> {
|
||||
let latest_block_id = self.sequencer_client.get_last_block_id().await?;
|
||||
println!("Latest block is {latest_block_id}");
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
use amm_core::{compute_liquidity_token_pda, compute_pool_pda, compute_vault_pda};
|
||||
use common::{HashType, transaction::NSSATransaction};
|
||||
use common::HashType;
|
||||
use nssa::{AccountId, program::Program};
|
||||
use sequencer_service_rpc::RpcClient as _;
|
||||
use token_core::TokenHolding;
|
||||
|
||||
use crate::{ExecutionFailureKind, WalletCore};
|
||||
use crate::{AccountIdentity, ExecutionFailureKind, WalletCore};
|
||||
pub struct Amm<'wallet>(pub &'wallet WalletCore);
|
||||
|
||||
impl Amm<'_> {
|
||||
@ -18,12 +17,6 @@ impl Amm<'_> {
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let program = Program::amm();
|
||||
let amm_program_id = Program::amm().id();
|
||||
let instruction = amm_core::Instruction::NewDefinition {
|
||||
token_a_amount: balance_a,
|
||||
token_b_amount: balance_b,
|
||||
amm_program_id,
|
||||
};
|
||||
|
||||
let user_a_acc = self
|
||||
.0
|
||||
.get_account_public(user_holding_a)
|
||||
@ -47,78 +40,29 @@ impl Amm<'_> {
|
||||
let vault_holding_a = compute_vault_pda(amm_program_id, amm_pool, definition_token_a_id);
|
||||
let vault_holding_b = compute_vault_pda(amm_program_id, amm_pool, definition_token_b_id);
|
||||
let pool_lp = compute_liquidity_token_pda(amm_program_id, amm_pool);
|
||||
let instruction = amm_core::Instruction::NewDefinition {
|
||||
token_a_amount: balance_a,
|
||||
token_b_amount: balance_b,
|
||||
amm_program_id,
|
||||
};
|
||||
let instruction_data =
|
||||
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||
|
||||
let account_ids = vec![
|
||||
amm_pool,
|
||||
vault_holding_a,
|
||||
vault_holding_b,
|
||||
pool_lp,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
user_holding_lp,
|
||||
];
|
||||
|
||||
let mut nonces = self
|
||||
.0
|
||||
.get_accounts_nonces(vec![user_holding_a, user_holding_b])
|
||||
self.0
|
||||
.send_pub_tx(
|
||||
vec![
|
||||
AccountIdentity::PublicNoSign(amm_pool),
|
||||
AccountIdentity::PublicNoSign(vault_holding_a),
|
||||
AccountIdentity::PublicNoSign(vault_holding_b),
|
||||
AccountIdentity::PublicNoSign(pool_lp),
|
||||
AccountIdentity::Public(user_holding_a),
|
||||
AccountIdentity::Public(user_holding_b),
|
||||
AccountIdentity::Public(user_holding_lp),
|
||||
],
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
.map_err(ExecutionFailureKind::SequencerError)?;
|
||||
|
||||
let mut private_keys = Vec::new();
|
||||
|
||||
let signing_key_a = self
|
||||
.0
|
||||
.storage
|
||||
.key_chain()
|
||||
.pub_account_signing_key(user_holding_a)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?;
|
||||
private_keys.push(signing_key_a);
|
||||
|
||||
let signing_key_b = self
|
||||
.0
|
||||
.storage
|
||||
.key_chain()
|
||||
.pub_account_signing_key(user_holding_b)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?;
|
||||
private_keys.push(signing_key_b);
|
||||
|
||||
if let Some(signing_key_lp) = self
|
||||
.0
|
||||
.storage
|
||||
.key_chain()
|
||||
.pub_account_signing_key(user_holding_lp)
|
||||
{
|
||||
private_keys.push(signing_key_lp);
|
||||
let lp_nonces = self
|
||||
.0
|
||||
.get_accounts_nonces(vec![user_holding_lp])
|
||||
.await
|
||||
.map_err(ExecutionFailureKind::SequencerError)?;
|
||||
nonces.extend(lp_nonces);
|
||||
} else {
|
||||
println!(
|
||||
"Liquidity pool tokens receiver's account ({user_holding_lp}) private key not found in wallet. Proceeding with only liquidity provider's keys."
|
||||
);
|
||||
}
|
||||
|
||||
let message = nssa::public_transaction::Message::try_new(
|
||||
program.id(),
|
||||
account_ids,
|
||||
nonces,
|
||||
instruction,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let witness_set =
|
||||
nssa::public_transaction::WitnessSet::for_message(&message, &private_keys);
|
||||
|
||||
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self
|
||||
.0
|
||||
.sequencer_client
|
||||
.send_transaction(NSSATransaction::Public(tx))
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn send_swap_exact_input(
|
||||
@ -129,14 +73,8 @@ impl Amm<'_> {
|
||||
min_amount_out: u128,
|
||||
token_definition_id_in: AccountId,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let instruction = amm_core::Instruction::SwapExactInput {
|
||||
swap_amount_in,
|
||||
min_amount_out,
|
||||
token_definition_id_in,
|
||||
};
|
||||
let program = Program::amm();
|
||||
let amm_program_id = Program::amm().id();
|
||||
|
||||
let user_a_acc = self
|
||||
.0
|
||||
.get_account_public(user_holding_a)
|
||||
@ -159,56 +97,47 @@ impl Amm<'_> {
|
||||
compute_pool_pda(amm_program_id, definition_token_a_id, definition_token_b_id);
|
||||
let vault_holding_a = compute_vault_pda(amm_program_id, amm_pool, definition_token_a_id);
|
||||
let vault_holding_b = compute_vault_pda(amm_program_id, amm_pool, definition_token_b_id);
|
||||
let instruction = amm_core::Instruction::SwapExactInput {
|
||||
swap_amount_in,
|
||||
min_amount_out,
|
||||
token_definition_id_in,
|
||||
};
|
||||
let instruction_data =
|
||||
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||
|
||||
let account_ids = vec![
|
||||
amm_pool,
|
||||
vault_holding_a,
|
||||
vault_holding_b,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
];
|
||||
|
||||
let account_id_auth = if definition_token_a_id == token_definition_id_in {
|
||||
user_holding_a
|
||||
} else if definition_token_b_id == token_definition_id_in {
|
||||
user_holding_b
|
||||
} else {
|
||||
if (token_definition_id_in != definition_token_a_id)
|
||||
&& (token_definition_id_in != definition_token_b_id)
|
||||
{
|
||||
return Err(ExecutionFailureKind::AccountDataError(
|
||||
token_definition_id_in,
|
||||
));
|
||||
}
|
||||
|
||||
let user_a_signing_indentity = if token_definition_id_in == definition_token_a_id {
|
||||
AccountIdentity::Public(user_holding_a)
|
||||
} else {
|
||||
AccountIdentity::PublicNoSign(user_holding_a)
|
||||
};
|
||||
|
||||
let nonces = self
|
||||
.0
|
||||
.get_accounts_nonces(vec![account_id_auth])
|
||||
let user_b_signing_indentity = if token_definition_id_in == definition_token_b_id {
|
||||
AccountIdentity::Public(user_holding_b)
|
||||
} else {
|
||||
AccountIdentity::PublicNoSign(user_holding_b)
|
||||
};
|
||||
|
||||
self.0
|
||||
.send_pub_tx(
|
||||
vec![
|
||||
AccountIdentity::PublicNoSign(amm_pool),
|
||||
AccountIdentity::PublicNoSign(vault_holding_a),
|
||||
AccountIdentity::PublicNoSign(vault_holding_b),
|
||||
user_a_signing_indentity,
|
||||
user_b_signing_indentity,
|
||||
],
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
.map_err(ExecutionFailureKind::SequencerError)?;
|
||||
|
||||
let signing_key = self
|
||||
.0
|
||||
.storage
|
||||
.key_chain()
|
||||
.pub_account_signing_key(account_id_auth)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?;
|
||||
|
||||
let message = nssa::public_transaction::Message::try_new(
|
||||
program.id(),
|
||||
account_ids,
|
||||
nonces,
|
||||
instruction,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let witness_set =
|
||||
nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]);
|
||||
|
||||
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self
|
||||
.0
|
||||
.sequencer_client
|
||||
.send_transaction(NSSATransaction::Public(tx))
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn send_swap_exact_output(
|
||||
@ -219,14 +148,8 @@ impl Amm<'_> {
|
||||
max_amount_in: u128,
|
||||
token_definition_id_in: AccountId,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let instruction = amm_core::Instruction::SwapExactOutput {
|
||||
exact_amount_out,
|
||||
max_amount_in,
|
||||
token_definition_id_in,
|
||||
};
|
||||
let program = Program::amm();
|
||||
let amm_program_id = Program::amm().id();
|
||||
|
||||
let user_a_acc = self
|
||||
.0
|
||||
.get_account_public(user_holding_a)
|
||||
@ -249,56 +172,47 @@ impl Amm<'_> {
|
||||
compute_pool_pda(amm_program_id, definition_token_a_id, definition_token_b_id);
|
||||
let vault_holding_a = compute_vault_pda(amm_program_id, amm_pool, definition_token_a_id);
|
||||
let vault_holding_b = compute_vault_pda(amm_program_id, amm_pool, definition_token_b_id);
|
||||
let instruction = amm_core::Instruction::SwapExactOutput {
|
||||
exact_amount_out,
|
||||
max_amount_in,
|
||||
token_definition_id_in,
|
||||
};
|
||||
let instruction_data =
|
||||
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||
|
||||
let account_ids = vec![
|
||||
amm_pool,
|
||||
vault_holding_a,
|
||||
vault_holding_b,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
];
|
||||
|
||||
let account_id_auth = if definition_token_a_id == token_definition_id_in {
|
||||
user_holding_a
|
||||
} else if definition_token_b_id == token_definition_id_in {
|
||||
user_holding_b
|
||||
} else {
|
||||
if (token_definition_id_in != definition_token_a_id)
|
||||
&& (token_definition_id_in != definition_token_b_id)
|
||||
{
|
||||
return Err(ExecutionFailureKind::AccountDataError(
|
||||
token_definition_id_in,
|
||||
));
|
||||
}
|
||||
|
||||
let user_a_signing_indentity = if token_definition_id_in == definition_token_a_id {
|
||||
AccountIdentity::Public(user_holding_a)
|
||||
} else {
|
||||
AccountIdentity::PublicNoSign(user_holding_a)
|
||||
};
|
||||
|
||||
let nonces = self
|
||||
.0
|
||||
.get_accounts_nonces(vec![account_id_auth])
|
||||
let user_b_signing_indentity = if token_definition_id_in == definition_token_b_id {
|
||||
AccountIdentity::Public(user_holding_b)
|
||||
} else {
|
||||
AccountIdentity::PublicNoSign(user_holding_b)
|
||||
};
|
||||
|
||||
self.0
|
||||
.send_pub_tx(
|
||||
vec![
|
||||
AccountIdentity::Public(amm_pool),
|
||||
AccountIdentity::Public(vault_holding_a),
|
||||
AccountIdentity::Public(vault_holding_b),
|
||||
user_a_signing_indentity,
|
||||
user_b_signing_indentity,
|
||||
],
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
.map_err(ExecutionFailureKind::SequencerError)?;
|
||||
|
||||
let signing_key = self
|
||||
.0
|
||||
.storage
|
||||
.key_chain()
|
||||
.pub_account_signing_key(account_id_auth)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?;
|
||||
|
||||
let message = nssa::public_transaction::Message::try_new(
|
||||
program.id(),
|
||||
account_ids,
|
||||
nonces,
|
||||
instruction,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let witness_set =
|
||||
nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]);
|
||||
|
||||
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self
|
||||
.0
|
||||
.sequencer_client
|
||||
.send_transaction(NSSATransaction::Public(tx))
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn send_add_liquidity(
|
||||
@ -310,14 +224,8 @@ impl Amm<'_> {
|
||||
max_amount_to_add_token_a: u128,
|
||||
max_amount_to_add_token_b: u128,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let instruction = amm_core::Instruction::AddLiquidity {
|
||||
min_amount_liquidity,
|
||||
max_amount_to_add_token_a,
|
||||
max_amount_to_add_token_b,
|
||||
};
|
||||
let program = Program::amm();
|
||||
let amm_program_id = Program::amm().id();
|
||||
|
||||
let user_a_acc = self
|
||||
.0
|
||||
.get_account_public(user_holding_a)
|
||||
@ -341,57 +249,29 @@ impl Amm<'_> {
|
||||
let vault_holding_a = compute_vault_pda(amm_program_id, amm_pool, definition_token_a_id);
|
||||
let vault_holding_b = compute_vault_pda(amm_program_id, amm_pool, definition_token_b_id);
|
||||
let pool_lp = compute_liquidity_token_pda(amm_program_id, amm_pool);
|
||||
let instruction = amm_core::Instruction::AddLiquidity {
|
||||
min_amount_liquidity,
|
||||
max_amount_to_add_token_a,
|
||||
max_amount_to_add_token_b,
|
||||
};
|
||||
let instruction_data =
|
||||
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||
|
||||
let account_ids = vec![
|
||||
amm_pool,
|
||||
vault_holding_a,
|
||||
vault_holding_b,
|
||||
pool_lp,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
user_holding_lp,
|
||||
];
|
||||
|
||||
let nonces = self
|
||||
.0
|
||||
.get_accounts_nonces(vec![user_holding_a, user_holding_b])
|
||||
self.0
|
||||
.send_pub_tx(
|
||||
vec![
|
||||
AccountIdentity::PublicNoSign(amm_pool),
|
||||
AccountIdentity::PublicNoSign(vault_holding_a),
|
||||
AccountIdentity::PublicNoSign(vault_holding_b),
|
||||
AccountIdentity::PublicNoSign(pool_lp),
|
||||
AccountIdentity::Public(user_holding_a),
|
||||
AccountIdentity::Public(user_holding_b),
|
||||
AccountIdentity::PublicNoSign(user_holding_lp),
|
||||
],
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
.map_err(ExecutionFailureKind::SequencerError)?;
|
||||
|
||||
let signing_key_a = self
|
||||
.0
|
||||
.storage
|
||||
.key_chain()
|
||||
.pub_account_signing_key(user_holding_a)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?;
|
||||
|
||||
let signing_key_b = self
|
||||
.0
|
||||
.storage
|
||||
.key_chain()
|
||||
.pub_account_signing_key(user_holding_b)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?;
|
||||
|
||||
let message = nssa::public_transaction::Message::try_new(
|
||||
program.id(),
|
||||
account_ids,
|
||||
nonces,
|
||||
instruction,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let witness_set = nssa::public_transaction::WitnessSet::for_message(
|
||||
&message,
|
||||
&[signing_key_a, signing_key_b],
|
||||
);
|
||||
|
||||
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self
|
||||
.0
|
||||
.sequencer_client
|
||||
.send_transaction(NSSATransaction::Public(tx))
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn send_remove_liquidity(
|
||||
@ -403,14 +283,8 @@ impl Amm<'_> {
|
||||
min_amount_to_remove_token_a: u128,
|
||||
min_amount_to_remove_token_b: u128,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let instruction = amm_core::Instruction::RemoveLiquidity {
|
||||
remove_liquidity_amount,
|
||||
min_amount_to_remove_token_a,
|
||||
min_amount_to_remove_token_b,
|
||||
};
|
||||
let program = Program::amm();
|
||||
let amm_program_id = Program::amm().id();
|
||||
|
||||
let user_a_acc = self
|
||||
.0
|
||||
.get_account_public(user_holding_a)
|
||||
@ -434,47 +308,28 @@ impl Amm<'_> {
|
||||
let vault_holding_a = compute_vault_pda(amm_program_id, amm_pool, definition_token_a_id);
|
||||
let vault_holding_b = compute_vault_pda(amm_program_id, amm_pool, definition_token_b_id);
|
||||
let pool_lp = compute_liquidity_token_pda(amm_program_id, amm_pool);
|
||||
let instruction = amm_core::Instruction::RemoveLiquidity {
|
||||
remove_liquidity_amount,
|
||||
min_amount_to_remove_token_a,
|
||||
min_amount_to_remove_token_b,
|
||||
};
|
||||
let instruction_data =
|
||||
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||
|
||||
let account_ids = vec![
|
||||
amm_pool,
|
||||
vault_holding_a,
|
||||
vault_holding_b,
|
||||
pool_lp,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
user_holding_lp,
|
||||
];
|
||||
|
||||
let nonces = self
|
||||
.0
|
||||
.get_accounts_nonces(vec![user_holding_lp])
|
||||
self.0
|
||||
.send_pub_tx(
|
||||
vec![
|
||||
AccountIdentity::PublicNoSign(amm_pool),
|
||||
AccountIdentity::PublicNoSign(vault_holding_a),
|
||||
AccountIdentity::PublicNoSign(vault_holding_b),
|
||||
AccountIdentity::PublicNoSign(pool_lp),
|
||||
AccountIdentity::PublicNoSign(user_holding_a),
|
||||
AccountIdentity::PublicNoSign(user_holding_b),
|
||||
AccountIdentity::Public(user_holding_lp),
|
||||
],
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
.map_err(ExecutionFailureKind::SequencerError)?;
|
||||
|
||||
let signing_key_lp = self
|
||||
.0
|
||||
.storage
|
||||
.key_chain()
|
||||
.pub_account_signing_key(user_holding_lp)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?;
|
||||
|
||||
let message = nssa::public_transaction::Message::try_new(
|
||||
program.id(),
|
||||
account_ids,
|
||||
nonces,
|
||||
instruction,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let witness_set =
|
||||
nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key_lp]);
|
||||
|
||||
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self
|
||||
.0
|
||||
.sequencer_client
|
||||
.send_transaction(NSSATransaction::Public(tx))
|
||||
.await?)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use ata_core::{compute_ata_seed, get_associated_token_account_id};
|
||||
use common::{HashType, transaction::NSSATransaction};
|
||||
use common::HashType;
|
||||
use nssa::{
|
||||
AccountId, privacy_preserving_transaction::circuit::ProgramWithDependencies, program::Program,
|
||||
};
|
||||
use nssa_core::SharedSecretKey;
|
||||
use sequencer_service_rpc::RpcClient as _;
|
||||
|
||||
use crate::{ExecutionFailureKind, PrivacyPreservingAccount, WalletCore};
|
||||
use crate::{AccountIdentity, ExecutionFailureKind, WalletCore};
|
||||
|
||||
pub struct Ata<'wallet>(pub &'wallet WalletCore);
|
||||
|
||||
@ -24,38 +23,21 @@ impl Ata<'_> {
|
||||
&ata_program_id,
|
||||
&compute_ata_seed(owner_id, definition_id),
|
||||
);
|
||||
|
||||
let account_ids = vec![owner_id, definition_id, ata_id];
|
||||
|
||||
let nonces = self
|
||||
.0
|
||||
.get_accounts_nonces(vec![owner_id])
|
||||
.await
|
||||
.map_err(ExecutionFailureKind::SequencerError)?;
|
||||
|
||||
let Some(signing_key) = self.0.storage.key_chain().pub_account_signing_key(owner_id) else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
let instruction = ata_core::Instruction::Create { ata_program_id };
|
||||
let instruction_data =
|
||||
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||
|
||||
let message = nssa::public_transaction::Message::try_new(
|
||||
program.id(),
|
||||
account_ids,
|
||||
nonces,
|
||||
instruction,
|
||||
)?;
|
||||
|
||||
let witness_set =
|
||||
nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]);
|
||||
|
||||
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self
|
||||
.0
|
||||
.sequencer_client
|
||||
.send_transaction(NSSATransaction::Public(tx))
|
||||
.await?)
|
||||
self.0
|
||||
.send_pub_tx(
|
||||
vec![
|
||||
AccountIdentity::Public(owner_id),
|
||||
AccountIdentity::PublicNoSign(definition_id),
|
||||
AccountIdentity::PublicNoSign(ata_id),
|
||||
],
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn send_transfer(
|
||||
@ -71,41 +53,24 @@ impl Ata<'_> {
|
||||
&ata_program_id,
|
||||
&compute_ata_seed(owner_id, definition_id),
|
||||
);
|
||||
|
||||
let account_ids = vec![owner_id, sender_ata_id, recipient_id];
|
||||
|
||||
let nonces = self
|
||||
.0
|
||||
.get_accounts_nonces(vec![owner_id])
|
||||
.await
|
||||
.map_err(ExecutionFailureKind::SequencerError)?;
|
||||
|
||||
let Some(signing_key) = self.0.storage.key_chain().pub_account_signing_key(owner_id) else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
let instruction = ata_core::Instruction::Transfer {
|
||||
ata_program_id,
|
||||
amount,
|
||||
};
|
||||
let instruction_data =
|
||||
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||
|
||||
let message = nssa::public_transaction::Message::try_new(
|
||||
program.id(),
|
||||
account_ids,
|
||||
nonces,
|
||||
instruction,
|
||||
)?;
|
||||
|
||||
let witness_set =
|
||||
nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]);
|
||||
|
||||
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self
|
||||
.0
|
||||
.sequencer_client
|
||||
.send_transaction(NSSATransaction::Public(tx))
|
||||
.await?)
|
||||
self.0
|
||||
.send_pub_tx(
|
||||
vec![
|
||||
AccountIdentity::Public(owner_id),
|
||||
AccountIdentity::PublicNoSign(sender_ata_id),
|
||||
AccountIdentity::PublicNoSign(recipient_id),
|
||||
],
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn send_burn(
|
||||
@ -120,41 +85,24 @@ impl Ata<'_> {
|
||||
&ata_program_id,
|
||||
&compute_ata_seed(owner_id, definition_id),
|
||||
);
|
||||
|
||||
let account_ids = vec![owner_id, holder_ata_id, definition_id];
|
||||
|
||||
let nonces = self
|
||||
.0
|
||||
.get_accounts_nonces(vec![owner_id])
|
||||
.await
|
||||
.map_err(ExecutionFailureKind::SequencerError)?;
|
||||
|
||||
let Some(signing_key) = self.0.storage.key_chain().pub_account_signing_key(owner_id) else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
let instruction = ata_core::Instruction::Burn {
|
||||
ata_program_id,
|
||||
amount,
|
||||
};
|
||||
let instruction_data =
|
||||
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||
|
||||
let message = nssa::public_transaction::Message::try_new(
|
||||
program.id(),
|
||||
account_ids,
|
||||
nonces,
|
||||
instruction,
|
||||
)?;
|
||||
|
||||
let witness_set =
|
||||
nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]);
|
||||
|
||||
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self
|
||||
.0
|
||||
.sequencer_client
|
||||
.send_transaction(NSSATransaction::Public(tx))
|
||||
.await?)
|
||||
self.0
|
||||
.send_pub_tx(
|
||||
vec![
|
||||
AccountIdentity::Public(owner_id),
|
||||
AccountIdentity::PublicNoSign(holder_ata_id),
|
||||
AccountIdentity::PublicNoSign(definition_id),
|
||||
],
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn send_create_private_owner(
|
||||
@ -176,8 +124,8 @@ impl Ata<'_> {
|
||||
self.0
|
||||
.resolve_private_account(owner_id)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?,
|
||||
PrivacyPreservingAccount::Public(definition_id),
|
||||
PrivacyPreservingAccount::Public(ata_id),
|
||||
AccountIdentity::Public(definition_id),
|
||||
AccountIdentity::Public(ata_id),
|
||||
];
|
||||
|
||||
self.0
|
||||
@ -213,8 +161,8 @@ impl Ata<'_> {
|
||||
self.0
|
||||
.resolve_private_account(owner_id)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?,
|
||||
PrivacyPreservingAccount::Public(sender_ata_id),
|
||||
PrivacyPreservingAccount::Public(recipient_id),
|
||||
AccountIdentity::Public(sender_ata_id),
|
||||
AccountIdentity::Public(recipient_id),
|
||||
];
|
||||
|
||||
self.0
|
||||
@ -249,8 +197,8 @@ impl Ata<'_> {
|
||||
self.0
|
||||
.resolve_private_account(owner_id)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?,
|
||||
PrivacyPreservingAccount::Public(holder_ata_id),
|
||||
PrivacyPreservingAccount::Public(definition_id),
|
||||
AccountIdentity::Public(holder_ata_id),
|
||||
AccountIdentity::Public(definition_id),
|
||||
];
|
||||
|
||||
self.0
|
||||
|
||||
@ -2,7 +2,7 @@ use common::HashType;
|
||||
use nssa::AccountId;
|
||||
|
||||
use super::{NativeTokenTransfer, auth_transfer_preparation};
|
||||
use crate::{ExecutionFailureKind, PrivacyPreservingAccount};
|
||||
use crate::{AccountIdentity, ExecutionFailureKind};
|
||||
|
||||
impl NativeTokenTransfer<'_> {
|
||||
pub async fn send_deshielded_transfer(
|
||||
@ -19,7 +19,7 @@ impl NativeTokenTransfer<'_> {
|
||||
self.0
|
||||
.resolve_private_account(from)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?,
|
||||
PrivacyPreservingAccount::Public(to),
|
||||
AccountIdentity::Public(to),
|
||||
],
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
|
||||
@ -5,7 +5,7 @@ use nssa::{AccountId, program::Program};
|
||||
use nssa_core::{Identifier, NullifierPublicKey, SharedSecretKey, encryption::ViewingPublicKey};
|
||||
|
||||
use super::{NativeTokenTransfer, auth_transfer_preparation};
|
||||
use crate::{ExecutionFailureKind, PrivacyPreservingAccount};
|
||||
use crate::{AccountIdentity, ExecutionFailureKind};
|
||||
|
||||
impl NativeTokenTransfer<'_> {
|
||||
pub async fn register_account_private(
|
||||
@ -49,7 +49,7 @@ impl NativeTokenTransfer<'_> {
|
||||
self.0
|
||||
.resolve_private_account(from)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?,
|
||||
PrivacyPreservingAccount::PrivateForeign {
|
||||
AccountIdentity::PrivateForeign {
|
||||
npk: to_npk,
|
||||
vpk: to_vpk,
|
||||
identifier: to_identifier,
|
||||
|
||||
@ -1,14 +1,12 @@
|
||||
use authenticated_transfer_core::Instruction as AuthTransferInstruction;
|
||||
use common::{HashType, transaction::NSSATransaction};
|
||||
use nssa::{
|
||||
AccountId, PublicTransaction,
|
||||
program::Program,
|
||||
public_transaction::{Message, WitnessSet},
|
||||
};
|
||||
use sequencer_service_rpc::RpcClient as _;
|
||||
use common::HashType;
|
||||
use nssa::{AccountId, program::Program};
|
||||
|
||||
use super::NativeTokenTransfer;
|
||||
use crate::ExecutionFailureKind;
|
||||
use crate::{
|
||||
AccountIdentity, ExecutionFailureKind,
|
||||
program_facades::native_token_transfer::auth_transfer_preparation,
|
||||
};
|
||||
|
||||
impl NativeTokenTransfer<'_> {
|
||||
pub async fn send_public_transfer(
|
||||
@ -17,101 +15,31 @@ impl NativeTokenTransfer<'_> {
|
||||
to: AccountId,
|
||||
balance_to_move: u128,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let balance = self
|
||||
.0
|
||||
.get_account_balance(from)
|
||||
.await
|
||||
.map_err(ExecutionFailureKind::SequencerError)?;
|
||||
let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move);
|
||||
|
||||
if balance >= balance_to_move {
|
||||
let account_ids = vec![from, to];
|
||||
let program_id = Program::authenticated_transfer_program().id();
|
||||
|
||||
let mut nonces = self
|
||||
.0
|
||||
.get_accounts_nonces(vec![from])
|
||||
.await
|
||||
.map_err(ExecutionFailureKind::SequencerError)?;
|
||||
|
||||
let mut private_keys = Vec::new();
|
||||
let from_signing_key = self.0.storage.key_chain().pub_account_signing_key(from);
|
||||
let Some(from_signing_key) = from_signing_key else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
private_keys.push(from_signing_key);
|
||||
|
||||
let to_signing_key = self.0.storage.key_chain().pub_account_signing_key(to);
|
||||
if let Some(to_signing_key) = to_signing_key {
|
||||
private_keys.push(to_signing_key);
|
||||
let to_nonces = self
|
||||
.0
|
||||
.get_accounts_nonces(vec![to])
|
||||
.await
|
||||
.map_err(ExecutionFailureKind::SequencerError)?;
|
||||
nonces.extend(to_nonces);
|
||||
} else {
|
||||
println!(
|
||||
"Receiver's account ({to}) private key not found in wallet. Proceeding with only sender's key."
|
||||
);
|
||||
}
|
||||
|
||||
let message = Message::try_new(
|
||||
program_id,
|
||||
account_ids,
|
||||
nonces,
|
||||
AuthTransferInstruction::Transfer {
|
||||
amount: balance_to_move,
|
||||
},
|
||||
self.0
|
||||
.send_pub_tx_with_pre_check(
|
||||
vec![AccountIdentity::Public(from), AccountIdentity::Public(to)],
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
tx_pre_check,
|
||||
)
|
||||
.unwrap();
|
||||
let witness_set = WitnessSet::for_message(&message, &private_keys);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self
|
||||
.0
|
||||
.sequencer_client
|
||||
.send_transaction(NSSATransaction::Public(tx))
|
||||
.await?)
|
||||
} else {
|
||||
Err(ExecutionFailureKind::InsufficientFundsError)
|
||||
}
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn register_account(
|
||||
&self,
|
||||
from: AccountId,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let nonces = self
|
||||
.0
|
||||
.get_accounts_nonces(vec![from])
|
||||
let instruction_data = Program::serialize_instruction(AuthTransferInstruction::Initialize)?;
|
||||
let program = Program::authenticated_transfer_program();
|
||||
|
||||
self.0
|
||||
.send_pub_tx(
|
||||
vec![AccountIdentity::Public(from)],
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
.map_err(ExecutionFailureKind::SequencerError)?;
|
||||
|
||||
let account_ids = vec![from];
|
||||
let program_id = Program::authenticated_transfer_program().id();
|
||||
let message = Message::try_new(
|
||||
program_id,
|
||||
account_ids,
|
||||
nonces,
|
||||
AuthTransferInstruction::Initialize,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let signing_key = self.0.storage.key_chain().pub_account_signing_key(from);
|
||||
|
||||
let Some(signing_key) = signing_key else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
let witness_set = WitnessSet::for_message(&message, &[signing_key]);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self
|
||||
.0
|
||||
.sequencer_client
|
||||
.send_transaction(NSSATransaction::Public(tx))
|
||||
.await?)
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ use nssa::AccountId;
|
||||
use nssa_core::{Identifier, NullifierPublicKey, SharedSecretKey, encryption::ViewingPublicKey};
|
||||
|
||||
use super::{NativeTokenTransfer, auth_transfer_preparation};
|
||||
use crate::{ExecutionFailureKind, PrivacyPreservingAccount};
|
||||
use crate::{AccountIdentity, ExecutionFailureKind};
|
||||
|
||||
impl NativeTokenTransfer<'_> {
|
||||
pub async fn send_shielded_transfer(
|
||||
@ -17,7 +17,7 @@ impl NativeTokenTransfer<'_> {
|
||||
self.0
|
||||
.send_privacy_preserving_tx_with_pre_check(
|
||||
vec![
|
||||
PrivacyPreservingAccount::Public(from),
|
||||
AccountIdentity::Public(from),
|
||||
self.0
|
||||
.resolve_private_account(to)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?,
|
||||
@ -49,8 +49,8 @@ impl NativeTokenTransfer<'_> {
|
||||
self.0
|
||||
.send_privacy_preserving_tx_with_pre_check(
|
||||
vec![
|
||||
PrivacyPreservingAccount::Public(from),
|
||||
PrivacyPreservingAccount::PrivateForeign {
|
||||
AccountIdentity::Public(from),
|
||||
AccountIdentity::PrivateForeign {
|
||||
npk: to_npk,
|
||||
vpk: to_vpk,
|
||||
identifier: to_identifier,
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
use common::{HashType, transaction::NSSATransaction};
|
||||
use nssa::AccountId;
|
||||
use common::HashType;
|
||||
use nssa::{AccountId, program::Program};
|
||||
use nssa_core::{MembershipProof, SharedSecretKey};
|
||||
use sequencer_service_rpc::RpcClient as _;
|
||||
|
||||
use crate::{ExecutionFailureKind, PrivacyPreservingAccount, WalletCore};
|
||||
use crate::{AccountIdentity, ExecutionFailureKind, WalletCore};
|
||||
|
||||
pub struct Pinata<'wallet>(pub &'wallet WalletCore);
|
||||
|
||||
@ -14,20 +13,21 @@ impl Pinata<'_> {
|
||||
winner_account_id: AccountId,
|
||||
solution: u128,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let account_ids = vec![pinata_account_id, winner_account_id];
|
||||
let program_id = nssa::program::Program::pinata().id();
|
||||
let message =
|
||||
nssa::public_transaction::Message::try_new(program_id, account_ids, vec![], solution)
|
||||
.unwrap();
|
||||
let program = Program::pinata();
|
||||
let instruction = solution;
|
||||
let instruction_data =
|
||||
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||
|
||||
let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self
|
||||
.0
|
||||
.sequencer_client
|
||||
.send_transaction(NSSATransaction::Public(tx))
|
||||
.await?)
|
||||
self.0
|
||||
.send_pub_tx(
|
||||
vec![
|
||||
AccountIdentity::PublicNoSign(pinata_account_id),
|
||||
AccountIdentity::PublicNoSign(winner_account_id),
|
||||
],
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Claim a pinata reward using a privacy-preserving transaction for an already-initialized
|
||||
@ -55,7 +55,7 @@ impl Pinata<'_> {
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::Public(pinata_account_id),
|
||||
AccountIdentity::Public(pinata_account_id),
|
||||
self.0
|
||||
.resolve_private_account(winner_account_id)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?,
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
use common::{HashType, transaction::NSSATransaction};
|
||||
use common::HashType;
|
||||
use nssa::{AccountId, program::Program};
|
||||
use nssa_core::{Identifier, NullifierPublicKey, SharedSecretKey, encryption::ViewingPublicKey};
|
||||
use sequencer_service_rpc::RpcClient as _;
|
||||
use token_core::Instruction;
|
||||
|
||||
use crate::{ExecutionFailureKind, PrivacyPreservingAccount, WalletCore};
|
||||
use crate::{AccountIdentity, ExecutionFailureKind, WalletCore};
|
||||
|
||||
pub struct Token<'wallet>(pub &'wallet WalletCore);
|
||||
|
||||
@ -16,47 +15,21 @@ impl Token<'_> {
|
||||
name: String,
|
||||
total_supply: u128,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let account_ids = vec![definition_account_id, supply_account_id];
|
||||
let program_id = nssa::program::Program::token().id();
|
||||
let program = Program::token();
|
||||
let instruction = Instruction::NewFungibleDefinition { name, total_supply };
|
||||
let nonces = self
|
||||
.0
|
||||
.get_accounts_nonces(account_ids.clone())
|
||||
let instruction_data =
|
||||
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||
|
||||
self.0
|
||||
.send_pub_tx(
|
||||
vec![
|
||||
AccountIdentity::Public(definition_account_id),
|
||||
AccountIdentity::Public(supply_account_id),
|
||||
],
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
.map_err(ExecutionFailureKind::SequencerError)?;
|
||||
let message = nssa::public_transaction::Message::try_new(
|
||||
program_id,
|
||||
account_ids,
|
||||
nonces,
|
||||
instruction,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let def_private_key = self
|
||||
.0
|
||||
.storage
|
||||
.key_chain()
|
||||
.pub_account_signing_key(definition_account_id)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?;
|
||||
let supply_private_key = self
|
||||
.0
|
||||
.storage
|
||||
.key_chain()
|
||||
.pub_account_signing_key(supply_account_id)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?;
|
||||
|
||||
let witness_set = nssa::public_transaction::WitnessSet::for_message(
|
||||
&message,
|
||||
&[def_private_key, supply_private_key],
|
||||
);
|
||||
|
||||
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self
|
||||
.0
|
||||
.sequencer_client
|
||||
.send_transaction(NSSATransaction::Public(tx))
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn send_new_definition_private_owned_supply(
|
||||
@ -73,7 +46,7 @@ impl Token<'_> {
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::Public(definition_account_id),
|
||||
AccountIdentity::Public(definition_account_id),
|
||||
self.0
|
||||
.resolve_private_account(supply_account_id)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?,
|
||||
@ -108,7 +81,7 @@ impl Token<'_> {
|
||||
self.0
|
||||
.resolve_private_account(definition_account_id)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?,
|
||||
PrivacyPreservingAccount::Public(supply_account_id),
|
||||
AccountIdentity::Public(supply_account_id),
|
||||
],
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
@ -162,62 +135,23 @@ impl Token<'_> {
|
||||
recipient_account_id: AccountId,
|
||||
amount: u128,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let account_ids = vec![sender_account_id, recipient_account_id];
|
||||
let program_id = nssa::program::Program::token().id();
|
||||
let program = Program::token();
|
||||
let instruction = Instruction::Transfer {
|
||||
amount_to_transfer: amount,
|
||||
};
|
||||
let mut nonces = self
|
||||
.0
|
||||
.get_accounts_nonces(vec![sender_account_id])
|
||||
let instruction_data =
|
||||
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||
|
||||
self.0
|
||||
.send_pub_tx(
|
||||
vec![
|
||||
AccountIdentity::Public(sender_account_id),
|
||||
AccountIdentity::Public(recipient_account_id),
|
||||
],
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
.map_err(ExecutionFailureKind::SequencerError)?;
|
||||
|
||||
let mut private_keys = Vec::new();
|
||||
let sender_sk = self
|
||||
.0
|
||||
.storage
|
||||
.key_chain()
|
||||
.pub_account_signing_key(sender_account_id)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?;
|
||||
private_keys.push(sender_sk);
|
||||
|
||||
if let Some(recipient_sk) = self
|
||||
.0
|
||||
.storage
|
||||
.key_chain()
|
||||
.pub_account_signing_key(recipient_account_id)
|
||||
{
|
||||
private_keys.push(recipient_sk);
|
||||
let recipient_nonces = self
|
||||
.0
|
||||
.get_accounts_nonces(vec![recipient_account_id])
|
||||
.await
|
||||
.map_err(ExecutionFailureKind::SequencerError)?;
|
||||
nonces.extend(recipient_nonces);
|
||||
} else {
|
||||
println!(
|
||||
"Receiver's account ({recipient_account_id}) private key not found in wallet. Proceeding with only sender's key."
|
||||
);
|
||||
}
|
||||
|
||||
let message = nssa::public_transaction::Message::try_new(
|
||||
program_id,
|
||||
account_ids,
|
||||
nonces,
|
||||
instruction,
|
||||
)
|
||||
.unwrap();
|
||||
let witness_set =
|
||||
nssa::public_transaction::WitnessSet::for_message(&message, &private_keys);
|
||||
|
||||
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self
|
||||
.0
|
||||
.sequencer_client
|
||||
.send_transaction(NSSATransaction::Public(tx))
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn send_transfer_transaction_private_owned_account(
|
||||
@ -274,7 +208,7 @@ impl Token<'_> {
|
||||
self.0
|
||||
.resolve_private_account(sender_account_id)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?,
|
||||
PrivacyPreservingAccount::PrivateForeign {
|
||||
AccountIdentity::PrivateForeign {
|
||||
npk: recipient_npk,
|
||||
vpk: recipient_vpk,
|
||||
identifier: recipient_identifier,
|
||||
@ -310,7 +244,7 @@ impl Token<'_> {
|
||||
self.0
|
||||
.resolve_private_account(sender_account_id)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?,
|
||||
PrivacyPreservingAccount::Public(recipient_account_id),
|
||||
AccountIdentity::Public(recipient_account_id),
|
||||
],
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
@ -340,7 +274,7 @@ impl Token<'_> {
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::Public(sender_account_id),
|
||||
AccountIdentity::Public(sender_account_id),
|
||||
self.0
|
||||
.resolve_private_account(recipient_account_id)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?,
|
||||
@ -375,8 +309,8 @@ impl Token<'_> {
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::Public(sender_account_id),
|
||||
PrivacyPreservingAccount::PrivateForeign {
|
||||
AccountIdentity::Public(sender_account_id),
|
||||
AccountIdentity::PrivateForeign {
|
||||
npk: recipient_npk,
|
||||
vpk: recipient_vpk,
|
||||
identifier: recipient_identifier,
|
||||
@ -401,40 +335,23 @@ impl Token<'_> {
|
||||
holder_account_id: AccountId,
|
||||
amount: u128,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let account_ids = vec![definition_account_id, holder_account_id];
|
||||
let program = Program::token();
|
||||
let instruction = Instruction::Burn {
|
||||
amount_to_burn: amount,
|
||||
};
|
||||
let instruction_data =
|
||||
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||
|
||||
let nonces = self
|
||||
.0
|
||||
.get_accounts_nonces(vec![holder_account_id])
|
||||
self.0
|
||||
.send_pub_tx(
|
||||
vec![
|
||||
AccountIdentity::PublicNoSign(definition_account_id),
|
||||
AccountIdentity::Public(holder_account_id),
|
||||
],
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
.map_err(ExecutionFailureKind::SequencerError)?;
|
||||
let message = nssa::public_transaction::Message::try_new(
|
||||
Program::token().id(),
|
||||
account_ids,
|
||||
nonces,
|
||||
instruction,
|
||||
)
|
||||
.expect("Instruction should serialize");
|
||||
|
||||
let signing_key = self
|
||||
.0
|
||||
.storage
|
||||
.key_chain()
|
||||
.pub_account_signing_key(holder_account_id)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?;
|
||||
let witness_set =
|
||||
nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]);
|
||||
|
||||
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self
|
||||
.0
|
||||
.sequencer_client
|
||||
.send_transaction(NSSATransaction::Public(tx))
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn send_burn_transaction_private_owned_account(
|
||||
@ -489,7 +406,7 @@ impl Token<'_> {
|
||||
self.0
|
||||
.resolve_private_account(definition_account_id)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?,
|
||||
PrivacyPreservingAccount::Public(holder_account_id),
|
||||
AccountIdentity::Public(holder_account_id),
|
||||
],
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
@ -519,7 +436,7 @@ impl Token<'_> {
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::Public(definition_account_id),
|
||||
AccountIdentity::Public(definition_account_id),
|
||||
self.0
|
||||
.resolve_private_account(holder_account_id)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?,
|
||||
@ -543,62 +460,23 @@ impl Token<'_> {
|
||||
holder_account_id: AccountId,
|
||||
amount: u128,
|
||||
) -> Result<HashType, ExecutionFailureKind> {
|
||||
let account_ids = vec![definition_account_id, holder_account_id];
|
||||
let program = Program::token();
|
||||
let instruction = Instruction::Mint {
|
||||
amount_to_mint: amount,
|
||||
};
|
||||
let instruction_data =
|
||||
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||
|
||||
let mut nonces = self
|
||||
.0
|
||||
.get_accounts_nonces(vec![definition_account_id])
|
||||
self.0
|
||||
.send_pub_tx(
|
||||
vec![
|
||||
AccountIdentity::Public(definition_account_id),
|
||||
AccountIdentity::Public(holder_account_id),
|
||||
],
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
.map_err(ExecutionFailureKind::SequencerError)?;
|
||||
|
||||
let mut private_keys = Vec::new();
|
||||
let definition_sk = self
|
||||
.0
|
||||
.storage
|
||||
.key_chain()
|
||||
.pub_account_signing_key(definition_account_id)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?;
|
||||
private_keys.push(definition_sk);
|
||||
|
||||
if let Some(holder_sk) = self
|
||||
.0
|
||||
.storage
|
||||
.key_chain()
|
||||
.pub_account_signing_key(holder_account_id)
|
||||
{
|
||||
private_keys.push(holder_sk);
|
||||
let recipient_nonces = self
|
||||
.0
|
||||
.get_accounts_nonces(vec![holder_account_id])
|
||||
.await
|
||||
.map_err(ExecutionFailureKind::SequencerError)?;
|
||||
nonces.extend(recipient_nonces);
|
||||
} else {
|
||||
println!(
|
||||
"Holder's account ({holder_account_id}) private key not found in wallet. Proceeding with only definition's key."
|
||||
);
|
||||
}
|
||||
|
||||
let message = nssa::public_transaction::Message::try_new(
|
||||
Program::token().id(),
|
||||
account_ids,
|
||||
nonces,
|
||||
instruction,
|
||||
)
|
||||
.unwrap();
|
||||
let witness_set =
|
||||
nssa::public_transaction::WitnessSet::for_message(&message, &private_keys);
|
||||
|
||||
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self
|
||||
.0
|
||||
.sequencer_client
|
||||
.send_transaction(NSSATransaction::Public(tx))
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn send_mint_transaction_private_owned_account(
|
||||
@ -655,7 +533,7 @@ impl Token<'_> {
|
||||
self.0
|
||||
.resolve_private_account(definition_account_id)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?,
|
||||
PrivacyPreservingAccount::PrivateForeign {
|
||||
AccountIdentity::PrivateForeign {
|
||||
npk: holder_npk,
|
||||
vpk: holder_vpk,
|
||||
identifier: holder_identifier,
|
||||
@ -691,7 +569,7 @@ impl Token<'_> {
|
||||
self.0
|
||||
.resolve_private_account(definition_account_id)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?,
|
||||
PrivacyPreservingAccount::Public(holder_account_id),
|
||||
AccountIdentity::Public(holder_account_id),
|
||||
],
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
@ -721,7 +599,7 @@ impl Token<'_> {
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::Public(definition_account_id),
|
||||
AccountIdentity::Public(definition_account_id),
|
||||
self.0
|
||||
.resolve_private_account(holder_account_id)
|
||||
.ok_or(ExecutionFailureKind::KeyNotFoundError)?,
|
||||
@ -756,8 +634,8 @@ impl Token<'_> {
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
PrivacyPreservingAccount::Public(definition_account_id),
|
||||
PrivacyPreservingAccount::PrivateForeign {
|
||||
AccountIdentity::Public(definition_account_id),
|
||||
AccountIdentity::PrivateForeign {
|
||||
npk: holder_npk,
|
||||
vpk: holder_vpk,
|
||||
identifier: holder_identifier,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user