Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preview #87

Merged
merged 22 commits into from
Apr 9, 2024
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
11 changes: 11 additions & 0 deletions components/common/input/TransactionWithdraw.vue
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@
Insufficient balance
</template>
<template v-else-if="amountError === 'exceeds_balance' && !maxAmount">Amount exceeds balance</template>
<template v-else-if="amountError === 'exceeds_merge_limit'">
Input amount exceeds the merge limit.
</template>
<template v-else-if="amountError === 'exceeds_max_amount' || amountError === 'exceeds_balance'">
Max amount is
<button
Expand All @@ -66,6 +69,7 @@
<template v-else-if="amountError === 'exceeds_decimals'">
Max decimal length for {{ selectedToken?.symbol }} is {{ selectedToken?.decimals }}
</template>

</CommonInputErrorMessage>
<CommonButtonLabel v-else-if="inputted" as="div" variant="light" class="-mb-6 mt-1 text-right text-sm">
{{ totalAmountPrice }}
Expand Down Expand Up @@ -108,7 +112,7 @@
import { useNetworkStore } from "@/store/network";
import { decimalToBigNumber, formatTokenPrice, parseTokenAmount, removeSmallAmountPretty } from "@/utils/formatters";
import { ETH_ADDRESS, L2_ETH_TOKEN_ADDRESS } from "~/zksync-web3-nova/src/utils";
const { selectedNetwork } = storeToRefs(useNetworkStore());

Check failure on line 115 in components/common/input/TransactionWithdraw.vue

View workflow job for this annotation

GitHub Actions / Build

'storeToRefs' is not defined
const props = defineProps({
modelValue: {
type: String,
Expand Down Expand Up @@ -144,6 +148,10 @@
type: Boolean,
default: false,
},
mergeLimitExceeds: {
type: Boolean,
default: false
}
});

const emit = defineEmits<{
Expand Down Expand Up @@ -215,6 +223,9 @@
};

const amountError = computed(() => {
if(props.mergeLimitExceeds) {
return 'exceeds_merge_limit'
}
if (!selectedToken.value) return;
if (tokenBalance.value && totalComputeAmount.value.gt(tokenBalance.value.amount)) {
return "exceeds_balance";
Expand Down
7 changes: 7 additions & 0 deletions components/transaction/summary/AddressEntry.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,18 @@ const props = defineProps({
type: Object as PropType<TransactionDestination>,
required: true,
},
addressLabel: {
type: String,
required: false
}
});

const { account } = storeToRefs(useOnboardStore());

const accountLabel = computed(() => {
if(props.addressLabel) {
return props.addressLabel;
}
if (props.address === account.value.address) {
return `Your ${props.destination.label} account`;
}
Expand Down
65 changes: 65 additions & 0 deletions composables/transaction/useMergeToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import MergeTokenPortal from "@/zksync-web3-nova/abi/MergeTokenPortal.json";
import { useOnboardStore } from "@/store/onboard";

import type { Hash } from "@/types";
import type { BigNumberish } from "ethers";
import type { PublicClient } from "viem";
import type { Ref } from "vue";

const nodeType = process.env.NODE_TYPE;

export type SourceTokenInfo = {
isSupported: boolean;
isLocked: boolean;
mergeToken: string;
balance: bigint;
depositLimit: bigint;
};
const NOVA_CHAIN_ID = nodeType === "nexus" ? 810180 : 810182;
const MERGE_TOKEN_PORTAL_ADDRESSES =
nodeType === "nexus" ? "0x83FD59FD58C6A5E6eA449e5400D02803875e1104" : "0x83FD59FD58C6A5E6eA449e5400D02803875e1104";
export default (tokenL2Address: Ref<string | undefined>) => {
const onboardStore = useOnboardStore();
const {
result,
inProgress,
error,
execute: getMergeTokenInfo,
reset,
} = usePromise(
async () => {
const publicClient = onboardStore.getPublicClient(NOVA_CHAIN_ID);
const info = (await publicClient!.readContract({
address: MERGE_TOKEN_PORTAL_ADDRESSES,
abi: MergeTokenPortal,
functionName: "getSourceTokenInfos",
args: [tokenL2Address.value],
})) as SourceTokenInfo;
return info;
},
{ cache: false }
);

const requestMergeTokenInfo = async () => {
if (tokenL2Address.value) {
await getMergeTokenInfo();
} else {
reset();
}
};

watch(
[tokenL2Address],
() => {
requestMergeTokenInfo();
},
{ immediate: true }
);

return {
result: computed(() => result.value),
inProgress: computed(() => inProgress.value),
error: computed(() => error.value),
requestMergeTokenInfo,
};
};
2 changes: 2 additions & 0 deletions composables/zksync/deposit/useTransaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export default (getL1Signer: () => Promise<L1Signer | undefined>) => {
to: string;
tokenAddress: string;
amount: BigNumberish;
toMerge?: boolean;
},
fee: DepositFeeValues
) => {
Expand Down Expand Up @@ -48,6 +49,7 @@ export default (getL1Signer: () => Promise<L1Signer | undefined>) => {
to: transaction.to,
token: transaction.tokenAddress,
amount: transaction.amount,
toMerge: transaction.toMerge,
l2GasLimit: fee.l2GasLimit,
overrides,
});
Expand Down
3 changes: 3 additions & 0 deletions public/img/Shape.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion store/zksync/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ export const useZkSyncTokensStore = defineStore("zkSyncTokens", () => {
return Object.fromEntries(
tokensRaw.value
.filter((e) => e.l1Address)
.map((token) => [token.l1Address!, { ...token, l1Address: undefined, address: token.l1Address! }])
.map((token) => [
token.l1Address!,
{ ...token, l1Address: undefined, address: token.l1Address!, l2Address: token.l2Address },
])
);
});

Expand Down
2 changes: 1 addition & 1 deletion store/zksync/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export const useZkSyncWalletStore = defineStore("zkSyncWallet", () => {

const getPrimaryL1VoidSigner = () => {
const web3Provider = new ethers.providers.Web3Provider(
getPublicClient({ chainId: primaryNetwork.l1Network?.id }) as any,
onboardStore.getPublicClient(primaryNetwork.l1Network?.id) as any,
"any"
);
const voidSigner = new VoidSigner(account.value.address || ETH_TOKEN.address, web3Provider);
Expand Down
1 change: 1 addition & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export type Token = {
iconUrl?: string;
price?: TokenPrice;
networkKey?: string;
l2Address: string;
};
export type TokenAmount = Token & { amount: BigNumberish };

Expand Down
1 change: 1 addition & 0 deletions utils/mappers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export const mapApiToken = (token: Api.Response.Token): Token => {
}

return {
l2Address: token.l2Address,
l1Address: token.l1Address || undefined,
address: token.l2Address,
symbol: token.symbol || "unknown",
Expand Down
90 changes: 84 additions & 6 deletions views/transactions/Deposit.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
<a
href="https://www.okx.com/web3/discover/cryptopedia/event/28"
target="_blank"
class="okx-tips-title flex cursor-pointer items-center gap-[4px] z-2 relative"
class="okx-tips-title z-2 relative flex cursor-pointer items-center gap-[4px]"
>
<span>OKX Cryptopedia</span>
<img src="/img/launch.svg" />
<img :src="launchIcon" />
</a>
<div class="mt-[5px]">
<p class="okx-tips-desc">
Expand Down Expand Up @@ -72,6 +72,7 @@
:max-amount="maxAmount"
:approve-required="!enoughAllowance"
:loading="tokensRequestInProgress || balanceInProgress"
:merge-limit-exceeds="mergeLimitExceeds"
class="mb-block-padding-1/2 sm:mb-block-gap"
>
<template #dropdown>
Expand Down Expand Up @@ -134,6 +135,13 @@
<template v-else-if="step === 'confirm'">
<CommonCardWithLineButtons>
<TransactionSummaryTokenEntry label="You deposit" :token="transaction!.token" />
<TransactionSummaryAddressEntry
v-if="isMerge"
label="You Receive"
:address="mergeTokenInfo?.mergeToken"
:destination="{iconUrl: transaction!.token.iconUrl}"
:addressLabel="transaction!.token.symbol"
/>
<TransactionSummaryAddressEntry
label="From"
:address="transaction!.from.address"
Expand Down Expand Up @@ -204,6 +212,26 @@
<NuxtLink :to="{ name: 'receive-methods' }" class="alert-link">Receive funds</NuxtLink>
</CommonAlert>
</transition>
<div class="flex justify-between gap-3 sm:mt-2 mb-1" v-if="mergeSupported">
<CommonButtonLabel as="span" class="text-left relative showTip">
Merge Token <img src="/img/Shape.svg" class="ml-1 h-3 w-3 inline-block" alt="" />
<div class="tooltip">
All supported source tokens with the same entity from different networks can be merged into a single merged token. Holding or using merged token to engage with supported dApps could receive higher multipliers. <a href="https://docs.zklink.io/how-it-works/token-merge" target="_blank">Learn More</a>.
</div>
</CommonButtonLabel>
<CommonButtonLabel as="span" class="text-right">
<span v-if="isMerge">Merge</span> <Switch
v-model="isMerge"
:class="isMerge ? 'bg-blue-900' : 'bg-gray-500'"
class="relative inline-flex h-4 w-10 items-center rounded-full align-middle"
>
<span
:class="isMerge ? 'translate-x-0 bg-blue-600' : 'translate-x-4 bg-slate-600'"
class="inline-block h-6 w-6 transform rounded-full bg-[#888C91] transition"
/>
</Switch>
</CommonButtonLabel>
</div>
<CommonErrorBlock v-if="allowanceRequestError" class="mt-2" @try-again="requestAllowance">
Checking allowance error: {{ allowanceRequestError.message }}
</CommonErrorBlock>
Expand Down Expand Up @@ -374,6 +402,7 @@
import EthereumTransactionFooter from "@/components/transaction/EthereumTransactionFooter.vue";

import useAllowance from "@/composables/transaction/useAllowance";
import useMergeToken from "@/composables/transaction/useMergeToken";
import useInterval from "@/composables/useInterval";
import useNetworks from "@/composables/useNetworks";
import useEcosystemBanner from "@/composables/zksync/deposit/useEcosystemBanner";
Expand All @@ -387,6 +416,7 @@

import { useRoute, useRouter } from "#app";
import { customBridgeTokens } from "@/data/customBridgeTokens";
import { getWaitTime } from "@/data/networks";
import { useDestinationsStore } from "@/store/destinations";
import { useNetworkStore } from "@/store/network";
import { useOnboardStore } from "@/store/onboard";
Expand All @@ -403,13 +433,14 @@
import { TransitionAlertScaleInOutTransition, TransitionOpacity } from "@/utils/transitions";
import DepositSubmitted from "@/views/transactions/DepositSubmitted.vue";
import { ETH_ADDRESS } from "~/zksync-web3-nova/src/utils";
import { getWaitTime } from "@/data/networks";
import { Switch } from "@headlessui/vue";

const okxIcon = "/img/okx-cryptopedia.svg";
const launchIcon = "/img/launch.svg";

const route = useRoute();
const router = useRouter();

console.log("route", route.query);

const onboardStore = useOnboardStore();
const tokensStore = useZkSyncTokensStore();
const providerStore = useZkSyncProviderStore();
Expand All @@ -431,6 +462,7 @@
}
};
const step = ref<"form" | "confirm" | "submitted">("form");
const isMerge = ref<true | false>(true);
const destination = computed(() => destinations.value.nova);
const availableTokens = computed<Token[]>(() => {
if (balance.value) return balance.value;
Expand All @@ -439,7 +471,7 @@
(e) => e.networkKey === eraNetwork.value.key || e.address === ETH_TOKEN.l1Address
);
return filterL1tokens;
// return Object.values(l1Tokens.value ?? []);

Check failure on line 474 in views/transactions/Deposit.vue

View workflow job for this annotation

GitHub Actions / Build

'ETH_TOKEN' is not defined
});
const availableBalances = computed<TokenAmount[]>(() => {
return balance.value ?? [];
Expand Down Expand Up @@ -497,6 +529,9 @@
const tokenBalance = computed<BigNumberish | undefined>(() => {
return balance.value?.find((e) => e.address === selectedToken.value?.address)?.amount;
});
const { result: mergeTokenInfo, inProgress: mergeTokenInfoInProgress } = useMergeToken(
computed(() => selectedToken.value?.l2Address)
);

const {
result: allowance,
Expand Down Expand Up @@ -599,11 +634,24 @@
});
const enoughBalanceForTransaction = computed(() => !amountError.value);

const mergeSupported = computed(() => {
return mergeTokenInfo.value?.isSupported && !mergeTokenInfo.value?.isLocked;
});

const mergeLimitExceeds = computed(() => {
if (!selectedToken.value || !mergeTokenInfo.value || !amount.value) return false;
const amountVal = decimalToBigNumber(amount.value, selectedToken.value.decimals);
const exceeds = amountVal.add(mergeTokenInfo.value?.balance).gt(mergeTokenInfo.value?.depositLimit);
console.log("exceeds: ", exceeds);
return mergeSupported.value && isMerge.value && exceeds;
});

const transaction = computed<
| {
token: TokenAmount;
from: { address: string; destination: TransactionDestinfonboardStoreation };
to: { address: string; destination: TransactionDestination };
toMerge?: boolean;
}
| undefined
>(() => {
Expand All @@ -624,6 +672,7 @@
address: toAddress,
destination: destination.value,
},
toMerge: isMerge.value,
};
});
const transactionHasGateway = ref<TransactionInfo>();
Expand Down Expand Up @@ -689,6 +738,7 @@
if (!enoughAllowance.value) return false; // When allowance approval is required we can proceed to approve stage even if deposit fee is not loaded
if (!isAddressInputValid.value) return true;
if (feeLoading.value || !fee.value) return true;
if (mergeLimitExceeds.value) return true;
return false;
});

Expand Down Expand Up @@ -730,6 +780,7 @@
to: transaction.value!.to.address,
tokenAddress: transaction.value!.token.address,
amount: transaction.value!.token.amount,
toMerge: transaction.value!.toMerge,
},
feeValues.value!
);
Expand Down Expand Up @@ -773,7 +824,7 @@
transactionInfo.value = completedTransaction;
setTimeout(() => {
transfersHistoryStore.reloadRecentTransfers().catch(() => undefined);
eraWalletStore.requestBalance({ force: true }).catch(() => undefined);
fetchBalances(true).catch(() => undefined);
}, 2000);
})
.catch((err) => {
Expand Down Expand Up @@ -911,4 +962,31 @@
}
}
}
.merge {
border-radius: 16px;
background: rgba(3, 212, 152, 0.5) !important;
}
.notMerge {
border-radius: 16px;
background: rgba(23, 85, 244, 0.25) !important;
}
.showTip:hover{
.tooltip{
display: block;
z-index: 100;
}
}
.tooltip{
display: none;
position: absolute;
padding: 12px 20px 12px 24px;
top: -4.5rem;
width: 35rem;
left: -10rem;
border-radius: 8px;
background: #1F2127;
a{
color: #1755F4;
}
}
</style>
Loading
Loading