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

Support ahUSDT on mainnet and PINK #18

Merged
merged 6 commits into from
Apr 2, 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
31 changes: 31 additions & 0 deletions .github/workflows/deploy-dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Deploy development

on:
pull_request:
workflow_dispatch:

jobs:
deploy-package:
name: Deploy package
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- uses: actions/checkout@v2
with:
repository: darwinia-network/devops
path: .github

- uses: ./.github/actions/smart-vercel
name: Deploy app
with:
vercel_token: ${{ secrets.VERCEL_TOKEN }}
vercel_group: itering
preview_output: true
alias_domain: "crosschain-dev"
project_name: "crosschain-ui"
script_run: false
dist_path: .
enable_notify_slack: true
slack_channel: darwinia-apps
slack_webhook: ${{ secrets.SLACK_INCOMING_WEBHOOK_URL }}
Binary file added public/images/asset/pink.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/network/darwinia.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions public/images/warning.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ body {

@layer components {
.border-radius {
@apply rounded-lg;
@apply rounded-2xl;
}

.app-header {
Expand Down
4 changes: 2 additions & 2 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import TransferProvider from "@/providers/transfer-provider";
const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
title: "Darwinia Cross-Chain",
description: "Darwinia USDT Cross-Chain",
title: "Asset Hub Bridge - Darwinia",
description: "Assets cross-chain between Darwinia and Asset Hub.",
};

export default function RootLayout({ children }: { children: React.ReactNode }) {
Expand Down
6 changes: 3 additions & 3 deletions src/components/address-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export default function AddressInput({
clickable={!!options?.length || !canInput}
canInput={canInput}
innerSuffix={<ConnectWallet who={who} height="full" />}
wrapClassName={`h-10 bg-transparent flex items-center justify-between p-1 border border-radius transition-colors duration-200 ${
wrapClassName={`h-12 bg-transparent flex items-center justify-between p-1 border border-radius transition-colors duration-200 ${
value?.valid === false ? "border-alert" : "border-transparent"
}`}
inputClassName="w-full border-radius h-full bg-transparent px-1"
Expand Down Expand Up @@ -100,8 +100,8 @@ export default function AddressInput({
</button>
))
) : (
<div className="px-middle py-small">
<span className="text-sm font-medium">No data</span>
<div className="inline-flex justify-center px-middle py-small">
<span className="text-sm font-medium text-slate-400">No data</span>
</div>
)}
</InputSelect>
Expand Down
17 changes: 9 additions & 8 deletions src/components/asset-select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,31 @@ export default function AssetSelect({ value, options, disabled, onChange = () =>
return (
<Select
label={
<div className="flex items-center gap-small truncate">
<Image width={16} height={16} alt="Asset icon" src={getAssetIconSrc(value.icon)} />
<div className="flex items-center gap-small truncate px-1">
<Image width={22} height={22} alt="Asset icon" src={getAssetIconSrc(value.icon)} className="rounded-full" />
<span>{value.symbol}</span>
</div>
}
disabled={disabled}
sameWidth
labelClassName="flex items-center gap-middle shrink-0 w-28 justify-between bg-component h-full border-radius px-1 hover:opacity-80 transition-[transform,color] active:translate-y-1 disabled:translate-y-0 disabled:opacity-100 disabled:cursor-not-allowed"
childClassName="flex flex-col py-small bg-component border-primary border border-radius"
labelClassName="flex items-center gap-middle shrink-0 w-28 justify-between bg-component h-full border-radius px-1 hover:opacity-80 transition-[transform,color] disabled:translate-y-0 disabled:opacity-100 disabled:cursor-not-allowed"
childClassName="flex flex-col py-small bg-component border-primary border border-radius gap-[1px]"
>
{options?.length ? (
options.map((asset) => (
<button
key={asset.symbol}
disabled={asset.id === value.id}
onClick={() => onChange(asset)}
className="flex items-center gap-small px-middle py-2 transition-colors hover:bg-white/10"
className="flex items-center gap-small px-middle py-2 transition-colors hover:bg-white/10 disabled:bg-white/10"
>
<Image width={16} height={16} alt="Asset icon" src={getAssetIconSrc(asset.icon)} />
<Image width={20} height={20} alt="Asset icon" src={getAssetIconSrc(asset.icon)} className="rounded-full" />
<span className="text-sm font-medium">{asset.symbol}</span>
</button>
))
) : (
<div className="px-middle py-2">
<span className="text-sm font-medium">No data</span>
<div className="inline-flex justify-center px-middle py-2">
<span className="text-sm font-medium text-slate-400">No data</span>
</div>
)}
</Select>
Expand Down
17 changes: 11 additions & 6 deletions src/components/balance-input.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Asset } from "@/types";
import { Asset, Cross } from "@/types";
import Input from "@/ui/input";
import { BN, BN_ZERO, bnToBn } from "@polkadot/util";
import AssetSelect from "./asset-select";
Expand All @@ -18,7 +18,7 @@ interface Props {
disabled?: boolean;
placeholder?: string;
balance?: BN;
min?: BN;
cross?: Cross;
asset?: Asset;
assetSupply?: BN;
assetLimit?: BN;
Expand All @@ -32,7 +32,7 @@ export default function BalanceInput({
disabled,
placeholder,
balance,
min,
cross,
asset,
assetSupply,
assetLimit,
Expand All @@ -52,6 +52,13 @@ export default function BalanceInput({
return placeholder ?? "Enter an amount";
}, [balance, asset, placeholder]);

const min = useMemo(() => {
if (cross && cross.fee.asset.native) {
return cross.fee.amount;
}
return undefined;
}, [cross]);

const handleInputChange = useCallback<ChangeEventHandler<HTMLInputElement>>(
(e) => {
if (e.target.value) {
Expand All @@ -77,9 +84,7 @@ export default function BalanceInput({
const inputWidth = inputRef.current?.clientWidth || 1;
const spanWidth = spanRef.current?.clientWidth || 0;
const percent = (spanWidth / inputWidth) * 100;
if (percent < 10) {
setDynamicStyle("text-[3rem] font-extralight");
} else if (percent < 20) {
if (percent < 20) {
setDynamicStyle("text-[2.25rem] font-light");
} else if (percent < 30) {
setDynamicStyle("text-[1.875rem] font-light");
Expand Down
13 changes: 7 additions & 6 deletions src/components/chain-select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,31 @@ export default function ChainSelect({ value, options, disabled, onChange = () =>
<Select
label={
<div className="flex max-w-[140px] items-center gap-small">
<Image width={18} height={18} alt="Chain logo" src={getChainLogoSrc(value.logo)} />
<Image width={20} height={20} alt="Chain logo" src={getChainLogoSrc(value.logo)} />
<span className="truncate text-white/50">{value.name}</span>
</div>
}
disabled={disabled}
sameWidth
labelClassName="flex items-center gap-middle py-[4px] px-[6px] bg-transparent hover:bg-white/10 border-radius"
childClassName="flex flex-col py-small bg-component border-primary border border-radius"
childClassName="flex flex-col py-small bg-component border-primary border border-radius gap-[1px]"
arrowClassName="opacity-50"
>
{options?.length ? (
options.map((chain) => (
<button
key={chain.network}
disabled={chain.network === value.network}
onClick={() => onChange(chain)}
className="flex items-center gap-small px-middle py-2 transition-colors hover:bg-white/10"
className="flex items-center gap-small px-middle py-2 transition-colors hover:bg-white/10 disabled:bg-white/10"
>
<Image width={16} height={16} alt="Chain logo" src={getChainLogoSrc(chain.logo)} />
<Image width={18} height={18} alt="Chain logo" src={getChainLogoSrc(chain.logo)} />
<span className="truncate text-sm font-medium">{chain.name}</span>
</button>
))
) : (
<div className="px-middle py-2">
<span className="text-sm font-medium">No data</span>
<div className="inline-flex justify-center px-middle py-2">
<span className="text-sm font-medium text-slate-400">No data</span>
</div>
)}
</Select>
Expand Down
35 changes: 31 additions & 4 deletions src/components/transfer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Button from "@/ui/button";
import BalanceInput from "./balance-input";
import ChainSelect from "./chain-select";
import TransferSection from "./transfer-section";
import { isAssetExcess, parseCross } from "@/utils";
import { formatBalance, isAssetExcess, parseCross } from "@/utils";
import { useTalisman, useTransfer } from "@/hooks";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import SwitchCross from "./switch-cross";
Expand All @@ -13,6 +13,7 @@ import { useAccount, useNetwork, useSwitchNetwork } from "wagmi";
import { Asset, ChainConfig, WalletID } from "@/types";
import { BN_ZERO } from "@polkadot/util";
import notification from "@/ui/notification";
import Image from "next/image";

const {
defaultSourceChainOptions,
Expand All @@ -33,6 +34,7 @@ export default function Transfer() {
targetChain,
sourceAsset,
targetAsset,
usdtBalance,
sourceBalance,
targetBalance,
transferAmount,
Expand Down Expand Up @@ -76,6 +78,23 @@ export default function Transfer() {
[chain, sourceChain, activeSenderWallet],
);

const alert = useMemo(() => {
const fee = bridgeInstance?.getCrossInfo()?.fee;
const balance = usdtBalance?.asset.value;

if (fee && balance && fee.amount.gt(balance)) {
return (
<div className="flex items-start justify-center gap-small">
<Image alt="Warning" width={15} height={15} src="/images/warning.svg" />
<span className="text-xs text-alert">{`You need at least ${formatBalance(fee.amount, fee.asset.decimals)} ${
fee.asset.symbol
} in your account to cover cross-chain fees.`}</span>
</div>
);
}
return null;
}, [bridgeInstance, usdtBalance?.asset.value]);

const sourceChainRef = useRef(sourceChain);
const targetChainRef = useRef(targetChain);
const sourceAssetRef = useRef(sourceAsset);
Expand Down Expand Up @@ -219,7 +238,7 @@ export default function Transfer() {
: [];

return (
<div className="border-radius mx-auto mt-10 flex w-[30rem] flex-col gap-5 bg-component p-5">
<div className="border-radius mx-auto mt-10 flex w-[30rem] flex-col gap-5 bg-component p-5 pb-8">
{/* From */}
<TransferSection
label="From"
Expand All @@ -229,9 +248,9 @@ export default function Transfer() {
<BalanceInput
value={transferAmount}
asset={sourceAsset}
cross={bridgeInstance?.getCrossInfo()}
assetLimit={assetLimit}
assetSupply={targetAssetDetails?.supply}
min={sourceChain.minCross}
balance={sourceBalance?.asset.value}
assetOptions={sourceAssetOptions}
onChange={setTransferAmount}
Expand Down Expand Up @@ -281,9 +300,17 @@ export default function Transfer() {
</TransferSection>

{/* Send */}
<Button kind="primary" className="py-[7px]" onClick={handleSend} disabled={disabledSend} busy={busy}>
<Button
kind="primary"
className="mt-4 py-middle"
onClick={handleSend}
disabled={disabledSend || !!alert}
busy={busy}
>
{needSwitchNetwork ? "Switch network" : "Send"}
</Button>

{alert}
</div>
);
}
75 changes: 75 additions & 0 deletions src/config/chains/assethub-polkadot-chain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { ChainConfig, ChainID, ParachainID, WalletID } from "@/types";
import { bnToBn } from "@polkadot/util";

export const assethubPolkadotChain: ChainConfig = {
/**
* Chain
*/
id: ChainID.INVALID,
network: "assethub-polkadot",
name: "Polkadot AssetHub",
nativeCurrency: {
name: "DOT",
symbol: "DOT",
decimals: 10,
},
rpcUrls: {
default: {
http: [],
webSocket: [],
},
public: {
http: [],
webSocket: [],
},
},
blockExplorers: {
default: {
name: "Subscan",
url: "https://assethub-polkadot.subscan.io",
},
},

/**
* Custom
*/
logo: "asset-hub.svg",
assets: [
{
icon: "usdt.svg",
id: 1984,
name: "Tether USD",
symbol: "USDT",
decimals: 6,
cross: [
{
isReserve: true,
target: { network: "darwinia", symbol: "ahUSDT" },
fee: { amount: bnToBn(20000), asset: { id: 1984, decimals: 6, symbol: "USDT", native: true } }, // 0.02 USDT
},
],
},
{
icon: "pink.jpg",
id: 23,
name: "PINK",
symbol: "PINK",
decimals: 10,
cross: [
{
isReserve: true,
target: { network: "darwinia", symbol: "ahPINK" },
fee: { amount: bnToBn(20000), asset: { id: 1984, decimals: 6, symbol: "USDT", native: false } }, // 0.02 USDT
},
],
},
],
wallets: [WalletID.TALISMAN],
addressType: "substrate",

/**
* Substrate
*/
endpoint: "wss://polkadot-asset-hub-rpc.polkadot.io",
parachainId: ParachainID.ASSETHUB_POLKADOT,
};
Loading
Loading