Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
6e12445
"UPGRADE: Upgrading 3 package(s)\n\nPackages:\n @galacticcouncil/xc-…
actions-user Mar 10, 2026
50eae08
base jumpa
mrq1911 Mar 11, 2026
aabae98
good ol sdk
mrq1911 Mar 11, 2026
cb8e23a
c9
mrq1911 Mar 11, 2026
313ff6d
9b
mrq1911 Mar 11, 2026
c66eee2
Basejump
mrq1911 Mar 11, 2026
0b1842f
🪂
mrq1911 Mar 11, 2026
70240f6
bump ci
mrq1911 Mar 11, 2026
508d3d3
xcm form defaults
mrq1911 Mar 11, 2026
f6a2a11
tracking basejump status
mrq1911 Mar 15, 2026
62aa262
Merge remote-tracking branch 'origin/master' into base-jumper
mrq1911 Mar 31, 2026
dded083
basejump
mrq1911 Mar 31, 2026
e40767a
clenup
mrq1911 Mar 31, 2026
2437383
lint:fix
mrq1911 Mar 31, 2026
8c49d53
Merge branch 'master' into base-jumper
mrq1911 Mar 31, 2026
ce8434f
merge?
mrq1911 Mar 31, 2026
52b376b
fixed abi
mrq1911 Apr 1, 2026
0a7807b
Adjust design
jvonasek Apr 9, 2026
0ac5816
Merge branch 'master' into base-jumper
jvonasek Apr 9, 2026
220c474
Merge remote-tracking branch 'origin/master' into base-jumper
nohaapav Apr 15, 2026
710937f
remove suplementary routes logic
nohaapav Apr 15, 2026
202078d
shutup lint
nohaapav Apr 15, 2026
57a50a2
dest guard
nohaapav Apr 16, 2026
7d4d290
Fix source fee not available after approval
jvonasek Apr 16, 2026
33c2aee
Fix react errors
jvonasek Apr 16, 2026
a794a07
Merge branch 'master' into base-jumper
jvonasek Apr 17, 2026
e9fbf5a
Fix duplicate journeys
jvonasek Apr 17, 2026
44f6aa1
Merge branch 'master' into base-jumper
jvonasek Apr 20, 2026
7634c27
Merge branch 'master' into base-jumper
jvonasek Apr 21, 2026
7be61ad
bjscan
jvonasek Apr 21, 2026
2ee7de6
Adjust claimable journey window
jvonasek Apr 21, 2026
7e02dc6
Basejump scan link
jvonasek Apr 21, 2026
2ff60f1
Ignore xcscan basejump entry
jvonasek Apr 21, 2026
1a48144
Cleanup
jvonasek Apr 22, 2026
461efc1
Address PR comments - cleanup
jvonasek Apr 22, 2026
cfae3c3
Update basejump logo
jvonasek Apr 22, 2026
0fde9e7
fix lint
jvonasek Apr 22, 2026
e232dfc
jumper
mrq1911 Apr 23, 2026
076d20f
Update bridge selector
jvonasek Apr 23, 2026
dc1cbf2
xcm app layout adjustment
jvonasek Apr 24, 2026
dfd4680
bjscan journey processing
jvonasek Apr 24, 2026
c3f4d83
Improvements
jvonasek Apr 24, 2026
c8e307e
Filter basejump events by contract address
jvonasek Apr 24, 2026
7a5b7a6
Shorten relative datetime format
jvonasek Apr 24, 2026
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
27 changes: 20 additions & 7 deletions apps/main/src/api/xcm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ export type XcmTransferArgs = {
readonly destAddress: string
readonly destAsset: string
readonly destChain: string
readonly bridgeTag?: string
}

