Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@ sp-consensus-qpow = { path = "./primitives/consensus/qpow", default-features = f

# Quantus network dependencies
qp-plonky2 = { version = "1.1.3", default-features = false }
qp-poseidon = { version = "1.0.5", default-features = false }
qp-poseidon-core = { version = "1.0.5", default-features = false, features = ["p2", "p3"] }
qp-poseidon = { version = "1.0.6", default-features = false }
qp-poseidon-core = { version = "1.0.6", default-features = false, features = ["p2", "p3"] }
qp-rusty-crystals-dilithium = { version = "2.0.0", default-features = false }
qp-rusty-crystals-hdwallet = { version = "1.0.0" }
qp-wormhole-circuit = { version = "0.1.7", default-features = false }
Expand Down
128 changes: 88 additions & 40 deletions pallets/wormhole/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ extern crate alloc;

use core::marker::PhantomData;

use codec::{Decode, Encode, MaxEncodedLen};
use codec::{Decode, MaxEncodedLen};
use frame_support::StorageHasher;
use lazy_static::lazy_static;
pub use pallet::*;
use qp_poseidon::PoseidonHasher as PoseidonCore;
pub use qp_poseidon::{PoseidonHasher as PoseidonCore, ToFelts};
use qp_wormhole_verifier::WormholeVerifier;

#[cfg(test)]
Expand All @@ -35,17 +35,16 @@ pub fn get_wormhole_verifier() -> Result<&'static WormholeVerifier, &'static str
WORMHOLE_VERIFIER.as_ref().ok_or("Wormhole verifier not available")
}

pub struct PoseidonStorageHasher<T>(PhantomData<T>);
// We use a generic struct so we can pass the specific Key type to the hasher
pub struct PoseidonStorageHasher<Key>(PhantomData<Key>);

