Skip to content

Commit

Permalink
Use asset price data to calculate current OP token price in native cu…
Browse files Browse the repository at this point in the history
…rrency (#4589)
  • Loading branch information
jkadamczyk authored and Ibrahim Taveras committed Feb 7, 2023
1 parent 310ddc8 commit 17d4d07
Show file tree
Hide file tree
Showing 16 changed files with 262 additions and 98 deletions.
14 changes: 14 additions & 0 deletions src/analytics/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ export const event = {
qrCodeViewed: 'qr_code.viewed',
buyButtonPressed: 'buy_button.pressed',
addWalletFlowStarted: 'add_wallet_flow.started',
rewardsViewedSheet: 'rewards.viewed_sheet',
rewardsPressedPendingEarningsCard: 'rewards.pressed_pending_earnings_card',
rewardsPressedAvailableCard: 'rewards.pressed_available_card',
rewardsPressedPositionCard: 'rewards.pressed_position_card',
rewardsPressedSwappedCard: 'rewards.pressed_swapped_card',
rewardsPressedBridgedCard: 'rewards.pressed_bridged_card',
rewardsPressedLeaderboardItem: 'rewards.pressed_leaderboard_item',
} as const;

/**
Expand Down Expand Up @@ -95,4 +102,11 @@ export type EventProperties = {
isFirstWallet: boolean;
type: 'backup' | 'seed' | 'watch' | 'ledger_nano_x' | 'new';
};
[event.rewardsViewedSheet]: undefined;
[event.rewardsPressedPendingEarningsCard]: undefined;
[event.rewardsPressedAvailableCard]: undefined;
[event.rewardsPressedPositionCard]: { position: number };
[event.rewardsPressedSwappedCard]: undefined;
[event.rewardsPressedBridgedCard]: undefined;
[event.rewardsPressedLeaderboardItem]: { ens?: string };
};
4 changes: 3 additions & 1 deletion src/config/experimentalHooks.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { useContext } from 'react';
import { defaultConfig } from './experimental';
import { RainbowContext } from '@/helpers/RainbowContext';
import { IS_DEV } from '@/env';
import isTestFlight from '@/helpers/isTestFlight';

const useExperimentalFlag = (name: any) => {
if (IS_DEV) {
if (IS_DEV || isTestFlight) {
// @ts-expect-error ts-migrate(2339) FIXME: Property 'config' does not exist on type '{}'.
// eslint-disable-next-line react-hooks/rules-of-hooks
return useContext(RainbowContext).config[name];
Expand Down
1 change: 1 addition & 0 deletions src/helpers/RainbowContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import Emoji from '../components/text/Emoji';
import {
showReloadButton,
showSwitchModeButton,
// @ts-ignore
showConnectToHardhatButton,
} from '../config/debug';
import { defaultConfig } from '../config/experimental';
Expand Down
6 changes: 4 additions & 2 deletions src/languages/_english.json
Original file line number Diff line number Diff line change
Expand Up @@ -1297,6 +1297,10 @@
"my_stats": "My Stats",
"position": "Position",
"leaderboard": "Leaderboard",
"program_paused": "\uDBC0\uDE97 Paused",
"program_paused_will_resume": "The contest will resume once rewards refresh on %{resumeDate}.",
"program_finished": "\uDBC1\uDF2A Ended",
"program_finished_description": "The contest ended, the leaderboard shows the results from the last week of the contest",
"days_left": "%{days} days left",
"data_powered_by": "Data powered by",
"current_value": "Current Value",
Expand All @@ -1312,8 +1316,6 @@
"error_text": "Please check your internet connection and check back later.",
"ended_title": "Program ended",
"ended_text": "Stay tuned for what we have in store for you next!",
"paused_title": "Program paused",
"paused_text": "Check back later, stay tuned and look for any announcements!",
"op": {
"airdrop_timing": {
"title": "Airdrops Every Week",
Expand Down
6 changes: 4 additions & 2 deletions src/languages/_french.json
Original file line number Diff line number Diff line change
Expand Up @@ -1298,6 +1298,10 @@
"my_stats": "My Stats :)",
"position": "Position :)",
"leaderboard": "Leaderboard :)",
"program_paused": "\uDBC0\uDE97 Paused :)",
"program_paused_will_resume": "The contest will resume once rewards refresh on %{resumeDate}. :)",
"program_finished": "\uDBC1\uDF2A Ended :)",
"program_finished_description": "The contest ended, the leaderboard shows the results from the last week of the contest :)",
"days_left": "%{days} days left :)",
"data_powered_by": "Data powered by :)",
"current_value": "Current Value :)",
Expand All @@ -1313,8 +1317,6 @@
"error_text": "Please check your internet connection and check back later. :)",
"ended_title": "Program ended :)",
"ended_text": "Stay tuned for what we have in store for you next! :)",
"paused_title": "Program paused :)",
"paused_text": "Check back later, stay tuned and look for any announcements! :)",
"op": {
"airdrop_timing": {
"title": "Airdrops Every Week :)",
Expand Down
7 changes: 5 additions & 2 deletions src/model/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import Logger from '@/utils/logger';

export interface RainbowConfig extends Record<string, any> {
arbitrum_mainnet_rpc?: string;
bsc_mainnet_rpc?: string;
data_api_key?: string;
data_endpoint?: string;
data_origin?: string;
Expand All @@ -43,9 +44,9 @@ export interface RainbowConfig extends Record<string, any> {
f2c_enabled?: boolean;
flashbots_enabled?: boolean;
op_nft_network?: string;
op_rewards_enabled?: boolean;
optimism_mainnet_rpc?: string;
polygon_mainnet_rpc?: string;
bsc_mainnet_rpc?: string;
swagg_enabled?: boolean;
trace_call_block_number_offset?: number;
wyre_enabled?: boolean;
Expand All @@ -70,6 +71,7 @@ const DEFAULT_CONFIG = {
f2c_enabled: true,
flashbots_enabled: true,
op_nft_network: 'op-mainnet',
op_rewards_enabled: false,
optimism_mainnet_rpc: OPTIMISM_MAINNET_RPC,
polygon_mainnet_rpc: POLYGON_MAINNET_RPC,
bsc_mainnet_rpc: BSC_MAINNET_RPC,
Expand Down Expand Up @@ -108,7 +110,8 @@ const init = async () => {
key === 'flashbots_enabled' ||
key === 'wyre_enabled' ||
key === 'f2c_enabled' ||
key === 'swagg_enabled'
key === 'swagg_enabled' ||
key === 'op_rewards_enabled'
) {
config[key] = entry.asBoolean();
} else {
Expand Down
4 changes: 3 additions & 1 deletion src/redux/explorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import {
DPI_ADDRESS,
ETH_ADDRESS,
MATIC_MAINNET_ADDRESS,
OP_ADDRESS,
} from '@/references';
import { ethereumUtils, TokensListenedCache } from '@/utils';
import logger from '@/utils/logger';
Expand Down Expand Up @@ -326,7 +327,8 @@ const assetPricesSubscription = (
ETH_ADDRESS,
DPI_ADDRESS,
MATIC_MAINNET_ADDRESS,
BNB_MAINNET_ADDRESS
BNB_MAINNET_ADDRESS,
OP_ADDRESS
);
return [
action,
Expand Down
2 changes: 2 additions & 0 deletions src/references/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { savingsAssets } from './compound';
import { default as DefaultTokenListsSource } from './default-token-lists';
import { Asset, SavingsAsset, UniswapFavoriteTokenData } from '@/entities';
import { Network } from '@/helpers/networkTypes';

export { default as balanceCheckerContractAbi } from './balances-checker-abi.json';
export { default as chains } from './chains.json';
export { default as chainAssets } from './chain-assets.json';
Expand Down Expand Up @@ -94,6 +95,7 @@ export const GUSD_ADDRESS = '0x056fd409e1d7a124bd7017459dfea2f387b6d5cd';
export const SOCKS_ADDRESS = '0x23b608675a2b2fb1890d3abbd85c5775c51691d5';
export const WBTC_ADDRESS = '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599';
export const DOG_ADDRESS = '0xbaac2b4491727d78d2b78815144570b9f2fe8899';
export const OP_ADDRESS = '0x4200000000000000000000000000000000000042';

export const TRANSFER_EVENT_TOPIC_LENGTH = 3;
export const TRANSFER_EVENT_KECCAK =
Expand Down
7 changes: 5 additions & 2 deletions src/screens/discover/components/DiscoverHome.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ import {
cryptoAndWalletsCard,
} from '@/components/cards/utils/constants';
import { OpRewardsCard } from '@/components/cards/OpRewardsCard';
import config from '@/model/config';

export default function DiscoverHome() {
const { network } = useAccountSettings();
const accountAsset = useAccountAsset(ETH_ADDRESS);
const profilesEnabled = useExperimentalFlag(PROFILES);
const optimismRewardsEnabled = useExperimentalFlag(OP_REWARDS);
const opRewardsLocalFlag = useExperimentalFlag(OP_REWARDS);
const opRewardsRemoteFlag = config.op_rewards_enabled;
const testNetwork = isTestnetNetwork(network);

return (
Expand All @@ -40,7 +42,8 @@ export default function DiscoverHome() {
<GasCard />
<ENSSearchCard />
</Inline>
{optimismRewardsEnabled && <OpRewardsCard />}
{/* We have both flags here to be able to override the remote flag and show the card anyway in Dev*/}
{(opRewardsRemoteFlag || opRewardsLocalFlag) && <OpRewardsCard />}
<ENSCreateProfileCard />
<Inline space="20px">
<LearnCard cardDetails={backupsCard} type="square" />
Expand Down
22 changes: 21 additions & 1 deletion src/screens/rewards/RewardsSheet.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { SlackSheet } from '@/components/sheet';
import { useDimensions } from '@/hooks';
import { BackgroundProvider, Box } from '@/design-system';
Expand All @@ -9,6 +9,9 @@ import { StatusBar } from 'react-native';
import { useRewards } from '@/resources/rewards/rewardsQuery';
import { useSelector } from 'react-redux';
import { AppState } from '@/redux/store';
import { ethereumUtils } from '@/utils';
import { useFocusEffect } from '@react-navigation/native';
import { analyticsV2 } from '@/analytics';

