diff --git a/README.md b/README.md
index 95943b7..b900c97 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,13 @@ See https://docs.skale.network/metaport/1.1.x/
## Development
+### Storybook preview
+
+```
+bash prepare_meta.sh && bun install && bun build:lib
+bun dev
+```
+
### Debug mode
To enable debug mode, set `debug` environment variable to `true`:
diff --git a/src/components/AmountInput.tsx b/src/components/AmountInput.tsx
index ce75cd8..86a8724 100644
--- a/src/components/AmountInput.tsx
+++ b/src/components/AmountInput.tsx
@@ -12,6 +12,7 @@ import { useCollapseStore } from '../store/Store'
export default function AmountInput() {
const { address } = useAccount()
const transferInProgress = useMetaportStore((state) => state.transferInProgress)
+ const currentStep = useMetaportStore((state) => state.currentStep)
const setAmount = useMetaportStore((state) => state.setAmount)
const amount = useMetaportStore((state) => state.amount)
const expandedTokens = useCollapseStore((state) => state.expandedTokens)
@@ -21,6 +22,13 @@ export default function AmountInput() {
setAmount('', address)
return
}
+ if (event.target.value.length > 12) {
+ let initialSize = 22 - event.target.value.length / 3
+ initialSize = initialSize <= 12 ? 12 : initialSize
+ event.target.style.fontSize = initialSize + 'px'
+ } else {
+ event.target.style.fontSize = '22px'
+ }
setAmount(event.target.value, address)
}
@@ -34,7 +42,8 @@ export default function AmountInput() {
placeholder="0.00"
value={amount}
onChange={handleChange}
- disabled={transferInProgress}
+ disabled={transferInProgress || currentStep !== 0}
+ style={{ width: '100%' }}
/>
)}
diff --git a/src/components/Debug.tsx b/src/components/Debug.tsx
index 92e6525..cc2f877 100644
--- a/src/components/Debug.tsx
+++ b/src/components/Debug.tsx
@@ -21,21 +21,19 @@
* @copyright SKALE Labs 2023-Present
*/
-import Grid from '@mui/material/Grid';
-import Table from '@mui/material/Table';
-import TableBody from '@mui/material/TableBody';
-import TableCell from '@mui/material/TableCell';
-import TableContainer from '@mui/material/TableContainer';
-import TableHead from '@mui/material/TableHead';
-import TableRow from '@mui/material/TableRow';
-import Paper from '@mui/material/Paper';
+import Grid from '@mui/material/Grid'
+import Table from '@mui/material/Table'
+import TableBody from '@mui/material/TableBody'
+import TableCell from '@mui/material/TableCell'
+import TableContainer from '@mui/material/TableContainer'
+import TableHead from '@mui/material/TableHead'
+import TableRow from '@mui/material/TableRow'
+import Paper from '@mui/material/Paper'
import { useMetaportStore } from '../store/MetaportStore'
import { cls, cmn } from '../core/css'
-
export default function Debug() {
-
const debug = useMetaportStore((state) => state.mpc.config.debug)
const chainName1 = useMetaportStore((state) => state.chainName1)
const chainName2 = useMetaportStore((state) => state.chainName2)
@@ -46,15 +44,14 @@ export default function Debug() {
{ name: 'chainName1', value: chainName1 },
{ name: 'chainName2', value: chainName2 },
{ name: 'amount', value: amount },
- { name: 'stepsMetadata', value: JSON.stringify(stepsMetadata) },
+ { name: 'stepsMetadata', value: JSON.stringify(stepsMetadata) }
]
if (!debug) return
return (
-
+
@@ -80,7 +77,6 @@ export default function Debug() {
-
)
}
diff --git a/src/components/ErrorMessage.tsx b/src/components/ErrorMessage.tsx
index 88b4ac7..722e953 100644
--- a/src/components/ErrorMessage.tsx
+++ b/src/components/ErrorMessage.tsx
@@ -13,26 +13,26 @@ import LinkOffRoundedIcon from '@mui/icons-material/LinkOffRounded'
import PublicOffRoundedIcon from '@mui/icons-material/PublicOffRounded'
import SentimentDissatisfiedRoundedIcon from '@mui/icons-material/SentimentDissatisfiedRounded'
import ErrorRoundedIcon from '@mui/icons-material/ErrorRounded'
-import HourglassTopRoundedIcon from '@mui/icons-material/HourglassTopRounded';
-import CrisisAlertRoundedIcon from '@mui/icons-material/CrisisAlertRounded';
+import HourglassTopRoundedIcon from '@mui/icons-material/HourglassTopRounded'
+import CrisisAlertRoundedIcon from '@mui/icons-material/CrisisAlertRounded'
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
-import TextSnippetRoundedIcon from '@mui/icons-material/TextSnippetRounded';
-import HourglassBottomRoundedIcon from '@mui/icons-material/HourglassBottomRounded';
-import AvTimerRoundedIcon from '@mui/icons-material/AvTimerRounded';
-
+import HourglassBottomRoundedIcon from '@mui/icons-material/HourglassBottomRounded'
+import AvTimerRoundedIcon from '@mui/icons-material/AvTimerRounded'
+import RestartAltRoundedIcon from '@mui/icons-material/RestartAltRounded';
+import HelpOutlineRoundedIcon from '@mui/icons-material/HelpOutlineRounded';
+import SortRoundedIcon from '@mui/icons-material/SortRounded';
import { DEFAULT_ERROR_MSG } from '../core/constants'
const ERROR_ICONS = {
'link-off': ,
'public-off': ,
sentiment: ,
- warning: ,
+ warning: ,
error: ,
time:
}
export default function Error(props: { errorMessage: ErrorMessage }) {
-
const [expanded, setExpanded] = useState(false)
const handleChange = (panel: string) => (_: React.SyntheticEvent, isExpanded: boolean) => {
@@ -54,28 +54,79 @@ export default function Error(props: { errorMessage: ErrorMessage }) {
Logs are available in your browser's developer console
-
-
-
-
- When transferring from SKALE to Ethereum Mainnet, there are frequency limitations.
-
-
-
-
-
+ {props.errorMessage.showTips ? (
+
+
+
+
+
+
+ Transfers might occasionally delay, but all tokens will be sent.
+
+
+
+
+
+
+
+ If a transfer is interrupted, you can continue from where you stopped.
+
+
+
+
+
+ Transfers from SKALE to Ethereum Mainnet have frequency limits.
+
+
+
+
+
+
+
+ If you still have questions, consult FAQ or contact the support team.
+
+
-
- Sometimes transfers may take more time than expected.
-
-
-
-
+ ) : null}
+
}
@@ -84,7 +135,7 @@ export default function Error(props: { errorMessage: ErrorMessage }) {
>
-
+
{expanded === 'panel1' ? 'Hide' : 'Show'} error details
@@ -95,13 +146,20 @@ export default function Error(props: { errorMessage: ErrorMessage }) {
{props.errorMessage.text}
-
{props.errorMessage.fallback ? (
diff --git a/src/components/Stepper/SkStepper.tsx b/src/components/Stepper/SkStepper.tsx
index 6198db4..0e47e81 100644
--- a/src/components/Stepper/SkStepper.tsx
+++ b/src/components/Stepper/SkStepper.tsx
@@ -74,6 +74,10 @@ export default function SkStepper(props: { skaleNetwork: SkaleNetwork }) {
}, [transactionsHistory])
if (stepsMetadata.length === 0) return
+
+ const actionDisabled =
+ amountErrorMessage || loading || amount == '' || Number(amount) === 0 || !cpData.exitGasOk
+
return (
@@ -121,9 +125,7 @@ export default function SkStepper(props: { skaleNetwork: SkaleNetwork }) {
size="medium"
className={cls(styles.btnAction, cmn.mtop5)}
onClick={() => execute(address, switchNetworkAsync, walletClient)}
- disabled={
- !!(amountErrorMessage || loading || amount == '' || !cpData.exitGasOk)
- }
+ disabled={!!actionDisabled}
>
{step.btnText}
diff --git a/src/components/WidgetUI/WidgetUI.tsx b/src/components/WidgetUI/WidgetUI.tsx
index d9ad015..b522192 100644
--- a/src/components/WidgetUI/WidgetUI.tsx
+++ b/src/components/WidgetUI/WidgetUI.tsx
@@ -89,7 +89,7 @@ export function WidgetUI(props: { config: MetaportConfig }) {
{fabTop ? fabButton : null}
-
+
diff --git a/src/core/actions/action.ts b/src/core/actions/action.ts
index 4a72f92..2a2163f 100644
--- a/src/core/actions/action.ts
+++ b/src/core/actions/action.ts
@@ -64,7 +64,6 @@ export class Action {
chainName2: string
address: string
amount: string
- amountWei: bigint
tokenId: number
token: TokenData
@@ -86,9 +85,6 @@ export class Action {
constructor(
mpc: MetaportCore,
- // mainnet: MainnetChain,
- // sChain1: SChain,
- // sChain2: SChain,
chainName1: string,
chainName2: string,
address: string,
@@ -106,7 +102,6 @@ export class Action {
this.chainName2 = chainName2
this.address = address
this.amount = amount
- if (amount) this.amountWei = toWei(amount, token.meta.decimals)
this.tokenId = Number(tokenId)
this.token = createTokenData(token.keyname, chainName1, token.type, this.mpc.config)
@@ -167,6 +162,7 @@ export class Action {
updateState(currentState: interfaces.ActionState, transactionHash?: string, timestamp?: number) {
log(`actionStateUpd: ${this.constructor.name} - ${currentState} - ${this.token.keyname} \
- ${this.chainName1} -> ${this.chainName2}`)
+ const amountWei = toWei(this.amount, this.token.meta.decimals)
externalEvents.actionStateUpdated({
actionName: this.constructor.name,
actionState: currentState,
@@ -175,7 +171,7 @@ export class Action {
chainName2: this.chainName2,
address: this.address,
amount: this.amount,
- amountWei: this.amountWei,
+ amountWei: amountWei,
tokenId: this.tokenId
},
transactionHash,
diff --git a/src/core/actions/checks.ts b/src/core/actions/checks.ts
index 1470b8b..965ab2d 100644
--- a/src/core/actions/checks.ts
+++ b/src/core/actions/checks.ts
@@ -25,7 +25,7 @@ import debug from 'debug'
import { Contract } from 'ethers'
import { MainnetChain, SChain } from '@skalenetwork/ima-js'
-import { fromWei } from '../convertation'
+import { fromWei, toWei } from '../convertation'
import { TokenData } from '../dataclasses/TokenData'
import * as interfaces from '../interfaces'
import { addressesEqual } from '../helper'
@@ -41,7 +41,17 @@ export async function checkEthBalance( // TODO: optimize balance checks
tokenData: TokenData
): Promise {
const checkRes: interfaces.CheckRes = { res: false }
-
+ if (!amount || Number(amount) === 0) return checkRes
+ try {
+ toWei(amount, tokenData.meta.decimals)
+ } catch (err) {
+ if (err.fault && err.fault === 'underflow') {
+ checkRes.msg = 'The amount is too small'
+ } else {
+ checkRes.msg = 'Incorrect amount'
+ }
+ return checkRes
+ }
try {
const balance = await chain.ethBalance(address)
log(`address: ${address}, eth balance: ${balance}, amount: ${amount}`)
@@ -73,6 +83,16 @@ export async function checkERC20Balance(
): Promise {
const checkRes: interfaces.CheckRes = { res: false }
if (!amount || Number(amount) === 0) return checkRes
+ try {
+ toWei(amount, tokenData.meta.decimals)
+ } catch (err) {
+ if (err.fault && err.fault === 'underflow') {
+ checkRes.msg = 'The amount is too small'
+ } else {
+ checkRes.msg = 'Incorrect amount'
+ }
+ return checkRes
+ }
try {
const balance = await tokenContract.balanceOf(address)
log(`address: ${address}, balanceWei: ${balance}, amount: ${amount}`)
@@ -97,6 +117,16 @@ export async function checkSFuelBalance(
): Promise {
const checkRes: interfaces.CheckRes = { res: false }
if (!amount || Number(amount) === 0) return checkRes
+ try {
+ toWei(amount, DEFAULT_ERC20_DECIMALS)
+ } catch (err) {
+ if (err.fault && err.fault === 'underflow') {
+ checkRes.msg = 'The amount is too small'
+ } else {
+ checkRes.msg = 'Incorrect amount'
+ }
+ return checkRes
+ }
try {
const balance = await sChain.provider.getBalance(address)
log(`address: ${address}, balanceWei: ${balance}, amount: ${amount}`)
diff --git a/src/core/actions/erc20.ts b/src/core/actions/erc20.ts
index 5985f32..eecd984 100644
--- a/src/core/actions/erc20.ts
+++ b/src/core/actions/erc20.ts
@@ -116,9 +116,10 @@ export class WrapSFuelERC20S extends Action {
async execute() {
log('WrapSFuelERC20S:execute - starting')
this.updateState('wrap')
+ const amountWei = toWei(this.amount, this.token.meta.decimals)
const tx = await this.sChain1.erc20.fundExit(this.token.keyname, {
address: this.address,
- value: this.amountWei
+ value: amountWei
})
const block = await this.sChain1.provider.getBlock(tx.blockNumber)
this.updateState('wrapDone', tx.hash, block.timestamp)
diff --git a/src/core/dataclasses/ErrorMessage.ts b/src/core/dataclasses/ErrorMessage.ts
index 84157e9..2e46e33 100644
--- a/src/core/dataclasses/ErrorMessage.ts
+++ b/src/core/dataclasses/ErrorMessage.ts
@@ -21,9 +21,7 @@
* @copyright SKALE Labs 2022-Present
*/
-
-import { TRANSFER_ERROR_MSG } from "../constants"
-
+import { TRANSFER_ERROR_MSG } from '../constants'
export class ErrorMessage {
icon: string
diff --git a/src/core/metaport.ts b/src/core/metaport.ts
index da4e79f..c5a8793 100644
--- a/src/core/metaport.ts
+++ b/src/core/metaport.ts
@@ -99,7 +99,7 @@ export function createWrappedTokensMap(
): TokenDataTypesMap {
const wrappedTokens: TokenDataTypesMap = getEmptyTokenDataMap()
const tokenType = TokenType.erc20
- if (!chainName1) return wrappedTokens
+ if (!chainName1 || !config.connections[chainName1][tokenType]) return wrappedTokens
Object.keys(config.connections[chainName1][tokenType]).forEach((tokenKeyname) => {
const token = config.connections[chainName1][tokenType][tokenKeyname]
const wrapperAddress = findFirstWrapperAddress(token)
@@ -283,7 +283,8 @@ export default class MetaportCore {
destTokenContract,
destTokenBalance: null,
destChains: Object.keys(token.connections),
- amount: ''
+ amount: '',
+ currentStep: 0
}
}
diff --git a/src/metadata/metaportConfigStaging.ts b/src/metadata/metaportConfigStaging.ts
index 76296b2..517de25 100644
--- a/src/metadata/metaportConfigStaging.ts
+++ b/src/metadata/metaportConfigStaging.ts
@@ -392,4 +392,4 @@ export const METAPORT_CONFIG: interfaces.MetaportConfig = {
mode: 'dark',
vibrant: true
}
-}
\ No newline at end of file
+}
diff --git a/src/store/MetaportStore.ts b/src/store/MetaportStore.ts
index f8e05c0..588c692 100644
--- a/src/store/MetaportStore.ts
+++ b/src/store/MetaportStore.ts
@@ -133,6 +133,9 @@ export const useMetaportStore = create()((set, get) => ({
if (err.info && err.info.error && err.info.error.data && err.info.error.data.message) {
headline = err.info.error.data.message
}
+ if (err.shortMessage) {
+ headline = err.shortMessage
+ }
set({
errorMessage: new dataclasses.TransactionErrorMessage(
msg,
@@ -191,21 +194,36 @@ export const useMetaportStore = create()((set, get) => ({
loading: true,
btnText: 'Checking balance...'
})
- const stepMetadata = get().stepsMetadata[get().currentStep]
- const actionClass = ACTIONS[stepMetadata.type]
- await new actionClass(
- get().mpc,
- stepMetadata.from,
- stepMetadata.to,
- address,
- amount,
- get().tokenId,
- get().token,
- get().setAmountErrorMessage,
- get().setBtnText,
- null,
- null
- ).preAction()
+ try {
+ const stepMetadata = get().stepsMetadata[get().currentStep]
+ const actionClass = ACTIONS[stepMetadata.type]
+ await new actionClass(
+ get().mpc,
+ stepMetadata.from,
+ stepMetadata.to,
+ address,
+ amount,
+ get().tokenId,
+ get().token,
+ get().setAmountErrorMessage,
+ get().setBtnText,
+ null,
+ null
+ ).preAction()
+ } catch (err) {
+ console.error(err)
+ const msg = err.code && err.fault ? `${err.code} - ${err.fault}` : 'Something went wrong'
+ set({
+ errorMessage: new dataclasses.TransactionErrorMessage(
+ err.message,
+ get().errorMessageClosedFallback,
+ msg,
+ false
+ )
+ })
+ } finally {
+ set({ loading: false })
+ }
}
set({ loading: false })
},
diff --git a/src/styles/styles.module.scss b/src/styles/styles.module.scss
index 88fb215..c2f1260 100644
--- a/src/styles/styles.module.scss
+++ b/src/styles/styles.module.scss
@@ -384,7 +384,8 @@ button {
border-radius: 4px 0 0 4px;
padding: 9pt 15pt;
font-weight: bold !important;
- font-size: 1.3rem !important;
+ font-size: 22px;
+ transition: font-size 0.2s ease-in-out;
}
input::-webkit-outer-spin-button,