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
2 changes: 1 addition & 1 deletion porteer/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ benchmarks! {
<T::Fungible as fungible::Mutate<_>>::set_balance(&bob, 0u32.into());
let location = <T as Config>::BenchmarkHelper::get_whitelisted_location();

}: _(RawOrigin::Root, bob.clone(), mint_amount, Some(location))
}: _(RawOrigin::Root, bob.clone(), mint_amount, Some(location), 0u32.into())
verify {
assert_eq!(<T::Fungible as fungible::Inspect<_>>::balance(&bob), mint_amount);
}
Expand Down
38 changes: 33 additions & 5 deletions porteer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,14 @@ mod tests;

pub mod weights;

use frame_support::transactional;
use sp_runtime::DispatchError;

pub use crate::weights::WeightInfo;
use frame_support::{transactional, Parameter};
pub use pallet::*;
use parity_scale_codec::MaxEncodedLen;
use sp_runtime::{
traits::{AtLeast32BitUnsigned, MaybeSerializeDeserialize, Member},
DispatchError,
};

pub const LOG_TARGET: &str = "integritee::porteer";

Expand All @@ -63,6 +66,7 @@ pub mod pallet {

pub type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
pub type BalanceOf<T> = <<T as Config>::Fungible as fungible::Inspect<AccountIdOf<T>>>::Balance;
pub type PortTokensNonceOf<T> = <<T as Config>::PortTokensToDestination as PortTokens>::Nonce;

const STORAGE_VERSION: StorageVersion = StorageVersion::new(0);
#[pallet::pallet]
Expand Down Expand Up @@ -193,7 +197,11 @@ pub mod pallet {
/// Ported some tokens to the destination chain.
PortedTokens { who: AccountIdOf<T>, amount: BalanceOf<T> },
/// Minted some tokens ported from another chain!
MintedPortedTokens { who: AccountIdOf<T>, amount: BalanceOf<T> },
MintedPortedTokens {
who: AccountIdOf<T>,
amount: BalanceOf<T>,
source_nonce: PortTokensNonceOf<T>,
},
/// Forwarded some minted tokens to another location.
ForwardedPortedTokens { who: AccountIdOf<T>, amount: BalanceOf<T>, location: T::Location },
/// Failed to forward the tokens to the final destination.
Expand Down Expand Up @@ -231,10 +239,14 @@ pub mod pallet {
#[pallet::storage]
pub(super) type WatchdogAccount<T: Config> = StorageValue<_, AccountIdOf<T>, OptionQuery>;

/// The block number at which the last heartbeat was received.
/// The timestamp at which the last heartbeat was received.
#[pallet::storage]
pub(super) type LastHeartBeat<T: Config> = StorageValue<_, T::Moment, ValueQuery>;

/// The timestamp at which the last heartbeat was received.
#[pallet::storage]
pub(super) type PortTokensNonce<T: Config> = StorageValue<_, PortTokensNonceOf<T>, ValueQuery>;

/// Entails the amount of fees needed at the respective hops.
#[pallet::storage]
pub(super) type XcmFeeConfig<T: Config> =
Expand Down Expand Up @@ -407,10 +419,16 @@ pub mod pallet {
Fortitude::Polite,
)?;

let nonce = PortTokensNonce::<T>::mutate(|n| {
*n = n.saturating_add(1u32.into());
*n
});

T::PortTokensToDestination::port_tokens(
signer.clone(),
amount,
forward_tokens_to_location,
nonce,
)
.map_err(|e| {
log::error!(target: LOG_TARGET, "Port tokens error: {:?}", e);
Expand All @@ -432,6 +450,7 @@ pub mod pallet {
beneficiary: AccountIdOf<T>,
amount: BalanceOf<T>,
forward_tokens_to_location: Option<T::Location>,
source_nonce: PortTokensNonceOf<T>,
) -> DispatchResult {
let _signer = T::TokenSenderLocationOrigin::ensure_origin(origin)?;

Expand All @@ -442,6 +461,7 @@ pub mod pallet {
Self::deposit_event(Event::<T>::MintedPortedTokens {
who: beneficiary.clone(),
amount,
source_nonce,
});

// Forward the tokens if desired
Expand Down Expand Up @@ -473,6 +493,13 @@ pub trait PortTokens {
type AccountId;

type Balance;
type Nonce: Parameter
+ Member
+ AtLeast32BitUnsigned
+ Default
+ Copy
+ MaybeSerializeDeserialize
+ MaxEncodedLen;

type Location;

Expand All @@ -482,6 +509,7 @@ pub trait PortTokens {
who: Self::AccountId,
amount: Self::Balance,
forward_tokens_to: Option<Self::Location>,
nonce: Self::Nonce,
) -> Result<(), Self::Error>;
}

Expand Down
2 changes: 2 additions & 0 deletions porteer/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,15 @@ pub struct MockPortTokens;
impl PortTokens for MockPortTokens {
type AccountId = AccountId;
type Balance = Balance;
type Nonce = u32;
type Location = TestLocation;
type Error = DispatchError;

fn port_tokens(
_who: Self::AccountId,
_amount: Self::Balance,
_forward_tokens_to: Option<Self::Location>,
_nonce: Self::Nonce,
) -> Result<(), Self::Error> {
Ok(())
}
Expand Down
22 changes: 16 additions & 6 deletions porteer/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ fn port_tokens_system_test_works() {

assert_ok!(Porteer::set_watchdog(RuntimeOrigin::signed(alice.clone()), bob.clone()));

assert_eq!(PortTokensNonce::<Test>::get(), 0);
assert_eq!(LastHeartBeat::<Test>::get(), 0);
let now = Timestamp::get();

Expand All @@ -322,6 +323,7 @@ fn port_tokens_system_test_works() {
porteering_amount,
None
));
assert_eq!(PortTokensNonce::<Test>::get(), 1);

// Test that bridge stays enabled until the HeartbeatTimout
Timestamp::set_timestamp(now + HeartBeatTimeout::get());
Expand All @@ -330,13 +332,16 @@ fn port_tokens_system_test_works() {
porteering_amount,
None
));
assert_eq!(PortTokensNonce::<Test>::get(), 2);

// Bridge Send is disabled after HeartbeatTimeout has passed
Timestamp::set_timestamp(now + HeartBeatTimeout::get() + 1);
assert_noop!(
Porteer::port_tokens(RuntimeOrigin::signed(alice.clone()), porteering_amount, None),
Error::<Test>::WatchdogHeartbeatIsTooOld
);
// Nonce has not increased
assert_eq!(PortTokensNonce::<Test>::get(), 2);
})
}

Expand Down Expand Up @@ -396,12 +401,14 @@ fn minting_ported_tokens_works() {
RuntimeOrigin::signed(alice.clone()),
bob.clone(),
mint_amount,
None
None,
42
));

let expected_event = RuntimeEvent::Porteer(PorteerEvent::MintedPortedTokens {
who: bob.clone(),
amount: mint_amount,
source_nonce: 42,
});
assert!(System::events().iter().any(|a| a.event == expected_event));

Expand All @@ -415,7 +422,7 @@ fn minting_ported_tokens_errs_with_wrong_origin() {
let bob = Keyring::Bob.to_account_id();

assert_noop!(
Porteer::mint_ported_tokens(RuntimeOrigin::signed(bob.clone()), bob, 1, None),
Porteer::mint_ported_tokens(RuntimeOrigin::signed(bob.clone()), bob, 1, None, 0),
BadOrigin
);
})
Expand All @@ -430,7 +437,7 @@ fn minting_ported_tokens_errs_when_receiving_disabled() {
assert_ok!(Porteer::set_porteer_config(RuntimeOrigin::signed(alice.clone()), config));

assert_noop!(
Porteer::mint_ported_tokens(RuntimeOrigin::signed(alice.clone()), alice, 1, None),
Porteer::mint_ported_tokens(RuntimeOrigin::signed(alice.clone()), alice, 1, None, 0),
Error::<Test>::PorteerOperationDisabled
);
})
Expand All @@ -454,7 +461,8 @@ fn minting_ported_tokens_with_forwarding_works() {
RuntimeOrigin::signed(alice.clone()),
bob.clone(),
mint_amount,
Some(WHITELISTED_LOCATION)
Some(WHITELISTED_LOCATION),
0
));

// We keep the ED during forwarding
Expand All @@ -478,7 +486,8 @@ fn minting_ported_tokens_with_forwarding_non_whitelisted_location_preserves_bala
RuntimeOrigin::signed(alice.clone()),
bob.clone(),
mint_amount,
Some(WHITELISTED_LOCATION)
Some(WHITELISTED_LOCATION),
0
));

let expected_event = RuntimeEvent::Porteer(PorteerEvent::IllegalForwardingLocation {
Expand Down Expand Up @@ -510,7 +519,8 @@ fn minting_ported_tokens_with_forwarding_to_unsupported_location_preserves_balan
RuntimeOrigin::signed(alice.clone()),
bob.clone(),
mint_amount,
Some(WHITELISTED_BUT_UNSUPPORTED_LOCATION)
Some(WHITELISTED_BUT_UNSUPPORTED_LOCATION),
0
));

let expected_event = RuntimeEvent::Porteer(PorteerEvent::FailedToForwardTokens {
Expand Down
Loading