impl<AccountId: Decode + Encode + MaxEncodedLen + 'static> StorageHasher
for PoseidonStorageHasher<AccountId>
{
impl<Key: Decode + ToFelts + 'static> StorageHasher for PoseidonStorageHasher<Key> {
// We are lying here, but maybe it's ok because it's just metadata
const METADATA: StorageHasherIR = StorageHasherIR::Identity;
type Output = [u8; 32];

fn hash(x: &[u8]) -> Self::Output {
PoseidonCore::hash_storage::<AccountId>(x)
PoseidonCore::hash_storage::<Key>(x)
}

fn max_len<K: MaxEncodedLen>() -> usize {
Expand All @@ -55,10 +54,11 @@ impl<AccountId: Decode + Encode + MaxEncodedLen + 'static> StorageHasher

#[frame_support::pallet]
pub mod pallet {
use crate::{PoseidonStorageHasher, WeightInfo};
use crate::{PoseidonStorageHasher, ToFelts, WeightInfo};
use alloc::vec::Vec;
use codec::Decode;
use frame_support::{
dispatch::DispatchResult,
pallet_prelude::*,
traits::{
fungible::{Mutate, Unbalanced},
Expand All @@ -73,7 +73,7 @@ pub mod pallet {
use qp_wormhole_verifier::ProofWithPublicInputs;
use qp_zk_circuits_common::circuit::{C, D, F};
use sp_runtime::{
traits::{Saturating, StaticLookup, Zero},
traits::{MaybeDisplay, Saturating, StaticLookup, Zero},
Perbill,
};

Expand All @@ -87,42 +87,63 @@ pub mod pallet {
>>::Balance;
pub type AccountIdLookupOf<T> = <<T as frame_system::Config>::Lookup as StaticLookup>::Source;

pub type TransferProofKey<T> = (
AssetIdOf<T>,
<T as Config>::TransferCount,
<T as Config>::WormholeAccountId,
<T as Config>::WormholeAccountId,
BalanceOf<T>,
);

#[pallet::pallet]
pub struct Pallet<T>(_);

#[pallet::config]
pub trait Config: frame_system::Config
where
AssetIdOf<Self>: Default + From<u32> + Clone,
BalanceOf<Self>: Default,
AssetIdOf<Self>: Default + From<u32> + Clone + ToFelts,
BalanceOf<Self>: Default + ToFelts,
AssetBalanceOf<Self>: Into<BalanceOf<Self>> + From<BalanceOf<Self>>,
{
/// Currency type used for native token transfers and minting
type Currency: Mutate<Self::AccountId, Balance = BalanceOf<Self>>
+ Unbalanced<Self::AccountId>
+ Currency<Self::AccountId>;
type Currency: Mutate<<Self as frame_system::Config>::AccountId, Balance = BalanceOf<Self>>
+ Unbalanced<<Self as frame_system::Config>::AccountId>
+ Currency<<Self as frame_system::Config>::AccountId>;

/// Assets type used for managing fungible assets
type Assets: fungibles::Inspect<Self::AccountId>
+ fungibles::Mutate<Self::AccountId>
+ fungibles::Create<Self::AccountId>;
type Assets: fungibles::Inspect<<Self as frame_system::Config>::AccountId>
+ fungibles::Mutate<<Self as frame_system::Config>::AccountId>
+ fungibles::Create<<Self as frame_system::Config>::AccountId>;

/// Transfer count type used in storage
type TransferCount: Parameter
+ MaxEncodedLen
+ Default
+ Saturating
+ Copy
+ sp_runtime::traits::One;
+ sp_runtime::traits::One
+ ToFelts;

/// Account ID used as the "from" account when creating transfer proofs for minted tokens
#[pallet::constant]
type MintingAccount: Get<Self::AccountId>;
type MintingAccount: Get<<Self as frame_system::Config>::AccountId>;

/// Weight information for pallet operations.
type WeightInfo: WeightInfo;

type WeightToFee: WeightToFee<Balance = BalanceOf<Self>>;

/// Override system AccountId to make it felts encodable
type WormholeAccountId: Parameter
+ Member
+ MaybeSerializeDeserialize
+ core::fmt::Debug
+ MaybeDisplay
+ Ord
+ MaxEncodedLen
+ ToFelts
+ Into<<Self as frame_system::Config>::AccountId>
+ From<<Self as frame_system::Config>::AccountId>;
}

#[pallet::storage]
Expand All @@ -135,8 +156,8 @@ pub mod pallet {
#[pallet::getter(fn transfer_proof)]
pub type TransferProof<T: Config> = StorageMap<
_,
PoseidonStorageHasher<T::AccountId>,
(AssetIdOf<T>, T::TransferCount, T::AccountId, T::AccountId, BalanceOf<T>), /* (asset_id, tx_count, from, to, amount) */
PoseidonStorageHasher<TransferProofKey<T>>,
TransferProofKey<T>,
(),
OptionQuery,
>;
Expand All @@ -149,22 +170,22 @@ pub mod pallet {
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
ProofVerified {
exit_amount: BalanceOf<T>,
},
NativeTransferred {
from: T::AccountId,
to: T::AccountId,
from: <T as frame_system::Config>::AccountId,
to: <T as frame_system::Config>::AccountId,
amount: BalanceOf<T>,
transfer_count: T::TransferCount,
},
AssetTransferred {
asset_id: AssetIdOf<T>,
from: T::AccountId,
to: T::AccountId,
from: <T as frame_system::Config>::AccountId,
to: <T as frame_system::Config>::AccountId,
amount: AssetBalanceOf<T>,
transfer_count: T::TransferCount,
},
ProofVerified {
exit_amount: BalanceOf<T>,
},
}

#[pallet::error]
Expand Down Expand Up @@ -246,8 +267,9 @@ pub mod pallet {

// Decode exit account from public inputs
let exit_account_bytes = *public_inputs.exit_account;
let exit_account = T::AccountId::decode(&mut &exit_account_bytes[..])
.map_err(|_| Error::<T>::InvalidPublicInputs)?;
let exit_account =
<T as frame_system::Config>::AccountId::decode(&mut &exit_account_bytes[..])
.map_err(|_| Error::<T>::InvalidPublicInputs)?;

// Extract asset_id from public inputs
let asset_id_u32 = public_inputs.asset_id;
Expand Down Expand Up @@ -305,7 +327,12 @@ pub mod pallet {

// Create a transfer proof for the minted tokens
let mint_account = T::MintingAccount::get();
Self::record_transfer(asset_id, mint_account, exit_account, exit_balance)?;
Self::record_transfer(
asset_id,
mint_account.into(),
exit_account.into(),
exit_balance,
)?;

// Emit event
Self::deposit_event(Event::ProofVerified { exit_amount: exit_balance });
Expand All @@ -331,7 +358,7 @@ pub mod pallet {
<T::Currency as Mutate<_>>::transfer(&source, &dest, amount, Preservation::Expendable)?;

// Store proof with asset_id = Default (0 for native)
Self::record_transfer(AssetIdOf::<T>::default(), source, dest, amount)?;
Self::record_transfer(AssetIdOf::<T>::default(), source.into(), dest.into(), amount)?;

Ok(())
}
Expand Down Expand Up @@ -367,7 +394,7 @@ pub mod pallet {
)?;

// Store proof
Self::record_transfer(asset_id, source, dest, amount.into())?;
Self::record_transfer(asset_id, source.into(), dest.into(), amount.into())?;

Ok(())
}
Expand All @@ -379,31 +406,52 @@ pub mod pallet {
/// This should be called by transaction extensions or other runtime components
pub fn record_transfer(
asset_id: AssetIdOf<T>,
from: T::AccountId,
to: T::AccountId,
from: <T as Config>::WormholeAccountId,
to: <T as Config>::WormholeAccountId,
amount: BalanceOf<T>,
) -> DispatchResult {
let current_count = TransferCount::<T>::get();
TransferProof::<T>::insert(
(asset_id, current_count, from.clone(), to.clone(), amount),
(asset_id.clone(), current_count, from.clone(), to.clone(), amount),
(),
);
TransferCount::<T>::put(current_count.saturating_add(T::TransferCount::one()));

if asset_id == AssetIdOf::<T>::default() {
Self::deposit_event(Event::<T>::NativeTransferred {
from: from.into(),
to: to.into(),
amount,
transfer_count: current_count,
});
} else {
Self::deposit_event(Event::<T>::AssetTransferred {
from: from.into(),
to: to.into(),
asset_id,
amount: amount.into(),
transfer_count: current_count,
});
}

Ok(())
}
}

// Implement the TransferProofRecorder trait for other pallets to use
impl<T: Config> qp_wormhole::TransferProofRecorder<T::AccountId, AssetIdOf<T>, BalanceOf<T>>
for Pallet<T>
impl<T: Config>
qp_wormhole::TransferProofRecorder<
<T as Config>::WormholeAccountId,
AssetIdOf<T>,
BalanceOf<T>,
> for Pallet<T>
{
type Error = DispatchError;

fn record_transfer_proof(
asset_id: Option<AssetIdOf<T>>,
from: T::AccountId,
to: T::AccountId,
from: <T as Config>::WormholeAccountId,
to: <T as Config>::WormholeAccountId,
amount: BalanceOf<T>,
) -> Result<(), Self::Error> {
let asset_id_value = asset_id.unwrap_or_default();
Expand Down
1 change: 1 addition & 0 deletions pallets/wormhole/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ impl pallet_wormhole::Config for Test {
type Assets = Assets;
type TransferCount = u64;
type MintingAccount = MintingAccount;
type WormholeAccountId = AccountId;
}

// Helper function to build a genesis configuration
Expand Down
2 changes: 1 addition & 1 deletion pallets/wormhole/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ mod wormhole_tests {

let event_transfer_count = 0u64;

let leaf_hash = PoseidonHasher::hash_storage::<AccountId>(
let leaf_hash = PoseidonHasher::hash_storage::<crate::TransferProofKey<Test>>(
&(
0u32,
event_transfer_count,
Expand Down
3 changes: 2 additions & 1 deletion runtime/src/configs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ use qp_poseidon::PoseidonHasher;
use qp_scheduler::BlockNumberOrTimestamp;
use sp_runtime::{
traits::{AccountIdConversion, ConvertInto, One},
FixedU128, Perbill, Permill,
AccountId32, FixedU128, Perbill, Permill,
};
use sp_version::RuntimeVersion;

Expand Down Expand Up @@ -635,5 +635,6 @@ impl pallet_wormhole::Config for Runtime {
type Currency = Balances;
type Assets = Assets;
type TransferCount = u64;
type WormholeAccountId = AccountId32;
type WeightToFee = IdentityFee<Balance>;
}
Loading