zk-token-sdk: fix pod for zk-token transfer (#22957)
This commit is contained in:
parent
86cf226395
commit
7873175764
|
@ -52,31 +52,13 @@ impl TransferAmountEncryption {
|
|||
(transfer_amount_encryption, opening)
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> [u8; 128] {
|
||||
let mut bytes = [0u8; 128];
|
||||
bytes[..32].copy_from_slice(&self.commitment.to_bytes());
|
||||
bytes[32..64].copy_from_slice(&self.source.to_bytes());
|
||||
bytes[64..96].copy_from_slice(&self.dest.to_bytes());
|
||||
bytes[96..128].copy_from_slice(&self.auditor.to_bytes());
|
||||
bytes
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<Self, ProofError> {
|
||||
let bytes = array_ref![bytes, 0, 128];
|
||||
let (commitment, source, dest, auditor) = array_refs![bytes, 32, 32, 32, 32];
|
||||
|
||||
let commitment =
|
||||
PedersenCommitment::from_bytes(commitment).ok_or(ProofError::Verification)?;
|
||||
let source = DecryptHandle::from_bytes(source).ok_or(ProofError::Verification)?;
|
||||
let dest = DecryptHandle::from_bytes(dest).ok_or(ProofError::Verification)?;
|
||||
let auditor = DecryptHandle::from_bytes(auditor).ok_or(ProofError::Verification)?;
|
||||
|
||||
Ok(Self {
|
||||
commitment,
|
||||
source,
|
||||
dest,
|
||||
auditor,
|
||||
})
|
||||
pub fn to_pod(&self) -> pod::TransferAmountEncryption {
|
||||
pod::TransferAmountEncryption {
|
||||
commitment: self.commitment.into(),
|
||||
source: self.source.into(),
|
||||
dest: self.dest.into(),
|
||||
auditor: self.auditor.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -143,8 +125,11 @@ impl TransferData {
|
|||
- combine_u32_ciphertexts(&transfer_amount_lo_source, &transfer_amount_hi_source);
|
||||
|
||||
// generate transcript and append all public inputs
|
||||
let pod_transfer_pubkeys =
|
||||
pod::TransferPubkeys::new(&keypair_source.public, pubkey_dest, pubkey_auditor);
|
||||
let pod_transfer_pubkeys = pod::TransferPubkeys {
|
||||
source: keypair_source.public.into(),
|
||||
dest: (*pubkey_dest).into(),
|
||||
auditor: (*pubkey_auditor).into(),
|
||||
};
|
||||
let pod_ciphertext_lo: pod::TransferAmountEncryption = ciphertext_lo.into();
|
||||
let pod_ciphertext_hi: pod::TransferAmountEncryption = ciphertext_hi.into();
|
||||
let pod_ciphertext_new_source: pod::ElGamalCiphertext = ciphertext_new_source.into();
|
||||
|
@ -282,10 +267,21 @@ impl TransferProof {
|
|||
) -> Transcript {
|
||||
let mut transcript = Transcript::new(b"transfer-proof");
|
||||
|
||||
transcript.append_message(b"transfer-pubkeys", &transfer_pubkeys.0);
|
||||
transcript.append_message(b"ciphertext-lo", &ciphertext_lo.0);
|
||||
transcript.append_message(b"ciphertext-hi", &ciphertext_hi.0);
|
||||
transcript.append_message(b"ciphertext-new-source", &ciphertext_new_source.0);
|
||||
transcript.append_pubkey(b"pubkey_source", &transfer_pubkeys.source);
|
||||
transcript.append_pubkey(b"pubkey_dest", &transfer_pubkeys.dest);
|
||||
transcript.append_pubkey(b"pubkey_auditor", &transfer_pubkeys.auditor);
|
||||
|
||||
transcript.append_commitment(b"comm-lo-amount", &ciphertext_lo.commitment);
|
||||
transcript.append_handle(b"handle-lo-source", &ciphertext_lo.source);
|
||||
transcript.append_handle(b"handle-lo-dest", &ciphertext_lo.dest);
|
||||
transcript.append_handle(b"handle-lo-auditor", &ciphertext_lo.auditor);
|
||||
|
||||
transcript.append_commitment(b"comm-hi-amount", &ciphertext_hi.commitment);
|
||||
transcript.append_handle(b"handle-hi-source", &ciphertext_hi.source);
|
||||
transcript.append_handle(b"handle-hi-dest", &ciphertext_hi.dest);
|
||||
transcript.append_handle(b"handle-hi-auditor", &ciphertext_hi.auditor);
|
||||
|
||||
transcript.append_ciphertext(b"ciphertext-new-source", ciphertext_new_source);
|
||||
|
||||
transcript
|
||||
}
|
||||
|
@ -367,6 +363,8 @@ impl TransferProof {
|
|||
transcript,
|
||||
)?;
|
||||
|
||||
println!("equality pass");
|
||||
|
||||
// verify validity proof
|
||||
aggregated_validity_proof.verify(
|
||||
(&transfer_pubkeys.dest, &transfer_pubkeys.auditor),
|
||||
|
@ -376,6 +374,8 @@ impl TransferProof {
|
|||
transcript,
|
||||
)?;
|
||||
|
||||
println!("validity pass");
|
||||
|
||||
// verify range proof
|
||||
let commitment_new_source = self.commitment_new_source.try_into()?;
|
||||
range_proof.verify(
|
||||
|
@ -429,17 +429,6 @@ impl TransferPubkeys {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "bpf"))]
|
||||
impl pod::TransferPubkeys {
|
||||
pub fn new(source: &ElGamalPubkey, dest: &ElGamalPubkey, auditor: &ElGamalPubkey) -> Self {
|
||||
let mut bytes = [0u8; 96];
|
||||
bytes[..32].copy_from_slice(&source.to_bytes());
|
||||
bytes[32..64].copy_from_slice(&dest.to_bytes());
|
||||
bytes[64..96].copy_from_slice(&auditor.to_bytes());
|
||||
Self(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use {super::*, crate::encryption::elgamal::ElGamalKeypair};
|
||||
|
|
|
@ -123,21 +123,22 @@ impl TransferWithFeeData {
|
|||
FeeEncryption::new(fee_to_encrypt, pubkey_dest, pubkey_fee_collector);
|
||||
|
||||
// generate transcript and append all public inputs
|
||||
let pod_transfer_with_fee_pubkeys = pod::TransferWithFeePubkeys::new(
|
||||
&keypair_source.public,
|
||||
pubkey_dest,
|
||||
pubkey_auditor,
|
||||
pubkey_fee_collector,
|
||||
);
|
||||
let pod_ciphertext_lo = pod::TransferAmountEncryption(ciphertext_lo.to_bytes());
|
||||
let pod_ciphertext_hi = pod::TransferAmountEncryption(ciphertext_hi.to_bytes());
|
||||
let pod_transfer_with_fee_pubkeys = pod::TransferWithFeePubkeys {
|
||||
source: keypair_source.public.into(),
|
||||
dest: (*pubkey_dest).into(),
|
||||
auditor: (*pubkey_auditor).into(),
|
||||
fee_collector: (*pubkey_fee_collector).into(),
|
||||
};
|
||||
let pod_ciphertext_lo: pod::TransferAmountEncryption = ciphertext_lo.to_pod();
|
||||
let pod_ciphertext_hi: pod::TransferAmountEncryption = ciphertext_hi.to_pod();
|
||||
let pod_ciphertext_new_source: pod::ElGamalCiphertext = ciphertext_new_source.into();
|
||||
let pod_ciphertext_fee = pod::FeeEncryption(ciphertext_fee.to_bytes());
|
||||
let pod_ciphertext_fee: pod::FeeEncryption = ciphertext_fee.to_pod();
|
||||
|
||||
let mut transcript = TransferWithFeeProof::transcript_new(
|
||||
&pod_transfer_with_fee_pubkeys,
|
||||
&pod_ciphertext_lo,
|
||||
&pod_ciphertext_hi,
|
||||
&pod_ciphertext_new_source,
|
||||
&pod_ciphertext_fee,
|
||||
);
|
||||
|
||||
|
@ -225,13 +226,14 @@ impl Verifiable for TransferWithFeeData {
|
|||
&self.transfer_with_fee_pubkeys,
|
||||
&self.ciphertext_lo,
|
||||
&self.ciphertext_hi,
|
||||
&self.ciphertext_new_source,
|
||||
&self.ciphertext_fee,
|
||||
);
|
||||
|
||||
let ciphertext_lo = self.ciphertext_lo.try_into()?;
|
||||
let ciphertext_hi = self.ciphertext_hi.try_into()?;
|
||||
let transfer_with_fee_pubkeys = self.transfer_with_fee_pubkeys.try_into()?;
|
||||
let new_spendable_ciphertext = self.ciphertext_new_source.try_into()?;
|
||||
let pubkeys_transfer_with_fee = self.transfer_with_fee_pubkeys.try_into()?;
|
||||
let ciphertext_new_source = self.ciphertext_new_source.try_into()?;
|
||||
|
||||
let ciphertext_fee = self.ciphertext_fee.try_into()?;
|
||||
let fee_parameters = self.fee_parameters.into();
|
||||
|
@ -239,8 +241,8 @@ impl Verifiable for TransferWithFeeData {
|
|||
self.proof.verify(
|
||||
&ciphertext_lo,
|
||||
&ciphertext_hi,
|
||||
&transfer_with_fee_pubkeys,
|
||||
&new_spendable_ciphertext,
|
||||
&pubkeys_transfer_with_fee,
|
||||
&ciphertext_new_source,
|
||||
&ciphertext_fee,
|
||||
fee_parameters,
|
||||
&mut transcript,
|
||||
|
@ -268,14 +270,34 @@ impl TransferWithFeeProof {
|
|||
transfer_with_fee_pubkeys: &pod::TransferWithFeePubkeys,
|
||||
ciphertext_lo: &pod::TransferAmountEncryption,
|
||||
ciphertext_hi: &pod::TransferAmountEncryption,
|
||||
ciphertext_new_source: &pod::ElGamalCiphertext,
|
||||
ciphertext_fee: &pod::FeeEncryption,
|
||||
) -> Transcript {
|
||||
let mut transcript = Transcript::new(b"FeeProof");
|
||||
|
||||
transcript.append_message(b"transfer-with-fee-pubkeys", &transfer_with_fee_pubkeys.0);
|
||||
transcript.append_message(b"ciphertext-lo", &ciphertext_lo.0);
|
||||
transcript.append_message(b"ciphertext-hi", &ciphertext_hi.0);
|
||||
transcript.append_message(b"ciphertext-fee", &ciphertext_fee.0);
|
||||
transcript.append_pubkey(b"pubkey_source", &transfer_with_fee_pubkeys.source);
|
||||
transcript.append_pubkey(b"pubkey_dest", &transfer_with_fee_pubkeys.dest);
|
||||
transcript.append_pubkey(b"pubkey_auditor", &transfer_with_fee_pubkeys.auditor);
|
||||
transcript.append_pubkey(
|
||||
b"pubkey_fee_collector",
|
||||
&transfer_with_fee_pubkeys.fee_collector,
|
||||
);
|
||||
|
||||
transcript.append_commitment(b"comm-lo-amount", &ciphertext_lo.commitment);
|
||||
transcript.append_handle(b"handle-lo-source", &ciphertext_lo.source);
|
||||
transcript.append_handle(b"handle-lo-dest", &ciphertext_lo.dest);
|
||||
transcript.append_handle(b"handle-lo-auditor", &ciphertext_lo.auditor);
|
||||
|
||||
transcript.append_commitment(b"comm-hi-amount", &ciphertext_hi.commitment);
|
||||
transcript.append_handle(b"handle-hi-source", &ciphertext_hi.source);
|
||||
transcript.append_handle(b"handle-hi-dest", &ciphertext_hi.dest);
|
||||
transcript.append_handle(b"handle-hi-auditor", &ciphertext_hi.auditor);
|
||||
|
||||
transcript.append_ciphertext(b"ctxt-new-source", ciphertext_new_source);
|
||||
|
||||
transcript.append_commitment(b"comm-fee", &ciphertext_fee.commitment);
|
||||
transcript.append_handle(b"handle-fee-dest", &ciphertext_fee.dest);
|
||||
transcript.append_handle(b"handle-fee-auditor", &ciphertext_fee.fee_collector);
|
||||
|
||||
transcript
|
||||
}
|
||||
|
@ -510,23 +532,6 @@ impl TransferWithFeePubkeys {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "bpf"))]
|
||||
impl pod::TransferWithFeePubkeys {
|
||||
pub fn new(
|
||||
source: &ElGamalPubkey,
|
||||
dest: &ElGamalPubkey,
|
||||
auditor: &ElGamalPubkey,
|
||||
fee_collector: &ElGamalPubkey,
|
||||
) -> Self {
|
||||
let mut bytes = [0u8; 128];
|
||||
bytes[..32].copy_from_slice(&source.to_bytes());
|
||||
bytes[32..64].copy_from_slice(&dest.to_bytes());
|
||||
bytes[64..96].copy_from_slice(&auditor.to_bytes());
|
||||
bytes[96..128].copy_from_slice(&fee_collector.to_bytes());
|
||||
Self(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[repr(C)]
|
||||
#[cfg(not(target_arch = "bpf"))]
|
||||
|
@ -553,29 +558,12 @@ impl FeeEncryption {
|
|||
(fee_encryption, opening)
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> [u8; 96] {
|
||||
let mut bytes = [0u8; 96];
|
||||
bytes[..32].copy_from_slice(&self.commitment.to_bytes());
|
||||
bytes[32..64].copy_from_slice(&self.dest.to_bytes());
|
||||
bytes[64..96].copy_from_slice(&self.fee_collector.to_bytes());
|
||||
bytes
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<Self, ProofError> {
|
||||
let bytes = array_ref![bytes, 0, 96];
|
||||
let (commitment, dest, fee_collector) = array_refs![bytes, 32, 32, 32];
|
||||
|
||||
let commitment =
|
||||
PedersenCommitment::from_bytes(commitment).ok_or(ProofError::Verification)?;
|
||||
let dest = DecryptHandle::from_bytes(dest).ok_or(ProofError::Verification)?;
|
||||
let fee_collector =
|
||||
DecryptHandle::from_bytes(fee_collector).ok_or(ProofError::Verification)?;
|
||||
|
||||
Ok(Self {
|
||||
commitment,
|
||||
dest,
|
||||
fee_collector,
|
||||
})
|
||||
pub fn to_pod(&self) -> pod::FeeEncryption {
|
||||
pod::FeeEncryption {
|
||||
commitment: self.commitment.into(),
|
||||
dest: self.dest.into(),
|
||||
fee_collector: self.fee_collector.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -312,7 +312,11 @@ mod target_arch {
|
|||
|
||||
impl From<TransferPubkeys> for pod::TransferPubkeys {
|
||||
fn from(keys: TransferPubkeys) -> Self {
|
||||
Self(keys.to_bytes())
|
||||
Self {
|
||||
source: keys.source.into(),
|
||||
dest: keys.dest.into(),
|
||||
auditor: keys.auditor.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -320,13 +324,22 @@ mod target_arch {
|
|||
type Error = ProofError;
|
||||
|
||||
fn try_from(pod: pod::TransferPubkeys) -> Result<Self, Self::Error> {
|
||||
Self::from_bytes(&pod.0)
|
||||
Ok(Self {
|
||||
source: pod.source.try_into()?,
|
||||
dest: pod.dest.try_into()?,
|
||||
auditor: pod.auditor.try_into()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TransferWithFeePubkeys> for pod::TransferWithFeePubkeys {
|
||||
fn from(keys: TransferWithFeePubkeys) -> Self {
|
||||
Self(keys.to_bytes())
|
||||
Self {
|
||||
source: keys.source.into(),
|
||||
dest: keys.dest.into(),
|
||||
auditor: keys.auditor.into(),
|
||||
fee_collector: keys.fee_collector.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -334,13 +347,23 @@ mod target_arch {
|
|||
type Error = ProofError;
|
||||
|
||||
fn try_from(pod: pod::TransferWithFeePubkeys) -> Result<Self, Self::Error> {
|
||||
Self::from_bytes(&pod.0)
|
||||
Ok(Self {
|
||||
source: pod.source.try_into()?,
|
||||
dest: pod.dest.try_into()?,
|
||||
auditor: pod.auditor.try_into()?,
|
||||
fee_collector: pod.fee_collector.try_into()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TransferAmountEncryption> for pod::TransferAmountEncryption {
|
||||
fn from(ciphertext: TransferAmountEncryption) -> Self {
|
||||
Self(ciphertext.to_bytes())
|
||||
Self {
|
||||
commitment: ciphertext.commitment.into(),
|
||||
source: ciphertext.source.into(),
|
||||
dest: ciphertext.dest.into(),
|
||||
auditor: ciphertext.auditor.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -348,13 +371,22 @@ mod target_arch {
|
|||
type Error = ProofError;
|
||||
|
||||
fn try_from(pod: pod::TransferAmountEncryption) -> Result<Self, Self::Error> {
|
||||
Self::from_bytes(&pod.0)
|
||||
Ok(Self {
|
||||
commitment: pod.commitment.try_into()?,
|
||||
source: pod.source.try_into()?,
|
||||
dest: pod.dest.try_into()?,
|
||||
auditor: pod.auditor.try_into()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FeeEncryption> for pod::FeeEncryption {
|
||||
fn from(ciphertext: FeeEncryption) -> Self {
|
||||
Self(ciphertext.to_bytes())
|
||||
Self {
|
||||
commitment: ciphertext.commitment.into(),
|
||||
dest: ciphertext.dest.into(),
|
||||
fee_collector: ciphertext.fee_collector.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -362,19 +394,29 @@ mod target_arch {
|
|||
type Error = ProofError;
|
||||
|
||||
fn try_from(pod: pod::FeeEncryption) -> Result<Self, Self::Error> {
|
||||
Self::from_bytes(&pod.0)
|
||||
Ok(Self {
|
||||
commitment: pod.commitment.try_into()?,
|
||||
dest: pod.dest.try_into()?,
|
||||
fee_collector: pod.fee_collector.try_into()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FeeParameters> for pod::FeeParameters {
|
||||
fn from(parameters: FeeParameters) -> Self {
|
||||
Self(parameters.to_bytes())
|
||||
Self {
|
||||
fee_rate_basis_points: parameters.fee_rate_basis_points.into(),
|
||||
maximum_fee: parameters.maximum_fee.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<pod::FeeParameters> for FeeParameters {
|
||||
fn from(pod: pod::FeeParameters) -> Self {
|
||||
Self::from_bytes(&pod.0)
|
||||
Self {
|
||||
fee_rate_basis_points: pod.fee_rate_basis_points.into(),
|
||||
maximum_fee: pod.maximum_fee.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,34 @@
|
|||
pub use bytemuck::{Pod, Zeroable};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
|
||||
#[repr(transparent)]
|
||||
pub struct PodU16([u8; 2]);
|
||||
impl From<u16> for PodU16 {
|
||||
fn from(n: u16) -> Self {
|
||||
Self(n.to_le_bytes())
|
||||
}
|
||||
}
|
||||
impl From<PodU16> for u16 {
|
||||
fn from(pod: PodU16) -> Self {
|
||||
Self::from_le_bytes(pod.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
|
||||
#[repr(transparent)]
|
||||
pub struct PodU64([u8; 8]);
|
||||
impl From<u64> for PodU64 {
|
||||
fn from(n: u64) -> Self {
|
||||
Self(n.to_le_bytes())
|
||||
}
|
||||
}
|
||||
impl From<PodU64> for u64 {
|
||||
fn from(pod: PodU64) -> Self {
|
||||
Self::from_le_bytes(pod.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Pod, Zeroable, PartialEq)]
|
||||
#[repr(transparent)]
|
||||
pub struct Scalar(pub [u8; 32]);
|
||||
|
@ -153,31 +181,50 @@ impl Default for AeCiphertext {
|
|||
}
|
||||
|
||||
// TODO: refactor this code into the instruction module
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
pub struct TransferPubkeys(pub [u8; 96]);
|
||||
#[derive(Clone, Copy, Pod, Zeroable)]
|
||||
#[repr(C)]
|
||||
pub struct TransferPubkeys {
|
||||
pub source: ElGamalPubkey,
|
||||
pub dest: ElGamalPubkey,
|
||||
pub auditor: ElGamalPubkey,
|
||||
}
|
||||
|
||||
unsafe impl Zeroable for TransferPubkeys {}
|
||||
unsafe impl Pod for TransferPubkeys {}
|
||||
// pub struct TransferPubkeys(pub [u8; 96]);
|
||||
|
||||
// unsafe impl Zeroable for TransferPubkeys {}
|
||||
// unsafe impl Pod for TransferPubkeys {}
|
||||
|
||||
#[derive(Clone, Copy, Pod, Zeroable)]
|
||||
#[repr(transparent)]
|
||||
pub struct TransferWithFeePubkeys(pub [u8; 128]);
|
||||
#[repr(C)]
|
||||
pub struct TransferWithFeePubkeys {
|
||||
pub source: ElGamalPubkey,
|
||||
pub dest: ElGamalPubkey,
|
||||
pub auditor: ElGamalPubkey,
|
||||
pub fee_collector: ElGamalPubkey,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Pod, Zeroable)]
|
||||
#[repr(transparent)]
|
||||
pub struct TransferAmountEncryption(pub [u8; 128]);
|
||||
#[repr(C)]
|
||||
pub struct TransferAmountEncryption {
|
||||
pub commitment: PedersenCommitment,
|
||||
pub source: DecryptHandle,
|
||||
pub dest: DecryptHandle,
|
||||
pub auditor: DecryptHandle,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
pub struct FeeEncryption(pub [u8; 96]);
|
||||
#[derive(Clone, Copy, Pod, Zeroable)]
|
||||
#[repr(C)]
|
||||
pub struct FeeEncryption {
|
||||
pub commitment: PedersenCommitment,
|
||||
pub dest: DecryptHandle,
|
||||
pub fee_collector: DecryptHandle,
|
||||
}
|
||||
|
||||
unsafe impl Zeroable for FeeEncryption {}
|
||||
unsafe impl Pod for FeeEncryption {}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
pub struct FeeParameters(pub [u8; 10]);
|
||||
|
||||
unsafe impl Zeroable for FeeParameters {}
|
||||
unsafe impl Pod for FeeParameters {}
|
||||
#[derive(Clone, Copy, Pod, Zeroable)]
|
||||
#[repr(C)]
|
||||
pub struct FeeParameters {
|
||||
/// Fee rate expressed as basis points of the transfer amount, i.e. increments of 0.01%
|
||||
pub fee_rate_basis_points: PodU16,
|
||||
/// Maximum fee assessed on transfers, expressed as an amount of tokens
|
||||
pub maximum_fee: PodU64,
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue