Skip to content

Commit

Permalink
Merge branch 'main' into feat/solana
Browse files Browse the repository at this point in the history
  • Loading branch information
AntonioVentilii authored Dec 5, 2024
2 parents e38aa1c + baa8777 commit 77dd032
Show file tree
Hide file tree
Showing 17 changed files with 190 additions and 38 deletions.
15 changes: 11 additions & 4 deletions src/frontend/src/btc/components/convert/BtcConvertFeeTotal.svelte
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
<script lang="ts">
import { nonNullish } from '@dfinity/utils';
import { getContext } from 'svelte';
import { BTC_CONVERT_FEE } from '$btc/constants/btc.constants';
import { UTXOS_FEE_CONTEXT_KEY, type UtxosFeeContext } from '$btc/stores/utxos-fee.store';
import { ckBtcMinterInfoStore } from '$icp/stores/ckbtc.store';
import ConvertFeeTotal from '$lib/components/convert/ConvertFeeTotal.svelte';
import { CONVERT_CONTEXT_KEY, type ConvertContext } from '$lib/stores/convert.store';
export let totalFee: bigint | undefined = 0n;
export let totalFee: bigint | undefined = undefined;
const { sourceToken, sourceTokenExchangeRate, destinationToken } =
getContext<ConvertContext>(CONVERT_CONTEXT_KEY);
const { store: storeUtxosFeeData } = getContext<UtxosFeeContext>(UTXOS_FEE_CONTEXT_KEY);
let kytFee: bigint | undefined;
$: kytFee = $ckBtcMinterInfoStore?.[$destinationToken.id]?.data.kyt_fee;
let satoshisFee: bigint | undefined;
$: satoshisFee = $storeUtxosFeeData?.utxosFee?.feeSatoshis;
$: totalFee =
BTC_CONVERT_FEE +
($ckBtcMinterInfoStore?.[$destinationToken.id]?.data.kyt_fee ?? 0n) +
($storeUtxosFeeData?.utxosFee?.feeSatoshis ?? 0n);
nonNullish(kytFee) && nonNullish(satoshisFee)
? BTC_CONVERT_FEE + kytFee + satoshisFee
: undefined;
</script>

<ConvertFeeTotal
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
<script lang="ts">
import { isNullish } from '@dfinity/utils';
import { getContext } from 'svelte';
import { BTC_CONVERT_FEE } from '$btc/constants/btc.constants';
import { UTXOS_FEE_CONTEXT_KEY, type UtxosFeeContext } from '$btc/stores/utxos-fee.store';
import { ckBtcMinterInfoStore } from '$icp/stores/ckbtc.store';
import ConvertFee from '$lib/components/convert/ConvertFee.svelte';
import { CONVERT_CONTEXT_KEY, type ConvertContext } from '$lib/stores/convert.store';
import { i18n } from '$lib/stores/i18n.store';
import type { OptionAmount } from '$lib/types/send';
export let sendAmount: OptionAmount;
const { sourceToken, sourceTokenExchangeRate, destinationToken } =
getContext<ConvertContext>(CONVERT_CONTEXT_KEY);
Expand All @@ -20,10 +16,7 @@
$: kytFee = $ckBtcMinterInfoStore?.[$destinationToken.id]?.data.kyt_fee;
let satoshisFee: bigint | undefined;
$: satoshisFee =
isNullish(sendAmount) || Number(sendAmount) === 0
? 0n
: $storeUtxosFeeData?.utxosFee?.feeSatoshis;
$: satoshisFee = $storeUtxosFeeData?.utxosFee?.feeSatoshis;
</script>

<ConvertFee
Expand Down
11 changes: 6 additions & 5 deletions src/frontend/src/btc/components/convert/BtcConvertForm.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
initPendingSentTransactionsStatus
} from '$btc/derived/btc-pending-sent-transactions-status.derived';
import { UTXOS_FEE_CONTEXT_KEY, type UtxosFeeContext } from '$btc/stores/utxos-fee.store';
import type { UtxosFee } from '$btc/types/btc-send';
import ConvertForm from '$lib/components/convert/ConvertForm.svelte';
import InsufficientFundsForFee from '$lib/components/fee/InsufficientFundsForFee.svelte';
import Hr from '$lib/components/ui/Hr.svelte';
Expand All @@ -31,6 +32,9 @@
let hasPendingTransactionsStore: Readable<BtcPendingSentTransactionsStatus>;
$: hasPendingTransactionsStore = initPendingSentTransactionsStatus(source);
let utxosFee: UtxosFee | undefined;
$: utxosFee = nonNullish(sendAmount) ? $storeUtxosFeeData?.utxosFee : undefined;
let invalid: boolean;
$: invalid =
insufficientFunds ||
Expand All @@ -57,16 +61,13 @@
<InsufficientFundsForFee testId="btc-convert-form-insufficient-funds-for-fee" />
{:else if nonNullish($hasPendingTransactionsStore)}
<div class="mb-4" data-tid="btc-convert-form-send-warnings">
<BtcSendWarnings
utxosFee={$storeUtxosFeeData?.utxosFee}
pendingTransactionsStatus={$hasPendingTransactionsStore}
/>
<BtcSendWarnings {utxosFee} pendingTransactionsStatus={$hasPendingTransactionsStore} />
</div>
{/if}
</svelte:fragment>

<svelte:fragment slot="fee">
<BtcConvertFees {sendAmount} />
<BtcConvertFees />

<Hr spacing="md" />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<BtcConvertFeeTotal />
</div>

<BtcConvertFees {sendAmount} />
<BtcConvertFees />
</Collapsible>
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import { icTransactions } from '$icp/derived/ic-transactions.derived';
import { icTransactionsStore } from '$icp/stores/ic-transactions.store';
import type { IcTransactionUi } from '$icp/types/ic-transaction';
import { isIcTokenCanistersStrict } from '$icp/validation/ic-token.validation';
import { hasIndexCanister } from '$icp/validation/ic-token.validation';
import TransactionsPlaceholder from '$lib/components/transactions/TransactionsPlaceholder.svelte';
import Header from '$lib/components/ui/Header.svelte';
import { modalIcToken, modalIcTransaction } from '$lib/derived/modal.derived';
Expand Down Expand Up @@ -54,9 +54,6 @@
let noTransactions = false;
$: noTransactions = nonNullish($token) && $icTransactionsStore?.[$token.id] === null;
let hasIndexCanister = false;
$: hasIndexCanister = nonNullish($tokenAsIcToken) && isIcTokenCanistersStrict($tokenAsIcToken);
</script>

<Info />
Expand Down Expand Up @@ -86,7 +83,9 @@
{/if}

{#if noTransactions}
<IcNoIndexPlaceholder placeholderType={hasIndexCanister ? 'not-working' : 'missing'} />
<IcNoIndexPlaceholder
placeholderType={hasIndexCanister($tokenAsIcToken) ? 'not-working' : 'missing'}
/>
{:else if $icTransactions.length === 0}
<TransactionsPlaceholder />
{/if}
Expand Down
6 changes: 6 additions & 0 deletions src/frontend/src/icp/validation/ic-token.validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
} from '$icp/schema/ic-token.schema';
import type { IcCanistersStrict, IcCkToken, IcToken } from '$icp/types/ic-token';
import type { Token } from '$lib/types/token';
import { nonNullish } from '@dfinity/utils';

export const isIcToken = (token: Token): token is IcToken => {
const { success } = IcTokenSchema.safeParse(token);
Expand All @@ -29,3 +30,8 @@ export const isIcCkToken = (token: Token): token is IcCkToken => {

export const isNotIcCkToken = (token: Token): token is Exclude<Token, IcCkToken> =>
!isIcCkToken(token);

export const hasIndexCanister = (token: IcToken): boolean =>
nonNullish(token) && isIcTokenCanistersStrict(token);

export const hasNoIndexCanister = (token: IcToken): boolean => !hasIndexCanister(token);
2 changes: 1 addition & 1 deletion src/frontend/src/lib/components/core/SignOut.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
const logout = async () => {
dispatch('icLogoutTriggered');
await signOut();
await signOut({ resetUrl: true });
};
</script>

Expand Down
2 changes: 1 addition & 1 deletion src/frontend/src/lib/components/loaders/Loader.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@
);
if (!addressSuccess) {
await signOut();
await signOut({});
return;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,29 @@
<script lang="ts">
import { notEmptyString, type Token } from '@dfinity/utils';
import { icTransactionsStore } from '$icp/stores/ic-transactions.store';
import type { IcToken } from '$icp/types/ic-token';
import { hasNoIndexCanister } from '$icp/validation/ic-token.validation';
import NetworksSwitcher from '$lib/components/networks/NetworksSwitcher.svelte';
import AllTransactionsList from '$lib/components/transactions/AllTransactionsList.svelte';
import MessageBox from '$lib/components/ui/MessageBox.svelte';
import PageTitle from '$lib/components/ui/PageTitle.svelte';
import { enabledNetworkTokens } from '$lib/derived/network-tokens.derived';
import { testnetsEnabled } from '$lib/derived/settings.derived';
import { i18n } from '$lib/stores/i18n.store';
import type { TokenUi } from '$lib/types/token';
import { replacePlaceholders } from '$lib/utils/i18n.utils.js';
$: enabledTokensWithoutTransaction = $enabledNetworkTokens
.filter((token) => $icTransactionsStore?.[token.id] === null)
.map((token: TokenUi) => token as IcToken);
let enabledTokensWithoutCanister: Token[];
$: enabledTokensWithoutCanister = enabledTokensWithoutTransaction.filter(hasNoIndexCanister);
let tokenListWithoutCanister: string;
$: tokenListWithoutCanister = enabledTokensWithoutCanister
.map((token) => `$${token.symbol}`)
.join(', ');
</script>

<div class="flex flex-col gap-5">
Expand All @@ -16,6 +35,14 @@
</div>
{/if}

{#if notEmptyString(tokenListWithoutCanister)}
<MessageBox level="light-warning" closableKey="oisy_ic_hide_transaction_no_canister">
{replacePlaceholders($i18n.activity.warning.no_index_canister, {
$token_list: tokenListWithoutCanister
})}
</MessageBox>
{/if}

<MessageBox level="plain" closableKey="oisy_ic_hide_bitcoin_activity">
{$i18n.activity.info.btc_transactions}
</MessageBox>
Expand Down
3 changes: 3 additions & 0 deletions src/frontend/src/lib/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,9 @@
},
"info": {
"btc_transactions": "BTC transaction information is obtained from central third parties and should be independently verified."
},
"warning": {
"no_index_canister": "Transaction for $token_list can not be displayed. No Index canister."
}
}
}
12 changes: 10 additions & 2 deletions src/frontend/src/lib/services/auth.services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { i18n } from '$lib/stores/i18n.store';
import { testnetsStore } from '$lib/stores/settings.store';
import { toastsClean, toastsError, toastsShow } from '$lib/stores/toasts.store';
import type { ToastMsg } from '$lib/types/toast';
import { gotoReplaceRoot } from '$lib/utils/nav.utils';
import { replaceHistory } from '$lib/utils/route.utils';
import type { ToastLevel } from '@dfinity/gix-components';
import type { Principal } from '@dfinity/principal';
Expand Down Expand Up @@ -58,7 +59,8 @@ export const signIn = async (
}
};

export const signOut = (): Promise<void> => logout({});
export const signOut = ({ resetUrl = false }: { resetUrl?: boolean }): Promise<void> =>
logout({ resetUrl });

export const errorSignOut = (text: string): Promise<void> =>
logout({
Expand Down Expand Up @@ -115,10 +117,12 @@ const clearTestnetsOption = async () => {

const logout = async ({
msg = undefined,
clearStorages = true
clearStorages = true,
resetUrl = false
}: {
msg?: ToastMsg;
clearStorages?: boolean;
resetUrl?: boolean;
}) => {
// To mask not operational UI (a side effect of sometimes slow JS loading after window.reload because of service worker and no cache).
busy.start();
Expand All @@ -133,6 +137,10 @@ const logout = async ({
appendMsgToUrl(msg);
}

if (resetUrl) {
await gotoReplaceRoot();
}

// Auth: Delegation and identity are cleared from indexedDB by agent-js so, we do not need to clear these

// Preferences: We do not clear local storage as well. It contains anonymous information such as the selected theme.
Expand Down
1 change: 1 addition & 0 deletions src/frontend/src/lib/types/i18n.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,7 @@ interface I18nLicense_agreement {
interface I18nActivity {
text: { title: string };
info: { btc_transactions: string };
warning: { no_index_canister: string };
}

interface I18n {
Expand Down
3 changes: 2 additions & 1 deletion src/frontend/src/lib/utils/info.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ export type HideInfoKey =
| 'oisy_ic_hide_bitcoin_info'
| 'oisy_ic_hide_ethereum_info'
| 'oisy_ic_hide_erc20_info'
| 'oisy_ic_hide_bitcoin_activity';
| 'oisy_ic_hide_bitcoin_activity'
| 'oisy_ic_hide_transaction_no_canister';

export const saveHideInfo = (key: HideInfoKey) => {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,31 +44,27 @@ describe('BtcConvertFeeTotal', () => {
store.reset();
});

it('should calculate totalFee correctly if only default fee is available', () => {
it('should not update totalFee if only default fee is available', () => {
const { component } = render(BtcConvertFeeTotal, {
context: mockContext({ utxosFeeStore: store })
});
expect(component.$$.ctx[component.$$.props['totalFee']]).toBe(BTC_CONVERT_FEE);
expect(component.$$.ctx[component.$$.props['totalFee']]).toBeUndefined();
});

it('should calculate totalFee correctly if default and utxos fees are available', () => {
it('should not update totalFee if only default and utxos fees are available', () => {
store.setUtxosFee({ utxosFee: mockUtxosFee });
const { component } = render(BtcConvertFeeTotal, {
context: mockContext({ utxosFeeStore: store })
});
expect(component.$$.ctx[component.$$.props['totalFee']]).toBe(
BTC_CONVERT_FEE + mockUtxosFee.feeSatoshis
);
expect(component.$$.ctx[component.$$.props['totalFee']]).toBeUndefined();
});

it('should calculate totalFee correctly if default and ckBTC minter fees are available', () => {
it('should not update totalFee if only default and ckBTC minter fees are available', () => {
const tokenId = setupCkBTCStores();
const { component } = render(BtcConvertFeeTotal, {
context: mockContext({ utxosFeeStore: store, destinationTokenId: tokenId })
});
expect(component.$$.ctx[component.$$.props['totalFee']]).toBe(
BTC_CONVERT_FEE + mockCkBtcMinterInfo.kyt_fee
);
expect(component.$$.ctx[component.$$.props['totalFee']]).toBeUndefined();
});

it('should calculate totalFee correctly if all fees are available', () => {
Expand Down
30 changes: 30 additions & 0 deletions src/frontend/src/tests/icp/validation/ic-token.validation.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { IC_CKBTC_INDEX_CANISTER_ID } from '$env/networks.icrc.env';
import type { IcToken } from '$icp/types/ic-token';
import {
hasIndexCanister,
hasNoIndexCanister,
isIcCkToken,
isIcToken,
isIcTokenCanistersStrict,
Expand Down Expand Up @@ -92,4 +94,32 @@ describe('ic-token.validation', () => {
expect(isNotIcCkToken(mockValidToken)).toBe(true);
});
});

describe('hasIndexCanister', () => {
it('should return false for an IcToken without Index canister', () => {
expect(hasIndexCanister(mockValidIcToken)).toBe(false);
});

it('should return true for an IcToken with Index canister', () => {
expect(hasIndexCanister(mockValidIcTokenWithIndex)).toBe(true);
});

it('should return false for a token type casted to IcToken', () => {
expect(hasIndexCanister(mockValidToken as IcToken)).toBe(false);
});
});

describe('hasNoIndexCanister', () => {
it('should return true for an IcToken without Index canister', () => {
expect(hasNoIndexCanister(mockValidIcToken)).toBe(true);
});

it('should return false for an IcToken with Index canister', () => {
expect(hasNoIndexCanister(mockValidIcTokenWithIndex)).toBe(false);
});

it('should return true for a token type casted to IcToken', () => {
expect(hasNoIndexCanister(mockValidToken as IcToken)).toBe(true);
});
});
});
Loading

0 comments on commit 77dd032

Please sign in to comment.