Skip to content

Commit

Permalink
Merge pull request #133 from sander2/fix/redeem-events
Browse files Browse the repository at this point in the history
[BREAKING] Fix: redeem events
  • Loading branch information
gregdhill authored May 24, 2021
2 parents 5d0df77 + 109ed9c commit a06ada7
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 17 deletions.
39 changes: 24 additions & 15 deletions crates/redeem/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,10 @@ decl_event!(
LiquidationRedeem(AccountId, Wrapped),
// [redeem_id, redeemer, amount_wrapped, fee_wrapped, vault]
ExecuteRedeem(H256, AccountId, Wrapped, Wrapped, AccountId),
// [redeem_id, redeemer, vault_id, slashing_amount_in_collateral, reimburse]
CancelRedeem(H256, AccountId, AccountId, Collateral, bool),
// [redeem_id, redeemer, vault_id, slashing_amount_in_collateral, status]
CancelRedeem(H256, AccountId, AccountId, Collateral, RedeemRequestStatus),
// [vault_id, redeem_id, amount_minted]
MintTokensForReimbursedRedeem(AccountId, H256, Wrapped),
}
);

Expand Down Expand Up @@ -229,8 +231,8 @@ decl_module! {
fn mint_tokens_for_reimbursed_redeem(origin, redeem_id: H256)
-> DispatchResult
{
let redeemer = ensure_signed(origin)?;
Self::_mint_tokens_for_reimbursed_redeem(redeemer, redeem_id)?;
let vault = ensure_signed(origin)?;
Self::_mint_tokens_for_reimbursed_redeem(vault, redeem_id)?;
Ok(())
}
}
Expand Down Expand Up @@ -483,9 +485,9 @@ impl<T: Config> Module<T> {
};

// first update the issued tokens; this logic is the same regardless of whether or not the vault is liquidated
if reimburse {
let new_status = if reimburse {
// Transfer the transaction fee to the pool. Even though the redeem was not
// successful, the user receives a premium in collateral, so it's to take the fee.
// successful, the user receives a premium in collateral, so it's OK to take the fee.
ext::treasury::unlock_and_transfer::<T>(
redeem.redeemer.clone(),
ext::fee::fee_pool_account_id::<T>(),
Expand All @@ -497,7 +499,7 @@ impl<T: Config> Module<T> {
// vault can not afford to back the tokens that he would receive, so we burn it
ext::treasury::burn::<T>(redeemer.clone(), vault_to_be_burned_tokens)?;
ext::vault_registry::decrease_tokens::<T>(&redeem.vault, &redeem.redeemer, vault_to_be_burned_tokens)?;
Self::set_redeem_status(redeem_id, RedeemRequestStatus::Reimbursed(false));
Self::set_redeem_status(redeem_id, RedeemRequestStatus::Reimbursed(false))
} else {
// Transfer the rest of the user's issued tokens (i.e. excluding fee) to the vault
ext::treasury::unlock_and_transfer::<T>(
Expand All @@ -506,7 +508,7 @@ impl<T: Config> Module<T> {
vault_to_be_burned_tokens,
)?;
ext::vault_registry::decrease_to_be_redeemed_tokens::<T>(&vault_id, vault_to_be_burned_tokens)?;
Self::set_redeem_status(redeem_id, RedeemRequestStatus::Reimbursed(true));
Self::set_redeem_status(redeem_id, RedeemRequestStatus::Reimbursed(true))
}
} else {
// unlock user's issued tokens, including fee
Expand All @@ -518,16 +520,16 @@ impl<T: Config> Module<T> {
.ok_or(Error::<T>::ArithmeticOverflow)?;
ext::treasury::unlock::<T>(redeemer.clone(), total_wrapped)?;
ext::vault_registry::decrease_to_be_redeemed_tokens::<T>(&vault_id, vault_to_be_burned_tokens)?;
Self::set_redeem_status(redeem_id, RedeemRequestStatus::Retried);
}
Self::set_redeem_status(redeem_id, RedeemRequestStatus::Retried)
};

ext::sla::event_update_vault_sla::<T>(&vault_id, ext::sla::VaultEvent::RedeemFailure)?;
Self::deposit_event(<Event<T>>::CancelRedeem(
redeem_id,
redeemer,
redeem.vault,
slashed_amount,
reimburse,
new_status,
));

Ok(())
Expand Down Expand Up @@ -556,7 +558,13 @@ impl<T: Config> Module<T> {
ext::vault_registry::issue_tokens::<T>(&vault_id, reimbursed_amount)?;
ext::treasury::mint::<T>(vault_id, reimbursed_amount);

Self::set_redeem_status(redeem_id, RedeemRequestStatus::Completed);
Self::set_redeem_status(redeem_id, RedeemRequestStatus::Reimbursed(true));

Self::deposit_event(<Event<T>>::MintTokensForReimbursedRedeem(
redeem.vault,
redeem_id,
reimbursed_amount,
));

Ok(())
}
Expand Down Expand Up @@ -585,11 +593,12 @@ impl<T: Config> Module<T> {
<RedeemRequests<T>>::insert(key, value)
}

fn set_redeem_status(id: H256, status: RedeemRequestStatus) {
// TODO: delete redeem request from storage
fn set_redeem_status(id: H256, status: RedeemRequestStatus) -> RedeemRequestStatus {
<RedeemRequests<T>>::mutate(id, |request| {
request.status = status;
request.status = status.clone();
});

status
}

/// Fetch all redeem requests for the specified account.
Expand Down
8 changes: 7 additions & 1 deletion crates/redeem/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,13 @@ fn test_cancel_redeem_succeeds() {
Redeem::get_open_redeem_request_from_id(&H256([0u8; 32])),
TestError::RedeemCancelled,
);
assert_emitted!(Event::CancelRedeem(H256([0; 32]), ALICE, BOB, 0, false));
assert_emitted!(Event::CancelRedeem(
H256([0; 32]),
ALICE,
BOB,
0,
RedeemRequestStatus::Retried
));
})
}

Expand Down
2 changes: 1 addition & 1 deletion crates/redeem/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub(crate) type Collateral<T> = <<T as currency::Config<currency::Collateral>>::
pub(crate) type Wrapped<T> =
<<T as currency::Config<currency::Wrapped>>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;

#[derive(Encode, Decode, Clone, PartialEq)]
#[derive(Encode, Decode, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
pub enum RedeemRequestStatus {
Pending,
Expand Down
61 changes: 61 additions & 0 deletions parachain/runtime/tests/test_redeem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -802,3 +802,64 @@ fn integration_test_redeem_banning() {
);
})
}

mod mint_tokens_for_reimbursed_redeem_equivalence_test {
use super::*;

fn setup_cancelable_redeem_with_insufficient_collateral_for_reimburse() -> H256 {
let amount_btc = 10_000;

// set collateral to the minimum amount required, such that the vault can not afford to both
// reimburse and keep collateral his current tokens
let required_collateral =
VaultRegistryPallet::get_required_collateral_for_wrapped(DEFAULT_VAULT_ISSUED).unwrap();
CoreVaultData::force_to(
VAULT,
CoreVaultData {
backing_collateral: required_collateral,
..CoreVaultData::vault(VAULT)
},
);
let redeem_id = setup_cancelable_redeem(USER, VAULT, 100000000, amount_btc);
let redeem = RedeemPallet::get_open_redeem_request_from_id(&redeem_id).unwrap();
let amount_without_fee_as_collateral =
ExchangeRateOraclePallet::wrapped_to_collateral(redeem.amount_btc + redeem.transfer_fee_btc).unwrap();

let punishment_fee = FeePallet::get_punishment_fee(amount_without_fee_as_collateral).unwrap();
assert!(punishment_fee > 0);

SlaPallet::set_vault_sla(&account_of(VAULT), FixedI128::from(80));
redeem_id
}

fn get_additional_collateral() {
assert_ok!(VaultRegistryPallet::transfer_funds(
CurrencySource::FreeBalance(account_of(FAUCET)),
CurrencySource::Collateral(account_of(VAULT)),
100_000_000_000,
));
}

#[test]
fn integration_test_mint_tokens_for_reimbursed_redeem_equivalence_to_succesful_cancel() {
// scenario 1: sufficient collateral
let result1 = test_with(|| {
let redeem_id = setup_cancelable_redeem_with_insufficient_collateral_for_reimburse();
get_additional_collateral();
assert_ok!(Call::Redeem(RedeemCall::cancel_redeem(redeem_id, true)).dispatch(origin_of(account_of(USER))));
ParachainState::get()
});
// scenario 2: insufficient collateral
let result2 = test_with(|| {
let redeem_id = setup_cancelable_redeem_with_insufficient_collateral_for_reimburse();
assert_ok!(Call::Redeem(RedeemCall::cancel_redeem(redeem_id, true)).dispatch(origin_of(account_of(USER))));
get_additional_collateral();
SecurityPallet::set_active_block_number(100000000);
assert_ok!(Call::Redeem(RedeemCall::mint_tokens_for_reimbursed_redeem(redeem_id))
.dispatch(origin_of(account_of(VAULT))));
ParachainState::get()
});
// the states should be identical
assert_eq!(result1, result2);
}
}

0 comments on commit a06ada7

Please sign in to comment.