-
+
{{ title }}
{{ description }}
@@ -212,11 +216,11 @@ export default defineComponent({
}
.bal-alert-container {
- @apply flex;
+ @apply flex flex-grow;
}
.bal-alert-content {
- @apply flex whitespace-pre-wrap;
+ @apply flex whitespace-pre-wrap flex-grow;
min-width: 0;
}
diff --git a/src/components/_global/BalCheckbox/BalCheckbox.vue b/src/components/_global/BalCheckbox/BalCheckbox.vue
index 56ebf43f8a..d702a56f1d 100644
--- a/src/components/_global/BalCheckbox/BalCheckbox.vue
+++ b/src/components/_global/BalCheckbox/BalCheckbox.vue
@@ -148,7 +148,7 @@ export default defineComponent({
}
.bal-checkbox-input {
- @apply text-blue-600 dark:text-blue-400 bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600
+ @apply text-blue-600 dark:text-blue-400 bg-white dark:bg-gray-700 border border-gray-500 dark:border-gray-500
rounded leading-none;
appearance: none;
diff --git a/src/components/contextual/pages/claim/LegacyClaims.vue b/src/components/contextual/pages/claim/LegacyClaims.vue
index 6825a7f7ba..899c082a0f 100644
--- a/src/components/contextual/pages/claim/LegacyClaims.vue
+++ b/src/components/contextual/pages/claim/LegacyClaims.vue
@@ -7,7 +7,7 @@ import useUserClaimsQuery from '@/composables/queries/useUserClaimsQuery';
import useEthers from '@/composables/useEthers';
import useNumbers, { FNumFormats } from '@/composables/useNumbers';
import { useTokens } from '@/providers/tokens.provider';
-import useTranasactionErrors from '@/composables/useTransactionErrors';
+import useTransactionErrors from '@/composables/useTransactionErrors';
import useTransactions from '@/composables/useTransactions';
import { TOKENS } from '@/constants/tokens';
import { bnum } from '@/lib/utils';
@@ -55,7 +55,7 @@ const { account, getProvider, isMismatchedNetwork } = useWeb3();
const { txListener } = useEthers();
const { addTransaction } = useTransactions();
const { priceFor, getToken } = useTokens();
-const { parseError } = useTranasactionErrors();
+const { parseError } = useTransactionErrors();
const BALTokenAddress = getAddress(TOKENS.Addresses.BAL);
diff --git a/src/components/contextual/pages/pool/MyPoolBalancesCard.vue b/src/components/contextual/pages/pool/MyPoolBalancesCard.vue
index 92690c5a27..1b113c6941 100644
--- a/src/components/contextual/pages/pool/MyPoolBalancesCard.vue
+++ b/src/components/contextual/pages/pool/MyPoolBalancesCard.vue
@@ -45,7 +45,7 @@ const { isMigratablePool } = usePoolHelpers(toRef(props, 'pool'));
const { stakedShares } = usePoolStaking();
const { networkSlug } = useNetwork();
const router = useRouter();
-const { totalLockedValue } = useLock();
+const { totalLockedValue } = useLock({ enabled: isVeBalPool(props.pool.id) });
/**
* COMPUTED
diff --git a/src/components/contextual/pages/pool/PoolStatCards.vue b/src/components/contextual/pages/pool/PoolStatCards.vue
index 2b12cb7ae6..f558e7f13f 100644
--- a/src/components/contextual/pages/pool/PoolStatCards.vue
+++ b/src/components/contextual/pages/pool/PoolStatCards.vue
@@ -8,6 +8,8 @@ import { isLBP, totalAprLabel } from '@/composables/usePoolHelpers';
import { APR_THRESHOLD, VOLUME_THRESHOLD } from '@/constants/pools';
import { Pool } from '@/services/pool/types';
import { AprBreakdown } from '@balancer-labs/sdk';
+import { useCrossChainSync } from '@/providers/cross-chain-sync.provider';
+import useNetwork from '@/composables/useNetwork';
/**
* TYPES
@@ -33,6 +35,8 @@ const props = withDefaults(defineProps(), {
*/
const { fNum } = useNumbers();
const { t } = useI18n();
+const { l2VeBalBalances } = useCrossChainSync();
+const { networkId } = useNetwork();
/**
* COMPUTED
@@ -44,6 +48,20 @@ const aprLabel = computed((): string => {
return totalAprLabel(poolAPRs, props.pool?.boost);
});
+const syncVeBalTooltip = computed(() => {
+ const vebalBalance = Number(l2VeBalBalances.value?.[networkId.value]);
+
+ if (vebalBalance > 0) {
+ return 'Remember to resync if you have acquired more veBAL since your last sync, to get a higher boosted staking rate. Resync on the veBAL page on Ethereum Mainnet.';
+ }
+
+ if (vebalBalance === 0) {
+ return 'If you have veBAL, sync your balance on the veBAL page on Ethereum Mainnet to get higher boosted staking rates across L2 networks.';
+ }
+
+ return '';
+});
+
const stats = computed(() => {
const volumeSnapshot = Number(props.pool?.volumeSnapshot || '0');
const feesSnapshot = Number(props.pool?.feesSnapshot || '0');
@@ -80,6 +98,7 @@ const stats = computed(() => {
? '-'
: aprLabel.value,
loading: props.loadingApr,
+ tooltip: syncVeBalTooltip.value,
},
];
});
@@ -112,7 +131,12 @@ const stats = computed(() => {
},
]"
>
- {{ stat.value }}
+ {{ stat.value }}
+
+
+
+
+
diff --git a/src/components/contextual/pages/pool/staking/StakingIncentivesCard.vue b/src/components/contextual/pages/pool/staking/StakingIncentivesCard.vue
index 64ce2ed1e9..a1945d397c 100644
--- a/src/components/contextual/pages/pool/staking/StakingIncentivesCard.vue
+++ b/src/components/contextual/pages/pool/staking/StakingIncentivesCard.vue
@@ -14,6 +14,9 @@ import { usePoolStaking } from '@/providers/local/pool-staking.provider';
import { deprecatedDetails } from '@/composables/usePoolHelpers';
import { usePoolWarning } from '@/composables/usePoolWarning';
import { StakeAction } from './composables/useStakePreview';
+import StakingCardSyncAlert from '../../vebal/cross-chain-boost/StakingCardSyncAlert.vue';
+import useNetwork from '@/composables/useNetwork';
+import { Network } from '@/lib/config';
type Props = {
pool: Pool;
@@ -30,7 +33,7 @@ const emit = defineEmits<{
const isStakePreviewVisible = ref(false);
const stakeAction = ref
('stake');
const poolId = computed(() => props.pool.id);
-
+const isOpenedByDefault = ref(false);
/**
* COMPOSABLES
*/
@@ -44,6 +47,7 @@ const {
hasNonPrefGaugeBalance,
} = usePoolStaking();
const { isAffected } = usePoolWarning(poolId);
+const { networkId } = useNetwork();
/**
* COMPUTED
@@ -105,6 +109,7 @@ function handlePreviewClose() {
},
]"
:reCalcKey="hasNonPrefGaugeBalance ? 0 : 1"
+ :isOpenedByDefault="isOpenedByDefault"
>
+
diff --git a/src/components/contextual/pages/pools/StakedPoolsTable.vue b/src/components/contextual/pages/pools/StakedPoolsTable.vue
index 5a6621cc32..2f0467dbf2 100644
--- a/src/components/contextual/pages/pools/StakedPoolsTable.vue
+++ b/src/components/contextual/pages/pools/StakedPoolsTable.vue
@@ -8,13 +8,17 @@ import { useUserStaking } from '@/providers/local/user-staking.provider';
import { Pool } from '@/services/pool/types';
import { useUserPools } from '@/providers/local/user-pools.provider';
import StakePreviewModal from '../pool/staking/StakePreviewModal.vue';
+import ProceedToSyncModal from '@/components/contextual/pages/vebal/cross-chain-boost/ProceedToSyncModal.vue';
import { providePoolStaking } from '@/providers/local/pool-staking.provider';
+import PortfolioSyncTip from '../vebal/cross-chain-boost/PortfolioSyncTip.vue';
+
/**
* STATE
*/
const showUnstakeModal = ref(false);
const poolToUnstake = ref();
+const showProceedModal = ref(false);
/**
* PROVIDERS
@@ -26,6 +30,7 @@ providePoolStaking();
*/
const { stakedPools, poolBoostsMap, stakedShares, isLoading } =
useUserStaking();
+
const { refetchAllUserPools } = useUserPools();
const { isWalletReady, isWalletConnecting } = useWeb3();
const { t } = useI18n();
@@ -73,6 +78,7 @@ async function handleUnstakeSuccess() {
{{ $t('staking.stakedPools') }}
+
+
diff --git a/src/components/contextual/pages/vebal/cross-chain-boost/CheckpointGaugeModal.vue b/src/components/contextual/pages/vebal/cross-chain-boost/CheckpointGaugeModal.vue
new file mode 100644
index 0000000000..9966da26bb
--- /dev/null
+++ b/src/components/contextual/pages/vebal/cross-chain-boost/CheckpointGaugeModal.vue
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+ Even though you've synced new veBAL to this Layer 2, it isn’t
+ contributing to your staking boost yet on this pool. This is because,
+ pool gauges don't detect veBAL changes until you interact with them.
+ This transaction is the most gas efficient way to update the gauge but
+ you can also trigger the update by claiming any BAL incentives.
+
+
+
+
+
+ {{ $t('close') }}
+
+
+
+
diff --git a/src/components/contextual/pages/vebal/cross-chain-boost/CrossChainBoostCards.vue b/src/components/contextual/pages/vebal/cross-chain-boost/CrossChainBoostCards.vue
new file mode 100644
index 0000000000..afeca6275f
--- /dev/null
+++ b/src/components/contextual/pages/vebal/cross-chain-boost/CrossChainBoostCards.vue
@@ -0,0 +1,251 @@
+
+
+
+
+
+ {{ $t('crossChainBoost.title') }}
+
+
+
+
+
+
+
+
+
+ Error has occured while fetching syncing states of some networks. Please
+ refresh the page.
+
+
+
+
+
+ {{ warningMessage.text }}
+
+
+ {{ infoMessage.text }}
+
+
+
+
+
+
+
+ {{ $t('crossChainBoost.emptyState') }}
+
+
+
+
+ {{ $t('crossChainBoost.unsyncedNetworks') }}
+
+
+
+ {{ hasError ? '—' : $t('crossChainBoost.syncedAllDescription') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ getLoadingTooltipText(network) }}
+
+
+
+ Click this icon to view Layerzero transaction
+
+
+
+
+
+
+
Ethereum veBAL
+
+ {{ Number(veBalBalance).toFixed(4) }}
+
+
+
+
+
+
+
+
+ {{ configs[network].chainName }} veBAL
+
+
+ {{ l2VeBalBalances?.[network] }}
+
+
+
+
+
+
+
+
+
+
+ {{ $t('crossChainBoost.sync') }}
+
+
+
+
+
+ {{ $t('crossChainBoost.syncedNetworks') }}
+
+
+ {{ hasError ? '—' : $t('crossChainBoost.unsyncedAllDescription') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/contextual/pages/vebal/cross-chain-boost/CrossChainSyncModal.vue b/src/components/contextual/pages/vebal/cross-chain-boost/CrossChainSyncModal.vue
new file mode 100644
index 0000000000..4c3245ba37
--- /dev/null
+++ b/src/components/contextual/pages/vebal/cross-chain-boost/CrossChainSyncModal.vue
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/contextual/pages/vebal/cross-chain-boost/IconLoaderWrapper.vue b/src/components/contextual/pages/vebal/cross-chain-boost/IconLoaderWrapper.vue
new file mode 100644
index 0000000000..a9d0c2b7fd
--- /dev/null
+++ b/src/components/contextual/pages/vebal/cross-chain-boost/IconLoaderWrapper.vue
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/contextual/pages/vebal/cross-chain-boost/PortfolioSyncTip.vue b/src/components/contextual/pages/vebal/cross-chain-boost/PortfolioSyncTip.vue
new file mode 100644
index 0000000000..34e167cb45
--- /dev/null
+++ b/src/components/contextual/pages/vebal/cross-chain-boost/PortfolioSyncTip.vue
@@ -0,0 +1,71 @@
+
+
+
+
+
+
{{ veBalSyncTip.text }}
+
+
+ Sync veBAL
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/contextual/pages/vebal/cross-chain-boost/ProceedToSyncModal.vue b/src/components/contextual/pages/vebal/cross-chain-boost/ProceedToSyncModal.vue
new file mode 100644
index 0000000000..a539a95ee5
--- /dev/null
+++ b/src/components/contextual/pages/vebal/cross-chain-boost/ProceedToSyncModal.vue
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+ {{ $t('modals.veBalRedirectModal.title') }}
+
+
+
+
+ The sync veBAL operation needs to be performed on Ethereum Mainnet,
+ since that is where your veBAL balance lives.
+
+
+
+ Ethereum Mainnet to {{ configs[networkId].chainName }} will enable you
+ to get boosted APR’s for any pools where you stake in the new
+ boost-aware gauges.
+
+
+
+
+
diff --git a/src/components/contextual/pages/vebal/cross-chain-boost/StakingCardSyncAlert.vue b/src/components/contextual/pages/vebal/cross-chain-boost/StakingCardSyncAlert.vue
new file mode 100644
index 0000000000..bd8ab325fb
--- /dev/null
+++ b/src/components/contextual/pages/vebal/cross-chain-boost/StakingCardSyncAlert.vue
@@ -0,0 +1,134 @@
+
+
+
+
+
+
+
{{ warningAlert.text }}
+
+
+ Trigger update
+
+
+
+
+
+
+ {{ tipText.text }}
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/contextual/pages/vebal/cross-chain-boost/SyncFinalState.vue b/src/components/contextual/pages/vebal/cross-chain-boost/SyncFinalState.vue
new file mode 100644
index 0000000000..56c6ae002a
--- /dev/null
+++ b/src/components/contextual/pages/vebal/cross-chain-boost/SyncFinalState.vue
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+ {{ $t('crossChainBoost.syncInitiatedModal.title') }}
+
+
+ {{ $t('crossChainBoost.syncInitiatedModal.description') }}
+
+
+
+
+ Ethereum Mainnet
+
+
+ {{ veBalBalance }} veBAL
+
+
+
+
+ {{ configs[network].chainName }}
+
+
+ {{ veBalBalance }} veBAL
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('crossChainBoost.syncInitiatedModal.warningDescription') }}
+
+
+
+
+ {{ $t('close') }}
+
+
+
diff --git a/src/components/contextual/pages/vebal/cross-chain-boost/SyncNetworkAction.vue b/src/components/contextual/pages/vebal/cross-chain-boost/SyncNetworkAction.vue
new file mode 100644
index 0000000000..ea3f14e3e0
--- /dev/null
+++ b/src/components/contextual/pages/vebal/cross-chain-boost/SyncNetworkAction.vue
@@ -0,0 +1,177 @@
+
+
+
+
+
Sync veBAL
+
+ {{ $t('crossChainBoost.syncNetworkAction.title') }}
+
+
+
+
+
+
{{ configs[network].chainName }}
+
+
+
+
+
+
+ {{ $t('crossChainBoost.currentBalance') }}
+
+
+ {{ l2VeBalBalances?.[network] || '0.0000' }} veBAL
+
+
+
+
+ {{ $t('crossChainBoost.postSyncBalance') }}
+
+
+ {{ veBalBalance || '0.0000' }} veBAL
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/contextual/pages/vebal/cross-chain-boost/SyncSelectNetwork.vue b/src/components/contextual/pages/vebal/cross-chain-boost/SyncSelectNetwork.vue
new file mode 100644
index 0000000000..ed4a4c5569
--- /dev/null
+++ b/src/components/contextual/pages/vebal/cross-chain-boost/SyncSelectNetwork.vue
@@ -0,0 +1,93 @@
+
+
+
+
+
+ {{ $t('crossChainBoost.selectNetworkModal.title') }}
+
+
+
+ {{ $t('crossChainBoost.selectNetworkModal.description') }}
+
+
+
+
Ethereum
+
{{ veBalBalance }} veBAL
+
+
+
+
+ {{ tempSyncingNetworks.value }}
+
+
+
+ {{ l2VeBalBalances?.[network] || '0.0000' }} veBAL
+
+
+
+
+
+
+ {{ $t('next') }}
+
+
+
diff --git a/src/components/forms/lock_actions/LockForm/components/LockPreviewModal/components/LockActions.vue b/src/components/forms/lock_actions/LockForm/components/LockPreviewModal/components/LockActions.vue
index 01aded400c..5a6c4b55f3 100644
--- a/src/components/forms/lock_actions/LockForm/components/LockPreviewModal/components/LockActions.vue
+++ b/src/components/forms/lock_actions/LockForm/components/LockPreviewModal/components/LockActions.vue
@@ -24,6 +24,7 @@ import { VeBalLockInfo } from '@/services/balancer/contracts/contracts/veBAL';
import { ApprovalAction } from '@/composables/approvals/types';
import { captureException } from '@sentry/browser';
import useTokenApprovalActions from '@/composables/approvals/useTokenApprovalActions';
+import { isUserError } from '@/composables/useTransactionErrors';
/**
* TYPES
@@ -187,13 +188,15 @@ async function submit(lockType: LockType, actionIndex: number) {
// An exception is already logged in balancerContractsService, but we should
// log another here in case any exceptions are thrown before it's sent
- captureException(error, {
- level: 'fatal',
- extra: {
- lockType,
- props,
- },
- });
+ if (!isUserError(error)) {
+ captureException(error, {
+ level: 'fatal',
+ extra: {
+ lockType,
+ props,
+ },
+ });
+ }
return Promise.reject(error);
}
diff --git a/src/components/forms/pool_actions/AddLiquidityForm/AddLiquidityForm.vue b/src/components/forms/pool_actions/AddLiquidityForm/AddLiquidityForm.vue
index f9ba3c5998..52c7586e93 100644
--- a/src/components/forms/pool_actions/AddLiquidityForm/AddLiquidityForm.vue
+++ b/src/components/forms/pool_actions/AddLiquidityForm/AddLiquidityForm.vue
@@ -125,7 +125,7 @@ function tokenOptions(address: string): string[] {
return includesAddress(
[wrappedNativeAsset.value.address, nativeAsset.address],
address
- ) && !isDeepPool.value
+ )
? [wrappedNativeAsset.value.address, nativeAsset.address]
: [];
}
diff --git a/src/components/heros/PortfolioPageHero.vue b/src/components/heros/PortfolioPageHero.vue
index 18476beacb..2a73f2e7cd 100644
--- a/src/components/heros/PortfolioPageHero.vue
+++ b/src/components/heros/PortfolioPageHero.vue
@@ -1,6 +1,5 @@
@@ -59,19 +87,41 @@ const isLoadingTotalValue = computed((): boolean => isLoadingPools.value);