export const xcmTransferQuery = (
Expand All @@ -146,6 +147,7 @@ export const xcmTransferQuery = (
destAddress,
destChain,
destAsset,
bridgeTag,
}: XcmTransferArgs,
options?: UseQueryOptions<Transfer>,
) => {
Expand All @@ -162,17 +164,28 @@ export const xcmTransferQuery = (
destAsset,
srcChain,
destChain,
bridgeTag,
],
queryFn: () =>
TransferBuilder(wallet)
queryFn: async () => {
const builder = TransferBuilder(wallet)
.withAsset(srcAsset)
.withSource(srcChain)
.withDestination(destChain)
.build({
srcAddress: srcAddress,
dstAddress: destAddress,
dstAsset: destAsset,
}),

// Do not pass invalid/stale dest asset
const validDstAsset = builder.routes.some(
(r) => r.destination.asset.key === destAsset,
)
? destAsset
: undefined

return builder.build({
srcAddress,
dstAddress: destAddress,
dstAsset: validDstAsset,
tag: bridgeTag,
})
},
enabled:
!!srcAddress &&
!!destAddress &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import { useRelativeDate } from "@/hooks/useRelativeDate"

export type RelativeDateTextProps = TextProps & {
date: Date
shortFormat?: boolean
}

export const RelativeDateText: React.FC<RelativeDateTextProps> = ({
date,
shortFormat = false,
...props
}) => {
const dateString = useRelativeDate(date)
const dateString = useRelativeDate(date, { shortFormat })

return <Text {...props}>{dateString}</Text>
}
15 changes: 12 additions & 3 deletions apps/main/src/hooks/useRelativeDate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,24 @@ import { useState } from "react"
import { useTranslation } from "react-i18next"
import { useHarmonicIntervalFn } from "react-use"

export function useRelativeDate(date: Date) {
type UseRelativeDateOptions = {
shortFormat?: boolean
}

export function useRelativeDate(
date: Date,
{ shortFormat = false }: UseRelativeDateOptions = {},
) {
const { t } = useTranslation("common")

const [dateString, setDateString] = useState(() =>
t("date.relative", { value: date }),
t(shortFormat ? "date.relative.short" : "date.relative", { value: date }),
)

useHarmonicIntervalFn(() => {
setDateString(t("date.relative", { value: date }))
setDateString(
t(shortFormat ? "date.relative.short" : "date.relative", { value: date }),
)
}, getUpdateInterval(date))

return dateString
Expand Down
2 changes: 1 addition & 1 deletion apps/main/src/i18n/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@
"date.relative.short": "{{ value, relative(format: 'short') }}",
"date.time": "{{ value, date(format: 'HH:mm') }}",
"date.datetime": "{{ value, date(format: 'dd/MM/yyyy HH:mm:ss') }}",
"date.datetime.short": "{{ value, date(format: 'dd/MM/yyyy HH:mm') }}",
"date.datetime.short": "{{ value, date(format: 'dd/MM/yy HH:mm') }}",
"date.long": "{{ value, date(format: 'MMMM do, yyyy') }}",
"date.day": "{{ value, date(format: 'MMM dd') }}",
"date.daytime": "{{ value, date(format: 'MMM dd yyyy, HH:mm') }}",
Expand Down
3 changes: 3 additions & 0 deletions apps/main/src/i18n/locales/en/xcm.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
"approve.title": "Approve spending cap",
"approve.toast.submitted": "Approving {{ amount, number }} {{ symbol }} spending cap on {{ srcChain }}",
"approve.toast.success": "Approved {{ amount, number }} {{ symbol }} spending cap on {{ srcChain }}",
"approve.pending.title": "Approval Pending",
"approve.pending.description": "Your approval transaction is being confirmed on the blockchain.",
"bridge.wormhole": "Wormhole",
"bridge.snowbridge": "Snowbridge",
"bridge.basejump": "Basejump",
"chainAssetSelect.button.selectAssetChain": "Select asset & chain",
"chainAssetSelect.emptyState.noAssets": "No assets found",
"chainAssetSelect.modal.title": "Chain & asset",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useAccount } from "@galacticcouncil/web3-connect"
import { useQueryClient } from "@tanstack/react-query"
import { useMemo } from "react"

Expand All @@ -6,14 +7,21 @@ import { createToastProcessorFn } from "@/modules/transactions/utils/toasts"
import { useRpcProvider } from "@/providers/rpcProvider"

export const useTransactionToastProcessorFn = () => {
const { account } = useAccount()
const queryClient = useQueryClient()
const indexerClient = useIndexerClient()
const snowbridgeClient = useSnowbridgeClient()
const { evm } = useRpcProvider()

return useMemo(
() =>
createToastProcessorFn(queryClient, indexerClient, snowbridgeClient, evm),
[queryClient, indexerClient, snowbridgeClient, evm],
createToastProcessorFn(
account?.address ?? "",
queryClient,
indexerClient,
snowbridgeClient,
evm,
),
[account?.address, queryClient, indexerClient, snowbridgeClient, evm],
)
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import {
Modal,
ModalBody,
ModalFooter,
ModalHeader,
Stepper,
} from "@galacticcouncil/ui/components"
import { useEffect, useState } from "react"
import React, { useEffect, useState } from "react"
import { useTranslation } from "react-i18next"
import { isFunction, omit } from "remeda"

Expand Down Expand Up @@ -41,6 +42,7 @@ export const ReviewMultiTransaction: React.FC<ReviewMultiTransactionProps> = ({
const [resolvedTx, setResolvedTx] = useState<AnyTransaction | null>(null)
const [resolvedConfig, setResolvedConfig] =
useState<TransactionCommon | null>(null)
const [isPendingResolution, setIsPendingResolution] = useState(false)
const [isLoading, setIsLoading] = useState(false)
const [isLastSubmitted, setIsLastSubmitted] = useState(false)
const [hasUserClosedModal, setHasUserClosedModal] = useState(false)
Expand All @@ -63,12 +65,15 @@ export const ReviewMultiTransaction: React.FC<ReviewMultiTransactionProps> = ({
const tx = currentBaseConfig.tx

if (isFunction(tx)) {
setIsPendingResolution(true)
const previousResults = transactionResults.slice(0, currentIndex)
Promise.resolve(tx(previousResults)).then((resolved) => {
setIsPendingResolution(false)
setResolvedTx(resolved.tx)
setResolvedConfig(omit(resolved, ["tx"]))
})
} else {
setIsPendingResolution(false)
setResolvedTx(tx)
setResolvedConfig(null)
}
Expand Down Expand Up @@ -138,6 +143,9 @@ export const ReviewMultiTransaction: React.FC<ReviewMultiTransactionProps> = ({

const { title, description } = currentConfig

const PendingComponent =
isPendingResolution && currentBaseConfig?.pendingComponent

return (
<TransactionProvider key={currentConfig.id} transaction={currentConfig}>
<Modal
Expand Down Expand Up @@ -169,7 +177,13 @@ export const ReviewMultiTransaction: React.FC<ReviewMultiTransactionProps> = ({
title={title ?? t("transaction.title")}
description={description ?? t("transaction.description")}
/>
<ReviewTransactionContent />
{PendingComponent ? (
<ModalBody>
<PendingComponent />
</ModalBody>
) : (
<ReviewTransactionContent />
)}
<ModalFooter justify="space-between">
<ReviewTransactionFooter closable={isClosable} />
</ModalFooter>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
Text,
} from "@galacticcouncil/ui/components"
import { getToken } from "@galacticcouncil/ui/utils"
import { HYDRATION_CHAIN_KEY } from "@galacticcouncil/utils"
import { HYDRATION_CHAIN_KEY, isValidBigSource } from "@galacticcouncil/utils"
import {
useAccount,
useActiveMultisigConfig,
Expand Down Expand Up @@ -135,19 +135,26 @@ const XcmSummary = () => {
const srcChain = chainsMap.get(meta.srcChainKey)

const isPolkadotEcosystem = srcChain?.ecosystem === ChainEcosystem.Polkadot

return (
<Stack
separated
separator={<RowSeparator />}
sx={{ mb: "var(--modal-content-inset)" }}
>
<SummaryRow
label={t("transaction.summary.srcFee.label")}
content={t("currency", {
value: meta.srcChainFee,
symbol: meta.srcChainFeeSymbol,
})}
/>
{!!meta.srcChainFee && (
<SummaryRow
label={t("transaction.summary.srcFee.label")}
content={
isValidBigSource(meta.srcChainFee)
? t("currency", {
value: meta.srcChainFee,
symbol: meta.srcChainFeeSymbol,
})
: meta.srcChainFee
}
/>
)}
{Big(meta.dstChainFee || "0").gt(0) && (
<SummaryRow
label={t("transaction.summary.destFee.label")}
Expand Down
9 changes: 9 additions & 0 deletions apps/main/src/modules/transactions/utils/toasts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ enum ToastProcessorType {
Substrate = "Substrate",
Wormhole = "Wormhole",
Snowbridge = "Snowbridge",
Basejump = "Basejump",
Unknown = "Unknown",
}

Expand All @@ -25,6 +26,7 @@ const MAX_TOAST_MINUTE_AGE = {
[ToastProcessorType.Substrate]: 60,
[ToastProcessorType.Wormhole]: 70,
[ToastProcessorType.Snowbridge]: 70,
[ToastProcessorType.Basejump]: 60,
[ToastProcessorType.Unknown]: 0,
} as const

Expand Down Expand Up @@ -68,12 +70,16 @@ const getToastProcessorType = (toast: ToastData): ToastProcessorType => {
case type === TransactionType.Xcm && tags.includes(XcmTag.Snowbridge):
return ToastProcessorType.Snowbridge

case type === TransactionType.Xcm && tags.includes(XcmTag.Basejump):
return ToastProcessorType.Basejump

default:
return ToastProcessorType.Unknown
}
}

export const createToastProcessorFn = (
address: string,
queryClient: QueryClient,
indexerSdk: IndexerSdk,
snowbridgeSdk: SnowbridgeSdk,
Expand All @@ -83,6 +89,7 @@ export const createToastProcessorFn = (
const evmProcessor = processors.evm(queryClient, indexerSdk, evm)
const wormholeProcessor = processors.wormhole(queryClient, indexerSdk, evm)
const snowbridgeProcessor = processors.snowbridge(queryClient, snowbridgeSdk)
const basejumpProcessor = processors.basejump(address, queryClient)
const invalidProcessor = processors.invalid()

return async (toast) => {
Expand All @@ -102,6 +109,8 @@ export const createToastProcessorFn = (
return wormholeProcessor(toast)
case ToastProcessorType.Snowbridge:
return snowbridgeProcessor(toast)
case ToastProcessorType.Basejump:
return basejumpProcessor(toast)
case ToastProcessorType.Unknown:
return invalidProcessor(toast)
}
Expand Down
33 changes: 33 additions & 0 deletions apps/main/src/modules/transactions/utils/toasts/processors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,21 @@ import {
TransferStatusToPolkadotQuery,
} from "@galacticcouncil/indexer/snowbridge"
import {
basejumpscan,
HexString,
HYDRATION_CHAIN_KEY,
snowbridgescan,
stringEquals,
wormholescan,
} from "@galacticcouncil/utils"
import { CallType } from "@galacticcouncil/xc-core"
import { XcJourney } from "@galacticcouncil/xc-scan"
import { QueryClient } from "@tanstack/react-query"
import { first } from "remeda"
import { PublicClient } from "viem"

import { getWormholeHashByExtrinsicIndex } from "@/modules/transactions/utils/wormhole"
import { createBasejumpScanQueryKey } from "@/modules/xcm/history/useBasejumpScan"
import { ToastData } from "@/states/toasts"

type ToastStatus = {
Expand Down Expand Up @@ -286,10 +290,39 @@ const snowbridge =
}
}

const basejump =
(address: string, queryClient: QueryClient): ToastProcessorFn =>
async (toast) => {
const bjScanJourneys = queryClient.getQueryData<XcJourney[]>(
createBasejumpScanQueryKey(address),
)
const completedJourney = bjScanJourneys?.find(
(journey) =>
stringEquals(journey.originTxPrimary ?? "", toast.meta.txHash) &&
journey.status === "received",
)
if (completedJourney) {
return {
status: "success",
link: basejumpscan.tx(completedJourney.correlationId),
processed: true,
dateUpdated: completedJourney.recvAt
? new Date(completedJourney.recvAt).toISOString()
: new Date().toISOString(),
}
}
return {
status: "unknown",
processed: false,
dateUpdated: new Date().toISOString(),
}
}

export const processors = {
evm,
substrate,
wormhole,
snowbridge,
basejump,
invalid,
} as const
4 changes: 2 additions & 2 deletions apps/main/src/modules/xcm/XcmPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ export const XcmPage = () => {
const address = account?.address ?? ""

const claimable = useClaimableTransactions()
const { data: all, dataUpdatedAt } = useXcScan(address)
const { data: all, isLoading: isLoadingXcScan } = useXcScan(address)

const isLoading = !!account && dataUpdatedAt === 0
const isLoading = !!account && isLoadingXcScan
const isTwoColTemplate = !!account && (all.length > 0 || isLoading)

return (
Expand Down
Loading
Loading