use miden_protocol::account::auth::{AuthScheme, PublicKey};
use miden_protocol::account::component::{
AccountComponentCode,
AccountComponentMetadata,
SchemaType,
StorageSchema,
StorageSlotSchema,
};
use miden_protocol::account::{
AccountComponent,
AccountComponentName,
AccountId,
StorageSlot,
StorageSlotName,
};
use miden_protocol::crypto::dsa::{ecdsa_k256_keccak, falcon512_poseidon2};
use miden_protocol::note::{NoteTag, NoteType};
use miden_protocol::utils::sync::LazyLock;
use miden_protocol::{Felt, Hasher, Word};
use super::Approver;
use crate::account::account_component_code;
account_component_code!(AUTH_TX_FEE_COLLECTOR_CODE, "miden-standards-auth-tx-fee-collector.masp");
static PUBKEY_SLOT_NAME: LazyLock<StorageSlotName> = LazyLock::new(|| {
StorageSlotName::new("miden::standards::auth::tx_fee_collector::pub_key")
.expect("storage slot name should be valid")
});
static SIGNATURE_SCHEME_SLOT_NAME: LazyLock<StorageSlotName> = LazyLock::new(|| {
StorageSlotName::new("miden::standards::auth::tx_fee_collector::signature_scheme")
.expect("storage slot name should be valid")
});
pub struct AuthTxFeeCollector {
approver: Approver,
}
impl AuthTxFeeCollector {
pub const NAME: &'static str = "miden::standards::auth::tx_fee_collector";
pub const fn name() -> AccountComponentName {
AccountComponentName::from_static_str(Self::NAME)
}
pub fn code() -> &'static AccountComponentCode {
&AUTH_TX_FEE_COLLECTOR_CODE
}
pub fn new(approver: Approver) -> Self {
Self { approver }
}
pub fn falcon512_poseidon2(pub_key: falcon512_poseidon2::PublicKey) -> Self {
Self {
approver: Approver::new(pub_key.into(), AuthScheme::Falcon512Poseidon2),
}
}
pub fn ecdsa_k256_keccak(pub_key: ecdsa_k256_keccak::PublicKey) -> Self {
Self {
approver: Approver::new(pub_key.into(), AuthScheme::EcdsaK256Keccak),
}
}
pub fn from_public_key(pub_key: PublicKey) -> Self {
Self {
approver: Approver::new(pub_key.to_commitment(), pub_key.auth_scheme()),
}
}
pub fn approver(&self) -> Approver {
self.approver
}
pub fn auth_args(target: AccountId, note_type: NoteType) -> Word {
Word::new([
target.suffix(),
target.prefix().as_felt(),
Felt::from(NoteTag::with_account_target(target)),
Felt::from(note_type),
])
}
pub fn derive_serial_number(auth_args: Word, input_notes_commitment: Word) -> Word {
Hasher::merge(&[auth_args, input_notes_commitment])
}
pub fn public_key_slot() -> &'static StorageSlotName {
&PUBKEY_SLOT_NAME
}
pub fn signature_scheme_slot() -> &'static StorageSlotName {
&SIGNATURE_SCHEME_SLOT_NAME
}
pub fn public_key_slot_schema() -> (StorageSlotName, StorageSlotSchema) {
(
Self::public_key_slot().clone(),
StorageSlotSchema::value("Public key commitment", SchemaType::pub_key()),
)
}
pub fn signature_scheme_slot_schema() -> (StorageSlotName, StorageSlotSchema) {
(
Self::signature_scheme_slot().clone(),
StorageSlotSchema::value("Signature scheme", SchemaType::auth_scheme()),
)
}
pub fn component_metadata() -> AccountComponentMetadata {
let storage_schema = StorageSchema::new(vec![
Self::public_key_slot_schema(),
Self::signature_scheme_slot_schema(),
])
.expect("storage schema should be valid");
AccountComponentMetadata::new(Self::NAME)
.with_description("TX_FEE collector authentication component")
.with_storage_schema(storage_schema)
}
}
impl From<AuthTxFeeCollector> for AccountComponent {
fn from(collector: AuthTxFeeCollector) -> Self {
let metadata = AuthTxFeeCollector::component_metadata();
let storage_slots = vec![
StorageSlot::with_value(
AuthTxFeeCollector::public_key_slot().clone(),
collector.approver.pub_key().into(),
),
StorageSlot::with_value(
AuthTxFeeCollector::signature_scheme_slot().clone(),
Word::from([collector.approver.auth_scheme().as_u8(), 0, 0, 0]),
),
];
AccountComponent::new(AuthTxFeeCollector::code().clone(), storage_slots, metadata).expect(
"AuthTxFeeCollector component should satisfy the requirements of a valid account \
component",
)
}
}