export const RewardsSheet: React.FC = () => {
const { height } = useDimensions();
Expand All @@ -21,10 +24,26 @@ export const RewardsSheet: React.FC = () => {
address: accountAddress,
});

const assetPriceInNativeCurrency = useMemo(() => {
const assetCode = data?.rewards?.meta.token.asset.assetCode;

if (!assetCode) {
return undefined;
}

return ethereumUtils.getAssetPrice(assetCode);
}, [data?.rewards?.meta.token.asset]);

useEffect(() => {
setIsLoading(queryIsLoading);
}, [queryIsLoading]);

useFocusEffect(
useCallback(() => {
analyticsV2.track(analyticsV2.event.rewardsViewedSheet);
}, [])
);

return (
<BackgroundProvider color="surfaceSecondary">
{({ backgroundColor }) => (
Expand All @@ -39,6 +58,7 @@ export const RewardsSheet: React.FC = () => {
<Box padding="20px">
<RewardsContent
data={data}
assetPrice={assetPriceInNativeCurrency}
isLoadingError={isLoadingError}
isLoading={isLoading}
/>
Expand Down
43 changes: 27 additions & 16 deletions src/screens/rewards/components/RewardsAvailable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,33 +13,43 @@ import {
import { ButtonPressAnimation } from '@/components/animations';
import { useNavigation } from '@/navigation';
import Routes from '@/navigation/routesNames';
import {
convertAmountAndPriceToNativeDisplay,
convertAmountToNativeDisplay,
} from '@/helpers/utilities';
import { useSelector } from 'react-redux';
import { AppState } from '@/redux/store';
import { analyticsV2 } from '@/analytics';

type Props = {
totalAvailableRewards: number;
remainingRewards: number;
nextDistributionTimestamp: number;
assetPrice?: number;
color: string;
nextDistributionTimestamp: number;
remainingRewards: number;
totalAvailableRewardsInToken: number;
};

export const RewardsAvailable: React.FC<Props> = ({
remainingRewards,
totalAvailableRewards,
nextDistributionTimestamp,
assetPrice,
color,
nextDistributionTimestamp,
remainingRewards,
totalAvailableRewardsInToken,
}) => {
const infoIconColor = useInfoIconColor();
const nativeCurrency = useSelector(
(state: AppState) => state.settings.nativeCurrency
);
const { navigate } = useNavigation();

if (remainingRewards <= 0) {
const formattedTotalAvailableRewards = totalAvailableRewards.toLocaleString(
'en-US',
{
style: 'currency',
currency: 'USD',
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}
);
const formattedTotalAvailableRewards = assetPrice
? convertAmountAndPriceToNativeDisplay(
totalAvailableRewardsInToken,
assetPrice,
nativeCurrency
).display
: convertAmountToNativeDisplay(totalAvailableRewardsInToken, 'USD');

const now = new Date();
const nextDistribution = fromUnixTime(nextDistributionTimestamp);
Expand Down Expand Up @@ -77,10 +87,11 @@ export const RewardsAvailable: React.FC<Props> = ({
</Box>
);
} else {
const progress = remainingRewards / totalAvailableRewards;
const progress = remainingRewards / totalAvailableRewardsInToken;
const roundedProgressPercent = Math.round(progress * 10) * 10;

const navigateToAmountsExplainer = () => {
analyticsV2.track(analyticsV2.event.rewardsPressedAvailableCard);
navigate(Routes.EXPLAIN_SHEET, { type: 'op_rewards_amount_distributed' });
};

Expand Down
43 changes: 16 additions & 27 deletions src/screens/rewards/components/RewardsContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ import * as i18n from '@/languages';
const LEADERBOARD_ITEMS_THRESHOLD = 50;

type Props = {
assetPrice?: number;
data: GetRewardsDataForWalletQuery | undefined;
isLoading?: boolean;
isLoadingError?: boolean;
};

export const RewardsContent: React.FC<Props> = ({
assetPrice,
data,
isLoading,
isLoadingError,
Expand All @@ -38,24 +40,6 @@ export const RewardsContent: React.FC<Props> = ({
/>
);
}
if (data.rewards.meta.status === RewardsMetaStatus.Finished) {
return (
<RewardsProgramStatus
emoji="💸"
title={i18n.t(i18n.l.rewards.ended_title)}
text={i18n.t(i18n.l.rewards.ended_text)}
/>
);
}
if (data.rewards.meta.status === RewardsMetaStatus.Paused) {
return (
<RewardsProgramStatus
emoji="⏸️"
title={i18n.t(i18n.l.rewards.paused_title)}
text={i18n.t(i18n.l.rewards.paused_text)}
/>
);
}
const leaderboardData = data.rewards.leaderboard.accounts ?? [];
const limitedLeaderboardData = leaderboardData.slice(
0,
Expand All @@ -66,29 +50,34 @@ export const RewardsContent: React.FC<Props> = ({
<RewardsTitle text={data.rewards.meta.title} />
{data.rewards.earnings && (
<RewardsEarnings
totalEarnings={data.rewards.earnings.total}
assetPrice={assetPrice}
color={data.rewards.meta.color}
nextAirdropTimestamp={data.rewards.meta.distribution.next}
pendingEarningsToken={data.rewards.earnings?.pending.token ?? 0}
tokenImageUrl={data.rewards.meta.token.asset.iconURL ?? ''}
tokenSymbol={data.rewards.meta.token.asset.symbol}
pendingEarningsToken={data.rewards.earnings?.pending.token ?? 0}
nextAirdropTimestamp={data.rewards.meta.distribution.next}
color={data.rewards.meta.color}
totalEarnings={data.rewards.earnings.total}
/>
)}
<RewardsAvailable
totalAvailableRewards={data.rewards.meta.distribution.total}
remainingRewards={data.rewards.meta.distribution.left}
nextDistributionTimestamp={data.rewards.meta.distribution.next}
assetPrice={assetPrice}
color={data.rewards.meta.color}
nextDistributionTimestamp={data.rewards.meta.distribution.next}
remainingRewards={data.rewards.meta.distribution.left}
totalAvailableRewardsInToken={data.rewards.meta.distribution.total}
/>
<RewardsStats
position={data.rewards.stats?.position.current ?? 1}
positionChange={data.rewards.stats?.position.change.h24 ?? 0}
actions={data.rewards.stats?.actions ?? []}
assetPrice={assetPrice}
color={data.rewards.meta.color}
position={data.rewards.stats?.position.current ?? 1}
positionChange={data.rewards.stats?.position.change.h24 ?? 0}
/>
<RewardsLeaderboard
leaderboard={limitedLeaderboardData}
nextDistributionTimestamp={data.rewards.meta.distribution.next}
programEndTimestamp={data.rewards.meta.end}
status={data.rewards.meta.status}
tokenSymbol={data.rewards.meta.token.asset.symbol}
/>
<RewardsDuneLogo />
Expand Down
Loading

0 comments on commit 17d4d07

Please sign in to comment.