From 2a9202b8cf8081d6b798d1f74d1cf035d02918b5 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Mon, 7 Aug 2023 19:39:39 +0100 Subject: [PATCH 01/54] New metaport architecture --- .gitignore | 1 + .storybook/main.ts | 92 +- package.json | 41 +- src/Metaport.tsx | 4 +- .../AmountErrorMessage/AmountErrorMessage.tsx | 31 +- src/components/AmountInput/AmountInput.scss | 15 +- src/components/AmountInput/AmountInput.tsx | 87 +- src/components/BalanceBlock/BalanceBlock.tsx | 76 -- src/components/BalanceBlock/index.ts | 1 - src/components/ChainApps/ChainApps.tsx | 57 +- src/components/ChainIcon/ChainIcon.tsx | 30 + src/components/ChainIcon/index.ts | 1 + src/components/ChainsList/ChainsList.tsx | 146 ++- src/components/ChainsList/helper.tsx | 25 - .../CommunityPool/CommunityPool.tsx | 193 ---- src/components/CommunityPool/index.ts | 1 - src/components/CurrentChain/CurrentChain.tsx | 49 - src/components/CurrentChain/index.ts | 1 - .../CustomStationUrl/CustomStationUrl.tsx | 52 - src/components/CustomStationUrl/index.ts | 1 - src/components/Debug/Debug.tsx | 75 -- src/components/Debug/index.ts | 1 - src/components/ErrorMessage/ErrorMessage.tsx | 68 +- src/components/ErrorMessage/ErrorMessages.tsx | 80 -- src/components/ErrorMessage/index.ts | 3 +- src/components/Route/Route.tsx | 77 -- src/components/Route/index.ts | 1 - src/components/SFuelBadge/SFuelBadge.scss | 28 - src/components/SFuelBadge/SFuelBadge.tsx | 48 - src/components/SFuelBadge/index.ts | 1 - src/components/SFuelWarning/SFuelWarning.tsx | 252 ---- src/components/SFuelWarning/index.ts | 1 - src/components/SkConnect/SkConnect.tsx | 214 ++++ src/components/SkConnect/index.ts | 1 + src/components/SkPaper/SkPaper.tsx | 55 + src/components/SkPaper/index.ts | 1 + .../SkeletonLoader/SkeletonLoader.tsx | 5 +- .../StepperV2.scss => Stepper/SkStepper.scss} | 0 src/components/Stepper/SkStepper.tsx | 149 +++ src/components/Stepper/Stepper.scss | 37 - src/components/Stepper/Stepper.tsx | 78 -- src/components/Stepper/index.ts | 2 +- src/components/StepperV2/StepperV2.tsx | 69 -- src/components/StepperV2/index.ts | 1 - .../SwitchDirection/SwitchDirection.tsx | 73 ++ src/components/SwitchDirection/index.ts | 1 + src/components/TokenIcon/TokenIcon.tsx | 42 + src/components/TokenIcon/index.ts | 1 + src/components/TokenIdInput/TokenIdInput.scss | 43 - src/components/TokenIdInput/TokenIdInput.tsx | 39 - src/components/TokenIdInput/index.ts | 1 - src/components/TokenList/TokenBalance.tsx | 46 +- src/components/TokenList/TokenList.tsx | 164 +-- .../TokenListSection/TokenListSection.tsx | 95 +- .../TransactionData/TransactionData.scss | 26 - .../TransactionData/TransactionData.tsx | 112 -- src/components/TransactionData/index.ts | 1 - .../TransactionsHistory.tsx | 119 -- src/components/TransactionsHistory/index.ts | 1 - src/components/TransferETA/TransferETA.tsx | 50 - src/components/TransferETA/index.ts | 1 - src/components/TransferETF/TransferETF.tsx | 53 - src/components/TransferETF/index.ts | 1 - .../TransferRequest/TransferRequest.tsx | 217 ---- src/components/TransferRequest/index.ts | 1 - .../TransferSummary/TransferSummary.scss | 71 -- .../TransferSummary/TransferSummary.tsx | 59 - src/components/TransferSummary/index.ts | 1 - src/components/TransferUI/TransferUI.tsx | 197 ---- src/components/TransferUI/index.ts | 1 - src/components/UnwrapUI/UnwrapUI.tsx | 102 -- src/components/UnwrapUI/index.ts | 1 - src/components/WalletConnector/Connector.tsx | 55 - .../WalletConnector/MetamaskConnector.ts | 95 -- src/components/WalletConnector/index.ts | 2 - src/components/WalletConnector/metamask.svg | 61 - .../WalletConnector/walletconnect.svg | 1 - src/components/Widget/Widget.mdx | 4 - src/components/Widget/Widget.stories.tsx | 9 +- src/components/Widget/Widget.tsx | 1024 +++-------------- src/components/Widget/index.ts | 2 +- src/components/WidgetBody/WidgetBody.tsx | 239 ++-- src/components/WidgetUI/Common.stories.tsx | 100 -- src/components/WidgetUI/ERC1155.stories.tsx | 13 - src/components/WidgetUI/ERC20.stories.tsx | 253 ---- src/components/WidgetUI/ERC721.stories.tsx | 14 - src/components/WidgetUI/Errors.stories.tsx | 63 - .../WidgetUI/Guidelines.stories.mdx | 50 - .../WidgetUI/Multichain.stories.tsx | 149 --- src/components/WidgetUI/StoriesHelper.ts | 330 ------ src/components/WidgetUI/StorybookHelper.tsx | 245 ---- src/components/WidgetUI/Themes.stories.tsx | 99 -- src/components/WidgetUI/WidgetUI.scss | 725 ------------ src/components/WidgetUI/WidgetUI.tsx | 128 ++- src/components/WidgetUI/_variables.scss | 7 - .../WrappedTokensWarning.tsx | 56 - src/components/WrappedTokensWarning/index.ts | 1 - src/configs/metaportConfigStaging.json | 192 ---- src/core/actions/action.ts | 209 +++- src/core/actions/checks.ts | 34 +- src/core/actions/erc1155.ts | 222 ---- src/core/actions/erc20.ts | 366 +++--- src/core/actions/erc721.ts | 236 ---- src/core/actions/eth.ts | 121 -- src/core/actions/index.ts | 96 +- src/core/chain_id.ts | 48 + src/core/community_pool.ts | 138 +-- src/core/constants.ts | 8 +- src/core/contracts.ts | 59 + src/core/convertation.ts | 14 +- src/core/core.ts | 225 ---- src/core/dataclasses/ErrorMessage.ts | 74 ++ src/core/dataclasses/EthTokenData.ts | 38 +- src/core/dataclasses/StepMetadata.ts | 107 ++ src/core/dataclasses/TokenData.ts | 82 +- src/core/dataclasses/TokenType.ts | 6 + src/core/dataclasses/index.ts | 3 + src/core/ethers.ts | 47 + src/core/events.ts | 2 +- src/core/explorer.ts | 8 +- src/core/faucet.ts | 58 +- src/core/helper.ts | 42 +- src/core/index.ts | 1 - src/core/interfaces/Config.ts | 11 +- src/core/interfaces/TokenDataMap.ts | 6 +- src/core/interfaces/TokenMetadata.ts | 31 + src/core/interfaces/Tokens.ts | 28 +- src/core/interfaces/index.ts | 1 + .../TokenList/helper.ts => core/metadata.ts} | 64 +- src/core/metaport.ts | 237 ++++ src/core/network.ts | 104 ++ src/core/sfuel.ts | 228 ++-- .../WidgetUI/Themes.ts => core/themes.ts} | 16 +- src/core/tokens/erc20.ts | 173 --- src/core/tokens/eth.ts | 91 -- src/core/tokens/helper.ts | 4 +- src/core/tokens/index.ts | 121 -- src/core/tokens/m2s.ts | 210 ---- src/core/tokens/s2s.ts | 187 --- src/core/transfer_steps.ts | 251 ++-- src/core/views.ts | 2 +- src/core/wagmi_network.ts | 65 ++ src/metadata/addresses/staging.json | 16 +- src/metadata/addresses/staging3.json | 10 - src/metadata/faucet.json | 2 +- src/metadata/metaportConfigStaging.json | 314 +++++ src/metadata/proxy.json | 9 +- src/metadata/schainAbi.json | 2 +- src/store/MetaportState.ts | 326 ++++++ src/store/Store.ts | 75 ++ src/styles/_variables.scss | 14 + src/styles/common.scss | 233 ++++ src/styles/styles.scss | 262 +++++ src/types/custom.d.ts | 23 +- test/TestTest.ts | 105 ++ test/core/tokensTest.ts | 52 - test/test_utils.ts | 14 - tsconfig.json | 2 +- webpack.config.js | 68 +- 159 files changed, 4396 insertions(+), 8792 deletions(-) delete mode 100644 src/components/BalanceBlock/BalanceBlock.tsx delete mode 100644 src/components/BalanceBlock/index.ts create mode 100644 src/components/ChainIcon/ChainIcon.tsx create mode 100644 src/components/ChainIcon/index.ts delete mode 100644 src/components/ChainsList/helper.tsx delete mode 100644 src/components/CommunityPool/CommunityPool.tsx delete mode 100644 src/components/CommunityPool/index.ts delete mode 100644 src/components/CurrentChain/CurrentChain.tsx delete mode 100644 src/components/CurrentChain/index.ts delete mode 100644 src/components/CustomStationUrl/CustomStationUrl.tsx delete mode 100644 src/components/CustomStationUrl/index.ts delete mode 100644 src/components/Debug/Debug.tsx delete mode 100644 src/components/Debug/index.ts delete mode 100644 src/components/ErrorMessage/ErrorMessages.tsx delete mode 100644 src/components/Route/Route.tsx delete mode 100644 src/components/Route/index.ts delete mode 100644 src/components/SFuelBadge/SFuelBadge.scss delete mode 100644 src/components/SFuelBadge/SFuelBadge.tsx delete mode 100644 src/components/SFuelBadge/index.ts delete mode 100644 src/components/SFuelWarning/SFuelWarning.tsx delete mode 100644 src/components/SFuelWarning/index.ts create mode 100644 src/components/SkConnect/SkConnect.tsx create mode 100644 src/components/SkConnect/index.ts create mode 100644 src/components/SkPaper/SkPaper.tsx create mode 100644 src/components/SkPaper/index.ts rename src/components/{StepperV2/StepperV2.scss => Stepper/SkStepper.scss} (100%) create mode 100644 src/components/Stepper/SkStepper.tsx delete mode 100644 src/components/Stepper/Stepper.scss delete mode 100644 src/components/Stepper/Stepper.tsx delete mode 100644 src/components/StepperV2/StepperV2.tsx delete mode 100644 src/components/StepperV2/index.ts create mode 100644 src/components/SwitchDirection/SwitchDirection.tsx create mode 100644 src/components/SwitchDirection/index.ts create mode 100644 src/components/TokenIcon/TokenIcon.tsx create mode 100644 src/components/TokenIcon/index.ts delete mode 100644 src/components/TokenIdInput/TokenIdInput.scss delete mode 100644 src/components/TokenIdInput/TokenIdInput.tsx delete mode 100644 src/components/TokenIdInput/index.ts delete mode 100644 src/components/TransactionData/TransactionData.scss delete mode 100644 src/components/TransactionData/TransactionData.tsx delete mode 100644 src/components/TransactionData/index.ts delete mode 100644 src/components/TransactionsHistory/TransactionsHistory.tsx delete mode 100644 src/components/TransactionsHistory/index.ts delete mode 100644 src/components/TransferETA/TransferETA.tsx delete mode 100644 src/components/TransferETA/index.ts delete mode 100644 src/components/TransferETF/TransferETF.tsx delete mode 100644 src/components/TransferETF/index.ts delete mode 100644 src/components/TransferRequest/TransferRequest.tsx delete mode 100644 src/components/TransferRequest/index.ts delete mode 100644 src/components/TransferSummary/TransferSummary.scss delete mode 100644 src/components/TransferSummary/TransferSummary.tsx delete mode 100644 src/components/TransferSummary/index.ts delete mode 100644 src/components/TransferUI/TransferUI.tsx delete mode 100644 src/components/TransferUI/index.ts delete mode 100644 src/components/UnwrapUI/UnwrapUI.tsx delete mode 100644 src/components/UnwrapUI/index.ts delete mode 100644 src/components/WalletConnector/Connector.tsx delete mode 100644 src/components/WalletConnector/MetamaskConnector.ts delete mode 100644 src/components/WalletConnector/index.ts delete mode 100644 src/components/WalletConnector/metamask.svg delete mode 100644 src/components/WalletConnector/walletconnect.svg delete mode 100644 src/components/WidgetUI/Common.stories.tsx delete mode 100644 src/components/WidgetUI/ERC1155.stories.tsx delete mode 100644 src/components/WidgetUI/ERC20.stories.tsx delete mode 100644 src/components/WidgetUI/ERC721.stories.tsx delete mode 100644 src/components/WidgetUI/Errors.stories.tsx delete mode 100644 src/components/WidgetUI/Guidelines.stories.mdx delete mode 100644 src/components/WidgetUI/Multichain.stories.tsx delete mode 100644 src/components/WidgetUI/StoriesHelper.ts delete mode 100644 src/components/WidgetUI/StorybookHelper.tsx delete mode 100644 src/components/WidgetUI/Themes.stories.tsx delete mode 100644 src/components/WidgetUI/WidgetUI.scss delete mode 100644 src/components/WidgetUI/_variables.scss delete mode 100644 src/components/WrappedTokensWarning/WrappedTokensWarning.tsx delete mode 100644 src/components/WrappedTokensWarning/index.ts delete mode 100644 src/configs/metaportConfigStaging.json delete mode 100644 src/core/actions/erc1155.ts delete mode 100644 src/core/actions/erc721.ts delete mode 100644 src/core/actions/eth.ts create mode 100644 src/core/chain_id.ts create mode 100644 src/core/contracts.ts delete mode 100644 src/core/core.ts create mode 100644 src/core/dataclasses/ErrorMessage.ts create mode 100644 src/core/dataclasses/StepMetadata.ts create mode 100644 src/core/ethers.ts delete mode 100644 src/core/index.ts create mode 100644 src/core/interfaces/TokenMetadata.ts rename src/{components/TokenList/helper.ts => core/metadata.ts} (55%) create mode 100644 src/core/metaport.ts create mode 100644 src/core/network.ts rename src/{components/WidgetUI/Themes.ts => core/themes.ts} (85%) delete mode 100644 src/core/tokens/erc20.ts delete mode 100644 src/core/tokens/eth.ts delete mode 100644 src/core/tokens/index.ts delete mode 100644 src/core/tokens/m2s.ts delete mode 100644 src/core/tokens/s2s.ts create mode 100644 src/core/wagmi_network.ts delete mode 100644 src/metadata/addresses/staging3.json create mode 100644 src/metadata/metaportConfigStaging.json create mode 100644 src/store/MetaportState.ts create mode 100644 src/store/Store.ts create mode 100644 src/styles/_variables.scss create mode 100644 src/styles/common.scss create mode 100644 src/styles/styles.scss create mode 100644 test/TestTest.ts delete mode 100644 test/core/tokensTest.ts diff --git a/.gitignore b/.gitignore index bd5dd30..3c31b63 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,7 @@ test.mjs src/meta/ metaportConfig.json +metaportConfigMainnet.json storybook-static/ .vercel diff --git a/.storybook/main.ts b/.storybook/main.ts index f53eaea..79487d7 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -1,32 +1,56 @@ + const path = require("path"); -const NodePolyfillPlugin = require("node-polyfill-webpack-plugin"); -import type { StorybookConfig } from "@storybook/react-webpack5"; -const config: StorybookConfig = { +/** @type { import('@storybook/react-webpack5').StorybookConfig } */ +const config = { stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"], - core: {}, - addons: ["@storybook/addon-links", "@storybook/addon-essentials", "@storybook/preset-create-react-app", "@storybook/addon-interactions"], + staticDirs: ["../build"], + addons: [ + "@storybook/addon-links", + "@storybook/addon-essentials", + "@storybook/addon-interactions", + // "storybook-css-modules", + // { + // name: '@storybook/addon-styling', + // options: { + // sass: { + // // Require your Sass preprocessor here + // implementation: require('sass'), + // }, + // }, + // } + ], framework: { name: "@storybook/react-webpack5", - options: { - builder: { - lazyCompilation: true - } - } + options: {}, }, docs: { - autodocs: "tag" + autodocs: "tag", }, - staticDirs: ["../build"], webpackFinal: async config => { if (config.resolve && config.resolve.alias) { const { global, ...alias } = config.resolve.alias; - // config.resolve.alias['global'] = undefined; + config.resolve.alias['browser'] = false; // const { ...alias } = config.resolve.alias config.resolve.alias = alias; } + if (config.resolve && config.resolve.fallback) { + config.resolve.fallback = { + path: require.resolve('path-browserify'), + os: "os-browserify/browser", + "fs": false, + "browser": false, + "https": require.resolve("https-browserify"), + "http": require.resolve("stream-http"), + "crypto": require.resolve("crypto-browserify"), + "stream": require.resolve("stream-browserify"), + "buffer": require.resolve("buffer"), + "constants": require.resolve("constants-browserify") + //...config.resolve.fallback, + }; + } if (config.module && config.module.rules) { config.module.rules.push({ test: /\.scss$/, @@ -41,48 +65,10 @@ const config: StorybookConfig = { }, "sass-loader"], include: path.resolve(__dirname, "../") }); - config.module.rules.push({ - test: /\.(ts|tsx)$/, - loader: require.resolve("babel-loader"), - options: { - presets: [["react-app", { - flow: false, - typescript: true, - runtime: 'automatic' - }]] - } - }); - config.module.rules.push({ - test: /\.svg$/, - use: [{ - loader: 'svg-url-loader', - options: { - limit: 10000 - } - }] - }); - } - if (config.plugins) { - config.plugins.push(new NodePolyfillPlugin()); - } - if (config.resolve && config.resolve.extensions) { - config.resolve.extensions.push(".ts", ".tsx"); - } - if (config.resolve && config.resolve.fallback) { - config.resolve.fallback = { - path: require.resolve('path-browserify'), - os: "os-browserify/browser", - "fs": false, - "https": require.resolve("https-browserify"), - "http": require.resolve("stream-http"), - "crypto": require.resolve("crypto-browserify"), - "stream": require.resolve("stream-browserify"), - "buffer": require.resolve("buffer") - //...config.resolve.fallback, - }; } return config; } }; -export default config; \ No newline at end of file +export default config; + diff --git a/package.json b/package.json index 1bf67ba..01786cf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@skalenetwork/metaport", - "version": "1.2.0", + "version": "2.0.0", "description": "SKALE Metaport Widget", "keywords": [ "skale", @@ -21,7 +21,7 @@ "prepublish": "npm run build", "build": "NODE_ENV=production webpack --mode=production", "build-stats": " webpack --json > stats.json", - "test": "TS_NODE_PROJECT=\"tsconfig.test.json\" mocha -r ts-node/register test/**/*Test.ts", + "test": "TS_NODE_PROJECT=\"tsconfig.test.json\" mocha -t 300000 -r ts-node/register test/**/*Test.ts", "test-ts": "ts-mocha -n loader=ts-node/esm -p tsconfig.json test/**/*Test.ts", "lint": "tslint -c tslint.json 'src/**/*.ts'", "version": "node -e \"console.log(require('./package.json').version);\"" @@ -40,20 +40,21 @@ "@mui/icons-material": "^5.8.0", "@mui/lab": "^5.0.0-alpha.88", "@mui/material": "^5.8.1", + "@rainbow-me/rainbowkit": "^1.0.6", "@rollup/plugin-commonjs": "^17.1.0", "@rollup/plugin-image": "^2.1.1", "@rollup/plugin-json": "^4.1.0", "@rollup/plugin-node-resolve": "^11.2.1", - "@skalenetwork/ima-js": "1.1.3-custom", + "@skalenetwork/ima-js": "2.0.0-custom.5", "@skaleproject/pow-ethers": "0.3.2", - "@storybook/addon-essentials": "^7.0.6", - "@storybook/addon-interactions": "^7.0.6", - "@storybook/addon-links": "^7.0.6", - "@storybook/addon-mdx-gfm": "^7.0.6", - "@storybook/blocks": "^7.0.6", - "@storybook/preset-create-react-app": "^7.0.6", - "@storybook/react": "^7.0.6", - "@storybook/react-webpack5": "^7.0.6", + "@storybook/addon-essentials": "^7.1.0", + "@storybook/addon-interactions": "^7.1.0", + "@storybook/addon-links": "^7.1.0", + "@storybook/addon-mdx-gfm": "^7.1.0", + "@storybook/addon-styling": "^1.3.4", + "@storybook/blocks": "^7.1.0", + "@storybook/react": "^7.1.0", + "@storybook/react-webpack5": "^7.1.0", "@svgr/webpack": "^7.0.0", "@types/babel__core": "^7.1.19", "@types/mocha": "^9.1.1", @@ -64,6 +65,7 @@ "babel-loader": "^8.2.2", "babel-preset-react-app": "^10.0.0", "coingecko-api-v3": "0.0.13", + "constants-browserify": "^1.0.0", "crypto-browserify": "^3.12.0", "css-loader": "^6.7.1", "debug": "^4.3.4", @@ -76,8 +78,10 @@ "mocha": "^9.2.2", "node-polyfill-webpack-plugin": "^1.1.4", "postcss": "^8.4.14", + "postcss-loader": "^7.3.3", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-jazzicon": "^1.0.4", "react-script": "^2.0.5", "react-svg-loader": "^3.0.3", "rollup": "^2.56.3", @@ -88,7 +92,8 @@ "rollup-plugin-typescript2": "^0.29.0", "sass": "^1.54.0", "sass-loader": "^13.0.0", - "storybook": "^7.0.6", + "storybook": "^7.1.0", + "storybook-css-modules": "^1.0.8", "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", "style-loader": "^3.3.1", @@ -97,9 +102,13 @@ "ts-loader": "^9.3.0", "ts-mocha": "^10.0.0", "ts-node": "^10.9.1", - "typescript": "^4.4.2", + "typescript": "^5.1.6", + "viem": "^1.3.0", + "wagmi": "^1.3.9", "webpack": "^5.73.0", - "webpack-cli": "^4.10.0" + "webpack-cli": "^4.10.0", + "zustand": "^4.3.9" }, - "peerDependencies": {} -} \ No newline at end of file + "peerDependencies": {}, + "dependencies": {} +} diff --git a/src/Metaport.tsx b/src/Metaport.tsx index f851282..5fc667e 100644 --- a/src/Metaport.tsx +++ b/src/Metaport.tsx @@ -25,14 +25,14 @@ import React from 'react'; import { createRoot } from 'react-dom/client'; -import { Widget } from './components/Widget'; +import Widget from './components/Widget'; import { internalEvents } from './core/events'; import * as interfaces from './core/interfaces/index'; export * as dataclasses from './core/dataclasses/index'; export * as interfaces from './core/interfaces/index'; -export * as sfuel from './core/sfuel'; +// export * as sfuel from './core/sfuel'; export class Metaport { diff --git a/src/components/AmountErrorMessage/AmountErrorMessage.tsx b/src/components/AmountErrorMessage/AmountErrorMessage.tsx index 9ebd9c9..bc2a838 100644 --- a/src/components/AmountErrorMessage/AmountErrorMessage.tsx +++ b/src/components/AmountErrorMessage/AmountErrorMessage.tsx @@ -1,22 +1,27 @@ import Collapse from '@mui/material/Collapse'; -import { clsNames } from '../../core/helper'; -import styles from "../WidgetUI/WidgetUI.scss"; +import { cls } from '../../core/helper'; +import common from '../../styles/common.scss'; +import { useMetaportStore } from '../../store/MetaportState' -export default function AmountErrorMessage(props) { + +export default function AmountErrorMessage() { + const amountErrorMessage = useMetaportStore((state) => state.amountErrorMessage); return ( - -

+

- 🔴 {props.amountErrorMessage} + 🔴 {amountErrorMessage}

) } diff --git a/src/components/AmountInput/AmountInput.scss b/src/components/AmountInput/AmountInput.scss index 1c09027..bd3b898 100644 --- a/src/components/AmountInput/AmountInput.scss +++ b/src/components/AmountInput/AmountInput.scss @@ -1,7 +1,17 @@ -@import '../WidgetUI/variables'; +@import '../../styles/variables'; .mp__inputAmount { + .tokenSymbol { + font-weight: bold !important; + font-size: 1.3rem !important; + } + + .tokenSymbolPlaceholder { + color: #979797; + } + + :global .MuiInput-root::after { border-bottom: none !important; } @@ -14,6 +24,7 @@ border-radius: 4px 0 0 4px; padding: 9pt 15pt; font-weight: bold !important; + font-size: 1.3rem !important; } :global(.MuiFormControl-root) { @@ -21,7 +32,7 @@ // border-radius: 4px; } - background-color: $sk-paper-color !important; + background-color: transparent !important; border-radius: $sk-border-radius !important; diff --git a/src/components/AmountInput/AmountInput.tsx b/src/components/AmountInput/AmountInput.tsx index f591c99..c59e4df 100644 --- a/src/components/AmountInput/AmountInput.tsx +++ b/src/components/AmountInput/AmountInput.tsx @@ -1,65 +1,86 @@ import React from "react"; +import { useAccount } from 'wagmi' + import TextField from '@mui/material/TextField'; -import Button from '@mui/material/Button'; -import { clsNames } from '../../core/helper'; -import styles from '../WidgetUI/WidgetUI.scss'; +import { cls } from '../../core/helper'; +import common from '../../styles/common.scss'; import localStyles from './AmountInput.scss'; -import { TokenType } from '../../core/dataclasses/TokenType'; -import { SFUEL_RESERVE_AMOUNT } from "../../core/constants"; +import { useMetaportStore } from '../../store/MetaportState' + +export default function AmountInput() { -export default function AmountInput(props) { + const { address } = useAccount() + + const token = useMetaportStore((state) => state.token); + const transferInProgress = useMetaportStore((state) => state.transferInProgress); + const setAmount = useMetaportStore((state) => state.setAmount); + const amount = useMetaportStore((state) => state.amount); const handleChange = (event: React.ChangeEvent) => { if (parseFloat(event.target.value) < 0) { - props.setAmount(''); + setAmount('', address); return; } - props.setAmount(event.target.value); + setAmount(event.target.value, address); }; - const setMaxAmount = () => { - if (props.token && !props.token.clone && - (props.token.wrapsSFuel || props.token.type === TokenType.eth)) { - const adjustedAmount = Number(props.token.balance) - SFUEL_RESERVE_AMOUNT; - if (adjustedAmount > 0) { - props.setAmount(adjustedAmount.toString()); - } - } else { - if (props.token && !props.token.clone && props.token.unwrappedBalance) { - props.setAmount(props.token.unwrappedBalance); - } else { - props.setAmount(props.token.balance); - } - } - } + // const setMaxAmount = () => { + // if (token && !token.clone && + // (token.wrapsSFuel || token.type === TokenType.eth)) { + // const adjustedAmount = Number(token.balance) - SFUEL_RESERVE_AMOUNT; + // if (adjustedAmount > 0) { + // props.setAmount(adjustedAmount.toString()); + // } + // } else { + // if (token && !token.clone && token.unwrappedBalance) { + // props.setAmount(token.unwrappedBalance); + // } else { + // props.setAmount(token.balance); + // } + // } + // } - if (!props.token) return; + if (!token) return; return ( -
-
+
+
- {props.maxBtn ?
+ +
+ {token.meta.symbol} +
+ + {/* {props.maxBtn ?
-
: null} +
: null} */}
) } diff --git a/src/components/BalanceBlock/BalanceBlock.tsx b/src/components/BalanceBlock/BalanceBlock.tsx deleted file mode 100644 index 2a5a150..0000000 --- a/src/components/BalanceBlock/BalanceBlock.tsx +++ /dev/null @@ -1,76 +0,0 @@ - -/** - * @license - * SKALE Metaport - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -/** - * @file BalanceBlock.ts - * @copyright SKALE Labs 2023-Present - */ - -import { ReactElement } from "react"; -import Skeleton from '@mui/material/Skeleton'; -import styles from "../WidgetUI/WidgetUI.scss"; -import { clsNames } from "../../core/helper"; -import { fromWei } from '../../core/convertation'; -import { DEFAULT_ERC20_DECIMALS } from '../../core/constants'; - - -export default function BalanceBlock(props: { - icon: ReactElement, - disabled?: boolean, - balance: string | undefined, - token: string | undefined, - chainName: string, - margTop?: boolean -}) { - const displayedBalance = props.balance ? fromWei( - props.balance as string, - DEFAULT_ERC20_DECIMALS - ).substring(0, 5) : null; - const displayedToken = props.token ? props.token.toUpperCase() : null; - - return (
-
-
- {props.icon} -
-

- Balance on {props.chainName} -

-
-
- {props.balance ? (

- {displayedBalance} {displayedToken} -

) : } -
-
) -} \ No newline at end of file diff --git a/src/components/BalanceBlock/index.ts b/src/components/BalanceBlock/index.ts deleted file mode 100644 index 84ad926..0000000 --- a/src/components/BalanceBlock/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./BalanceBlock"; diff --git a/src/components/ChainApps/ChainApps.tsx b/src/components/ChainApps/ChainApps.tsx index a8f556a..94c228e 100644 --- a/src/components/ChainApps/ChainApps.tsx +++ b/src/components/ChainApps/ChainApps.tsx @@ -1,41 +1,48 @@ -import Tooltip from '@mui/material/Tooltip'; +import { cls, getChainAppsMeta, getChainAlias } from '../../core/helper'; -import { getChainIcon } from '../ChainsList/helper'; +import styles from "../../styles/styles.scss"; +import common from "../../styles/common.scss"; +import { SkaleNetwork } from '../../core/interfaces'; -import { clsNames, getChainAppsMeta } from '../../core/helper'; -import styles from "../WidgetUI/WidgetUI.scss"; -import { MetaportConfig } from '../../core/interfaces'; +import ChainIcon from '../ChainIcon'; export default function ChainApps(props: { - config: MetaportConfig, - chain: string, - dark: boolean + skaleNetwork: SkaleNetwork, + chain: string }) { - const apps = getChainAppsMeta(props.chain, props.config.skaleNetwork); + const apps = getChainAppsMeta(props.chain, props.skaleNetwork); if (!apps || !Object.keys(apps) || Object.keys(apps).length === 0) return
; return ( -
-
+
{Object.keys(apps).map((key, _) => ( - -
- {getChainIcon(props.config.skaleNetwork, props.chain, props.dark, key)} -
-
+
+ +

+ {getChainAlias(props.skaleNetwork, props.chain, key)} +

+
))}
diff --git a/src/components/ChainIcon/ChainIcon.tsx b/src/components/ChainIcon/ChainIcon.tsx new file mode 100644 index 0000000..2488da8 --- /dev/null +++ b/src/components/ChainIcon/ChainIcon.tsx @@ -0,0 +1,30 @@ +import OfflineBoltRoundedIcon from '@mui/icons-material/OfflineBoltRounded'; +import { SkaleNetwork } from '../../core/interfaces'; +import { chainIconPath } from '../../core/metadata'; + +import { cls } from '../../core/helper'; +import styles from "../../styles/styles.scss"; + + +export default function ChainIcon(props: { + skaleNetwork: SkaleNetwork, + chainName: string, + className?: string, + app?: string, + size?: 'xs' | 'sm' | 'md' | 'lg' +}) { + const iconPath = chainIconPath( + props.skaleNetwork, + props.chainName, + props.app + ) + const size = props.size ?? 'sm'; + const className = styles[`chainIcon${size}`] + ' ' + props.className; + if (iconPath !== undefined) { + if (iconPath.default) { + return ; + } + return ; + } + return (); +} \ No newline at end of file diff --git a/src/components/ChainIcon/index.ts b/src/components/ChainIcon/index.ts new file mode 100644 index 0000000..78b7638 --- /dev/null +++ b/src/components/ChainIcon/index.ts @@ -0,0 +1 @@ +export { default } from "./ChainIcon"; diff --git a/src/components/ChainsList/ChainsList.tsx b/src/components/ChainsList/ChainsList.tsx index 4d59655..b36e98f 100644 --- a/src/components/ChainsList/ChainsList.tsx +++ b/src/components/ChainsList/ChainsList.tsx @@ -7,26 +7,27 @@ import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import Tooltip from '@mui/material/Tooltip'; import Button from '@mui/material/Button'; -import OfflineBoltIcon from '@mui/icons-material/OfflineBolt'; import ChainApps from '../ChainApps'; -import { getChainIcon } from '../ChainsList/helper'; +import ChainIcon from '../ChainIcon'; -import { clsNames, getChainName } from '../../core/helper'; -import styles from "../WidgetUI/WidgetUI.scss"; +import { MetaportConfig } from '../../core/interfaces'; - -function stringToColor(_, dark) { - if (dark) { - // return `hsl(${hashCode(str) % 360}, 100%, 80%)`; - return 'hsl(120deg 2% 88%)'; - } - return 'hsl(0deg 0% 15%)'; - // return `hsl(${hashCode(str) % 360}, 55%, 40%)`; -} +import { cls, getChainAlias } from '../../core/helper'; +import common from "../../styles/common.scss"; +import styles from "../../styles/styles.scss"; -export default function ChainsList(props) { +export default function ChainsList(props: { + config: MetaportConfig, + expanded: string | false, + setExpanded: (expanded: string | false) => void, + setChain: (chain: string) => void, + chain: string, + disabledChain: string, + from?: boolean, + disabled?: boolean +}) { const handleChange = (panel: string) => (_: React.SyntheticEvent, isExpanded: boolean) => { props.setExpanded(isExpanded ? panel : false); @@ -57,68 +58,125 @@ export default function ChainsList(props) { expandIcon={} aria-controls="panel1bh-content" id="panel1bh-header" + className={styles.accordionSummary} > {props.chain ? ( -
-
- {getChainIcon(props.config.skaleNetwork, props.chain, props.dark)} +
+
+
-

- {getChainName(props.config.chainsMetadata, props.chain, props.config.skaleNetwork)} + {getChainAlias(props.config.skaleNetwork, props.chain)}

-
-
+
+ {/*
-
+
*/}
) : ( -
-
- +
+
+
-

- Select chain +

+ Transfer {props.from ? 'from' : 'to'}...

) } -
+
+
+ +
{schainNames.map((name) => ( +
+ +
+
))}
diff --git a/src/components/ChainsList/helper.tsx b/src/components/ChainsList/helper.tsx deleted file mode 100644 index 527da31..0000000 --- a/src/components/ChainsList/helper.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import OfflineBoltIcon from '@mui/icons-material/OfflineBolt'; - -import { chainIconPath } from '../TokenList/helper'; - - -function stringToColor(_, dark) { - if (dark) { - // return `hsl(${hashCode(str) % 360}, 100%, 80%)`; - return 'hsl(120deg 2% 88%)'; - } - return 'hsl(0deg 0% 15%)'; - // return `hsl(${hashCode(str) % 360}, 55%, 40%)`; -} - - -export function getChainIcon(skaleNetwork: string, chainName: string, dark: boolean, app?: string) { - const iconPath = chainIconPath(skaleNetwork, chainName, app); - if (iconPath !== undefined) { - if (iconPath.default) { - return ; - } - return ; - } - return (); -} diff --git a/src/components/CommunityPool/CommunityPool.tsx b/src/components/CommunityPool/CommunityPool.tsx deleted file mode 100644 index efed9e2..0000000 --- a/src/components/CommunityPool/CommunityPool.tsx +++ /dev/null @@ -1,193 +0,0 @@ - -/** - * @license - * SKALE Metaport - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -/** - * @file CommunityPool.ts - * @copyright SKALE Labs 2023-Present - */ - -import React from 'react'; - -import Accordion from '@mui/material/Accordion'; -import AccordionSummary from '@mui/material/AccordionSummary'; -import AccordionDetails from '@mui/material/AccordionDetails'; -import Grid from '@mui/material/Grid'; - -import Button from '@mui/material/Button'; - -import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; - -import CheckCircleIcon from '@mui/icons-material/CheckCircle'; -import ErrorIcon from '@mui/icons-material/Error'; -import AccountBalanceWalletRoundedIcon from '@mui/icons-material/AccountBalanceWalletRounded'; - -import AmountInput from '../AmountInput'; -import BalanceBlock from "../BalanceBlock"; - -import { fromWei } from '../../core/convertation'; -import { DEFAULT_ERC20_DECIMALS } from '../../core/constants'; - -import { clsNames } from '../../core/helper'; -import styles from "../WidgetUI/WidgetUI.scss"; -import { CommunityPoolData } from '../../core/interfaces'; -import { getChainIcon } from '../ChainsList/helper'; - - -export default function CommunityPool(props: { - communityPoolData: CommunityPoolData, - loading: string | false, - rechargeAmount: string, - setRechargeAmount: (amount: string) => {}, - expanded: string | false, - setExpanded: (expanded: string | false) => {}, - recharge: () => {}, - withdraw: () => {}, - marg: boolean -}) { - - const handleChange = (panel: string) => (_: React.SyntheticEvent, isExpanded: boolean) => { - props.setExpanded(isExpanded ? panel : false); - }; - - const text = props.communityPoolData.exitGasOk ? 'Exit gas wallet OK' : 'Recharge exit gas wallet'; - const icon = props.communityPoolData.exitGasOk ? : - const accountBalanceEther = props.communityPoolData.accountBalance ? fromWei( - props.communityPoolData.accountBalance as string, - DEFAULT_ERC20_DECIMALS - ) : null; - - function getRechargeBtnText() { - if (props.loading === 'recharge') return 'Recharging...'; - if (props.loading === 'activate') return 'Activating account...'; - if (Number(props.rechargeAmount) > Number(accountBalanceEther)) return 'Insufficient ETH balance'; - if (props.rechargeAmount === '' || props.rechargeAmount === '0' || !props.rechargeAmount) return 'Enter an amount'; - return 'Recharge exit gas wallet'; - } - - function getWithdrawBtnText() { - if (props.loading === 'withdraw') return 'Withdrawing...'; - return 'Withdraw all'; - } - - return (
- - } - aria-controls="panel1a-content" - id="panel1a-header" - > -
-
- {icon} -
-

- {text} -

-
-
- -
-

- Exit gas wallet support is in BETA.

- This wallet is used to pay for Ethereum gas fees from your transactions to - the Ethereum Mainnet. You may withdraw funds from your SKALE Gas Wallet at - anytime. -

- - - - - - } - chainName='exit wallet' - balance={props.communityPoolData.balance} - token='eth' - /> - - - -

- Recharge amount -

- -
- -
-
- -
- -
-
-
-
-
-
) -} diff --git a/src/components/CommunityPool/index.ts b/src/components/CommunityPool/index.ts deleted file mode 100644 index 982e615..0000000 --- a/src/components/CommunityPool/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./CommunityPool"; \ No newline at end of file diff --git a/src/components/CurrentChain/CurrentChain.tsx b/src/components/CurrentChain/CurrentChain.tsx deleted file mode 100644 index 1c52ce7..0000000 --- a/src/components/CurrentChain/CurrentChain.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import Collapse from '@mui/material/Collapse'; -import IconButton from '@mui/material/IconButton'; -import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos'; -import { clsNames } from '../../core/helper'; -import { View } from '../../core/dataclasses/View'; - -import styles from '../WidgetUI/WidgetUI.scss'; - -import ChainsList from '../ChainsList'; - - -export default function CurrentChain(props) { - return ( - -
- {props.view === View.UNWRAP ? (
- { props.resetWidgetState(true); }} - > - - -

- UNWRAP STUCK TOKENS -

-
) : - (

- FROM -

)} - {/*
- -
*/} -
- -
- ) -} \ No newline at end of file diff --git a/src/components/CurrentChain/index.ts b/src/components/CurrentChain/index.ts deleted file mode 100644 index 13dc6ce..0000000 --- a/src/components/CurrentChain/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./CurrentChain"; diff --git a/src/components/CustomStationUrl/CustomStationUrl.tsx b/src/components/CustomStationUrl/CustomStationUrl.tsx deleted file mode 100644 index b187287..0000000 --- a/src/components/CustomStationUrl/CustomStationUrl.tsx +++ /dev/null @@ -1,52 +0,0 @@ - -/** - * @license - * SKALE Metaport - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -/** - * @file CustomStationUrl.ts - * @copyright SKALE Labs 2023-Present - */ - - -import Link from '@mui/material/Link'; - -import { DEFAULT_FAUCET_URL } from '../../core/constants'; - -import { clsNames } from '../../core/helper'; -import { StationData } from '../../core/sfuel'; -import styles from "../WidgetUI/WidgetUI.scss"; - - -export default function CustomStationUrl(props: { - stationData: StationData, - type: 'source' | 'destination' | 'hub' -}) { - return (props.stationData && props.stationData.faucetUrl && - props.stationData.faucetUrl !== DEFAULT_FAUCET_URL ?

- 🔗 - - Custom Faucet for {props.type} chain - -

: null) -} diff --git a/src/components/CustomStationUrl/index.ts b/src/components/CustomStationUrl/index.ts deleted file mode 100644 index d753d71..0000000 --- a/src/components/CustomStationUrl/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./CustomStationUrl"; \ No newline at end of file diff --git a/src/components/Debug/Debug.tsx b/src/components/Debug/Debug.tsx deleted file mode 100644 index c6d5012..0000000 --- a/src/components/Debug/Debug.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import React from 'react'; - -import styles from '../WidgetUI/WidgetUI.scss'; -import { clsNames } from '../../core/helper'; - -import Collapse from '@mui/material/Collapse'; -import Button from '@mui/material/Button'; - - -export default function Debug(props) { - const [open, setOpen] = React.useState(true); - - const handleClick = (_: React.MouseEvent) => { - setOpen(open ? false : true); - }; - - return (props.config.debug ? ( -
- - - transferRequest: {props.transferRequest ? JSON.stringify(props.transferRequest) : null} -
- transferRequestStatus: {props.transferRequestStatus} -
- transferRequestStep: {props.transferRequestStep} -
- transferRequestSteps len: {props.transferRequestSteps ? props.transferRequestSteps.length : null} -
- transferRequestLoading: {props.transferRequestLoading} -
- view: {props.view} -
- amount: {props.amount} -
- tokenId: {props.tokenId} -
- token: {props.token ? props.token.keyname : null} -
- chain1: {props.chain1} -
- chain2: {props.chain2} -
- actionName: {props.actionName} -
- actionSteps len: {props.actionSteps ? props.actionSteps.length : null} -
- activeStep: {props.activeStep} -
- sFuelOk: {props.sFuelOk} -
- chainId: {props.chainId} -
- extChainId: {props.extChainId} - -
-
-
-
- -
- ) : null - ) -} diff --git a/src/components/Debug/index.ts b/src/components/Debug/index.ts deleted file mode 100644 index 8b88959..0000000 --- a/src/components/Debug/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./Debug"; diff --git a/src/components/ErrorMessage/ErrorMessage.tsx b/src/components/ErrorMessage/ErrorMessage.tsx index 581511b..ce79b02 100644 --- a/src/components/ErrorMessage/ErrorMessage.tsx +++ b/src/components/ErrorMessage/ErrorMessage.tsx @@ -1,25 +1,63 @@ import Button from '@mui/material/Button'; -import { clsNames } from '../../core/helper'; -import styles from "../WidgetUI/WidgetUI.scss"; +import { cls } from '../../core/helper'; +import common from "../../styles/common.scss"; +import styles from "../../styles/styles.scss"; +import { ErrorMessage } from '../../core/dataclasses'; -export default function ErrorMessage(props) { +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'; + + +const ERROR_ICONS = { + 'link-off': , + 'public-off': , + 'sentiment': , + 'error': +}; + + +export default function Error(props: { errorMessage: ErrorMessage }) { if (!props.errorMessage) return return (
-
- {props.errorMessage.icon} +
+ {ERROR_ICONS[props.errorMessage.icon]}
-
-

+ Error occured +

+

+ Please check logs in developer console +

+
+

{props.errorMessage.text}

@@ -27,7 +65,7 @@ export default function ErrorMessage(props) { {props.errorMessage.fallback ? (
- - ) -} diff --git a/src/components/Route/index.ts b/src/components/Route/index.ts deleted file mode 100644 index 89c99e4..0000000 --- a/src/components/Route/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./Route"; diff --git a/src/components/SFuelBadge/SFuelBadge.scss b/src/components/SFuelBadge/SFuelBadge.scss deleted file mode 100644 index 7a2ef7c..0000000 --- a/src/components/SFuelBadge/SFuelBadge.scss +++ /dev/null @@ -1,28 +0,0 @@ -.mp__chip { - opacity: 0.9; - // color: #3fb354 !important; - - height: 10px; - margin-top: -12px; - - - :global(.MuiChip-root) { - height: 15px !important; - } - - :global(.MuiChip-label) { - font-size: 0.6525rem !important; - font-weight: 600; - letter-spacing: 0.1rem; - // opacity: 0.8; - } - - :global(.MuiChip-filledSuccess) { - background-color: #3fb354 !important; - } - - :global(svg) { - width: 9pt; - height: 9pt; - } -} \ No newline at end of file diff --git a/src/components/SFuelBadge/SFuelBadge.tsx b/src/components/SFuelBadge/SFuelBadge.tsx deleted file mode 100644 index 5e9c83c..0000000 --- a/src/components/SFuelBadge/SFuelBadge.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import Chip from '@mui/material/Chip'; -import DoneIcon from '@mui/icons-material/Done'; -import PriorityHighIcon from '@mui/icons-material/PriorityHigh'; -import ErrorIcon from '@mui/icons-material/Error'; -import Tooltip from '@mui/material/Tooltip'; - -import localStyles from './SFuelBadge.scss'; - - -const BadgeStates = { - success: { - tooltip: 'Everything is good', - color: 'success', - icon: - }, - warning: { - tooltip: 'You do not have enough sFUEL on the chain', - color: 'warning', - icon: - }, - error: { - tooltip: 'You do not have enough sFUEL on the chain', - color: 'error', - icon: - } -} - -export default function SFuelBadge(props) { - if (!props.data || props.data.ok) return; - if (Object.keys(props.data).length === 0) return; - - let type = props.from ? 'error' : 'warning'; - let badgeInfo = BadgeStates[type]; - - return ( - -
- window.open(props.data.faucetUrl, '_blank')?.focus()) : null} - icon={badgeInfo.icon} - label="sFUEL" - size="small" - /> -
-
- ) -} diff --git a/src/components/SFuelBadge/index.ts b/src/components/SFuelBadge/index.ts deleted file mode 100644 index 2b4cdb7..0000000 --- a/src/components/SFuelBadge/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./SFuelBadge"; diff --git a/src/components/SFuelWarning/SFuelWarning.tsx b/src/components/SFuelWarning/SFuelWarning.tsx deleted file mode 100644 index 31a5533..0000000 --- a/src/components/SFuelWarning/SFuelWarning.tsx +++ /dev/null @@ -1,252 +0,0 @@ - -/** - * @license - * SKALE Metaport - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -/** - * @file SFuelWarning.ts - * @copyright SKALE Labs 2023-Present - */ - -import React, { useEffect } from 'react'; -import debug from 'debug'; - -import Button from '@mui/material/Button'; - -import LoadingButton from '@mui/lab/LoadingButton'; - -import { Collapse } from '@mui/material'; -import { - MAINNET_CHAIN_NAME, - SFUEL_CHEKCS_INTERVAL, - SFUEL_TEXT, - DEFAULT_FAUCET_URL -} from '../../core/constants'; - -import { clsNames } from '../../core/helper'; -import { Station, StationData } from '../../core/sfuel'; -import styles from "../WidgetUI/WidgetUI.scss"; -import { TransferParams } from 'core/interfaces'; -import { View } from '../../core/dataclasses/View'; - -import CustomStationUrl from '../CustomStationUrl'; - - -debug.enable('*'); -const log = debug('metaport:components:SFuel'); - - -export default function SFuelWarning(props: { - chain1: string, - chain2: string, - transferRequest: TransferParams, - config: any, - address: string, - setSFuelOk: any, - view: View -}) { - - let fromChain; - let toChain; - let hubChain; - - if (props.transferRequest && props.view !== View.SANDBOX) { - // log('Getting chains from transferRequest'); - fromChain = props.transferRequest.chains[0]; - toChain = props.transferRequest.chains[1]; - hubChain = props.transferRequest.route ? props.transferRequest.route.hub : undefined; - } else { - // log('Getting chains from props'); - fromChain = props.chain1; - toChain = props.chain2; - } - - const [loading, setLoading] = React.useState(true); - const [mining, setMining] = React.useState(false); - - const [fromChainStation, setFromChainStation] = React.useState(); - const [toChainStation, setToChainStation] = React.useState(); - const [hubChainStation, setHubChainStation] = React.useState(); - - const [updateBalanceTime, setUpdateBalanceTime] = React.useState(Date.now()); - - const [fromStationData, setFromStationData] = React.useState(); - const [toStationData, setToStationData] = React.useState(); - const [hubStationData, setHubStationData] = React.useState(); - - const [sFuelStatus, setSFuelStatus] = React.useState<'action' | 'warning' | 'error'>('action'); - - useEffect(() => { - if (!fromChain || !toChain || !props.address) return; - log('Initializing SFuelWarning web3', fromChain, toChain, hubChain, props.address); - - setFromChainStation(new Station( - fromChain, - props.config.skaleNetwork, - props.config.mainnetEndpoint, - props.config.chainsMetadata - )); - - setToChainStation(new Station( - toChain, - props.config.skaleNetwork, - props.config.mainnetEndpoint, - props.config.chainsMetadata - )); - - if (hubChain) { - setHubChainStation(new Station( - hubChain, - props.config.skaleNetwork, - props.config.mainnetEndpoint, - props.config.chainsMetadata - )); - } - - const interval = setInterval( - () => setUpdateBalanceTime(Date.now()), SFUEL_CHEKCS_INTERVAL * 1000); - return () => clearInterval(interval); - }, [fromChain, toChain, hubChain]); - - useEffect(() => { updateFromStationData(); }, [fromChainStation]); - useEffect(() => { updateToStationData(); }, [toChainStation]); - useEffect(() => { updateHubStationData(); }, [hubChainStation]); - - useEffect(() => { updateBalances(); }, [updateBalanceTime, props.address]); - - useEffect(() => { - if (!fromStationData || !toStationData) return; - setLoading(true); - if (!fromStationData.ok || (hubStationData && !hubStationData.ok)) { - setSFuelStatus('error'); - props.setSFuelOk(false); - } else { - if (!toStationData.ok) { - setSFuelStatus('warning'); - } else { - setSFuelStatus('action'); - } - props.setSFuelOk(true); - } - setLoading(false); - }, [fromStationData, toStationData, hubStationData]); - - function updateBalances() { - updateFromStationData(); - updateToStationData(); - updateHubStationData(); - } - - async function updateFromStationData() { - if (!fromChainStation) return; - setFromStationData(await fromChainStation.getData(props.address)); - } - - async function updateToStationData() { - if (!toChainStation) return; - setToStationData(await toChainStation.getData(props.address)); - } - - async function updateHubStationData() { - if (!hubChainStation) return; - setHubStationData(await hubChainStation.getData(props.address)); - } - - async function doPoW() { - let fromPowRes; - let toPowRes; - let hubPowRes; - - setMining(true); - - if (fromStationData && !fromStationData.ok) { - log(`Doing PoW on ${fromChainStation.chainName}`); - fromPowRes = await fromChainStation.doPoW(props.address); - } - if (toStationData && !toStationData.ok) { - log(`Doing PoW on ${toChainStation.chainName}`); - toPowRes = await toChainStation.doPoW(props.address); - } - if (hubStationData && !hubStationData.ok) { - log(`Doing PoW on ${hubChainStation.chainName}`); - hubPowRes = await hubChainStation.doPoW(props.address); - } - - if ( - (fromPowRes && !fromPowRes.ok) || - (toPowRes && !toPowRes.ok) || - (hubPowRes && !hubPowRes.ok) - ) { - log('PoW failed!'); - if (fromPowRes) log(fromChain, fromPowRes.message); - if (toPowRes) log(toChain, toPowRes.message); - if (hubPowRes) log(hubChain, hubPowRes.message); - window.open(DEFAULT_FAUCET_URL, '_blank'); - } - - await updateFromStationData(); - await updateToStationData(); - await updateHubStationData(); - setMining(false); - } - - const noEth = (fromStationData && !fromStationData.ok && fromChain === MAINNET_CHAIN_NAME); - const noEthDest = (toStationData && !toStationData.ok && toChain === MAINNET_CHAIN_NAME); - - function getSFuelText() { - if (noEth || (fromStationData && fromStationData.ok && noEthDest)) { - return SFUEL_TEXT['gas'][sFuelStatus]; - } - return SFUEL_TEXT['sfuel'][sFuelStatus]; - } - - return ( -

- ⛽ {getSFuelText()} -

- { - !noEth && ((fromStationData && !fromStationData.ok) || !noEthDest) ? (
- {mining ? - Getting sFUEL... - : } - - - -
- ) : null - } -
) -} diff --git a/src/components/SFuelWarning/index.ts b/src/components/SFuelWarning/index.ts deleted file mode 100644 index d96f36f..0000000 --- a/src/components/SFuelWarning/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./SFuelWarning"; \ No newline at end of file diff --git a/src/components/SkConnect/SkConnect.tsx b/src/components/SkConnect/SkConnect.tsx new file mode 100644 index 0000000..126052b --- /dev/null +++ b/src/components/SkConnect/SkConnect.tsx @@ -0,0 +1,214 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +/** + * @file WidgetUI.ts + * @copyright SKALE Labs 2023-Present + */ + +import { ConnectButton } from '@rainbow-me/rainbowkit'; +import Jazzicon, { jsNumberForAddress } from 'react-jazzicon' + +import Button from '@mui/material/Button'; +import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; + +import { cls } from '../../core/helper'; + +import styles from "../../styles/styles.scss"; +import common from "../../styles/common.scss"; + +import skaleLogoFull from '../WidgetUI/skale_logo.svg'; +import { useMetaportStore } from '../../store/MetaportState'; + +import ChainIcon from "../ChainIcon"; + +export default function SkConnect() { + const transferInProgress = useMetaportStore((state) => state.transferInProgress); + return ( + + {({ + account, + chain, + openAccountModal, + openChainModal, + openConnectModal, + authenticationStatus, + mounted, + }) => { + // Note: If your app doesn't use authentication, you + // can remove all 'authenticationStatus' checks + const ready = mounted && authenticationStatus !== 'loading'; + const connected = + ready && + account && + chain && + (!authenticationStatus || + authenticationStatus === 'authenticated'); + return ( +
+ {(() => { + if (!connected) { + return ( +
+
+ +
+
+ + + + + + + + +
+

Connect a wallet to use SKALE Metaport

+ +
+ + ); + } + if (chain.unsupported) { + return ( + + + + ); + } + return ( +
+
+ {/* */} +
+
+ +
+ +
+ ); + })()} +
+ ); + }} +
) +}; \ No newline at end of file diff --git a/src/components/SkConnect/index.ts b/src/components/SkConnect/index.ts new file mode 100644 index 0000000..03890dd --- /dev/null +++ b/src/components/SkConnect/index.ts @@ -0,0 +1 @@ +export { default } from "./SkConnect"; diff --git a/src/components/SkPaper/SkPaper.tsx b/src/components/SkPaper/SkPaper.tsx new file mode 100644 index 0000000..84ed4e6 --- /dev/null +++ b/src/components/SkPaper/SkPaper.tsx @@ -0,0 +1,55 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +/** + * @file SkPaper.ts + * @copyright SKALE Labs 2023-Present +*/ + +import { ReactElement } from 'react'; +import { cls } from '../../core/helper'; + +import styles from "../../styles/styles.scss"; +import common from "../../styles/common.scss"; + +import { useUIStore } from '../../store/Store' + + +export default function SkPaper(props: { + className?: string, + children?: ReactElement | ReactElement[], + background?: string, + gray?: boolean, + rounded?: boolean, + fullHeight?: boolean, + margTop?: boolean +}) { + const metaportTheme = useUIStore((state) => state.theme); + const localStyle = { + 'background': props.background ?? metaportTheme.background + }; + return (
+ {props.children} +
) +} \ No newline at end of file diff --git a/src/components/SkPaper/index.ts b/src/components/SkPaper/index.ts new file mode 100644 index 0000000..d565a0d --- /dev/null +++ b/src/components/SkPaper/index.ts @@ -0,0 +1 @@ +export { default } from "./SkPaper"; diff --git a/src/components/SkeletonLoader/SkeletonLoader.tsx b/src/components/SkeletonLoader/SkeletonLoader.tsx index 62cca76..ad7d6de 100644 --- a/src/components/SkeletonLoader/SkeletonLoader.tsx +++ b/src/components/SkeletonLoader/SkeletonLoader.tsx @@ -1,11 +1,8 @@ import Skeleton from '@mui/material/Skeleton'; -import styles from '../WidgetUI/WidgetUI.scss'; - - export default function SkeletonLoader(props) { return ( -
+
{props.header ? : null} diff --git a/src/components/StepperV2/StepperV2.scss b/src/components/Stepper/SkStepper.scss similarity index 100% rename from src/components/StepperV2/StepperV2.scss rename to src/components/Stepper/SkStepper.scss diff --git a/src/components/Stepper/SkStepper.tsx b/src/components/Stepper/SkStepper.tsx new file mode 100644 index 0000000..9ae61e0 --- /dev/null +++ b/src/components/Stepper/SkStepper.tsx @@ -0,0 +1,149 @@ +import { useEffect, useState } from 'react'; + +import Box from '@mui/material/Box'; +import Stepper from '@mui/material/Stepper'; +import Step from '@mui/material/Step'; +import StepLabel from '@mui/material/StepLabel'; +import StepContent from '@mui/material/StepContent'; +import Button from '@mui/material/Button'; +import LoadingButton from '@mui/lab/LoadingButton'; + +import { cls, getChainAlias, getRandom } from '../../core/helper'; +import common from '../../styles/common.scss'; +import styles from '../../styles/styles.scss'; +import localStyles from './SkStepper.scss'; +import ChainIcon from "../ChainIcon"; +import SkPaper from "../SkPaper"; + +import { useMetaportStore } from '../../store/MetaportState' +import { Collapse } from '@mui/material'; +import { SkaleNetwork } from '../../core/interfaces'; + +import { useWalletClient } from 'wagmi' + + +import SettingsBackupRestoreRoundedIcon from '@mui/icons-material/SettingsBackupRestoreRounded'; + +import { useSwitchNetwork, useAccount } from 'wagmi' +import { SUCCESS_EMOJIS } from '../../core/constants'; + + +export default function SkStepper(props: { + skaleNetwork: SkaleNetwork +}) { + + const { address } = useAccount() + const { switchNetworkAsync } = useSwitchNetwork() + + const { data: walletClient } = useWalletClient() + + const stepsMetadata = useMetaportStore((state) => state.stepsMetadata); + const currentStep = useMetaportStore((state) => state.currentStep); + const amountErrorMessage = useMetaportStore((state) => state.amountErrorMessage); + const actionBtnDisabled = useMetaportStore((state) => state.actionBtnDisabled); + const loading = useMetaportStore((state) => state.loading); + const btnText = useMetaportStore((state) => state.btnText); + + const execute = useMetaportStore((state) => state.execute); + const startOver = useMetaportStore((state) => state.startOver); + + const [emoji, setEmoji] = useState(); + useEffect(() => { + setEmoji(getRandom(SUCCESS_EMOJIS)); + }, []); + + if (stepsMetadata.length === 0) return (
); + return ( + + + + + + {stepsMetadata.map((step, i) => ( + +
+
+

{step.headline}

+
+ +
+

{getChainAlias( + props.skaleNetwork, + step.onSource ? step.from : step.to + )}

+
+
+
+ + +

+ {step.text} +

+
+ {loading ? ( + + {btnText} + {/* {props.loadingTokens ? 'Loading...' : step.btnLoadingText} */} + + ) : ( + + )} +
+
+
+
))} +
+
+ + + {currentStep === stepsMetadata.length && ( +
+
+

+ {emoji} Transfer completed +

+
+ +
+ + )} +
+
+ +
+ ); +} \ No newline at end of file diff --git a/src/components/Stepper/Stepper.scss b/src/components/Stepper/Stepper.scss deleted file mode 100644 index 479c847..0000000 --- a/src/components/Stepper/Stepper.scss +++ /dev/null @@ -1,37 +0,0 @@ -.mp__labelStep { - // font-weight: 600 !important; - text-transform: uppercase !important; - font-size: 0.6525rem !important; - line-height: 1.6 !important; - letter-spacing: 0.02857em !important; -} - -.mp__stepper { - - :global span { - font-weight: 600 !important; - text-transform: uppercase !important; - font-size: 0.6525rem !important; - line-height: 1.6 !important; - letter-spacing: 0.02857em !important; - } - - :global .MuiStepConnector-line { - min-height: 0 !important; - } - - :global .MuiBox-root { - margin-bottom: 5px !important; - } - - :global .MuiSvgIcon-root { - width: 18px; - height: 18px; - } - - :global .MuiStepContent-root { - padding-right: 0; - margin-left: 8px; - padding-left: 18px - } -} \ No newline at end of file diff --git a/src/components/Stepper/Stepper.tsx b/src/components/Stepper/Stepper.tsx deleted file mode 100644 index 0651440..0000000 --- a/src/components/Stepper/Stepper.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import Box from '@mui/material/Box'; -import Stepper from '@mui/material/Stepper'; -import Step from '@mui/material/Step'; -import StepLabel from '@mui/material/StepLabel'; -import StepContent from '@mui/material/StepContent'; -import Button from '@mui/material/Button'; -import LoadingButton from '@mui/lab/LoadingButton'; - -import { TokenType } from '../../core/dataclasses/TokenType'; - -import { clsNames } from '../../core/helper'; -import styles from '../WidgetUI/WidgetUI.scss'; -import localStyles from './Stepper.scss'; - - -export default function ActionsStepper(props) { - const handleReset = () => { - props.setAmount(''); - props.setTokenId(''); - props.setLoading(false); - props.setAmountLocked(false); - props.setActiveStep(0); - }; - if (!props.token) return; - const nextStepDisabledAmount = [TokenType.erc20, TokenType.erc1155].includes(props.token.type) && (props.amount === '' || Number(props.amount) === 0); - const nextStepDisabledTokenId = [TokenType.erc721, TokenType.erc721meta, TokenType.erc1155].includes(props.token.type) && !props.tokenId; - const noSFuel = props.sFuelData && Object.keys(props.sFuelData).length !== 0 && !props.sFuelData.ok; - const nextStepDisabled = nextStepDisabledAmount || nextStepDisabledTokenId || props.loading || props.actionBtnDisabled || noSFuel; - - return ( - - - {props.actionSteps.map((step, _) => ( - - - {step.label} - - - -
- {props.loading ? ( - - {props.btnText} - - ) : ( - - )} -
-
-
-
- ))} -
- {props.activeStep === props.actionSteps.length && ( - - )} -
- ); -} \ No newline at end of file diff --git a/src/components/Stepper/index.ts b/src/components/Stepper/index.ts index 7512bf9..e3595f4 100644 --- a/src/components/Stepper/index.ts +++ b/src/components/Stepper/index.ts @@ -1 +1 @@ -export { default } from "./Stepper"; +export { default } from "./SkStepper"; diff --git a/src/components/StepperV2/StepperV2.tsx b/src/components/StepperV2/StepperV2.tsx deleted file mode 100644 index 623193a..0000000 --- a/src/components/StepperV2/StepperV2.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import Box from '@mui/material/Box'; -import Stepper from '@mui/material/Stepper'; -import Step from '@mui/material/Step'; -import StepLabel from '@mui/material/StepLabel'; -import StepContent from '@mui/material/StepContent'; -import Button from '@mui/material/Button'; -import LoadingButton from '@mui/lab/LoadingButton'; - -import { clsNames } from '../../core/helper'; -import styles from '../WidgetUI/WidgetUI.scss'; -import localStyles from './StepperV2.scss'; -import SkeletonLoader from "../SkeletonLoader"; - - -export default function StepperV2(props) { - if (props.transferRequestLoading || !props.transferRequestSteps) return (); - return ( - - - {props.transferRequestSteps.map((step, i) => ( - -
-
-

{step.headline}

-
- {step.chainIcon} -
-

{step.chainName}

-
-
-
- - -

- {step.text} -

-
- {props.loading || props.loadingTokens ? ( - - {props.loadingTokens ? 'Loading...' : props.btnText} - - ) : ( - - )} -
-
-
-
))} -
-
- ); -} \ No newline at end of file diff --git a/src/components/StepperV2/index.ts b/src/components/StepperV2/index.ts deleted file mode 100644 index 656d9db..0000000 --- a/src/components/StepperV2/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./StepperV2"; diff --git a/src/components/SwitchDirection/SwitchDirection.tsx b/src/components/SwitchDirection/SwitchDirection.tsx new file mode 100644 index 0000000..0eb2930 --- /dev/null +++ b/src/components/SwitchDirection/SwitchDirection.tsx @@ -0,0 +1,73 @@ +import { useRef } from 'react'; + +import IconButton from '@mui/material/IconButton'; +import ArrowDownwardRoundedIcon from '@mui/icons-material/ArrowDownwardRounded'; +import styles from '../../styles/styles.scss'; +import common from '../../styles/common.scss'; +import { cls } from '../../core/helper'; + +import { useUIStore } from '../../store/Store' +import { useMetaportStore } from '../../store/MetaportState' + + +export default function SwitchDirection() { + + const myElement = useRef(null); + + const metaportTheme = useUIStore((state) => state.theme); + + const chainName1 = useMetaportStore((state) => state.chainName1); + const chainName2 = useMetaportStore((state) => state.chainName2); + + const setChainName1 = useMetaportStore((state) => state.setChainName1); + const setChainName2 = useMetaportStore((state) => state.setChainName2); + const startOver = useMetaportStore((state) => state.startOver); + const loading = useMetaportStore((state) => state.loading); + const transferInProgress = useMetaportStore((state) => state.transferInProgress); + + return ( +
+
+
+
+ { + const element = myElement.current; + const rotate = () => { + if (element) { + element.classList.add('spin'); + setTimeout(() => { + element.classList.remove('spin'); + }, 400); + } + }; + rotate() + let chain1 = chainName1; + setChainName1(chainName2); + setChainName2(chain1); + startOver(); + }}> + + +
+
+
+ + +
+ ) +} \ No newline at end of file diff --git a/src/components/SwitchDirection/index.ts b/src/components/SwitchDirection/index.ts new file mode 100644 index 0000000..b86abe8 --- /dev/null +++ b/src/components/SwitchDirection/index.ts @@ -0,0 +1 @@ +export { default } from "./SwitchDirection"; diff --git a/src/components/TokenIcon/TokenIcon.tsx b/src/components/TokenIcon/TokenIcon.tsx new file mode 100644 index 0000000..2332518 --- /dev/null +++ b/src/components/TokenIcon/TokenIcon.tsx @@ -0,0 +1,42 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/** + * @file TokensIcon.ts + * @copyright SKALE Labs 2023-Present + */ + +import TollRoundedIcon from '@mui/icons-material/TollRounded'; +import { TokenData } from '../../core/dataclasses'; +import { tokenIconPath } from '../../core/metadata'; + +import styles from "../../styles/styles.scss"; + + +export default function TokenIcon(props: { + token?: TokenData, + size?: 'xs' | 'sm' | 'md' | 'lg' +}) { + const size = props.size ?? 'sm'; + const className = styles[`chainIcon${size}`]; + if (props.token === undefined || props.token === null) { + return + // return + } + return +} \ No newline at end of file diff --git a/src/components/TokenIcon/index.ts b/src/components/TokenIcon/index.ts new file mode 100644 index 0000000..6412a21 --- /dev/null +++ b/src/components/TokenIcon/index.ts @@ -0,0 +1 @@ +export { default } from "./TokenIcon"; diff --git a/src/components/TokenIdInput/TokenIdInput.scss b/src/components/TokenIdInput/TokenIdInput.scss deleted file mode 100644 index bc1c2ae..0000000 --- a/src/components/TokenIdInput/TokenIdInput.scss +++ /dev/null @@ -1,43 +0,0 @@ -@import '../WidgetUI/variables'; - -.mp__inputAmount { - - :global .MuiInput-root::after { - border-bottom: none !important; - } - - :global .MuiInput-root::before { - border-bottom: none !important; - } - - :global input { - border-radius: 4px 0 0 4px; - padding: 9pt 15pt; - font-weight: bold !important; - } - - :global .MuiFormControl-root { - width: 100%; - // border-radius: 4px; - } - - background-color: $sk-paper-color !important; - border-radius: $sk-border-radius !important; - - :global .MuiButton-root { - border-radius: 0 10px 10px 0 !important; - } - - input::-webkit-outer-spin-button, - input::-webkit-inner-spin-button { - /* display: none; <- Crashes Chrome on hover */ - -webkit-appearance: none; - margin: 0; - /* <-- Apparently some margin are still there even though it's hidden */ - } - - :global input[type=number] { - -moz-appearance: textfield; - /* Firefox */ - } -} \ No newline at end of file diff --git a/src/components/TokenIdInput/TokenIdInput.tsx b/src/components/TokenIdInput/TokenIdInput.tsx deleted file mode 100644 index 23cae03..0000000 --- a/src/components/TokenIdInput/TokenIdInput.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import React from "react"; -import TextField from '@mui/material/TextField'; - -import { clsNames } from '../../core/helper'; -import styles from '../WidgetUI/WidgetUI.scss'; -import localStyles from './TokenIdInput.scss'; - - -export default function TokenIdInput(props) { - - const handleChange = (event: React.ChangeEvent) => { - props.setTokenId(event.target.value); - }; - - if (!props.token) return; - return ( -
- -
- {/*
- -
*/} - -
-
-

- Token ID -

-
-
- ) -} diff --git a/src/components/TokenIdInput/index.ts b/src/components/TokenIdInput/index.ts deleted file mode 100644 index c0cab84..0000000 --- a/src/components/TokenIdInput/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./TokenIdInput"; diff --git a/src/components/TokenList/TokenBalance.tsx b/src/components/TokenList/TokenBalance.tsx index 9cc4091..ca02b24 100644 --- a/src/components/TokenList/TokenBalance.tsx +++ b/src/components/TokenList/TokenBalance.tsx @@ -1,35 +1,37 @@ -import { TokenType } from '../../core/dataclasses/TokenType'; -import { clsNames } from '../../core/helper'; -import styles from "../WidgetUI/WidgetUI.scss"; +import { formatUnits } from 'ethers'; +import { TokenType, TokenData } from '../../core/dataclasses'; +import { TokenBalancesMap } from '../../core/interfaces'; -function roundDown(number, decimals) { - decimals = decimals || 0; - return (Math.floor(number * Math.pow(10, decimals)) / Math.pow(10, decimals)); +import { cls } from '../../core/helper'; +import common from "../../styles/common.scss"; + + +function formatBalance(balance: bigint, token: TokenData): string { + return formatUnits(balance, parseInt(token.meta.decimals)); } -export default function TokenBalance(props) { +export default function TokenBalance(props: { + token: TokenData, + tokenBalances: TokenBalancesMap +}) { if ([TokenType.erc721, TokenType.erc721meta, TokenType.erc1155].includes(props.token.type)) return; - let balance = props.token.unwrappedSymbol ? props.token.unwrappedBalance : props.token.balance; - let symbol = props.token.unwrappedSymbol ? props.token.unwrappedSymbol : props.token.symbol; - if (props.token.clone) { - balance = props.token.balance; - symbol = props.token.cloneSymbol ? props.token.cloneSymbol : symbol; - } + const balance = props.tokenBalances[props.token.keyname]; - if (!balance) return; + if (balance === undefined || balance === null) return; return ( -
-

+

- {roundDown(balance, 8)} {symbol} + {formatBalance(balance, props.token)} {props.token.meta.symbol}

) diff --git a/src/components/TokenList/TokenList.tsx b/src/components/TokenList/TokenList.tsx index 2fbdcfa..629eacd 100644 --- a/src/components/TokenList/TokenList.tsx +++ b/src/components/TokenList/TokenList.tsx @@ -1,5 +1,8 @@ +import { useEffect } from 'react'; import React from 'react'; +import { useAccount } from 'wagmi' + import Accordion from '@mui/material/Accordion'; import AccordionDetails from '@mui/material/AccordionDetails'; import AccordionSummary from '@mui/material/AccordionSummary'; @@ -8,26 +11,66 @@ import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import { getAvailableTokensTotal, getDefaultToken } from '../../core/tokens/helper'; -import { clsNames } from '../../core/helper'; +import { cls } from '../../core/helper'; -import ErrorMessage, { NoTokenPairsMessage } from '../ErrorMessage'; +import ErrorMessage from '../ErrorMessage'; import TokenListSection from '../TokenListSection'; import TokenBalance from './TokenBalance'; +import TokenIcon from "../TokenIcon"; + +import styles from "../../styles/styles.scss"; +import common from "../../styles/common.scss"; +import { getTokenName } from "../../core/metadata"; + +import { useCollapseStore } from '../../store/Store'; +import { useMetaportStore } from '../../store/MetaportState'; +import { TokenType, NoTokenPairsMessage } from '../../core/dataclasses'; + + +export default function TokenList() { + + const token = useMetaportStore((state) => state.token); + const tokens = useMetaportStore((state) => state.tokens); + const setToken = useMetaportStore((state) => state.setToken); + const updateTokenBalances = useMetaportStore((state) => state.updateTokenBalances); + const tokenContracts = useMetaportStore((state) => state.tokenContracts); + + const tokenBalances = useMetaportStore((state) => state.tokenBalances); + const transferInProgress = useMetaportStore((state) => state.transferInProgress); + + const expandedTokens = useCollapseStore((state) => state.expandedTokens); + const setExpandedTokens = useCollapseStore((state) => state.setExpandedTokens); -import styles from "../WidgetUI/WidgetUI.scss"; -import localStyles from "./TokenList.scss"; -import { getIconSrc, iconPath, getTokenName } from "./helper"; + const { address } = useAccount(); -export default function TokenList(props) { - let availableTokensTotal = getAvailableTokensTotal(props.availableTokens); + useEffect(() => { + updateTokenBalances(address); // Fetch users immediately on component mount + const intervalId = setInterval(() => { + updateTokenBalances(address); + }, 10000) // Fetch users every 10 seconds + + return () => { + clearInterval(intervalId) // Clear interval on component unmount + } + }, [updateTokenBalances, tokenContracts, address]); + + useEffect(() => { + const defaultToken = getDefaultToken(tokens); + if (defaultToken) { + setToken(defaultToken); + } + }, [tokens]); + + + let availableTokensTotal = getAvailableTokensTotal(tokens); let disabled = availableTokensTotal === 1; let noTokens = availableTokensTotal === 0; const handleChange = (panel: string) => (_: React.SyntheticEvent, isExpanded: boolean) => { - props.setExpanded(isExpanded ? panel : false); + setExpandedTokens(isExpanded ? panel : false); }; if (noTokens) { @@ -36,89 +79,72 @@ export default function TokenList(props) { />) } - const defaultToken = getDefaultToken(props.availableTokens); - if (defaultToken) { - props.setToken(defaultToken); - } - return (
} aria-controls="panel1bh-content" id="panel1bh-header" + className={styles.accordionSummary} + style={{paddingTop: '0'}} > - {props.token ? ( -
-
- -
-

- {getTokenName(props.token)} -

- +
+
+
- ) : ( -
-
- -
-

- Select token -

+

+ {token ? getTokenName(token) : 'Select token'} +

+
+ {token ? : null}
- ) - } +
+ {/* */} - diff --git a/src/components/TokenListSection/TokenListSection.tsx b/src/components/TokenListSection/TokenListSection.tsx index 07d6740..d1804a7 100644 --- a/src/components/TokenListSection/TokenListSection.tsx +++ b/src/components/TokenListSection/TokenListSection.tsx @@ -1,17 +1,24 @@ -import Typography from '@mui/material/Typography'; import Button from '@mui/material/Button'; -import TokenData from '../../core/dataclasses/TokenData'; -import { clsNames } from '../../core/helper'; +import { TokenData, TokenType } from '../../core/dataclasses'; +import { TokenBalancesMap, TokenDataMap } from '../../core/interfaces'; +import { cls } from '../../core/helper'; import TokenBalance from '../TokenList/TokenBalance'; +import TokenIcon from '../TokenIcon'; -import styles from "../WidgetUI/WidgetUI.scss"; -import localStyles from "./TokenListSection.scss"; -import { getIconSrc, getTokenName } from "../TokenList/helper"; +import common from "../../styles/common.scss"; +import { getTokenName } from "../../core/metadata"; -export default function TokenListSection(props) { + +export default function TokenListSection(props: { + setExpanded: (expanded: string | false) => void, + setToken: (token: TokenData) => void, + tokens: TokenDataMap, + type: TokenType, + tokenBalances?: TokenBalancesMap +}) { function handle(tokenData: TokenData): void { props.setExpanded(false); @@ -21,37 +28,57 @@ export default function TokenListSection(props) { if (Object.keys(props.tokens).length === 0) return; return ( -
-

+

+

{props.type}

{Object.keys(props.tokens).map((key, _) => ( - - - +
+ ))}
) diff --git a/src/components/TransactionData/TransactionData.scss b/src/components/TransactionData/TransactionData.scss deleted file mode 100644 index 1174d9b..0000000 --- a/src/components/TransactionData/TransactionData.scss +++ /dev/null @@ -1,26 +0,0 @@ -@import '../WidgetUI/variables'; - -.br__transactionDataIcon { - width: 30px; - height: 30px; - border-radius: 50%; - - svg, - img { - width: 15px !important; - height: 15px !important; - } -} - - -.sk__openExplorerBtn { - svg { - width: 15px !important; - height: 15px !important; - } - - background-color: $sk-paper-color !important; - - height: 30px; - width: 30px; -} \ No newline at end of file diff --git a/src/components/TransactionData/TransactionData.tsx b/src/components/TransactionData/TransactionData.tsx deleted file mode 100644 index b5db127..0000000 --- a/src/components/TransactionData/TransactionData.tsx +++ /dev/null @@ -1,112 +0,0 @@ -/** - * @license - * SKALE Metaport - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -/** - * @file TransactionData.ts - * @copyright SKALE Labs 2023-Present -*/ - -import { ReactElement } from 'react'; - -import IconButton from '@mui/material/IconButton'; - -import MoveUpIcon from '@mui/icons-material/MoveUp'; -import MoveDownIcon from '@mui/icons-material/MoveDown'; -import LockOpenIcon from '@mui/icons-material/LockOpen'; -import ArrowOutwardIcon from '@mui/icons-material/ArrowOutward'; -import OpenInNewIcon from '@mui/icons-material/OpenInNew'; -import LogoutIcon from '@mui/icons-material/Logout'; -import DoneRoundedIcon from '@mui/icons-material/DoneRounded'; - -import { getTxUrl } from '../../core/explorer'; -import { MetaportConfig, TransactionHistory } from '../../core/interfaces'; - -import styles from "../WidgetUI/WidgetUI.scss"; -import localStyles from "./TransactionData.scss"; -import { clsNames } from '../../core/helper'; - - -const actionIcons: { [actionName: string]: ReactElement; } = { - 'deposit': , - 'transferToSchain': , - 'wrap': , - 'unwrap': , - 'getMyEth': , - 'withdraw': , - 'approve': , - 'approveWrap': , - 'wrapsfuel': -} - - -const actionAliases: { [actionName: string]: string; } = { - 'deposit': 'Deposit', - 'transferToSchain': 'Transfer', - 'wrap': 'Wrap', - 'unwrap': 'Unwrap', - 'getMyEth': 'Unlock ETH', - 'withdraw': 'Withdraw', - 'approve': 'Approve', - 'approveWrap': 'Approve wrap', - 'wrapsfuel': 'Wrap sFUEL' -} - - -export default function TransactionData(props: { - transactionData: TransactionHistory, - config: MetaportConfig -}) { - const explorerUrl = getTxUrl( - props.transactionData.chainName, - props.config.skaleNetwork, - props.transactionData.tx.transactionHash - ); - return (
-
-
- {actionIcons[props.transactionData.txName]} -
-
-
-
-

- {actionAliases[props.transactionData.txName]} -

-

- {new Date(props.transactionData.timestamp * 1000).toUTCString()} -

-
-
-
- - - -
-
) -} diff --git a/src/components/TransactionData/index.ts b/src/components/TransactionData/index.ts deleted file mode 100644 index d73f5d5..0000000 --- a/src/components/TransactionData/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./TransactionData"; diff --git a/src/components/TransactionsHistory/TransactionsHistory.tsx b/src/components/TransactionsHistory/TransactionsHistory.tsx deleted file mode 100644 index d2cefea..0000000 --- a/src/components/TransactionsHistory/TransactionsHistory.tsx +++ /dev/null @@ -1,119 +0,0 @@ - -/** - * @license - * SKALE Metaport - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -/** - * @file TransactionsHistory.ts - * @copyright SKALE Labs 2023-Present - */ - -import React from 'react'; - -import { Collapse } from '@mui/material'; -import Button from '@mui/material/Button'; - -import Accordion from '@mui/material/Accordion'; -import AccordionSummary from '@mui/material/AccordionSummary'; -import AccordionDetails from '@mui/material/AccordionDetails'; -import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; -import HistoryRoundedIcon from '@mui/icons-material/HistoryRounded'; -import ClearAllIcon from '@mui/icons-material/ClearAll'; - -import { TransactionHistory, MetaportConfig } from '../../core/interfaces'; -import TransactionData from '../TransactionData'; - -import { clsNames } from '../../core/helper'; -import styles from "../WidgetUI/WidgetUI.scss"; - - -export default function TransactionsHistory(props: { - transactionsHistory: TransactionHistory[], - clearTransactionsHistory: any, - config: MetaportConfig, - setExpanded: any, - expanded: string | false, - transferRequestView?: boolean -}) { - - const handleChange = - (panel: string) => (_: React.SyntheticEvent, isExpanded: boolean) => { - props.setExpanded(isExpanded ? panel : false); - }; - - function clearTransferHistory() { - props.clearTransactionsHistory(); - props.setExpanded(false); - } - - return ( - -
-
- - } - aria-controls="panel1a-content" - id="panel1a-header" - > -
-
- -
-

- Completed transactions ({props.transactionsHistory.length}) -

-
-
- -
- {props.transactionsHistory.map((transactionData: any) => ( - - ))} - -
- -
- -
-
-
-
) -} diff --git a/src/components/TransactionsHistory/index.ts b/src/components/TransactionsHistory/index.ts deleted file mode 100644 index 6519b11..0000000 --- a/src/components/TransactionsHistory/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./TransactionsHistory"; \ No newline at end of file diff --git a/src/components/TransferETA/TransferETA.tsx b/src/components/TransferETA/TransferETA.tsx deleted file mode 100644 index ebe5374..0000000 --- a/src/components/TransferETA/TransferETA.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import React, { useEffect } from 'react'; -import Tooltip from '@mui/material/Tooltip'; -import InfoIcon from '@mui/icons-material/Info'; -import Skeleton from '@mui/material/Skeleton'; - -import { isMainnet, clsNames } from '../../core/helper'; -import { IMA_M2S_WAIT, IMA_S2S_WAIT, IMA_HUB_WAIT } from '../../core/constants'; -import { getAvgWaitTime } from '../../core/gas_station'; -import styles from '../WidgetUI/WidgetUI.scss'; - - -export default function TransferETA(props) { - const [eta, setEta] = React.useState(); - const [isLoaded, setIsLoaded] = React.useState(false); - - async function calcETA() { - setIsLoaded(false); - let baseETA = 0; - const fromMainnet = isMainnet(props.transferRequest.chains[0]); - const toMainnet = isMainnet(props.transferRequest.chains[1]); - baseETA += fromMainnet || toMainnet ? IMA_M2S_WAIT : IMA_S2S_WAIT; - if (props.transferRequest.route && props.transferRequest.route.hub) baseETA += IMA_HUB_WAIT; - if (fromMainnet || toMainnet) baseETA += await getAvgWaitTime(); - setEta(baseETA) - setIsLoaded(true); - } - - useEffect(() => { - if (props.transferRequest) calcETA(); - }, [props.transferRequest]); - - const tooltipText = 'Estimated transfer time (may vary depending on the network load)'; - - return ( - -
-
-

- ETA -

- -
- {isLoaded ? ( -

~{eta}-{eta + 2} min

) : ( - - )} -
-
- ) -} diff --git a/src/components/TransferETA/index.ts b/src/components/TransferETA/index.ts deleted file mode 100644 index f7a5cb6..0000000 --- a/src/components/TransferETA/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./TransferETA"; diff --git a/src/components/TransferETF/TransferETF.tsx b/src/components/TransferETF/TransferETF.tsx deleted file mode 100644 index 626a592..0000000 --- a/src/components/TransferETF/TransferETF.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import React, { useEffect } from 'react'; -import Tooltip from '@mui/material/Tooltip'; -import InfoIcon from '@mui/icons-material/Info'; -import Skeleton from '@mui/material/Skeleton'; - -import { isMainnet, clsNames } from '../../core/helper'; -import { getTransactionFee } from '../../core/fee_calculator'; -import styles from '../WidgetUI/WidgetUI.scss'; - - -function roundDown(number, decimals) { - decimals = decimals || 0; - return (Math.floor(number * Math.pow(10, decimals)) / Math.pow(10, decimals)); -} - - -export default function TransferETF(props) { - const [etf, setEtf] = React.useState(); - const [isLoaded, setIsLoaded] = React.useState(false); - - async function calcETF() { - setIsLoaded(false); - const fromMainnet = isMainnet(props.transferRequest.chains[0]); - let baseETF = 0; - if (fromMainnet) baseETF = await getTransactionFee(props.transferRequest); - setEtf(baseETF) - setIsLoaded(true); - } - - useEffect(() => { - if (props.transferRequest) calcETF(); - }, [props.transferRequest]); - - const tooltipText = 'Estimated transaction fee (You pay only for Mainnet transactions, all transfers within SKALE are free)'; - const etfText = (etf === 0) ? 'Free' : `~${roundDown(etf, 3)} USD` - - return ( - -
-
-

- Estimated Transaction Fee -

- -
- {isLoaded ? ( -

{etfText}

) : ( - - )} -
-
- ) -} diff --git a/src/components/TransferETF/index.ts b/src/components/TransferETF/index.ts deleted file mode 100644 index 2e377d0..0000000 --- a/src/components/TransferETF/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./TransferETF"; diff --git a/src/components/TransferRequest/TransferRequest.tsx b/src/components/TransferRequest/TransferRequest.tsx deleted file mode 100644 index 689bab6..0000000 --- a/src/components/TransferRequest/TransferRequest.tsx +++ /dev/null @@ -1,217 +0,0 @@ -import Collapse from '@mui/material/Collapse'; -import Button from '@mui/material/Button'; - -import styles from "../WidgetUI/WidgetUI.scss"; -import { clsNames, getChainName } from '../../core/helper'; - -import ErrorMessage from '../ErrorMessage'; -import StepperV2 from '../StepperV2'; -import TransferSummary from '../TransferSummary'; -import Route from '../Route'; -import { getIconSrc } from "../TokenList/helper"; - -import TokenData from '../../core/dataclasses/TokenData'; -import EthTokenData from '../../core/dataclasses/EthTokenData'; -import { TransferRequestStatus } from '../../core/dataclasses'; -import { TokenType } from '../../core/dataclasses/TokenType'; -import * as interfaces from '../../core/interfaces/index'; -import { isTransferRequestSteps } from '../../core/views'; - -import TransactionsHistory from '../TransactionsHistory'; -import SkeletonLoader from '../SkeletonLoader'; -import WrappedTokensWarning from '../WrappedTokensWarning'; -import SFuelWarning from '../SFuelWarning'; -import AmountErrorMessage from '../AmountErrorMessage'; -import CommunityPool from '../CommunityPool'; - - -function getTokenDataFromConfig( - configTokens: interfaces.TokensMap, - transferRequest: interfaces.TransferParams -): TokenData { - // TODO: refactor! - - if (transferRequest.tokenType === TokenType.eth) { - return new EthTokenData(false); - } - - let configToken; - let isClone = false; - - const fromChainName = transferRequest.chains[0]; - const toChainName = transferRequest.route ? transferRequest.route.hub : transferRequest.chains[1]; - - if (configTokens[fromChainName] && - configTokens[fromChainName][transferRequest.tokenType] && - configTokens[fromChainName][transferRequest.tokenType][transferRequest.tokenKeyname]) { - configToken = configTokens[fromChainName][transferRequest.tokenType][transferRequest.tokenKeyname]; - } - if (configTokens[toChainName] && - configTokens[toChainName][transferRequest.tokenType] && - configTokens[toChainName][transferRequest.tokenType][transferRequest.tokenKeyname]) { - configToken = configTokens[toChainName][transferRequest.tokenType][transferRequest.tokenKeyname]; - isClone = true; - } - if (!configToken) return; - - let unwrappedSymbol; - let unwrappedAddress; - let unwrappedIconUrl; - if (configToken.wraps) { - unwrappedSymbol = configToken.wraps.symbol; - unwrappedAddress = configToken.wraps.address; - unwrappedIconUrl = configToken.wraps.iconUrl; - } - - return new TokenData( - null, - configToken.address, - configToken.name, - configToken.symbol, - configToken.cloneSymbol, - isClone, - configToken.iconUrl, - configToken.decimals, - transferRequest.tokenType, - unwrappedSymbol, - unwrappedAddress, - unwrappedIconUrl - ); -} - - -export default function TransferRequest(props) { - if (!props.transferRequest) { - return () - } - - const trReq: interfaces.TransferParams = props.transferRequest; - const token = getTokenDataFromConfig(props.config.tokens, trReq); - - const fromChainName = getChainName( - props.config.chainsMetadata, - trReq.chains[0], - props.config.skaleNetwork, - trReq.fromApp - ); - const toChainName = getChainName( - props.config.chainsMetadata, - trReq.chains[1], - props.config.skaleNetwork, - trReq.toApp - ); - - let explanationText = 'Transfer assets from ' + fromChainName + ' to ' + toChainName + '.'; - if (trReq.route) { - const hubChainName = getChainName( - props.config.chainsMetadata, - trReq.route.hub, - props.config.skaleNetwork - ); - if (token.clone) { - explanationText += ' Tokens will be unwrapped on ' + hubChainName + '.'; - } else { - explanationText += ' Tokens will be wrapped on ' + hubChainName + '.'; - } - }; - - const showAmount = trReq.lockValue && trReq.amount; - let amountText = showAmount ? `${trReq.amount} ${token.symbol}` : token.symbol; - amountText += trReq.tokenId ? ` (#${trReq.tokenId})` : ''; - - return ( -
- -
-

Transfer

- -

- {amountText} -

-
- - - - - - - {isTransferRequestSteps(props.view) ? - : - - } - - - -

- 💫 You've successfully transferred {amountText} from {fromChainName} to {toChainName}. -

- -
- - {props.transferRequestStep === 0 ? () : null} - - - -
- - - - - - -
- ) -} diff --git a/src/components/TransferRequest/index.ts b/src/components/TransferRequest/index.ts deleted file mode 100644 index 51e3ef6..0000000 --- a/src/components/TransferRequest/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./TransferRequest"; diff --git a/src/components/TransferSummary/TransferSummary.scss b/src/components/TransferSummary/TransferSummary.scss deleted file mode 100644 index abd3c86..0000000 --- a/src/components/TransferSummary/TransferSummary.scss +++ /dev/null @@ -1,71 +0,0 @@ -.mp__labelStep { - // font-weight: 600 !important; - text-transform: uppercase !important; - font-size: 0.6525rem !important; - line-height: 1.6 !important; - letter-spacing: 0.02857em !important; -} - -.mp__stepper { - - :global span { - font-weight: 600 !important; - text-transform: none !important; - font-size: 0.9025rem !important; - line-height: 1.6 !important; - //letter-spacing: 0.02857em !important; - font-family: inherit !important; - } - - :global .MuiStepConnector-line { - min-height: 0 !important; - } - - :global .MuiBox-root { - margin-bottom: 5px !important; - } - - :global .MuiSvgIcon-root { - width: 22px; - height: 22px; - align-items: start; - } - - :global .MuiStepContent-root { - padding-right: 0; - margin-left: 8px; - padding-left: 18px; - border-left: none !important; - } - - :global(.MuiChip-icon) { - width: 15pt; - height: 15pt; - } - - :global(.MuiStepLabel-root) { - align-items: start; - } - - :global(.MuiStepLabel-iconContainer) { - margin-top: 11pt; - } - - :global(.MuiStepLabel-labelContainer) { - img { - filter: saturate(0) opacity(0.7); - } - - } - - - :global(.MuiStepLabel-label.Mui-active) { - span, svg { - color: inherit; - } - - img { - filter: inherit; - } - } -} \ No newline at end of file diff --git a/src/components/TransferSummary/TransferSummary.tsx b/src/components/TransferSummary/TransferSummary.tsx deleted file mode 100644 index ba82dd7..0000000 --- a/src/components/TransferSummary/TransferSummary.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import Box from '@mui/material/Box'; -import Button from '@mui/material/Button'; -import { clsNames } from '../../core/helper'; -import styles from '../WidgetUI/WidgetUI.scss'; -import AmountInput from "../AmountInput"; - -import TransferETA from '../TransferETA'; -import TransferETF from '../TransferETF'; -import { Collapse } from '@mui/material'; - - -export default function TransferSummary(props) { - const text = props.transferRequest && props.transferRequest.text ? props.transferRequest.text : props.explanationText; - return ( - -
- -
- -
-
- - {props.transferRequest.lockValue ? null :
-

- Amount -

- -
- } - -

- {text} -

- -
-
- ); -} \ No newline at end of file diff --git a/src/components/TransferSummary/index.ts b/src/components/TransferSummary/index.ts deleted file mode 100644 index 3de6f45..0000000 --- a/src/components/TransferSummary/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./TransferSummary"; diff --git a/src/components/TransferUI/TransferUI.tsx b/src/components/TransferUI/TransferUI.tsx deleted file mode 100644 index 97bb79a..0000000 --- a/src/components/TransferUI/TransferUI.tsx +++ /dev/null @@ -1,197 +0,0 @@ -import Collapse from '@mui/material/Collapse'; -import Skeleton from '@mui/material/Skeleton'; -import IconButton from '@mui/material/IconButton'; -import Tooltip from '@mui/material/Tooltip'; -import ImportExportIcon from '@mui/icons-material/ImportExport'; - -import { clsNames } from '../../core/helper'; -import styles from '../WidgetUI/WidgetUI.scss'; - -import ChainsList from '../ChainsList'; -import TokenList from '../TokenList'; -import AmountInput from '../AmountInput'; -import TokenIdInput from '../TokenIdInput'; -import Stepper from '../Stepper'; -import AmountErrorMessage from '../AmountErrorMessage'; -import CommunityPool from '../CommunityPool'; - -import { TokenType } from '../../core/dataclasses/TokenType'; - - -export default function TransferUI(props) { - return ( -
- - - { - let chain1 = props.chain1; - props.cleanData(); - props.setChain1(props.chain2); - props.setChain2(chain1); - }}> - - - - - - -
-

- TO -

- {/*
- -
*/} -
- -
- - - -

- Token -

-
- -
- {(props.loadingTokens || props.transferRequest) ? ( - ) : ()} -
-
- -
- -
-
- -
- -
-
- -
- -
- {!props.token ? ( -
- ) : ( -
- {(!props.actionSteps) ? () : ()} -
- )} -
-
- - - -
- ) -} \ No newline at end of file diff --git a/src/components/TransferUI/index.ts b/src/components/TransferUI/index.ts deleted file mode 100644 index 4a06d20..0000000 --- a/src/components/TransferUI/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./TransferUI"; diff --git a/src/components/UnwrapUI/UnwrapUI.tsx b/src/components/UnwrapUI/UnwrapUI.tsx deleted file mode 100644 index c9bc287..0000000 --- a/src/components/UnwrapUI/UnwrapUI.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import Skeleton from '@mui/material/Skeleton'; -import Button from '@mui/material/Button'; -import Collapse from '@mui/material/Collapse'; -import RocketLaunchIcon from '@mui/icons-material/RocketLaunch'; - -import { clsNames } from '../../core/helper'; -import styles from '../WidgetUI/WidgetUI.scss'; - -import Stepper from '../Stepper'; -import TokenList from '../TokenList'; -import AmountErrorMessage from '../AmountErrorMessage'; - - -export default function UnwrapUI(props) { - if (!props.wrappedTokens || !props.wrappedTokens.erc20) return; - const wrappedTokens = Object.entries(props.wrappedTokens.erc20); - if (wrappedTokens.length === 0) return ( -
-
- -
-
-

- You don't have any wrapped tokens -

-
- -
- ); - - return ( -
- - - - - -
- {!props.token ? ( -
- ) : ( -
- {(!props.actionSteps) ? () : ()} -
- )} -
-
-
- ) -} \ No newline at end of file diff --git a/src/components/UnwrapUI/index.ts b/src/components/UnwrapUI/index.ts deleted file mode 100644 index 2271cd1..0000000 --- a/src/components/UnwrapUI/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./UnwrapUI"; diff --git a/src/components/WalletConnector/Connector.tsx b/src/components/WalletConnector/Connector.tsx deleted file mode 100644 index 47ce418..0000000 --- a/src/components/WalletConnector/Connector.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import Paper from '@mui/material/Paper'; -import ButtonBase from '@mui/material/ButtonBase/ButtonBase'; - -import metamaskLogo from './metamask.svg'; - -import { clsNames } from '../../core/helper'; -import styles from '../WidgetUI/WidgetUI.scss'; - - -export function Connector(props) { - return ( -
-

- Connect a wallet -

- - -

Metamask

- logo -
-
- {/* -
- - -

WalletConnect

- logo -
-
-
-
*/} -
- ) -} \ No newline at end of file diff --git a/src/components/WalletConnector/MetamaskConnector.ts b/src/components/WalletConnector/MetamaskConnector.ts deleted file mode 100644 index 67eba54..0000000 --- a/src/components/WalletConnector/MetamaskConnector.ts +++ /dev/null @@ -1,95 +0,0 @@ -import Web3 from 'web3'; - -export const CHAIN_IDS = { - 'staging': '0x4', - 'staging3': '0x5', - 'legacy': '0x5', - 'qatestnet': '0x4', - 'mainnet': '0x1' -} - - -export async function changeMetamaskNetwork(networkParams) { - try { - await window.ethereum.request({ - method: 'wallet_switchEthereumChain', - params: [{ chainId: networkParams.chainId }], - }); - } catch (switchError) { - // This error code indicates that the chain has not been added to MetaMask. - if (switchError.code === 4902) { - try { - await window.ethereum.request({ - method: 'wallet_addEthereumChain', - params: [networkParams], - }); - return [0, new Web3(window.ethereum)]; - } catch (addError) { - return [1, addError]; - } - } - return [1, switchError]; - } - return [0, new Web3(window.ethereum)]; -} - - -export const connect = (connectFallback) => { - window.ethereum - .request({ method: 'eth_requestAccounts' }) - .then(connectFallback) - .catch((err) => { - if (err.code === 4001) { - // EIP-1193 userRejectedRequest error - // If this happens, the user rejected the connection request. - // console.log('Please connect to MetaMask.'); - } else { - // console.error(err); - } - }); -} - - -export const addAccountChangedListener = (accountsChangedFallback) => { - window.ethereum.on('accountsChanged', accountsChangedFallback); // todo: do only once!!!! - window.ethereum - .request({ method: 'eth_accounts' }) - .then(accountsChangedFallback) - .catch((_) => { - // Some unexpected error. - // For backwards compatibility reasons, if no accounts are available, - // eth_accounts will return an empty array. - // console.error(err); - }); -} - - -export const addChainChangedListener = (chainChangedFallback) => { - window.ethereum.on('chainChanged', chainChangedFallback); -} - - -export function schainNetworkParams( - chainName: string, - schainChainUrl: string, - schainChainId: string -) { - return { - chainId: schainChainId, - chainName: "[S] " + chainName, - rpcUrls: [schainChainUrl], - nativeCurrency: { - name: "sFUEL", - symbol: "sFUEL", - decimals: 18 - } - }; -} - - -export function mainnetNetworkParams(network: string, mainnetEndpoint: string) { - return { - chainId: CHAIN_IDS[network], - rpcUrls: [mainnetEndpoint], - }; -} diff --git a/src/components/WalletConnector/index.ts b/src/components/WalletConnector/index.ts deleted file mode 100644 index 35ce818..0000000 --- a/src/components/WalletConnector/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./MetamaskConnector"; -export * from "./Connector"; diff --git a/src/components/WalletConnector/metamask.svg b/src/components/WalletConnector/metamask.svg deleted file mode 100644 index 6cb41ba..0000000 --- a/src/components/WalletConnector/metamask.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/components/WalletConnector/walletconnect.svg b/src/components/WalletConnector/walletconnect.svg deleted file mode 100644 index d90457a..0000000 --- a/src/components/WalletConnector/walletconnect.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/components/Widget/Widget.mdx b/src/components/Widget/Widget.mdx index fd677d5..bdf93cc 100644 --- a/src/components/Widget/Widget.mdx +++ b/src/components/Widget/Widget.mdx @@ -9,7 +9,6 @@ import Button from "@mui/material/Button"; import { internalEvents } from "../../core/events"; import * as WidgetStories from "./Widget.stories"; -import { TransferRequestEditor } from "../WidgetUI/StorybookHelper"; # Functional Metaport Demo @@ -21,8 +20,5 @@ import { TransferRequestEditor } from "../WidgetUI/StorybookHelper"; -## Transfer request mode - You can try functional Metaport demo in a Transfer request mode here. - {TransferRequestEditor()} diff --git a/src/components/Widget/Widget.stories.tsx b/src/components/Widget/Widget.stories.tsx index 4b15ec7..c052ee8 100644 --- a/src/components/Widget/Widget.stories.tsx +++ b/src/components/Widget/Widget.stories.tsx @@ -1,16 +1,15 @@ import type { Meta, StoryObj } from '@storybook/react'; -import { Widget } from "./Widget"; -import { storyDecorator } from "../WidgetUI/StorybookHelper"; +import Widget from "./Widget"; +// import { storyDecorator } from "../WidgetUI/StorybookHelper"; - -const METAPORT_CONFIG = require('../../configs/metaportConfigStaging.json'); +const METAPORT_CONFIG = require('../../metadata/metaportConfigStaging.json'); METAPORT_CONFIG.mainnetEndpoint = process.env.STORYBOOK_MAINNET_ENDPOINT; const meta: Meta = { title: "Functional/Widget", component: Widget, - decorators: [storyDecorator], + // decorators: [storyDecorator], }; export default meta; diff --git a/src/components/Widget/Widget.tsx b/src/components/Widget/Widget.tsx index d865d0a..e2df2f7 100644 --- a/src/components/Widget/Widget.tsx +++ b/src/components/Widget/Widget.tsx @@ -1,908 +1,144 @@ -import React, { useEffect } from 'react'; -import debug from 'debug'; -import WidgetUI from '../WidgetUI'; -import { getWidgetTheme } from '../WidgetUI/Themes'; -import { WrongNetworkMessage, TransactionErrorMessage } from '../ErrorMessage'; +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +/** + * @file Widget.ts + * @copyright SKALE Labs 2023-Present + */ + +import { useEffect } from 'react'; import { - initSChain, - initSChainMetamask, - initMainnet, - initMainnetMetamask, - updateWeb3SChain, - updateWeb3Mainnet, - updateWeb3SChainMetamask, - updateWeb3MainnetMetamask, - getChainId -} from '../../core'; + RainbowKitProvider, + darkTheme, + lightTheme +} from '@rainbow-me/rainbowkit'; +import { configureChains, createConfig, WagmiConfig } from 'wagmi'; +import { mainnet, goerli } from 'wagmi/chains'; +import { jsonRpcProvider } from 'wagmi/providers/jsonRpc'; +import { connectorsForWallets } from '@rainbow-me/rainbowkit'; -import { getCommunityPoolData, getEmptyCommunityPoolData } from '../../core/community_pool'; -import { getAvailableTokens, getTokenBalances } from '../../core/tokens/index'; -import { getWrappedTokens } from '../../core/tokens/erc20'; -import { getEmptyTokenDataMap, getDefaultToken } from '../../core/tokens/helper'; -import { MainnetChain, SChain } from '@skalenetwork/ima-js'; -import { connect, addAccountChangedListener, addChainChangedListener } from '../WalletConnector' -import { externalEvents } from '../../core/events'; import { - MAINNET_CHAIN_NAME, - DEFAULT_ERROR_MSG, - DEFAULT_ERC20_DECIMALS, - COMMUNITY_POOL_WITHDRAW_GAS_LIMIT, - BALANCE_UPDATE_INTERVAL_SECONDS -} from '../../core/constants'; -import { getActionName, getActionSteps } from '../../core/actions'; -import { ActionType } from '../../core/actions/action'; + injectedWallet, + coinbaseWallet, + metaMaskWallet +} from '@rainbow-me/rainbowkit/wallets'; -import { isTransferRequestActive, delay } from '../../core/helper'; -import { getTransferSteps } from '../../core/transfer_steps'; +import { MetaportConfig } from "core/interfaces" -import * as interfaces from '../../core/interfaces/index'; -import { TransactionHistory, CommunityPoolData, MetaportTheme } from '../../core/interfaces'; -import TokenData from '../../core/dataclasses/TokenData'; -import { TransferRequestStatus } from '../../core/dataclasses/TransferRequestStatus'; -import { View } from '../../core/dataclasses/View'; -import { TokenType } from '../../core/dataclasses'; +import WidgetUI from '../WidgetUI' +import { useUIStore } from '../../store/Store' +import { useMetaportStore } from '../../store/MetaportState' +import { getWidgetTheme } from '../../core/themes'; +import MetaportCore from '../../core/metaport' -import { toWei } from '../../core/convertation'; +import '@rainbow-me/rainbowkit/styles.css'; +import { constructWagmiChain, getWebSocketUrl } from '../../core/wagmi_network'; -debug.enable('*'); -const log = debug('metaport:WidgetV2'); - -export function Widget(props) { - - // STATE - - const [walletConnected, setWalletConnected] = React.useState(undefined); - - const [availableTokens, setAvailableTokens] = React.useState( - getEmptyTokenDataMap() - ); - const [wrappedTokens, setWrappedTokens] = React.useState( - getEmptyTokenDataMap() - ); - - const [chainId, setChainId] = React.useState(undefined); - const [extChainId, setExtChainId] = React.useState(undefined); - - const [amountLocked, setAmountLocked] = React.useState(false); - - const [address, setAddress] = React.useState(undefined); - - const [amount, setAmount] = React.useState(''); - const [tokenId, setTokenId] = React.useState(); - - const [sFuelData1, setSFuelData1] = React.useState(undefined); - const [sFuelData2, setSFuelData2] = React.useState(undefined); - - const [chainName1, setChainName1] = React.useState(undefined); - const [chainName2, setChainName2] = React.useState(undefined); - - const [sChain1, setSChain1] = React.useState(undefined); - const [sChain2, setSChain2] = React.useState(undefined); - const [mainnet, setMainnet] = React.useState(undefined); - - const [token, setToken] = React.useState(undefined); - - const [activeStep, setActiveStep] = React.useState(0); - const [actionName, setActionName] = React.useState(undefined); - const [actionSteps, setActionSteps] = React.useState(undefined); - - const [loading, setLoading] = React.useState(false); - const [loadingTokens, setLoadingTokens] = React.useState(false); - const [actionBtnDisabled, setActionBtnDisabled] = React.useState(false); - - const [open, setOpen] = React.useState(props.config.openOnLoad); - const [firstOpen, setFirstOpen] = React.useState(props.config.openOnLoad); - - const [sFuelOk, setSFuelOk] = React.useState(false); - - const [view, setView] = React.useState(View.SANDBOX); - - const [theme, setTheme] = React.useState(getWidgetTheme(props.config.theme)); - - const [transferRequest, setTransferRequest] = React.useState( - undefined); - const [transferRequestStatus, setTransferRequestStatus] = React.useState( - TransferRequestStatus.NO_REQEST); - const [transferRequestStep, setTransferRequestStep] = React.useState(0); - const [transferRequestSteps, setTransferRequestSteps] = React.useState>(); - const [transferRequestLoading, setTransferRequestLoading] = React.useState(false); - - const [errorMessage, setErrorMessage] = React.useState(undefined); - const [amountErrorMessage, setAmountErrorMessage] = React.useState(undefined); - - const [transactionsHistory, setTransactionsHistory] = React.useState([]); - - const [btnText, setBtnText] = React.useState(); - - const [communityPoolData, setCommunityPoolData] = React.useState( - getEmptyCommunityPoolData()); - const [rechargeAmount, setRechargeAmount] = React.useState(''); - const [loadingCommunityPool, setLoadingCommunityPool] = React.useState(false); - const [updateCommunityDataFlag, setUpdateCommunityDataFlag] = React.useState(false); - - // EFFECTS - - useEffect(() => { - setWalletConnected(false); - addAccountChangedListener(accountsChangedFallback); - addChainChangedListener(chainChangedFallback); - addinternalEventsListeners(); - updateTransactionCompletedEventListener(); - const interval = setInterval( - () => { setUpdateCommunityDataFlag((updateCommunityDataFlag) => !updateCommunityDataFlag) }, - BALANCE_UPDATE_INTERVAL_SECONDS * 1000 - ); - return () => { - window.removeEventListener('metaport_transactionCompleted', transactionCompleted, false); - clearInterval(interval); - }; - }, []); - - useEffect(() => { - if (open && !firstOpen) setFirstOpen(true); - }, [open]); - - useEffect(() => { - if (!open && !firstOpen) return; - if (chainName1 !== MAINNET_CHAIN_NAME && chainName2 !== MAINNET_CHAIN_NAME) setMainnet(null); - if (chainName1) setChainId(getChainId(props.config.skaleNetwork, chainName1)); - if (address && chainName1) { - if (chainName1 == MAINNET_CHAIN_NAME) { - initMainnet1(); - } else { - initSchain1(); - } - } - }, [chainName1, address]); - - useEffect(() => { - if (chainName1 !== MAINNET_CHAIN_NAME && chainName2 !== MAINNET_CHAIN_NAME) setMainnet(null); - if (address && chainName2) { - if (chainName2 == MAINNET_CHAIN_NAME) { - setMainnet(initMainnet(props.config.skaleNetwork, props.config.mainnetEndpoint)) - } else { - log(`Running initSchain2: ${chainName2}`); - setSChain2(initSChain( - props.config.skaleNetwork, - chainName2 - )); - } - log(`chain2 changed ${chainName2}`); - } - }, [chainName2, address]); - - useEffect(() => { - if (props.config.tokens) checkWrappedTokens(); - if (((sChain1 && sChain2) || (sChain1 && mainnet) || (mainnet && sChain2))) { - externalEvents.connected(); - setToken(undefined); - setLoading(false); - setActiveStep(0); - updateCommunityPoolData(); - tokenLookup(); - } - }, [sChain1, sChain2, mainnet]); - - useEffect(() => { - if (!loadingCommunityPool) { - updateCommunityPoolData(); - } - }, [updateCommunityDataFlag]); - - useEffect(() => { - if (communityPoolData.recommendedRechargeAmount) { - setRechargeAmount(communityPoolData.recommendedRechargeAmount); - } - }, [communityPoolData]); - - async function updateCommunityPoolData() { - const cpData = await getCommunityPoolData( - address, - chainName1, - chainName2, - mainnet, - sChain1 - ); - setCommunityPoolData(cpData); - return cpData; - } - - useEffect(() => { - log(`view changed: ${view}`); - - setToken(undefined); - setAmountLocked(false); - setActiveStep(0); - setActionSteps(undefined); - setActionName(undefined); - setTransferRequestStep(0); - - if (view !== null) return; - if (transferRequest) { - if (transferRequestStatus === TransferRequestStatus.RECEIVED) { - setView(View.TRANSFER_REQUEST_SUMMARY); - } else { - setView(View.TRANSFER_REQUEST_STEPS); - } - } else { - setView(View.SANDBOX); - } - }, [view]); - - useEffect(() => { - if (isTransferRequestActive(transferRequestStatus)) { - const tokenKeyname = (transferRequest.route && transferRequestStatus === TransferRequestStatus.IN_PROGRESS_HUB) ? transferRequest.route.tokenKeyname : transferRequest.tokenKeyname; - const tokenType = (transferRequest.route && transferRequestStatus === TransferRequestStatus.IN_PROGRESS_HUB) ? transferRequest.route.tokenType : transferRequest.tokenType; - log(`Loading transfer request - ${tokenKeyname}, ${transferRequest.amount}, ${transferRequest.tokenId}`); - const tokenData = availableTokens[tokenType][tokenKeyname]; - if (!tokenData) { - setTransferRequestStatus(TransferRequestStatus.ERROR); - log(`No token data: ${tokenKeyname}`); - log(availableTokens); - return - } - setToken(tokenData); - setAmount(transferRequest.amount); - setTokenId(transferRequest.tokenId); - // setTransferRequestStatus(TransferRequestStatus.IN_PROGRESS); - setTransferRequestLoading(false); - log(`Loading transfer request - DONE`); - } - }, [availableTokens]); - - useEffect(() => { - setDefaultWrappedToken(); - }, [wrappedTokens]); - - useEffect(() => { - setAmountErrorMessage(undefined); - setActiveStep(0); - setActionSteps(undefined); - setActionName(undefined); - if (token === undefined) return; - let actionName = getActionName(chainName1, chainName2, token.type, view); - setActionName(actionName); - }, [chainName1, chainName2, token, availableTokens, view]); - - useEffect(() => { - if (!actionName || !token) return; - setActionSteps(getActionSteps(actionName, token)); - if (actionName === 'erc20_unwrap') { // TODO: tmp fix to unwrap - log('Setting max amount for unwrap: ' + token.balance); - setAmount(token.balance); - } - }, [actionName, token]); - - useEffect(() => { - setAmountErrorMessage(undefined); - runPreAction(); - }, [actionSteps, activeStep, amount, tokenId]); - - useEffect(() => { - if (transferRequestStatus === TransferRequestStatus.DONE) { - log('Transfer request completed'); - externalEvents.transferRequestCompleted(transferRequest); - setTransferRequestStep(0); - } - }, [transferRequestStatus]); - - useEffect(() => { - if (token && transferRequest) { - if (transferRequestStatus === TransferRequestStatus.IN_PROGRESS) { - setTransferRequestSteps(getTransferSteps(transferRequest, props.config, theme, token)); - } - } - }, [token, transferRequest]); - - useEffect(() => { - // TODO: tmp fix for unwrap - const isUnwrapActionSteps = activeStep === 1 || activeStep === 2; - const isUwrapAction = token && token.unwrappedSymbol && token.clone && isUnwrapActionSteps; - const isUnlockAction = actionName === 'eth_s2m' && isUnwrapActionSteps; - if (extChainId && chainId && extChainId !== chainId && !isUwrapAction && !isUnlockAction - && !transferRequestLoading) { - log('_MP_INFO: setting WrongNetworkMessage'); - setTransferRequestLoading(true); - setErrorMessage(new WrongNetworkMessage(enforceMetamaskNetwork)); - } else { - setErrorMessage(undefined); - } - }, [extChainId, chainId, token, activeStep, transferRequest, view]); - - - useEffect(() => { - updateTransactionCompletedEventListener() - }, [transactionsHistory]); - - // FALLBACKS & HANDLERS - - function transactionCompleted(e: any) { - transactionsHistory.push(e.detail); // todo: fix - setTransactionsHistory([...transactionsHistory]); - } - - function updateTransactionCompletedEventListener() { - window.removeEventListener("metaport_transactionCompleted", transactionCompleted, false); - window.addEventListener("metaport_transactionCompleted", transactionCompleted, false); - } - - function clearTransactionsHistory() { - updateTransactionCompletedEventListener(); - setTransactionsHistory([]); - } - - function addinternalEventsListeners() { - window.addEventListener("_metaport_transfer", transferHandler, false); - window.addEventListener("_metaport_close", closeHandler, false); - window.addEventListener("_metaport_open", openHandler, false); - window.addEventListener("_metaport_reset", resetHandler, false); - window.addEventListener("_metaport_setTheme", themeHandler, false); - } - - function chainChangedFallback(_extChainId: string): void { - setExtChainId(_extChainId); - } - - function accountsChangedFallback(accounts) { - if (accounts.length === 0) { - // MetaMask is locked or the user has not connected any accounts - console.log('Please connect to MetaMask!'); - } else { - setAddress(accounts[0]); - setWalletConnected(true); - } - } - - function networkConnectFallback(accounts) { - if (accounts.length === 0) { - // MetaMask is locked or the user has not connected any accounts - console.log('Please connect to MetaMask!'); - } - // todo: handle accounts in Metamask module - - setAddress(accounts[0]); - setWalletConnected(true); - externalEvents.connected(); - } - - function transferHandler(e) { - resetWidgetState(false); - const params: interfaces.TransferParams = e.detail.params; - - const { - tokenType, - tokenId, - amount, - } = params; - - if (tokenType === TokenType.erc20 || tokenType === TokenType.erc1155) { - if (!amount) { - log('! ERROR: amount is required for this token type'); - return; - } - if (tokenType === TokenType.erc20 && tokenId) { - log('! WARNING: tokenId will be ignored for this token type'); - params.tokenId = undefined; - } - } - - if ( - tokenType === TokenType.erc721 || - tokenType === TokenType.erc721meta || - tokenType === TokenType.erc1155 - ) { - if (!tokenId) { - log('! ERROR: tokenId is required for this token type'); - } - if ( - (tokenType === TokenType.erc721 || tokenType === TokenType.erc721meta) && - amount - ) { - log('! WARNING: amount will be ignored for this token type'); - params.amount = undefined; - } - } - - params.lockValue = true; // todo: tmp fix - setTransferRequestStatus(TransferRequestStatus.RECEIVED); - setTransferRequest(params); - setView(View.TRANSFER_REQUEST_SUMMARY); - setOpen(true); - } - - function closeHandler(_) { - setOpen(false); - log('closeWidget event processed'); - } - - function openHandler(_) { - setOpen(true); - log('openWidget event processed'); - } - - function resetHandler(_) { - resetWidgetState(false); - log('resetWidget event processed'); - } - - function themeHandler(e) { - const theme: MetaportTheme = e.detail.theme; - setTheme(getWidgetTheme(theme)); - log('setTheme event processed'); - } - - function connectMetamask() { - console.log('connectMetamask...'); - connect(networkConnectFallback); - externalEvents.connected(); - console.log('Done: connectMetamask...'); - } - - const handleNextStep = async () => { - setLoading(true); - const ActionClass: ActionType = actionSteps[activeStep]; - try { - await new ActionClass( - mainnet, - sChain1, - sChain2, - chainName1, - chainName2, - address, - amount, - tokenId, - token, - switchMetamaskChain, - setActiveStep, - activeStep, - setAmountErrorMessage, - setBtnText - ).execute(); - } catch (err) { - console.error(err); - const msg = err.message ? err.message : DEFAULT_ERROR_MSG; - setErrorMessage(new TransactionErrorMessage(msg, errorMessageClosedFallback)); - return; - } - await updateTokenBalances(); - setLoading(false); - setActiveStep((prevActiveStep) => prevActiveStep + 1); - setTransferRequestStep((prevTrReqStep) => prevTrReqStep + 1); - if (transferRequestStatus === TransferRequestStatus.IN_PROGRESS && transferRequest.route) { - // TODO: tmp fix for unwrap - if (actionSteps.length !== 2 || (actionSteps.length === 2 && transferRequestStep === 1)) { - moveToHub(); - } - } - if (transferRequestSteps && transferRequestSteps.length !== 0 && - transferRequestStep === transferRequestSteps.length - 1) { - setTransferRequestStatus(TransferRequestStatus.DONE); - } - }; - - function errorMessageClosedFallback() { - setLoading(false); - setAmountLocked(false); - setErrorMessage(undefined); - } - - // CORE FUNCTIONS - - async function enforceMetamaskNetwork() { - if (!chainName1) { - setErrorMessage(undefined); - return; - } - if (chainName1 === MAINNET_CHAIN_NAME) { - await initMainnet1(); - } else { - await initSchain1(); - } - } - - function confirmSummary() { - setLoading(true); - setView(View.TRANSFER_REQUEST_STEPS); - setTransferRequestStatus(TransferRequestStatus.IN_PROGRESS); - const fromChain = transferRequest.chains[0]; - const toChain = transferRequest.route ? transferRequest.route.hub : transferRequest.chains[1]; - log(`confirmSummary - fromChain: ${fromChain}, toChain: ${toChain}`); - setChainName1(fromChain); - setChainName2(toChain); - } - - function moveToHub() { - setTransferRequestLoading(true); - setTransferRequestStatus(TransferRequestStatus.IN_PROGRESS_HUB); - const fromChain = transferRequest.route.hub; - const toChain = transferRequest.chains[1]; - log(`moveToHub - fromChain: ${fromChain}, toChain: ${toChain}`); - setChainName1(fromChain); - setChainName2(toChain); - } - - async function initSchain1() { - log('Running initSchain1...'); - setSChain1(await initSChainMetamask( - props.config.skaleNetwork, - chainName1, - props.config.chainsMetadata - )); - } - - async function initMainnet1() { - log(`Running initSchain1: ${chainName1}`); - const mainnetMetamask = await initMainnetMetamask( - props.config.skaleNetwork, - props.config.mainnetEndpoint - ); - setMainnet(mainnetMetamask); - return mainnetMetamask; - } - - async function checkWrappedTokens() { - if (!sChain1 || !chainName1) { - log('No chainName1 or sChain1, skipping checkWrappedTokens'); - setWrappedTokens(getEmptyTokenDataMap()); - return; - } - log('_MP_INFO: Running checkWrappedTokens'); - try { - const wrappedTokens = await getWrappedTokens(sChain1, chainName1, props.config.tokens, address); - if (Object.entries(wrappedTokens).length === 0 && view !== View.SANDBOX) { - setAmount(''); - setView(View.SANDBOX); - } - setWrappedTokens(wrappedTokens); - } catch (err) { - log('_MP_ERROR: checkWrappedTokens failed!'); - log(err); - } - } - - function setDefaultWrappedToken() { - const defaultToken = getDefaultToken(wrappedTokens); - if (defaultToken && view === View.UNWRAP) { - log(`Setting defaultToken: ${defaultToken.keyname} from wrappedTokens`) - setToken(defaultToken); - } - } - - async function tokenLookup() { - setLoadingTokens(true); - try { - let tokens = await getAvailableTokens( +const { chains, webSocketPublicClient } = configureChains( + [ mainnet, - sChain1, - sChain2, - chainName1, - chainName2, - props.config.tokens, - props.autoLookup - ); - await getTokenBalances( - tokens, - chainName1, - mainnet, - sChain1, - address - ); - setAvailableTokens(tokens); - } catch (err) { - log('_MP_ERROR: tokenLookup failed'); - log(err); - } - setLoadingTokens(false); - } - - async function updateTokenBalances() { - let tokens = availableTokens; - await getTokenBalances( - tokens, - chainName1, - mainnet, - sChain1, - address - ); - setAvailableTokens(tokens); - checkWrappedTokens(); - } - - function resetWidgetState(keepTransferRequest: boolean) { - setAvailableTokens(getEmptyTokenDataMap()); - setWrappedTokens(getEmptyTokenDataMap()); - setToken(undefined); - - setAmount(''); - setTokenId(0); - - setChainName1(null); - setChainName2(null); - - setTransferRequestStep(0); - - setSChain1(null); - setSChain2(null); - setMainnet(null); - - setLoading(false); - - setView(View.SANDBOX); - - setSFuelData1({}); - setSFuelData2({}); - - setAmountLocked(false); - setActiveStep(0); - setActionSteps(undefined); - setActionName(undefined); - setAmountErrorMessage(undefined); - setActionBtnDisabled(false); - setTransferRequestLoading(false); - setTransferRequestStatus(TransferRequestStatus.NO_REQEST); - - setCommunityPoolData(getEmptyCommunityPoolData()); - - if (transferRequest && keepTransferRequest) { - setTransferRequestStatus(TransferRequestStatus.RECEIVED); - setView(View.TRANSFER_REQUEST_SUMMARY); - } - if (!keepTransferRequest) { - setTransferRequest(undefined); - } - } - - async function runPreAction() { - if (actionSteps && actionSteps[activeStep] && token) { - log('Running preAction'); - setActionBtnDisabled(true); - const ActionClass: ActionType = actionSteps[activeStep]; - try { - await new ActionClass( - mainnet, - sChain1, - sChain2, - chainName1, - chainName2, - address, - amount, - tokenId, - token, - switchMetamaskChain, - setActiveStep, - activeStep, - setAmountErrorMessage, - setBtnText - ).preAction(); - } catch (e) { - console.error(e); - } finally { - setActionBtnDisabled(false); - log('preAction done'); - } - } - } - - async function switchMetamaskChain(switchBack?: boolean): Promise { - // if (chainName1 === MAINNET_CHAIN_NAME) { - // updateWeb3SChain( - // switchBack ? sChain2 : sChain1, - // props.network, - // switchBack ? chainName2 : chainName1 - // ); - // await updateWeb3SChainMetamask( - // switchBack ? sChain1 : sChain2, - // props.network, - // switchBack ? chainName1 : chainName2 - // ); - // } - if (chainName2 === MAINNET_CHAIN_NAME) { - if (switchBack) { - await updateWeb3SChainMetamask( - sChain1, - props.config.skaleNetwork, - chainName1, - props.config.chainsMetadata - ); - updateWeb3Mainnet(mainnet, props.config.mainnetEndpoint); - } else { - updateWeb3SChain( - sChain1, - props.config.skaleNetwork, - chainName1 - ) - await updateWeb3MainnetMetamask( - mainnet, - props.config.skaleNetwork, - props.config.mainnetEndpoint - ) - } - return; - } - updateWeb3SChain( - switchBack ? sChain2 : sChain1, - props.config.skaleNetwork, - switchBack ? chainName2 : chainName1 - ); - await updateWeb3SChainMetamask( - switchBack ? sChain1 : sChain2, - props.config.skaleNetwork, - switchBack ? chainName1 : chainName2, - props.config.chainsMetadata - ); - } - - function cleanData() { - setAmountErrorMessage(undefined); - setActionBtnDisabled(false); - setTokenId(undefined); - setAmount(''); - setLoading(false); - setActiveStep(0); - setTransferRequestLoading(false); - setTransferRequestStatus(TransferRequestStatus.NO_REQEST); - } - - async function rechargeCommunityPool() { - // todo: optimize - setLoadingCommunityPool('recharge'); - try { - log('Recharging community pool...') - const sChain = initSChain( - props.config.skaleNetwork, - chainName1 - ); - const mainnetMetamask = await initMainnet1(); - setChainId(getChainId(props.config.skaleNetwork, MAINNET_CHAIN_NAME)); - await mainnetMetamask.communityPool.recharge(chainName1, address, { - address: address, - value: toWei(rechargeAmount, DEFAULT_ERC20_DECIMALS) - }); - setLoadingCommunityPool('activate'); - let active = false; - const chainHash = mainnet.web3.utils.soliditySha3(chainName1); - let counter = 0; - while (!active) { - log('Waiting for account activation...'); - let activeM = await mainnet.communityPool.contract.methods.activeUsers( - address, - chainHash - ).call(); - let activeS = await sChain.communityLocker.contract.methods.activeUsers( - address - ).call(); - active = activeS && activeM; - await delay(BALANCE_UPDATE_INTERVAL_SECONDS * 1000); - counter++; - if (counter >= 10) break; - } - } catch (err) { - console.error(err); - const msg = err.message ? err.message : DEFAULT_ERROR_MSG; - setErrorMessage(new TransactionErrorMessage(msg, errorMessageClosedFallback)); - } finally { - await initSchain1(); - setChainId(getChainId(props.config.skaleNetwork, chainName1)); - setMainnet(initMainnet(props.config.skaleNetwork, props.config.mainnetEndpoint)); - await updateCommunityPoolData(); - setLoadingCommunityPool(false); - } - } - - async function withdrawCommunityPool() { - // todo: optimize - setLoadingCommunityPool('withdraw'); - try { - log('Withdrawing community pool...') - setSChain1(null); - const mainnetMetamask = await initMainnet1(); - setChainId(getChainId(props.config.skaleNetwork, MAINNET_CHAIN_NAME)); - await mainnetMetamask.communityPool.withdraw(chainName1, communityPoolData.balance, { - address: address, - customGasLimit: COMMUNITY_POOL_WITHDRAW_GAS_LIMIT - }); - } catch (err) { - console.error(err); - const msg = err.message ? err.message : DEFAULT_ERROR_MSG; - setErrorMessage(new TransactionErrorMessage(msg, errorMessageClosedFallback)); - } finally { - await initSchain1(); - setChainId(getChainId(props.config.skaleNetwork, chainName1)); - setMainnet(initMainnet(props.config.skaleNetwork, props.config.mainnetEndpoint)); - const cpData = await updateCommunityPoolData(); - setRechargeAmount(cpData.recommendedRechargeAmount); - setLoadingCommunityPool(false); - } - } - - return () + goerli, + + constructWagmiChain('staging', "staging-legal-crazy-castor"), + constructWagmiChain('staging', "staging-utter-unripe-menkar"), + constructWagmiChain('staging', "staging-faint-slimy-achird"), + constructWagmiChain('staging', "staging-perfect-parallel-gacrux"), + constructWagmiChain('staging', "staging-severe-violet-wezen"), + constructWagmiChain('staging', "staging-weepy-fitting-caph"), + + constructWagmiChain('mainnet', 'honorable-steel-rasalhague'), + constructWagmiChain('mainnet', 'elated-tan-skat'), + constructWagmiChain('mainnet', 'affectionate-immediate-pollux') + ], + [ + jsonRpcProvider({ + rpc: chain => ({ + http: chain.rpcUrls.default.http[0], + webSocket: getWebSocketUrl(chain) + }), + }) + ] +); + + +const connectors = connectorsForWallets([ + { + groupName: 'Supported Wallets', + wallets: [ + metaMaskWallet({ chains, projectId: '' }), + injectedWallet({ chains }), + coinbaseWallet({ chains, appName: 'TEST' }) + ], + } +]); + + +const wagmiConfig = createConfig({ + autoConnect: true, + connectors, + publicClient: webSocketPublicClient +}); + + + + +export default function Widget(props: { + config: MetaportConfig +}) { + const widgetTheme = getWidgetTheme(props.config.theme); + const theme = widgetTheme.mode === 'dark' ? darkTheme() : lightTheme(); + + const setTheme = useUIStore((state) => state.setTheme); + const setMpc = useMetaportStore((state) => state.setMpc); + const setOpen = useUIStore((state) => state.setOpen); + + theme.colors.connectButtonInnerBackground = widgetTheme.background; + theme.colors.connectButtonBackground = widgetTheme.background; + + useEffect(() => { + setOpen(props.config.openOnLoad); + }, []); + + useEffect(() => { + setTheme(widgetTheme); + }, [setTheme]); + + useEffect(() => { + setMpc(new MetaportCore(props.config)); + }, [setMpc]); + + return ( + + + + + + ) } \ No newline at end of file diff --git a/src/components/Widget/index.ts b/src/components/Widget/index.ts index 1cb0e8c..820393d 100644 --- a/src/components/Widget/index.ts +++ b/src/components/Widget/index.ts @@ -1 +1 @@ -export { Widget } from "./Widget"; +export { default } from "./Widget"; diff --git a/src/components/WidgetBody/WidgetBody.tsx b/src/components/WidgetBody/WidgetBody.tsx index e9e2fcd..249eb00 100644 --- a/src/components/WidgetBody/WidgetBody.tsx +++ b/src/components/WidgetBody/WidgetBody.tsx @@ -1,164 +1,95 @@ -import React from 'react'; - -import Collapse from '@mui/material/Collapse'; - -import { View } from '../../core/dataclasses/View'; -import { isTransferRequestView } from '../../core/views'; - -import CurrentChain from '../CurrentChain'; -import ErrorMessage from '../ErrorMessage'; -import UnwrapUI from '../UnwrapUI'; -import TransferUI from '../TransferUI'; -import WrappedTokensWarning from '../WrappedTokensWarning'; -import TransferRequest from '../TransferRequest'; -import SFuelWarning from '../SFuelWarning'; -import TransactionsHistory from '../TransactionsHistory'; - - -export default function WidgetBody(props) { - - const [expandedFrom, setExpandedFrom] = React.useState(false); - const [expandedTo, setExpandedTo] = React.useState(false); - const [expandedTokens, setExpandedTokens] = React.useState(false); - const [expandedHistory, setExpandedHistory] = React.useState(false); - const [expandedExit, setExpandedExit] = React.useState(false); - - // TODO: tmp wrap tokens fix - const wrapTransferAction = props.actionSteps && props.actionSteps.length === 2 && props.activeStep > 0; - - if (props.errorMessage) { - return () - } - - if (isTransferRequestView(props.view)) { - return - } - - if (props.view === View.UNWRAP) { - return
- - - - -
- } +import { useCollapseStore } from '../../store/Store' +import { useMetaportStore } from '../../store/MetaportState' + +import TokenList from '../TokenList'; +import ChainsList from '../ChainsList'; +import AmountInput from '../AmountInput'; +import SkStepper from '../Stepper'; +import SkPaper from '../SkPaper'; +import AmountErrorMessage from '../AmountErrorMessage'; +import SwitchDirection from '../SwitchDirection'; + +import common from '../../styles/common.scss'; +import { cls } from '../../core/helper'; +import { Collapse } from '@mui/material'; + + +export function WidgetBody(props) { + + const expandedFrom = useCollapseStore((state) => state.expandedFrom); + const setExpandedFrom = useCollapseStore((state) => state.setExpandedFrom); + + const expandedTo = useCollapseStore((state) => state.expandedTo); + const setExpandedTo = useCollapseStore((state) => state.setExpandedTo); + + const token = useMetaportStore((state) => state.token); + const chainName1 = useMetaportStore((state) => state.chainName1); + const chainName2 = useMetaportStore((state) => state.chainName2); + + const setChainName1 = useMetaportStore((state) => state.setChainName1); + const setChainName2 = useMetaportStore((state) => state.setChainName2); + + const transferInProgress = useMetaportStore((state) => state.transferInProgress); return (
- - + + - - - - + +
+ +
+
+
+ + + + + -
- - + + + - -
- ) -} \ No newline at end of file + + {/*
+
+ +
+
+ {token ? : null} +
+
*/} + + + + +
+ + ); +} + + +export default WidgetBody; diff --git a/src/components/WidgetUI/Common.stories.tsx b/src/components/WidgetUI/Common.stories.tsx deleted file mode 100644 index da95c95..0000000 --- a/src/components/WidgetUI/Common.stories.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import React from "react"; -import { WidgetUI } from "./WidgetUI"; -import { commonProps, defaultTokenData, commonConfig } from './StoriesHelper'; -import { getEmptyTokenDataMap } from '../../core/tokens/helper'; -import { Positions } from '../../core/dataclasses/Position'; -import { getWidgetTheme } from '../WidgetUI/Themes'; - - -export default { - title: "Common elements" -}; - - -export const ConnectScreen = () => ( - -); - - -export const ConnectScreenLight = () => ( - -); - - -export const ClosedLight = () => ( - -); - - -export const TopLeft = () => ( - -); - - -export const ClosedDark = () => ( - -); - - -export const SelectChains = () => ( - -); - -export const SelectChainsLight = () => ( - -); - - -export const LoadingTokens = () => ( - -); - - -export const NoButton = () => ( - -); \ No newline at end of file diff --git a/src/components/WidgetUI/ERC1155.stories.tsx b/src/components/WidgetUI/ERC1155.stories.tsx deleted file mode 100644 index 35086fa..0000000 --- a/src/components/WidgetUI/ERC1155.stories.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from "react"; -import { WidgetUI } from "./WidgetUI"; -import { commonProps, defaultERC1155TokenData } from './StoriesHelper'; - - -export default { - title: "ERC1155 UI" -}; - -export const TransferNFT = () => ( - -); - \ No newline at end of file diff --git a/src/components/WidgetUI/ERC20.stories.tsx b/src/components/WidgetUI/ERC20.stories.tsx deleted file mode 100644 index cce6fc1..0000000 --- a/src/components/WidgetUI/ERC20.stories.tsx +++ /dev/null @@ -1,253 +0,0 @@ -import React from "react"; -import { WidgetUI } from "./WidgetUI"; -import { - commonProps, - defaultTokenData, - generateTokenData, - getWrapActionSteps, - getUnwrapActionSteps, - generateWrappedTokens -} from './StoriesHelper'; -import { getWidgetTheme } from '../WidgetUI/Themes'; - -import { View } from '../../core/dataclasses/View'; - - -export default { - title: "ERC20 UI" -}; - -export const TransferUIDark = () => ( - -); - -export const TransferUILight = () => ( - -); - - -export const MainnetTransfer = () => ( - { }} - setChain2={() => { }} - setToken={() => { }} - setActiveStep={() => { }} - - chain1='mainnet' - chain2='staging-severe-violet-wezen' - theme={getWidgetTheme(null)} - /> -); - -export const MainnetTransferLight = () => ( - { }} - setChain2={() => { }} - setToken={() => { }} - setActiveStep={() => { }} - - chain1='mainnet' - chain2='staging-severe-violet-wezen' - theme={getWidgetTheme({ mode: 'light' })} - /> -); - -export const LoadingSteps = () => ( - { }} - setChain2={() => { }} - setToken={() => { }} - setActiveStep={() => { }} - - loading={true} - - chain1='staging-perfect-parallel-gacrux' - chain2='staging-severe-violet-wezen' - theme={getWidgetTheme(null)} - /> -); - - -export const SelectToken = () => ( - -); - - -export const Approved = () => ( - -); - - -export const Loading = () => ( - -); - - -export const LoadingCustom = () => ( - -); - - -export const LoadingLight = () => ( - -); - - -export const TransferComplete = () => ( - -); - - -export const WrapUI = () => ( - -); - - -export const UnwrapWarning = () => ( - -); - - -export const UnwrapWarningLight = () => ( - -); - - -export const UnwrapUINoTokens = () => ( - -); - - -export const UnwrapUILoading = () => ( - -); - -export const UnwrapUI = () => ( - -); \ No newline at end of file diff --git a/src/components/WidgetUI/ERC721.stories.tsx b/src/components/WidgetUI/ERC721.stories.tsx deleted file mode 100644 index 62310be..0000000 --- a/src/components/WidgetUI/ERC721.stories.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from "react"; -import { WidgetUI } from "./WidgetUI"; -import { commonProps, defaultERC721TokenData, generateTokenData } from './StoriesHelper'; - -import PublicOffIcon from '@mui/icons-material/PublicOff'; - - -export default { - title: "ERC721 UI" -}; - -export const TransferNFT = () => ( - -); diff --git a/src/components/WidgetUI/Errors.stories.tsx b/src/components/WidgetUI/Errors.stories.tsx deleted file mode 100644 index 2697846..0000000 --- a/src/components/WidgetUI/Errors.stories.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import React from "react"; - -import PublicOffIcon from '@mui/icons-material/PublicOff'; - -import { WidgetUI } from "./WidgetUI"; -import { commonProps, defaultTokenData, generateTokenData } from './StoriesHelper'; -import { getEmptyTokenDataMap } from '../../core/tokens/helper'; -import { getWidgetTheme } from '../WidgetUI/Themes'; - - -export default { - title: "Errors" -}; - - -export const NoTokenPairs = () => (); - - -export const NoTokenPairsLight = () => ( - -); - - -export const WrongNetwork = () => ( - , - text: 'test test test test test test test test test test', - btnText: 'aaaa', - fallback: () => { console.log('test test test') } - }} - /> -); - - -export const WrongNetworkLight = () => ( - , - text: 'test test test test test test test test test test', - btnText: 'aaaa', - fallback: () => { console.log('test test test') } - }} - /> -); - - -export const Error = () => ( - -); - diff --git a/src/components/WidgetUI/Guidelines.stories.mdx b/src/components/WidgetUI/Guidelines.stories.mdx deleted file mode 100644 index 1fe5390..0000000 --- a/src/components/WidgetUI/Guidelines.stories.mdx +++ /dev/null @@ -1,50 +0,0 @@ -import { - Meta, - ColorPalette, - ColorItem, - Title, - Subtitle, -} from "@storybook/blocks"; -import Button from "@mui/material/Button"; - -import { clsNames } from "../../core/helper"; -import styles from "../WidgetUI/WidgetUI.scss"; - - - -# SKALE Design Guidelines - -## SKALE Brand colors - - - - - - -## SKALE Components - -### Buttons - -{/*
- -
*/} diff --git a/src/components/WidgetUI/Multichain.stories.tsx b/src/components/WidgetUI/Multichain.stories.tsx deleted file mode 100644 index b0349ac..0000000 --- a/src/components/WidgetUI/Multichain.stories.tsx +++ /dev/null @@ -1,149 +0,0 @@ -import React from "react"; -import { WidgetUI } from "./WidgetUI"; -import { - commonProps, - defaultTokenData, - generateTokenData, - getWrapActionSteps, - getUnwrapActionSteps, - generateWrappedTokens, - generateTransferRequest, - generateTransferRequestSimple, - generateTransferRequestUnwrap, - generateConfigTokens, - generateTransferRequestSteps -} from './StoriesHelper'; -import { getWidgetTheme } from '../WidgetUI/Themes'; - -import { View } from '../../core/dataclasses/View'; - - -export default { - title: "Multichain UI" -}; - - - -export const TransferSummaryLoading = () => ( - -); - -export const TransferSummary = () => ( - -); - -export const TransferSummaryLight = () => ( - -); - -export const TransferSummarySimple = () => ( - -); - -export const TransferSummaryUnwrap = () => ( - -); - -export const TransferSummaryApps = () => ( - -); - - -export const TransferRequestSteps = () => ( - -); - -export const TransferRequestStepsLight = () => ( - -); - - -export const TransferRequestStepsLoading = () => ( - -); - - - - -export const TransferRequestStepsApps = () => ( - -); \ No newline at end of file diff --git a/src/components/WidgetUI/StoriesHelper.ts b/src/components/WidgetUI/StoriesHelper.ts deleted file mode 100644 index f06462a..0000000 --- a/src/components/WidgetUI/StoriesHelper.ts +++ /dev/null @@ -1,330 +0,0 @@ -import { getActionSteps } from '../../core/actions'; -import TokenData from '../../core/dataclasses/TokenData'; -import { TokenType } from '../../core/dataclasses/TokenType'; -import { getEmptyTokenDataMap } from '../../core/tokens/helper'; -import { getWidgetTheme } from '../WidgetUI/Themes'; -export * as dataclasses from '../../core/dataclasses/index'; -import * as interfaces from '../../core/interfaces/index'; -import { View } from '../../core/dataclasses/View'; -import { getTransferSteps } from '../../core/transfer_steps'; - -function setMock() { return }; - - -function getRandomInt(min, max) { - min = Math.ceil(min); - max = Math.floor(max); - return Math.floor(Math.random() * (max - min) + min); -} - - -export const commonConfig: interfaces.MetaportConfig = { - skaleNetwork: 'staging3', - openButton: true, - openOnLoad: true, - tokens: generateConfigTokens(), - chains: ['Europa Chain', 'Calypso'], - chainsMetadata: { - 'staging-perfect-parallel-gacrux': { - alias: 'Europa Hub', // optional - minSfuelWei: '27000000000000', // optional - faucetUrl: 'https://github.com/skalenetwork/skale-network', - apps: { - "ruby": { - "alias": "Ruby Exchange", - "background": "#02001f", - "url": "https://ruby.exchange/" - } - } - }, - 'staging-severe-violet-wezen': { - alias: 'Calypso Hub', - apps: { - "nftrade": { - "alias": "NFTrade", - "background": "#ffffff", - "url": "https://nftrade.com/" - } - } - } - } -} - - -export const commonProps = { - sFuelOk: true, - view: View.SANDBOX, - open: true, - config: commonConfig, - chain1: 'staging-perfect-parallel-gacrux', - chain2: 'staging-severe-violet-wezen', - setChain1: setMock, - setChain2: setMock, - setToken: setMock, - setLoading: setMock, - setView: setMock, - setActiveStep: () => { return }, - walletConnected: true, - actionSteps: getActionSteps('erc20_s2s', new TokenData( - '', - null, - '', - 'test', - null, - null, - null, - null, - TokenType.erc20, - null, - null, - null - )), - theme: getWidgetTheme(null), - transferRequestLoading: true -} - - - -export function getWrapActionSteps() { - return getActionSteps('erc20_s2s', new TokenData( - '', - null, - '', - 'test', - null, - null, - null, - null, - TokenType.erc20, - 'ETHC', - '0x0', - null - )) -} - - -export function getUnwrapActionSteps() { - return getActionSteps('erc20_unwrap', new TokenData( - '', - null, - '', - 'test', - null, - null, - null, - null, - TokenType.erc20, - 'ETHC', - '0x0', - null - )) -} - - -export function generateTokenData(tokenSymbol, tokenName, wrapped = false) { - const data = { - token: tokenSymbol, - amount: getRandomInt(1000, 10000), - availableTokens: getEmptyTokenDataMap(), - wrappedTokens: getEmptyTokenDataMap(), - wrappedToken: undefined - } - // tslint:disable-next-line - const unwrappedIconUrl = wrapped ? "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Globe%20showing%20americas/3D/globe_showing_americas_3d.png" : null - data.availableTokens.erc20[tokenSymbol] = new TokenData( - '0x0', - '0x0', - tokenName, - tokenSymbol, - undefined, - false, - undefined, - '18', - TokenType.erc20, - undefined, - undefined, - unwrappedIconUrl - ); - if (wrapped) { - data.availableTokens.erc20[tokenSymbol].unwrappedBalance = getRandomInt( - 10000, 70000).toString(); - data.availableTokens.erc20[tokenSymbol].unwrappedSymbol = 'u' + tokenSymbol; - }; - data.availableTokens.erc20[tokenSymbol].balance = getRandomInt(10000, 70000).toString(); - data.token = data.availableTokens.erc20[tokenSymbol]; - return data; -} - -export const defaultTokenData = generateTokenData('usdt', 'Tether'); - - -export function generateERC721TokenData(tokenSymbol, tokenName) { - const data = { - token: tokenSymbol, - amount: getRandomInt(1000, 10000), - availableTokens: getEmptyTokenDataMap() - } - data.availableTokens.erc721[tokenSymbol] = new TokenData( - '0x0', - '0x0', - tokenName, - tokenSymbol, - tokenSymbol, - false, - undefined, - undefined, - TokenType.erc721, - undefined, - undefined, - undefined - ); - data.token = data.availableTokens.erc721[tokenSymbol]; - return data; -} - -export const defaultERC721TokenData = generateERC721TokenData('skl', 'SKALE Space'); - - -export function generateERC1155TokenData(tokenSymbol, tokenName) { - const data = { - token: tokenSymbol, - amount: getRandomInt(1000, 10000), - availableTokens: getEmptyTokenDataMap() - } - data.availableTokens.erc1155[tokenSymbol] = new TokenData( - '0x0', - '0x0', - tokenName, - tokenSymbol, - undefined, - false, - undefined, - '18', - TokenType.erc1155, - undefined, - undefined, - undefined - ); - // data.availableTokens.erc1155[tokenSymbol].balance = getRandomInt(10000, 70000).toString(); - data.token = data.availableTokens.erc1155[tokenSymbol]; - return data; -} - -export const defaultERC1155TokenData = generateERC1155TokenData('XEM', 'SKALIENS'); - - - -export function generateWrappedTokens() { - const data = generateTokenData('eth', 'ETH'); - data.wrappedTokens.erc20 = data.availableTokens.erc20; - data.token.balance = undefined; - return data; -} - -export function generateTransferRequest(apps?: boolean) { - const trReq = { - toApp: undefined, - amount: getRandomInt(100, 1000).toString(), - chains: ['mainnet', 'staging-severe-violet-wezen'], - tokenKeyname: 'eth', - tokenType: TokenType.eth, - lockValue: true, - route: { - hub: 'staging-perfect-parallel-gacrux', - tokenKeyname: '_wrETH_0xBA3f8192e28224790978794102C0D7aaa65B7d70' - }, - text: 'Your assets will be routed though Europa Hub - all transactions on Europa and\ - Calypso are free.' - }; - if (apps) { - trReq.toApp = 'nftrade'; - } - return trReq; -} - -export function generateTransferRequestUnwrap() { - return { - amount: getRandomInt(100, 1000), - chains: ['staging-severe-violet-wezen', 'mainnet'], - tokenKeyname: 'eth', - tokenType: TokenType.eth, - lockValue: true, - route: { - hub: 'staging-perfect-parallel-gacrux', - tokenKeyname: '_wrETH_0xBA3f8192e28224790978794102C0D7aaa65B7d70' - }, - text: 'Your assets will be routed though Europa Hub - all transactions on Europa and Calypso \ - are free.' - }; -} - - -export function generateTransferRequestSimple(apps?: boolean) { - const trReq = { - fromApp: undefined, - toApp: undefined, - amount: getRandomInt(100, 1000), - chains: ['staging-perfect-parallel-gacrux', 'staging-severe-violet-wezen'], - tokenKeyname: 'eth', - tokenType: TokenType.eth, - lockValue: true - }; - if (apps) { - trReq.fromApp = 'ruby'; - trReq.toApp = 'nftrade'; - } - return trReq; -} - - -export function generateConfigTokens(): interfaces.TokensMap { - return { - mainnet: { - eth: { - chains: [ - 'staging-perfect-parallel-gacrux' - ] - } - }, - 'staging-perfect-parallel-gacrux': { - 'erc20': { - "WRETH": { - "address": "0xBA3f8192e28224790978794102C0D7aaa65B7d70", - "name": "ETH", - "symbol": "ETH", - "cloneSymbol": "ETH", - "wraps": { - "address": "0xD2Aaa00700000000000000000000000000000000", - "symbol": "ETH" - } - }, - "usdc": { - "address": "0xBA3f8192e28224790978794102C0D7aaa65B7d70", - "name": "usdc", - "symbol": "usdc", - "cloneSymbol": "usdc" - } - } - } - } -} - - -export function generateTransferRequestSteps(apps?: boolean) { - return getTransferSteps( - generateTransferRequest(apps) as interfaces.TransferParams, - commonConfig as interfaces.MetaportConfig, getWidgetTheme(null), new TokenData( - '', - null, - '', - 'test', - null, - null, - null, - null, - TokenType.erc20, - 'ETHC', - '0x0', - null - )) -} \ No newline at end of file diff --git a/src/components/WidgetUI/StorybookHelper.tsx b/src/components/WidgetUI/StorybookHelper.tsx deleted file mode 100644 index 85c63fc..0000000 --- a/src/components/WidgetUI/StorybookHelper.tsx +++ /dev/null @@ -1,245 +0,0 @@ -import { useEffect, useState } from 'react'; - -import TextField from "@mui/material/TextField"; -import Button from "@mui/material/Button"; - -import { internalEvents } from "../../core/events"; - - -const btnStyles = { - fontSize: '0.7525rem', - lineHeight: '2.6', - letterSpacing: '0.02857em', - fontWeight: '600', - borderRadius: '15px' -}; - -const styles = { - transform: 'scale(1)', - height: '85vh', - backgroundColor: 'rgb(243 243 243)', - borderRadius: '15px', - boxShadow: 'rgba(0, 0, 0, 0.10) 0 1px 3px 0', - border: '1px solid hsla(203, 50%, 30%, 0.15)' -}; - - -const ERC20_TR_REQ_SAMPLE = { - "amount": "100", - "chains": ["mainnet", "staging-perfect-parallel-gacrux"], - "tokenKeyname": "_skl_0x2868716b3B4AEa43E8387922AFE71a77D101854e", - "tokenType": "erc20", - "lockValue": true, - "toApp": "ruby" -}; - - -const ERC721_TR_REQ_SAMPLE = { - "tokenId": "1", - "chains": ["mainnet", "staging-perfect-parallel-gacrux"], - "tokenKeyname": "_SPACE_0x1b7729d7E1025A031aF9D6E68598b57f4C2adfF6", - "tokenType": "erc721meta", - "lockValue": true, - "toApp": "ruby" -} - -const ERC1155_TR_REQ_SAMPLE = { - "tokenId": "1", - "amount": "5", - "chains": ["mainnet", "staging-perfect-parallel-gacrux"], - "tokenKeyname": "_SKALIENS_0x6cb73D413970ae9379560aA45c769b417Fbf33D6", - "tokenType": "erc1155", - "lockValue": true, - "toApp": "ruby" -} - -const ERC20_S2S_TR_REQ_SAMPLE = { - "amount": "10", - "chains": ["staging-perfect-parallel-gacrux", "staging-severe-violet-wezen"], - "tokenKeyname": "_SKL_0x099A46F35b627CABee27dc917eDA253fFbC55Be6", - "tokenType": "erc20", - "lockValue": true, - "fromApp": "ruby", - "toApp": "nftrade" -} - -const ETH_ROUTED_TR_REQ_SAMPLE = { - "amount": "0.01", - "chains": ["mainnet", "staging-severe-violet-wezen"], - "tokenKeyname": "eth", - "tokenType": "eth", - "lockValue": true, - "toApp": "nftrade", - "route": { - "hub": "staging-perfect-parallel-gacrux", - "tokenType": "erc20", - "tokenKeyname": "_ETH_0xBA3f8192e28224790978794102C0D7aaa65B7d70" - } -} - -const ETH_ROUTED_REVERSED_TR_REQ_SAMPLE = { - "amount": "0.01", - "chains": ["staging-severe-violet-wezen", "mainnet"], - "tokenKeyname": "_ETH_0xBA3f8192e28224790978794102C0D7aaa65B7d70", - "tokenType": "erc20", - "lockValue": true, - "toApp": "nftrade", - "route": { - "hub": "staging-perfect-parallel-gacrux", - "tokenType": "eth", - "tokenKeyname": "eth" - } -} - -const ETH_S2M_TR_REQ_SAMPLE = { - "amount": "0.01", - "chains": ["staging-perfect-parallel-gacrux", "mainnet"], - "tokenKeyname": "eth", - "tokenType": "eth", - "lockValue": true -}; - - -export const storyDecorator = storyFn =>
-
-
-
- {storyFn()} -
; - - -export const TransferRequestEditor = () => { - const [inputValue, setInputValue] = useState(JSON.stringify(ERC20_TR_REQ_SAMPLE)); - const [events, setEvents] = useState([]); - - const handleInputChange = (event: React.ChangeEvent) => { - setInputValue(event.target.value); - }; - - const handleButtonClick = () => { - try { - const parsedJSON = JSON.parse(inputValue); - internalEvents.transfer(parsedJSON); - } catch (error) { - console.error('Invalid JSON object'); - } - }; - - useEffect(() => { - window.addEventListener('metaport_actionStateUpdated', eventHandled, false); - return () => { - window.removeEventListener('metaport_actionStateUpdated', eventHandled, false); - }; - }, []); - - function eventHandled(e: any) { - events.push(e.detail); - setEvents([...events]); - } - - return ( -
- - - - - - - - - - - - - - - - - - - -
-

Events

- {events.map((event, key) => ( -
{event.actionName} - {event.actionState}
- ))} -
-
- ); -} \ No newline at end of file diff --git a/src/components/WidgetUI/Themes.stories.tsx b/src/components/WidgetUI/Themes.stories.tsx deleted file mode 100644 index 0ffc4ec..0000000 --- a/src/components/WidgetUI/Themes.stories.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import React from "react"; -import { WidgetUI } from "./WidgetUI"; -import { storyDecorator } from "./StorybookHelper"; -import { commonProps, generateTokenData } from './StoriesHelper'; -import { Positions } from '../../core/dataclasses/Position'; - - -const meta: Meta = { - title: 'Themes/Customization', - component: WidgetUI, - tags: ['autodocs'], - argTypes: { - theme: { - description: "The theme to use for the widget", - }, - "theme.primary": { - control: { - type: 'color' - } - } - }, - decorators: [storyDecorator], - -}; - -export default meta; -type Story = StoryObj; - - -export const ThemeRuby: Story = { - args: { - ...commonProps, - ...generateTokenData('ruby', 'Ruby'), - theme: { - primary: '#b01571', - background: '#f3f2ff', - mode: 'light', - position: Positions.bottomRight - } - } -}; - - -export const DarkBlue: Story = { - args: { - ...commonProps, - ...generateTokenData('zrx', '0x'), - theme: { - primary: '#00d4ff', - background: '#0a2540', - mode: 'dark', - position: Positions.bottomLeft - } - } -}; - - -export const LightOrange: Story = { - args: { - ...commonProps, - ...generateTokenData('link', 'Chainlink'), - theme: { - primary: '#f96300', - background: '#ffffff', - mode: 'light', - position: Positions.topRight - } - } -}; - - -export const LightViolet: Story = { - args: { - ...commonProps, - ...generateTokenData('skl', 'Skale'), - theme: { - primary: '#9a66ff', - background: '#fbf8ff', - mode: 'light', - position: Positions.bottomRight - } - } -}; - - -export const CustomZIndex: Story = { - args: { - ...commonProps, - ...generateTokenData('skl', 'Skale'), - theme: { - primary: '#9a66ff', - background: '#fbf8ff', - mode: 'light', - position: Positions.bottomRight, - zIndex: 9991 - } - } -}; \ No newline at end of file diff --git a/src/components/WidgetUI/WidgetUI.scss b/src/components/WidgetUI/WidgetUI.scss deleted file mode 100644 index cbf3afd..0000000 --- a/src/components/WidgetUI/WidgetUI.scss +++ /dev/null @@ -1,725 +0,0 @@ -@import './variables'; - -.imaWidgetBody { - position: fixed; -} - -.skaleLogoSm { - width: 18pt; -} - -.mp__popupWrapper, -.mp__fullsreenWrapper { - // margin: 20pt; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif !important; - -webkit-font-smoothing: antialiased; - - p { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif !important; - -webkit-font-smoothing: antialiased; - margin-top: 0; - margin-bottom: 0; - } - - .mp__p__marg { - margin-top: 1em !important; - margin-bottom: 1em !important; - } - - button { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif !important; - -webkit-font-smoothing: antialiased; - } - - :global(.MuiPaper-root) { - background-image: none; - } - - - :global(.MuiSvgIcon-fontSizeSmall) { - width: 10pt; - height: 10pt; - } -} - -.mp__popup { - padding: 14pt; - max-height: calc(100vh - 110pt); - - :global(.MuiButton-root) { - font-weight: 600 !important; - box-shadow: none !important; - border-radius: $sk-border-radius !important; - } -} - -.mp__paper { - border-radius: 20px !important; - border: 1px #7f7f7f45 solid; -} - -.mp__flex { - display: flex; - vertical-align: middle; -} - -.fl-right { - justify-content: end; -} - -.mp__flexCentered { - align-items: center; - justify-content: center; -} - -.mp__flexCenteredVert { - align-items: center; -} - -.mp__flexGrow { - flex-grow: 1; -} - -.mp_flexRow { - flex-direction: row; - flex-wrap: wrap; -} - -.mp__margTop10 { - margin-top: 10px !important; -} - -.mp__margTop20 { - margin-top: 20px !important; -} - -.mp__margTop40 { - margin-top: 40px !important; -} - - -.mp__margLeft5 { - margin-left: 5px !important; -} - -.mp__margLeft10 { - margin-left: 10px !important; -} - -.mp__margLeft20 { - margin-left: 20px !important; -} - -.mp__margRi20 { - margin-right: 20px !important; -} - -.mp__margRi10 { - margin-right: 10px !important; -} - -.mp__margRi5 { - margin-right: 5px !important; -} - -.mp__margBottMin10 { - margin-bottom: -10px !important; -} - -.mp__margBottMin15 { - margin-bottom: -15px !important; -} - -.marg-top-20 { - margin-top: 20px !important; -} - -.mp__margTop20Pt { - margin-top: 20pt !important; -} - -.marg-top-30 { - margin-top: 30px !important; -} - -.mp__margBott20 { - margin-bottom: 20px !important; -} - -.mp__margBott15 { - margin-bottom: 15px !important; -} - -.mp__margBott10 { - margin-bottom: 10px !important; -} - -.marg-bott-40 { - margin-bottom: 40px !important; -} - -.mp__margBott5 { - margin-bottom: 5px !important; -} - -.mp__margTop5 { - margin-top: 5px !important; -} - - -.mp__noMargTop { - margin-top: 0 !important; -} - - -.mp__noMargBott { - margin-bottom: 0 !important; -} - -.mp__noMarg { - margin: 0 !important; -} - -.mp__paddTop10 { - padding-top: 10px !important; -} - - -.mp__capitalize { - text-transform: capitalize; -} - -.mp__chainName { - font-weight: bold; - padding-left: 10pt; - margin-top: 1em !important; - margin-bottom: 1em !important; -} - - -.mp__chainsList { - overflow: auto; - max-height: 45vh; -} - -.mp__btnChain { - width: 100%; - text-align: left; - text-transform: uppercase; - font-size: 0.6525rem !important; - line-height: 1.6; - letter-spacing: 0.02857em; -} - -.mp__btnAction { - width: 100%; - text-transform: uppercase; - font-size: 0.7525rem !important; - line-height: 1.6 !important; - letter-spacing: 0.02857em !important; - font-weight: 600 !important; - padding-top: 0.8em !important; - padding-bottom: 0.8em !important; - min-height: $sk-btn-height !important; -} - - -.mp__popup { - :global .MuiAccordionSummary-content { - margin: 0 !important; - } - - :global(.MuiAccordionSummary-root) { - min-height: $sk-btn-height !important; - } - - :global .MuiAccordion-root { - border-radius: $sk-border-radius !important; - background-color: $sk-paper-color !important; - box-shadow: none !important; - - .Mui-disabled { - .MuiAccordionSummary-expandIconWrapper { - display: none !important; - } - opacity: 1 !important; - } - } -} - -.mp__btnSwitch { - width: 100%; - text-align: center; - margin-top: -6pt; - margin-bottom: -24pt; - - button { - border: 10px #1a1a1a solid; - } - - :global(svg) { - width: 14pt; - height: 14pt; - } -} - - -.darkTheme { - .br__action_deposit { - background-image: linear-gradient(45deg, #8A463C 0%, #b02d50 100%); - } - - .br__action_transferToSchain { - background-image: linear-gradient(120deg, #9c27b0 0%, #3f51b5 100%) - } - - .br__action_wrap { - background-image: linear-gradient(160deg, #237bc3 0%, #1a3b94 100%); - } - - .br__action_unwrap { - background-image: linear-gradient(160deg, #1a3b94 0%, #237bc3 100%); - } - - .br__action_withdraw { - background-image: linear-gradient(45deg, #b02d50 0%, #8A463C 100%); - } - - .br__action_getMyEth { - background-image: linear-gradient(45deg, #009688 0%, #0c5f57 100%); - } - - .br__action_approve { - background-image: linear-gradient(135deg, #29b1a9 0%, #14532a 100%); - } - - .br__action_approveWrap { - background-image: linear-gradient(135deg, #14532a 0%, #29b1a9 100%); - } - - .br__action_wallet { - background-image: linear-gradient(135deg, #dedede 0%, #aeaeae 100%); - } - - .br__action_wrapsfuel { - background-image: linear-gradient(160deg, #237bc3 0%, #1a3b94 100%); - } - - .mp__chainName { - color: white !important; - } - - .eth-logo { - filter: invert(1) contrast(1.5); - } - - .skaleLogoSm { - filter: invert(1); - } - - .mp__p, - .mp__infoIcon, - .mp__backIcon { - color: rgb(255 255 255 / 65%) !important; - } - - .sk__colorText, - .mp__chainName, - .mp__pWhite { - color: white !important; - } - - .mp__textGray, - .mp__iconGray { - color: #bdbdbd; - } - - :global(.MuiStepIcon-root.Mui-active, - .MuiStepIcon-root.Mui-completed) { - color: #ffffff !important; - } - - :global .MuiIconButton-root { - svg { - color: #000000; - } - } - - :global(.MuiIconButton-root.Mui-disabled) { - svg { - color: rgba(255, 255, 255, 0.3); - } - } - - .mp__btnSwitch { - :global(.Mui-disabled) { - background-color: $sk-paper-color !important; - } - } - - .mp__routeIcon { - svg { - width: 14pt; - color: rgba(255, 255, 255, 0.65) !important; - } - } - - .mp__routeSmall { - h4 { - color: rgba(255, 255, 255, 0.65) !important; - } - } -} - - -.lightTheme { - - .br__action_deposit { - background-image: linear-gradient(45deg, #f7c9b1 0%, #f8d4da 100%); - } - - .br__action_transferToSchain { - background-image: linear-gradient(120deg, #e0baf0 0%, #c1ccf8 100%); - } - - .br__action_wrap { - background-image: linear-gradient(160deg, #9dcff1 0%, #8ab1dd 100%); - } - - .br__action_unwrap { - background-image: linear-gradient(160deg, #8ab1dd 0%, #9dcff1 100%); - } - - .br__action_withdraw { - background-image: linear-gradient(45deg, #f8d4da 0%, #f7c9b1 100%); - } - - .br__action_getMyEth { - background-image: linear-gradient(45deg, #92f7e1 0%, #76afaa 100%); - } - - .br__action_approve { - background-image: linear-gradient(135deg, #89e0ce 0%, #58a47c 100%); - } - - .br__action_approveWrap { - background-image: linear-gradient(135deg, #58a47c 0%, #89e0ce 100%); - } - - .br__action_wallet { - background-image: linear-gradient(135deg, #f5f5f5 0%, #dfdfdf 100%); - } - - .br__action_wrapsfuel { - background-image: linear-gradient(160deg, #9dcff1 0%, #8ab1dd 100%); - } - - .mp__chainName { - color: black !important; - } - - .mp__p, - .mp__infoIcon, - .mp__backIcon { - color: rgb(0 0 0 / 65%) !important; - } - - .sk__colorText { - color: black !important; - } - - .MuiInput-root { - .Mui-disabled { - color: rgb(0 0 0 / 60%); - } - } - - .mp__textGray, - .mp__iconGray { - color: #4f4f4f; - } - - .MuiStepIcon-root.Mui-active, - .MuiStepIcon-root.Mui-completed { - color: rgba(0, 0, 0, 0.87) !important; - } - - .MuiButton-root.Mui-disabled { - color: rgba(0, 0, 0, 0.26) !important; - } - - .mp__btnSwitch { - :global(.Mui-disabled) { - background-color: rgb(224 224 224) !important; - } - } - - :global(.MuiIconButton-root) { - svg { - color: #ffffff; - } - } - - :global(.MuiIconButton-root.Mui-disabled) { - svg { - color: rgba(0, 0, 0, 0.26); - } - } - - .mp__routeIcon { - svg { - width: 14pt; - color: rgba(0, 0, 0, 0.65) !important; - } - } - - .mp__routeSmall { - h4 { - color: rgba(0, 0, 0, 0.65) !important; - } - } -} - -.mp__routeSmall { - h4 { - font-weight: 500 !important; - text-transform: none !important; - font-size: 0.8525rem !important; - line-height: 1.6 !important; - letter-spacing: 0.03857em !important; - } -} - -.mp__p3 { - margin: 0; - font-weight: 600 !important; - // text-transform: uppercase !important; - font-size: 0.6525rem !important; - line-height: 1.6 !important; - letter-spacing: 0.02857em !important; -} - -.mp__p2 { - margin: 0; - font-weight: 600 !important; - // text-transform: uppercase !important; - font-size: 0.8525rem !important; - line-height: 1.6 !important; - letter-spacing: 0.03857em !important; -} - -.mp__completeText { - font-weight: 600 !important; - text-transform: none !important; - font-size: .8525rem !important; - line-height: 1.6 !important; - letter-spacing: .03857em !important; - color: white !important; -} - -.mp__code { - font-size: 0.75rem; -} - -.mp__codeWrap { - position: fixed; - top: 0; - left: 0; - margin: 20px; - padding: 20px; - background-color: black; -} - -.mp_p_desc { - margin: 0; - font-weight: 500 !important; - text-transform: none !important; - font-size: 0.8025rem !important; - line-height: 1.6 !important; - letter-spacing: 0.03857em !important; -} - - -.mp__btnConnect { - width: 100%; - margin-top: 10pt; - border-radius: 15px !important; - - text-align: left; - - .mp__iconConnect { - width: 20pt !important; - } - - :global(.MuiPaper-root) { - background-color: $sk-paper-color !important; - width: 100%; - padding: 10pt 15pt; - border-radius: 15px !important; - } - - .mp__iconGray { - width: 12pt; - } -} - -:global(.Mui-disabled) { - .mp__iconConnect { - filter: saturate(0) !important; - } -} - - -.mp__textToken { - padding-top: 25pt !important; -} - -.btn-bg { - background-color: #0d0d0d !important; -} - -.hidden { - opacity: 0; -} - -.noDisplay { - display: none !important; -} - -.skaleBtnHidden { - display: none !important; -} - -.skaleBtn { - border: 1px #7f7f7f45 solid; -} - -.mp__popper { - width: 300pt; -} - -.mp__transferToFix { - margin-top: 26pt !important; -} - -.mp__textCentered { - text-align: center; -} - - -.mp__infoIcon { - svg { - height: 25pt; - width: 100%; - } -} - -.mp__minContent { - width: min-content; -} - -.tokenIdIcon { - padding: 0 0 0 16px; - - :global(svg) { - //width: 20px; - } -} - -.mp__backIcon { - width: 8pt !important; - height: 8pt !important; - // margin-left: 2pt !important; -} - -.mp__amountChip { - :global(.MuiChip-label) { - text-transform: uppercase !important; - } -} - -.mp__amount { - text-transform: uppercase !important; -} - -.mp__amountIcon { - width: 18pt; -} - -.mp__chainIcon { - img { - width: 15pt !important; - height: 15pt !important; - } - - svg { - width: 16pt !important; - height: 16pt !important; - color: white; - } -} - - -.mp__summaryChip { - :global(.MuiChip-icon) { - width: 17pt; - height: 17pt; - } - - margin-left: 5px; - - span { - font-size: 1.3em; - font-weight: 600; - } -} - - -.br__history { - :global .MuiAccordion-root:before { - opacity: 0; - } -} - -.sk__smBth { - font-size: 0.7rem !important; - padding-left: 10px !important; - padding-right: 10px !important; -} - -.sk__uppercase { - text-transform: uppercase !important; -} - -.sk__skeleton { - border-radius: $sk-border-radius !important; -} - - -.sk__balanceCard { - .chainIcon { - width: 15px !important; - height: 15px !important; - } -} - - -.mp__chainIconSm { - :global(img) { - width: 22px; - height: 22px; - } -} - -.mp__chainIconXs { - :global(img) { - width: 17px; - height: 17px; - } -} - -.sk__chainApps { - background-color: $sk-paper-color; - border-radius: $sk-border-radius !important; - padding: 5px; -} \ No newline at end of file diff --git a/src/components/WidgetUI/WidgetUI.tsx b/src/components/WidgetUI/WidgetUI.tsx index 2d7e12e..101065d 100644 --- a/src/components/WidgetUI/WidgetUI.tsx +++ b/src/components/WidgetUI/WidgetUI.tsx @@ -1,67 +1,112 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +/** + * @file WidgetUI.ts + * @copyright SKALE Labs 2023-Present + */ + import React from 'react'; import { StyledEngineProvider } from '@mui/material/styles'; +import { useAccount } from 'wagmi'; + +import Collapse from '@mui/material/Collapse'; import Fab from '@mui/material/Fab'; import CloseIcon from '@mui/icons-material/Close'; -import Paper from '@mui/material/Paper'; import { createTheme, ThemeProvider } from '@mui/material/styles'; -import { getMuiZIndex } from './Themes'; +import { getMuiZIndex } from '../../core/themes'; import skaleLogo from './skale_logo_short.svg'; +import { useUIStore } from '../../store/Store' +import { useMetaportStore } from '../../store/MetaportState' +import SkPaper from '../SkPaper'; + import WidgetBody from '../WidgetBody'; -import { Connector } from '../WalletConnector'; -import Debug from '../Debug'; -import { clsNames } from '../../core/helper'; -import styles from "./WidgetUI.scss"; + +import { cls } from '../../core/helper'; + +import styles from "../../styles/styles.scss"; +import common from "../../styles/common.scss"; +import { PaletteMode } from '@mui/material'; + +import SkConnect from '../SkConnect'; +import ErrorMessage from '../ErrorMessage'; export function WidgetUI(props) { + + const { address } = useAccount(); + + const metaportTheme = useUIStore((state) => state.theme); + const isOpen = useUIStore((state) => state.open); + const setOpen = useUIStore((state) => state.setOpen); + + const errorMessage = useMetaportStore((state) => state.errorMessage); + + if (!metaportTheme) return
+ let theme = createTheme({ - zIndex: getMuiZIndex(props.theme), + zIndex: getMuiZIndex(metaportTheme), palette: { - mode: props.theme.mode, + mode: metaportTheme.mode as PaletteMode, background: { - paper: props.theme.background + paper: metaportTheme.background }, primary: { - main: props.theme.primary, + main: metaportTheme.primary, }, secondary: { - main: props.theme.background + main: metaportTheme.background }, }, }); const handleClick = (_: React.MouseEvent) => { - props.setOpen(props.open ? false : true); + setOpen(isOpen ? false : true); }; - const themeCls = props.theme.mode === 'dark' ? styles.darkTheme : styles.lightTheme; + const themeCls = metaportTheme.mode === 'dark' ? styles.darkTheme : styles.lightTheme; + const commonThemeCls = metaportTheme.mode === 'dark' ? common.darkTheme : common.lightTheme; let fabTop: boolean = false; let fabLeft: boolean = false; - if (props.theme) { - fabTop = props.theme.position.bottom === 'auto'; - fabLeft = props.theme.position.right === 'auto'; + if (metaportTheme) { + fabTop = metaportTheme.position.bottom === 'auto'; + fabLeft = metaportTheme.position.right === 'auto'; } - const fabButton = (
-
-
+ const fabButton = (
+
+
- {props.open ? ( + {isOpen ? ( ) : (
-
+
{fabTop ? fabButton : null}
-
-
- -
- - {props.walletConnected ? ( - - ) : ( - - )} -
-
-
-
-
+ + + + + + + + + {address ? :
} +
+
+
+
{fabTop ? null : fabButton}
diff --git a/src/components/WidgetUI/_variables.scss b/src/components/WidgetUI/_variables.scss deleted file mode 100644 index 5737ead..0000000 --- a/src/components/WidgetUI/_variables.scss +++ /dev/null @@ -1,7 +0,0 @@ -$sk-border-radius: 15px; - -$sk-paper-color: rgb(136 135 135 / 15%); -$sk-gray-background-color: rgba(161, 161, 161, 0.2); - - -$sk-btn-height: 47px; \ No newline at end of file diff --git a/src/components/WrappedTokensWarning/WrappedTokensWarning.tsx b/src/components/WrappedTokensWarning/WrappedTokensWarning.tsx deleted file mode 100644 index 36e5313..0000000 --- a/src/components/WrappedTokensWarning/WrappedTokensWarning.tsx +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @license - * SKALE Metaport - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -/** - * @file WrappedTokensWarning.ts - * @copyright SKALE Labs 2022-Present - */ - -import Button from '@mui/material/Button'; - -import { View } from '../../core/dataclasses/View'; - -import { clsNames } from '../../core/helper'; -import styles from "../WidgetUI/WidgetUI.scss"; - - -export default function WrappedTokensWarning(props) { - if (!props.wrappedTokens || !props.wrappedTokens.erc20) return; - const wrappedTokens = Object.entries(props.wrappedTokens.erc20); - if (wrappedTokens.length === 0) return; - return (
-

- ❗ You have wrapped tokens in your wallet. Please unwrap them before proceeding with your transfer. -

- -
) -} diff --git a/src/components/WrappedTokensWarning/index.ts b/src/components/WrappedTokensWarning/index.ts deleted file mode 100644 index 081c48c..0000000 --- a/src/components/WrappedTokensWarning/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./WrappedTokensWarning"; \ No newline at end of file diff --git a/src/configs/metaportConfigStaging.json b/src/configs/metaportConfigStaging.json deleted file mode 100644 index 5026dec..0000000 --- a/src/configs/metaportConfigStaging.json +++ /dev/null @@ -1,192 +0,0 @@ -{ - "skaleNetwork": "staging3", - "autoLookup": false, - "openOnLoad": true, - "openButton": true, - "debug": false, - "chains": [ - "mainnet", - "staging-perfect-parallel-gacrux", - "staging-severe-violet-wezen", - "staging-legal-crazy-castor", - "staging-utter-unripe-menkar", - "staging-faint-slimy-achird", - "staging-weepy-fitting-caph" - ], - "tokens": { - "mainnet": { - "eth": { - "chains": [ - "staging-perfect-parallel-gacrux", - "staging-legal-crazy-castor" - ] - }, - "erc20": { - "_SKL_0x493D4442013717189C9963a2e275Ad33bfAFcE11": { - "name": "SKL", - "address": "0x493D4442013717189C9963a2e275Ad33bfAFcE11", - "symbol": "SKL" - }, - "_skl_0x2868716b3B4AEa43E8387922AFE71a77D101854e": { - "address": "0x2868716b3B4AEa43E8387922AFE71a77D101854e", - "decimals": "18", - "name": "SKALE", - "symbol": "skl", - "mappings": { - "staging-perfect-parallel-gacrux": "0x6FA34A9A1eb81d550D6bB5E129B9FDc35aa0F021" - } - }, - "_usdc_0xdE7EBAA09961D4BdD9E41206De23D2214e22b5d2": { - "address": "0xdE7EBAA09961D4BdD9E41206De23D2214e22b5d2", - "decimals": "18", - "name": "USDC", - "symbol": "usdc" - }, - "_usdt_0xB89fCb83F7868d8Cfd104c768FF93FDF74C8a590": { - "address": "0xB89fCb83F7868d8Cfd104c768FF93FDF74C8a590", - "decimals": "18", - "name": "USDT", - "symbol": "usdt" - }, - "_wbtc_0xd7BAd1A8E66050178a815355567E5e0218a5B659": { - "address": "0xd7BAd1A8E66050178a815355567E5e0218a5B659", - "decimals": "18", - "name": "WBTC", - "symbol": "wbtc" - } - }, - "erc721meta": { - "_SPACE_0x1b7729d7E1025A031aF9D6E68598b57f4C2adfF6": { - "address": "0x1b7729d7E1025A031aF9D6E68598b57f4C2adfF6", - "name": "SKALE Space", - "symbol": "SPACE", - "iconUrl": "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Rocket/3D/rocket_3d.png" - } - }, - "erc1155": { - "_SKALIENS_0x6cb73D413970ae9379560aA45c769b417Fbf33D6": { - "address": "0x6cb73D413970ae9379560aA45c769b417Fbf33D6", - "name": "SKALIENS Collection", - "symbol": "SKALIENS", - "iconUrl": "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Alien/3D/alien_3d.png" - } - } - }, - "staging-utter-unripe-menkar": { - "erc721": { - "_TANK_0x4aaa1bb85d9339811b65566fa1aae11a8a9db28d": { - "name": "TANK", - "address": "0x4aaa1bb85d9339811b65566fa1aae11a8a9db28d", - "symbol": "TANK", - "iconUrl": "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Bomb/3D/bomb_3d.png" - } - } - }, - "staging-legal-crazy-castor": { - "erc20": { - "_ETH_0xa270484784f043e159f74C03B691F80B6F6e3c24": { - "name": "ETH", - "address": "0xa270484784f043e159f74C03B691F80B6F6e3c24", - "symbol": "ETH", - "iconUrl": "https://ruby.exchange/images/tokens/eth-square.jpg", - "wraps": { - "iconUrl": "https://ruby.exchange/images/tokens/eth-square.jpg", - "address": "0xD2Aaa00700000000000000000000000000000000", - "symbol": "ETHC" - } - }, - "_SKL_0x6a679eF80aF3fE01A646F858Ca1e26D58b5430B6": { - "name": "SKL", - "symbol": "SKL", - "address": "0x6a679eF80aF3fE01A646F858Ca1e26D58b5430B6", - "iconUrl": "https://ruby.exchange/images/tokens/skl-square.jpg", - "wraps": { - "address": "0xbA1E9BA7CDd4815Da6a51586bE56e8643d1bEAb6", - "symbol": "SKL", - "iconUrl": "https://ruby.exchange/images/tokens/skl-square.jpg" - } - }, - "_USDC_0x4f250cCE5b8B39caA96D1144b9A32E1c6a9f97b0": { - "name": "USDC", - "symbol": "USDC", - "address": "0x4f250cCE5b8B39caA96D1144b9A32E1c6a9f97b0", - "iconUrl": "https://ruby.exchange/images/tokens/usdc-square.jpg", - "wraps": { - "address": "0x5d42495D417fcd9ECf42F3EA8a55FcEf44eD9B33", - "symbol": "USDC", - "iconUrl": "https://ruby.exchange/images/tokens/usdc-square.jpg" - } - } - } - }, - "staging-perfect-parallel-gacrux": { - "erc20": { - "_ETH_0xBA3f8192e28224790978794102C0D7aaa65B7d70": { - "address": "0xBA3f8192e28224790978794102C0D7aaa65B7d70", - "name": "ETH", - "symbol": "ETH", - "cloneSymbol": "ETH", - "wraps": { - "address": "0xD2Aaa00700000000000000000000000000000000", - "symbol": "ETH", - "name": "aaaa" - } - }, - "_SKILL_0xb36A1DdaBf21161ad71013A34D502381DD1aa7BA": { - "address": "0xb36A1DdaBf21161ad71013A34D502381DD1aa7BA", - "name": "SKILL Token", - "symbol": "SKILL", - "iconUrl": "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Compass/3D/compass_3d.png" - }, - "DMT": { - "address": "0xb36A1DdaBf21161ad71013A34D502381DD1aa7BA", - "name": "DMT", - "symbol": "DMT", - "cloneSymbol": "DMTC", - "wraps": { - "address": "0x688f6d050B935BF06531b51B5e598318788fA7a5", - "symbol": "DMT", - "iconUrl": "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Compass/3D/compass_3d.png" - } - }, - "_SKL_0x099A46F35b627CABee27dc917eDA253fFbC55Be6": { - "address": "0x099A46F35b627CABee27dc917eDA253fFbC55Be6", - "decimals": "18", - "name": "SKL S2S", - "symbol": "SKL" - } - }, - "erc721": { - "_SPS_0x30216880A73B67133F37de35e769b8e1A943D35c": { - "address": "0x30216880A73B67133F37de35e769b8e1A943D35c", - "name": "SKALE Space S2S", - "symbol": "SPS", - "iconUrl": "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Glowing%20star/3D/glowing_star_3d.png" - } - }, - "erc1155": { - "skaliens": { - "address": "0xBA9fF38A2b22edDfa8e05805bD22C8f20c40546e", - "name": "SKALIENS Collection", - "symbol": "SKALIENS2S", - "iconUrl": "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Alien/3D/alien_3d.png" - }, - "medals": { - "address": "0x5D8bD602dC5468B3998e8514A1851bd5888E9639", - "name": "Medals", - "symbol": "MEDALS2S", - "iconUrl": "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/1st%20place%20medal/3D/1st_place_medal_3d.png" - }, - "_ANIMALS_0xDf87EEF0977148129969b01b329379b17756cdDE": { - "address": "0xDf87EEF0977148129969b01b329379b17756cdDE", - "name": "Funny Animals", - "symbol": "ANIMALS", - "iconUrl": "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Frog/3D/frog_3d.png" - } - } - } - }, - "theme": { - "mode": "dark" - } -} \ No newline at end of file diff --git a/src/core/actions/action.ts b/src/core/actions/action.ts index d206977..2332845 100644 --- a/src/core/actions/action.ts +++ b/src/core/actions/action.ts @@ -21,11 +21,27 @@ * @copyright SKALE Labs 2022-Present */ +import debug from 'debug'; + +import { Chain } from '@wagmi/core'; +import { WalletClient } from 'viem'; +import { Contract, Provider } from 'ethers'; + import { MainnetChain, SChain } from '@skalenetwork/ima-js'; -import TokenData from '../dataclasses/TokenData'; +import { TokenData, CustomAbiTokenType } from '../dataclasses'; +import MetaportCore, { createTokenData } from '../metaport'; import { externalEvents } from '../events'; import { toWei } from '../convertation'; import { ActionState, LOADING_BUTTON_TEXT } from './actionState'; +import { isMainnet } from '../helper'; + +import { IMA_ABIS } from '../contracts'; +import { isMainnetChainId, getMainnetAbi } from '../network'; + +import { walletClientToSigner } from '../ethers'; + +debug.enable('*'); +const log = debug('metaport:actions'); export type ActionType = typeof Action; @@ -35,72 +51,162 @@ export class Action { execute(): void { return; }; preAction(): void { return; }; - static label: string = ''; - static buttonText: string = ''; - static loadingText: string = ''; + mpc: MetaportCore mainnet: MainnetChain sChain1: SChain sChain2: SChain + chainName1: string chainName2: string address: string amount: string - amountWei: string + amountWei: bigint tokenId: number - tokenData: TokenData + token: TokenData + + walletClient: WalletClient + + sourceToken: Contract + destToken: Contract + unwrappedToken: Contract | undefined + + originAddress: string - switchMetamaskChain: (switchBack: boolean) => Promise - setActiveStep: React.Dispatch> activeStep: number + setActiveStep: React.Dispatch> setAmountErrorMessage: React.Dispatch> setBtnText: (btnText: string) => void - wrap: boolean + _switchNetwork: (chainId: number | bigint) => Chain | undefined constructor( - mainnet: MainnetChain, - sChain1: SChain, - sChain2: SChain, + mpc: MetaportCore, + // mainnet: MainnetChain, + // sChain1: SChain, + // sChain2: SChain, chainName1: string, chainName2: string, address: string, amount: string, tokenId: number, - tokenData: TokenData, - switchMetamaskChain: (switchBack: boolean) => Promise, - setActiveStep: React.Dispatch>, - activeStep: number, - setAmountErrorMessage: React.Dispatch>, - setBtnText: (btnText: string) => void + token: TokenData, + setAmountErrorMessage: (amountErrorMessage: string) => void, + setBtnText: (btnText: string) => void, + switchNetwork: (chainId: number | bigint) => Chain | undefined, + walletClient: WalletClient ) { - this.mainnet = mainnet; - this.sChain1 = sChain1; - this.sChain2 = sChain2; + this.mpc = mpc; + // this.mainnet = mainnet; + // this.sChain1 = sChain1; + // this.sChain2 = sChain2; this.chainName1 = chainName1; this.chainName2 = chainName2; this.address = address; this.amount = amount; - if (amount) this.amountWei = toWei(amount, tokenData.decimals); + if (amount) this.amountWei = toWei(amount, token.meta.decimals); this.tokenId = Number(tokenId); - this.tokenData = tokenData; - this.switchMetamaskChain = switchMetamaskChain; - this.setActiveStep = setActiveStep; - this.activeStep = activeStep; + this.token = createTokenData(token.keyname, chainName1, token.type, this.mpc.config); + //! todo: init token here!!!!!, do not pass !!! + + // todo: init token contracts! + + if (isMainnet(chainName1)) { + this.mainnet = this.mpc.mainnet() + } else { + this.sChain1 = this.mpc.schain(this.chainName1) + } + if (isMainnet(chainName2)) { + this.mainnet = this.mpc.mainnet() + } else { + this.sChain2 = this.mpc.schain(this.chainName2) + } + + const provider1 = isMainnet(chainName1) ? this.mainnet.provider : this.sChain1.provider; + const provider2 = isMainnet(chainName2) ? this.mainnet.provider : this.sChain2.provider; + + this.sourceToken = mpc.tokenContract( + chainName1, + token.keyname, + token.type, + provider1, + this.token.wrapper(this.chainName2) ? CustomAbiTokenType.erc20wrap : null, + this.token.wrapper(this.chainName2) ? this.chainName2 : null + ); + + this.originAddress = this.mpc.originAddress( + chainName1, chainName2, token.keyname, token.type); + + + console.log('----') + console.log(this.chainName2) + console.log(token) + console.log(token.wrapper(this.chainName2)) + console.log('----') + + if (this.token.wrapper(this.chainName2)) { + this.unwrappedToken = mpc.tokenContract( + chainName1, + token.keyname, + token.type, + provider1 + ); + } + + // todo: use wrapper address! + const destWrapperAddress = this.mpc.config.connections[this.chainName2][this.token.type][this.token.keyname].chains[this.chainName1].wrapper; + if (this.token.isClone(this.chainName2) && destWrapperAddress) { + this.destToken = mpc.tokenContract( + chainName2, + token.keyname, + token.type, + provider2, + CustomAbiTokenType.erc20wrap, + this.chainName1 + ) + } else { + this.destToken = mpc.tokenContract( + chainName2, + token.keyname, + token.type, + provider2 + ) + } + + // this.switchMetamaskChain = switchMetamaskChain; + + // this.setActiveStep = setActiveStep; + // this.activeStep = activeStep; this.setAmountErrorMessage = setAmountErrorMessage; this.setBtnText = setBtnText; + this._switchNetwork = switchNetwork; + this.walletClient = walletClient; - if (this.tokenData) this.wrap = !!this.tokenData.unwrappedSymbol && !this.tokenData.clone; + // if (this.tokenData) this.wrap = !!this.token.unwrappedSymbol && !this.token.clone; } + // tokenContract( + // provider: Provider, + // source: boolean = true + // ): Contract { + // return this.mpc.tokenContract( + // source ? this.chainName1 : this.chainName2, + // this.token.keyname, + // this.token.type, + // provider + // ) + // } + updateState( currentState: ActionState, transactionHash?: string, timestamp?: string | number ) { + log(`actionStateUpd: ${this.constructor.name} - ${currentState} - ${this.token.keyname} \ +- ${this.chainName1} -> ${this.chainName2}`); externalEvents.actionStateUpdated( this.constructor.name, currentState, @@ -117,28 +223,53 @@ export class Action { ); this.setBtnText(LOADING_BUTTON_TEXT[currentState]); } + + async getConnectedChain( + provider: Provider, + customAbiTokenType?: CustomAbiTokenType, + destChainName?: string + ): Promise { + let chain: MainnetChain | SChain; + this.updateState('switch'); + const currentChainId = this.walletClient.chain.id; + const { chainId } = await provider.getNetwork(); + log(`Current chainId: ${currentChainId}, required chainId: ${chainId} `); + if (currentChainId !== Number(chainId)) { + log(`Switching network to ${chainId}...`); + const chain = await this._switchNetwork(Number(chainId)); + if (!chain) { + throw new Error(`Failed to switch from ${currentChainId} to ${chainId} `); + } + log(`Network switched to ${chainId}...`); + } + const signer = walletClientToSigner(this.walletClient) + if (isMainnetChainId(chainId, this.mpc.config.skaleNetwork)) { + chain = new MainnetChain(signer.provider, getMainnetAbi(this.mpc.config.skaleNetwork)); + } else { + chain = new SChain(signer.provider, IMA_ABIS.schain); + } + const token = this.mpc.tokenContract( + destChainName === this.chainName1 ? this.chainName2 : this.chainName1, + this.token.keyname, + this.token.type, + chain.provider, + customAbiTokenType, + destChainName + ); + chain.erc20.addToken(this.token.keyname, token); + return chain; + } } export abstract class TransferAction extends Action { - static label = 'Transfer' - static buttonText = 'Transfer' - static loadingText = 'Transferring' - transferComplete(tx): void { externalEvents.transferComplete( tx, this.chainName1, this.chainName2, - this.tokenData.keyname, + this.token.keyname, false ); } } - - -export abstract class ApproveAction extends Action { - static label = 'Approve transfer' - static buttonText = 'Approve' - static loadingText = 'Approving' -} diff --git a/src/core/actions/checks.ts b/src/core/actions/checks.ts index 972aec3..f971539 100644 --- a/src/core/actions/checks.ts +++ b/src/core/actions/checks.ts @@ -23,11 +23,11 @@ import debug from 'debug'; -import { Contract } from 'web3-eth-contract'; +import { Contract } from "ethers"; import { MainnetChain, SChain } from '@skalenetwork/ima-js'; import { fromWei } from '../convertation'; -import TokenData from '../dataclasses/TokenData'; +import { TokenData } from '../dataclasses/TokenData'; import * as interfaces from '../interfaces'; import { addressesEqual } from '../helper'; import { DEFAULT_ERC20_DECIMALS, SFUEL_RESERVE_AMOUNT } from '../constants'; @@ -48,9 +48,9 @@ export async function checkEthBalance( // TODO: optimize balance checks try { const balance = await chain.ethBalance(address); log(`address: ${address}, eth balance: ${balance}, amount: ${amount}`); - const balanceEther = fromWei(balance, tokenData.decimals); + const balanceEther = fromWei(balance, tokenData.meta.decimals); if (Number(amount) + SFUEL_RESERVE_AMOUNT > Number(balanceEther)) { - checkRes.msg = `Current balance: ${balanceEther} ${tokenData.symbol}. \ + checkRes.msg = `Current balance: ${balanceEther} ${tokenData.meta.symbol}. \ ${SFUEL_RESERVE_AMOUNT} ETH will be reserved to cover transfer costs.`; } else { checkRes.res = true; @@ -73,11 +73,11 @@ export async function checkERC20Balance( const checkRes: interfaces.CheckRes = { res: false }; if (!amount || Number(amount) === 0) return checkRes; try { - const balance = await tokenContract.methods.balanceOf(address).call(); + const balance = await tokenContract.balanceOf(address); log(`address: ${address}, balanceWei: ${balance}, amount: ${amount}`); - const balanceEther = fromWei(balance, tokenData.decimals); + const balanceEther = fromWei(balance, tokenData.meta.decimals); if (Number(amount) > Number(balanceEther)) { - checkRes.msg = `Current balance: ${balanceEther} ${tokenData.symbol}`; + checkRes.msg = `Insufficient balance: ${balanceEther} ${tokenData.meta.symbol}`; } else { checkRes.res = true; } @@ -97,7 +97,7 @@ export async function checkSFuelBalance( const checkRes: interfaces.CheckRes = { res: false }; if (!amount || Number(amount) === 0) return checkRes; try { - const balance = await sChain.web3.eth.getBalance(address); + const balance = await sChain.provider.getBalance(address); log(`address: ${address}, balanceWei: ${balance}, amount: ${amount}`); const balanceEther = fromWei(balance, DEFAULT_ERC20_DECIMALS); if (Number(amount) + SFUEL_RESERVE_AMOUNT > Number(balanceEther)) { @@ -125,11 +125,11 @@ export async function checkERC20Allowance( const checkRes: interfaces.CheckRes = { res: false }; if (!amount || Number(amount) === 0) return checkRes; try { - const allowance = await tokenContract.methods.allowance( + const allowance = await tokenContract.allowance( address, approvalAddress - ).call(); - const allowanceEther = fromWei(allowance, tokenData.decimals); + ) + const allowanceEther = fromWei(allowance, tokenData.meta.decimals); log(`allowanceEther: ${allowanceEther}, amount: ${amount}`); checkRes.res = Number(allowanceEther) >= Number(amount); return checkRes; @@ -151,7 +151,7 @@ export async function checkERC721( const checkRes: interfaces.CheckRes = { res: true, approved: false }; if (!tokenId) return checkRes; try { - approvedAddress = await tokenContract.methods.getApproved(tokenId).call(); + approvedAddress = await tokenContract.getApproved(tokenId) log(`approvedAddress: ${approvedAddress}, address: ${address}`); } catch (err) { log(err); @@ -159,7 +159,7 @@ export async function checkERC721( return checkRes; } try { - const currentOwner = await tokenContract.methods.ownerOf(tokenId).call();; + const currentOwner = await tokenContract.ownerOf(tokenId); log(`currentOwner: ${currentOwner}, address: ${address}`); if (!addressesEqual(currentOwner, address)) { checkRes.msg = 'This account is not an owner of this tokenId'; @@ -187,15 +187,15 @@ export async function checkERC1155( if (!tokenId || !amount) return checkRes; try { - const balance = await tokenContract.methods.balanceOf(address, tokenId).call(); + const balance = await tokenContract.balanceOf(address, tokenId) log(`address: ${address}, balanceEther: ${balance}, amount: ${amount}`); if (Number(amount) > Number(balance)) { - checkRes.msg = `Current balance: ${balance} ${tokenData.symbol}`; + checkRes.msg = `Current balance: ${balance} ${tokenData.meta.symbol}`; } - checkRes.approved = await tokenContract.methods.isApprovedForAll( + checkRes.approved = await tokenContract.isApprovedForAll( address, approvalAddress - ).call(); + ) } catch (err) { log(err); checkRes.msg = 'Something went wrong, check developer console'; diff --git a/src/core/actions/erc1155.ts b/src/core/actions/erc1155.ts deleted file mode 100644 index 66f0d42..0000000 --- a/src/core/actions/erc1155.ts +++ /dev/null @@ -1,222 +0,0 @@ -/** - * @license - * SKALE Metaport - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -/** - * @file erc1155.ts - * @copyright SKALE Labs 2022-Present - */ - - -import debug from 'debug'; - -import { TransferAction } from './action'; -import { checkERC1155 } from './checks'; -import { externalEvents } from '../events'; - - -debug.enable('*'); -const log = debug('metaport:actions:erc1155'); - - -export class TransferERC1155M extends TransferAction { - async approve(): Promise { - const checkRes = await checkERC1155( - this.address, - this.mainnet.erc1155.address, - this.tokenId, - this.amount, - this.tokenData, - this.mainnet.erc1155.tokens[this.tokenData.keyname] - ); - this.setAmountErrorMessage(checkRes.msg); - if (!checkRes.approved) { - this.updateState('approve'); - log(`TransferERC1155M:execute - approving token ${this.tokenId} (${this.chainName1})`); - const approveTx = await this.mainnet.erc1155.approveAll( - this.tokenData.keyname, - { address: this.address } - ) - const txBlock = await this.mainnet.web3.eth.getBlock(approveTx.blockNumber); - this.updateState('approveDone', approveTx.transactionHash, txBlock.timestamp); - externalEvents.transactionCompleted( - approveTx, txBlock.timestamp, this.chainName1, 'approve'); - log('TransferERC1155M:execute - approve tx completed: %O', approveTx); - } - } -} - - -export class TransferERC1155S extends TransferAction { - async approve(): Promise { - const checkRes = await checkERC1155( - this.address, - this.sChain1.erc1155.address, - this.tokenId, - this.amount, - this.tokenData, - this.sChain1.erc1155.tokens[this.tokenData.keyname] - ); - this.setAmountErrorMessage(checkRes.msg); - if (!checkRes.approved) { - this.updateState('approve'); - log(`TransferERC1155S:execute - approving token ${this.tokenId} (${this.chainName1})`); - const approveTx = await this.sChain1.erc1155.approveAll( - this.tokenData.keyname, - this.tokenId, - { address: this.address } - ); - const txBlock = await this.sChain1.web3.eth.getBlock(approveTx.blockNumber); - this.updateState('approveDone', approveTx.transactionHash, txBlock.timestamp); - externalEvents.transactionCompleted( - approveTx, txBlock.timestamp, this.chainName1, 'approve'); - log('TransferERC1155M:execute - approve tx completed: %O', approveTx); - } - } -} - - -export class TransferERC1155M2S extends TransferERC1155M { - async execute() { - this.updateState('init'); - await this.approve(); - this.updateState('transfer'); - const destTokenContract = this.sChain2.erc1155.tokens[this.tokenData.keyname] - const balanceOnDestination = await this.sChain2.getERC1155Balance( - destTokenContract, - this.address, - this.tokenId - ); - const tx = await this.mainnet.erc1155.deposit( - this.chainName2, - this.tokenData.keyname, - this.tokenId, - this.amount, - { address: this.address } - ); - const block = await this.mainnet.web3.eth.getBlock(tx.blockNumber); - this.updateState('transferDone', tx.transactionHash, block.timestamp); - externalEvents.transactionCompleted( - tx, block.timestamp, this.chainName1, 'deposit'); - log('TransferERC1155M2S:execute - tx completed %O', tx); - await this.sChain2.waitERC1155BalanceChange( - destTokenContract, this.address, this.tokenId, balanceOnDestination); - this.updateState('received'); - log('TransferERC1155M2S:execute - tokens received to destination chain'); - this.transferComplete(tx); - } - - async preAction() { - const checkRes = await checkERC1155( - this.address, - this.mainnet.erc1155.address, - this.tokenId, - this.amount, - this.tokenData, - this.mainnet.erc1155.tokens[this.tokenData.keyname] - ); - this.setAmountErrorMessage(checkRes.msg); - if (!checkRes.approved) this.setActiveStep(0); - } -} - - -export class TransferERC1155S2M extends TransferERC1155S { - async execute() { - this.updateState('init'); - await this.approve(); - this.updateState('transfer'); - const destTokenContract = this.mainnet.erc1155.tokens[this.tokenData.keyname]; - const balanceOnDestination = await this.mainnet.getERC1155Balance( - destTokenContract, - this.address, - this.tokenId - ); - const tx = await this.sChain1.erc1155.withdraw( - this.tokenData.originAddress, - this.tokenId, - this.amount, - { address: this.address } - ); - const block = await this.sChain1.web3.eth.getBlock(tx.blockNumber); - this.updateState('transferDone', tx.transactionHash, block.timestamp); - externalEvents.transactionCompleted( - tx, block.timestamp, this.chainName1, 'withdraw'); - await this.mainnet.waitERC1155BalanceChange( - destTokenContract, this.address, this.tokenId, balanceOnDestination); - this.updateState('received'); - log('TransferERC1155S2M:execute - tokens received to destination chain'); - this.transferComplete(tx); - } - - async preAction() { - const checkRes = await checkERC1155( - this.address, - this.sChain1.erc1155.address, - this.tokenId, - this.amount, - this.tokenData, - this.sChain1.erc1155.tokens[this.tokenData.keyname] - ); - this.setAmountErrorMessage(checkRes.msg); - if (!checkRes.approved) this.setActiveStep(0); - } -} - - -export class TransferERC1155S2S extends TransferERC1155S { - async execute() { - this.updateState('init'); - await this.approve(); - this.updateState('transfer'); - const destTokenContract = this.sChain2.erc1155.tokens[this.tokenData.keyname]; - const ownerOnDestination = await this.sChain2.getERC1155Balance( - destTokenContract, - this.address, - this.tokenId - ); - const tx = await this.sChain1.erc1155.transferToSchain( - this.chainName2, - this.tokenData.originAddress, - this.tokenId, - this.amount, - { address: this.address } - ); - const block = await this.sChain1.web3.eth.getBlock(tx.blockNumber); - this.updateState('transferDone', tx.transactionHash, block.timestamp); - externalEvents.transactionCompleted( - tx, block.timestamp, this.chainName1, 'transferToSchain'); - await this.sChain2.waitERC1155BalanceChange( - destTokenContract, this.address, this.tokenId, ownerOnDestination); - this.updateState('received'); - log('TransferERC1155S2S:execute - tokens received to destination chain'); - this.transferComplete(tx); - } - - async preAction() { - const checkRes = await checkERC1155( - this.address, - this.sChain1.erc1155.address, - this.tokenId, - this.amount, - this.tokenData, - this.sChain1.erc1155.tokens[this.tokenData.keyname] - ); - this.setAmountErrorMessage(checkRes.msg); - if (!checkRes.approved) this.setActiveStep(0); - } -} \ No newline at end of file diff --git a/src/core/actions/erc20.ts b/src/core/actions/erc20.ts index 5e73483..18b549e 100644 --- a/src/core/actions/erc20.ts +++ b/src/core/actions/erc20.ts @@ -24,12 +24,15 @@ import debug from 'debug'; +import { MainnetChain, SChain } from '@skalenetwork/ima-js'; + import { externalEvents } from '../events'; import { toWei } from '../convertation'; import { MAX_APPROVE_AMOUNT } from '../constants'; -import { TransferAction, Action } from './action'; +import { TransferAction, Action } from '../actions/action'; import { checkERC20Balance, checkERC20Allowance, checkSFuelBalance } from './checks'; +import { CustomAbiTokenType } from '../dataclasses'; debug.enable('*'); @@ -38,28 +41,29 @@ const log = debug('metaport:actions:erc20'); export class TransferERC20S2S extends TransferAction { async execute() { - log('TransferERC20S2S:execute - starting'); this.updateState('init'); - - const tokenContract = this.sChain1.erc20.tokens[this.tokenData.keyname]; const checkResAllowance = await checkERC20Allowance( this.address, this.sChain1.erc20.address, this.amount, - this.tokenData, - tokenContract + this.token, + this.sourceToken ); - + const sChain = await this.getConnectedChain( + this.sChain1.provider, + this.token.wrapper(this.chainName2) ? CustomAbiTokenType.erc20wrap : null, + this.token.wrapper(this.chainName2) ? this.chainName2 : null + ) as SChain; if (!checkResAllowance.res) { this.updateState('approve'); - const approveTx = await this.sChain1.erc20.approve( - this.tokenData.keyname, + const approveTx = await sChain.erc20.approve( + this.token.keyname, MAX_APPROVE_AMOUNT, - this.sChain1.erc20.address, + sChain.erc20.address, { address: this.address } ); - const txBlock = await this.sChain1.web3.eth.getBlock(approveTx.blockNumber); - this.updateState('approveDone', approveTx.transactionHash, txBlock.timestamp); + const txBlock = await sChain.provider.getBlock(approveTx.blockNumber); + this.updateState('approveDone', approveTx.hash, txBlock.timestamp); externalEvents.transactionCompleted( approveTx, txBlock.timestamp, this.chainName1, 'approve'); log('ApproveERC20S:execute - tx completed: %O', approveTx); @@ -69,92 +73,74 @@ export class TransferERC20S2S extends TransferAction { this.updateState('transfer'); - const amountWei = toWei(this.amount, this.tokenData.decimals); - const destTokenContract = this.sChain2.erc20.tokens[this.tokenData.keyname]; + const amountWei = toWei(this.amount, this.token.meta.decimals); let balanceOnDestination; - if (this.tokenData.wrapsSFuel && this.tokenData.clone) { - balanceOnDestination = await this.sChain2.web3.eth.getBalance(this.address); + const tokenConnection = this.token.connections[this.chainName2]; + + const isDestinationSFuel = tokenConnection.wrapsSFuel && tokenConnection.clone; // TODO! + + if (isDestinationSFuel) { + balanceOnDestination = await this.sChain2.provider.getBalance(this.address); } else { balanceOnDestination = await this.sChain2.getERC20Balance( - destTokenContract, + this.destToken, this.address ); } - - const tx = await this.sChain1.erc20.transferToSchain( + const tx = await sChain.erc20.transferToSchain( this.chainName2, - this.tokenData.originAddress, + this.originAddress, amountWei, { address: this.address } ); - const block = await this.sChain1.web3.eth.getBlock(tx.blockNumber); - this.updateState('transferDone', tx.transactionHash, block.timestamp); - externalEvents.transactionCompleted( - tx, block.timestamp, this.chainName1, 'transferToSchain'); - log('TransferERC20S2S:execute - tx completed %O', tx); - - if (this.tokenData.wrapsSFuel && this.tokenData.clone) { + const block = await sChain.provider.getBlock(tx.blockNumber); + this.updateState('transferDone', tx.hash, block.timestamp); + if (isDestinationSFuel) { await this.sChain2.waitETHBalanceChange( this.address, balanceOnDestination ); } else { await this.sChain2.waitERC20BalanceChange( - destTokenContract, + this.destToken, this.address, balanceOnDestination ); } - this.updateState('received'); - log('TransferERC20S2S:execute - tokens received to destination chain'); - - const unwrap = !!this.tokenData.unwrappedSymbol && this.tokenData.clone; - externalEvents.transferComplete( - tx, - this.chainName1, - this.chainName2, - this.tokenData.keyname, - unwrap - ); } async preAction() { - const tokenContract = this.sChain1.erc20.tokens[this.tokenData.keyname]; - const checkResBalance = await checkERC20Balance( this.address, this.amount, - this.tokenData, - tokenContract + this.token, + this.sourceToken ); - if (!checkResBalance.res) { this.setAmountErrorMessage(checkResBalance.msg); + return } + this.setAmountErrorMessage(null); } } export class WrapSFuelERC20S extends Action { - static label = 'Wrap token' - static buttonText = 'Wrap token' - static loadingText = 'Wrapping token' - async execute() { log('WrapSFuelERC20S:execute - starting'); this.updateState('wrap'); const tx = await this.sChain1.erc20.fundExit( - this.tokenData.keyname, + this.token.keyname, { address: this.address, value: this.amountWei } ); - const block = await this.sChain1.web3.eth.getBlock(tx.blockNumber); - this.updateState('wrapDone', tx.transactionHash, block.timestamp); + const block = await this.sChain1.provider.getBlock(tx.blockNumber); + this.updateState('wrapDone', tx.hash, block.timestamp); externalEvents.transactionCompleted(tx, block.timestamp, this.chainName1, 'wrapsfuel'); log('WrapSFuelERC20S:execute - tx completed %O', tx); } @@ -170,154 +156,158 @@ export class WrapSFuelERC20S extends Action { this.setAmountErrorMessage(checkResBalance.msg); return } + this.setAmountErrorMessage(null); } } export class WrapERC20S extends Action { - static label = 'Wrap' - static buttonText = 'Wrap' - static loadingText = 'Wrapping' - async execute() { - log('WrapERC20S:execute - starting'); this.updateState('init'); - - const tokenContract = this.sChain1.erc20.tokens[this.tokenData.unwrappedSymbol]; const checkResAllowance = await checkERC20Allowance( this.address, - this.tokenData.originAddress, + this.token.connections[this.chainName2].wrapper, this.amount, - this.tokenData, - tokenContract + this.token, + this.unwrappedToken ); - + const sChain = await this.getConnectedChain(this.sChain1.provider) as SChain; + const wrapperToken = this.mpc.tokenContract( + this.chainName1, + this.token.keyname, + this.token.type, + sChain.provider, + CustomAbiTokenType.erc20wrap, + this.chainName2 + ); + sChain.erc20.addToken(`wrap_${this.token.keyname}`, wrapperToken); if (!checkResAllowance.res) { this.updateState('approveWrap'); - log('ApproveWrapERC20S:execute - starting'); - const approveTx = await this.sChain1.erc20.approve( - this.tokenData.unwrappedSymbol, + const approveTx = await sChain.erc20.approve( + this.token.keyname, MAX_APPROVE_AMOUNT, - this.tokenData.originAddress, + this.token.address, { address: this.address } ); - const txBlock = await this.sChain1.web3.eth.getBlock(approveTx.blockNumber); - this.updateState('approveWrapDone', approveTx.transactionHash, txBlock.timestamp); - externalEvents.transactionCompleted( - approveTx, txBlock.timestamp, this.chainName1, 'approveWrap'); - log('ApproveWrapERC20S:execute - tx completed %O', approveTx); + const txBlock = await this.sChain1.provider.getBlock(approveTx.blockNumber); + this.updateState('approveWrapDone', approveTx.hash, txBlock.timestamp); } - this.updateState('wrap'); - - const amountWei = toWei(this.amount, this.tokenData.decimals); - const tx = await this.sChain1.erc20.wrap( - this.tokenData.keyname, + const amountWei = toWei(this.amount, this.token.meta.decimals); + const tx = await sChain.erc20.wrap( + `wrap_${this.token.keyname}`, amountWei, { address: this.address } ); - const block = await this.sChain1.web3.eth.getBlock(tx.blockNumber); - this.updateState('wrapDone', tx.transactionHash, block.timestamp); - externalEvents.transactionCompleted(tx, block.timestamp, this.chainName1, 'wrap'); - log('WrapERC20S:execute - tx completed %O', tx); + const block = await this.sChain1.provider.getBlock(tx.blockNumber); + this.updateState('wrapDone', tx.hash, block.timestamp); } async preAction() { - const tokenContract = this.sChain1.erc20.tokens[this.tokenData.unwrappedSymbol]; const checkResBalance = await checkERC20Balance( this.address, this.amount, - this.tokenData, - tokenContract + this.token, + this.unwrappedToken ); if (!checkResBalance.res) { this.setAmountErrorMessage(checkResBalance.msg); return } + this.setAmountErrorMessage(null); } } -export class UnWrapERC20S2S extends Action { - static label = 'Unwrap' - static buttonText = 'Unwrap' - static loadingText = 'Unwrapping' - async execute() { - log('UnWrapERC20S2S:execute - starting'); - this.updateState('switch'); - await this.switchMetamaskChain(false); - this.updateState('unwrap'); - try { - const amountWei = toWei(this.amount, this.tokenData.decimals); - const tx = await this.sChain2.erc20.unwrap( - this.tokenData.keyname, - amountWei, - { address: this.address } - ); - const block = await this.sChain2.web3.eth.getBlock(tx.blockNumber); - this.updateState('unwrapDone', tx.transactionHash, block.timestamp); - externalEvents.transactionCompleted(tx, block.timestamp, this.chainName2, 'unwrap'); - externalEvents.unwrapComplete(tx, this.chainName2, this.tokenData.keyname); - log('UnWrapERC20S2S:execute - tx completed %O', tx); - } finally { - // log('UnWrapERC20S2S:execute - switchMetamaskChain back'); - // this.switchMetamaskChain(true); - } - } - - async preAction() { - log('preAction: UnWrapERC20S2S'); - const tokenContract = this.sChain2.erc20.tokens[this.tokenData.keyname]; - const checkResBalance = await checkERC20Balance( - this.address, - this.amount, - this.tokenData, - tokenContract - ); - if (!checkResBalance.res) { - this.setAmountErrorMessage(checkResBalance.msg); - return - } - } -} +// export class UnWrapERC20S2S123 extends Action { +// static label = 'Unwrap' +// static buttonText = 'Unwrap' +// static loadingText = 'Unwrapping' +// async execute() { +// log('UnWrapERC20S2S:execute - starting'); + +// const sChain = await this.getConnectedChain(this.sChain2.provider) as SChain; +// this.updateState('unwrap'); +// try { +// const amountWei = toWei(this.amount, this.token.meta.decimals); +// const tx = await sChain.erc20.unwrap( +// this.token.keyname, +// amountWei, +// { address: this.address } +// ); +// const block = await sChain.provider.getBlock(tx.blockNumber); +// this.updateState('unwrapDone', tx.hash, block.timestamp); +// externalEvents.transactionCompleted(tx, block.timestamp, this.chainName2, 'unwrap'); +// externalEvents.unwrapComplete(tx.hash, this.chainName2, this.token.keyname); +// log('UnWrapERC20S2S:execute - tx completed %O', tx); +// } finally { +// // log('UnWrapERC20S2S:execute - switchMetamaskChain back'); +// // this.switchMetamaskChain(true); +// } +// } + +// async preAction() { +// log('preAction: UnWrapERC20S2S'); +// const tokenContract = this.sChain2.erc20.tokens[this.token.keyname]; +// const checkResBalance = await checkERC20Balance( +// this.address, +// this.amount, +// this.token, +// tokenContract +// ); +// if (!checkResBalance.res) { +// this.setAmountErrorMessage(checkResBalance.msg); +// return +// } +// } +// } export class UnWrapERC20S extends Action { - static label = 'Unwrap stuck tokens' - static buttonText = 'Unwrap All' - static loadingText = 'Unwrapping' - async execute() { - log('UnWrapERC20S:execute - starting'); + const sChain = await this.getConnectedChain( + this.sChain2.provider, + CustomAbiTokenType.erc20wrap, + this.chainName1 + ) as SChain; + // const token = this.mpc.tokenContract( + // this.chainName2, + // this.token.keyname, + // this.token.type, + // sChain.provider, + // CustomAbiTokenType.erc20wrap, + // this.chainName1 + // ); + // sChain.erc20.addToken(this.token.keyname, token); this.updateState('unwrap'); let tx; - if (this.tokenData.wrapsSFuel) { - tx = await this.sChain1.erc20.undoExit( - this.tokenData.keyname, + if (this.token.connections[this.chainName2].wrapsSFuel) { + tx = await sChain.erc20.undoExit( + this.token.keyname, { address: this.address } ); } else { - const amountWei = toWei(this.amount, this.tokenData.decimals); - tx = await this.sChain1.erc20.unwrap( - this.tokenData.keyname, + const amountWei = toWei(this.amount, this.token.meta.decimals); + tx = await sChain.erc20.unwrap( + this.token.keyname, amountWei, { address: this.address } ); } log('UnWrapERC20S:execute - tx completed %O', tx); - const block = await this.sChain1.web3.eth.getBlock(tx.blockNumber); - this.updateState('unwrapDone', tx.transactionHash, block.timestamp); + const block = await sChain.provider.getBlock(tx.blockNumber); + this.updateState('unwrapDone', tx.hash, block.timestamp); externalEvents.transactionCompleted(tx, block.timestamp, this.chainName1, 'unwrap'); - externalEvents.unwrapComplete(tx, this.chainName2, this.tokenData.keyname); + externalEvents.unwrapComplete(tx, this.chainName2, this.token.keyname); } async preAction() { log('preAction: UnWrapERC20S'); - const tokenContract = this.sChain1.erc20.tokens[this.tokenData.keyname]; + const tokenContract = this.sChain1.erc20.tokens[this.token.keyname]; const checkResBalance = await checkERC20Balance( this.address, this.amount, - this.tokenData, + this.token, tokenContract ); if (!checkResBalance.res) { @@ -330,150 +320,136 @@ export class UnWrapERC20S extends Action { export class TransferERC20M2S extends TransferAction { async execute() { - log('TransferERC20M2S:execute - starting'); this.updateState('init'); // check approve + approve - - const tokenContract = this.mainnet.erc20.tokens[this.tokenData.keyname]; const checkResAllowance = await checkERC20Allowance( this.address, this.mainnet.erc20.address, this.amount, - this.tokenData, - tokenContract + this.token, + this.sourceToken ); - + const mainnet = await this.getConnectedChain(this.mainnet.provider) as MainnetChain; if (!checkResAllowance.res) { this.updateState('approve'); - const approveTx = await this.mainnet.erc20.approve( - this.tokenData.keyname, + const approveTx = await mainnet.erc20.approve( + this.token.keyname, MAX_APPROVE_AMOUNT, { address: this.address } ); - const txBlock = await this.mainnet.web3.eth.getBlock(approveTx.blockNumber); - this.updateState('approveDone', approveTx.transactionHash, txBlock.timestamp); - externalEvents.transactionCompleted( - approveTx, txBlock.timestamp, this.chainName1, 'approve'); - log('ApproveERC20S:execute - tx completed: %O', approveTx); + const txBlock = await mainnet.provider.getBlock(approveTx.blockNumber); + this.updateState('approveDone', approveTx.hash, txBlock.timestamp); } - this.updateState('transfer'); - - const amountWei = toWei(this.amount, this.tokenData.decimals); - const destTokenContract = this.sChain2.erc20.tokens[this.tokenData.keyname]; + const amountWei = toWei(this.amount, this.token.meta.decimals); + // const destTokenContract = this.sChain2.erc20.tokens[this.token.keyname]; const balanceOnDestination = await this.sChain2.getERC20Balance( - destTokenContract, + this.destToken, this.address ); - const tx = await await this.mainnet.erc20.deposit( + const tx = await await mainnet.erc20.deposit( this.chainName2, - this.tokenData.keyname, + this.token.keyname, amountWei, { address: this.address } ); - const block = await this.mainnet.web3.eth.getBlock(tx.blockNumber); - this.updateState('transferDone', tx.transactionHash, block.timestamp); + const block = await mainnet.provider.getBlock(tx.blockNumber); + this.updateState('transferDone', tx.hash, block.timestamp); externalEvents.transactionCompleted(tx, block.timestamp, this.chainName1, 'deposit'); log('TransferERC20M2S:execute - tx completed %O', tx); await this.sChain2.waitERC20BalanceChange( - destTokenContract, this.address, balanceOnDestination); + this.destToken, this.address, balanceOnDestination); this.updateState('received'); log('TransferERC20M2S:execute - tokens received to destination chain'); externalEvents.transferComplete( - tx, + tx.hash, this.chainName1, this.chainName2, - this.tokenData.keyname, + this.token.keyname, false ); } async preAction() { - const tokenContract = this.mainnet.erc20.tokens[this.tokenData.keyname]; const checkResBalance = await checkERC20Balance( this.address, this.amount, - this.tokenData, - tokenContract + this.token, + this.sourceToken ); if (!checkResBalance.res) { this.setAmountErrorMessage(checkResBalance.msg); return } + this.setAmountErrorMessage(null); } } export class TransferERC20S2M extends TransferAction { async execute() { - log('TransferERC20S2M:execute - starting'); this.updateState('init'); // check approve + approve - const tokenContract = this.sChain1.erc20.tokens[this.tokenData.keyname]; const checkResAllowance = await checkERC20Allowance( this.address, this.sChain1.erc20.address, this.amount, - this.tokenData, - tokenContract + this.token, + this.sourceToken ); - + const sChain = await this.getConnectedChain(this.sChain1.provider) as SChain; if (!checkResAllowance.res) { this.updateState('approve'); - const approveTx = await this.sChain1.erc20.approve( - this.tokenData.keyname, + const approveTx = await sChain.erc20.approve( + this.token.keyname, MAX_APPROVE_AMOUNT, - this.sChain1.erc20.address, + sChain.erc20.address, { address: this.address } ); - const txBlock = await this.sChain1.web3.eth.getBlock(approveTx.blockNumber); - this.updateState('approveDone', approveTx.transactionHash, txBlock.timestamp); + const txBlock = await sChain.provider.getBlock(approveTx.blockNumber); + this.updateState('approveDone', approveTx.hash, txBlock.timestamp); externalEvents.transactionCompleted( approveTx, txBlock.timestamp, this.chainName1, 'approve'); log('ApproveERC20S:execute - tx completed: %O', approveTx); } - this.updateState('transfer'); - - const amountWei = toWei(this.amount, this.tokenData.decimals); - const destTokenContract = this.mainnet.erc20.tokens[this.tokenData.keyname]; + const amountWei = toWei(this.amount, this.token.meta.decimals); const balanceOnDestination = await this.mainnet.getERC20Balance( - destTokenContract, this.address); - - const tx = await this.sChain1.erc20.withdraw( - this.tokenData.originAddress, + this.destToken, this.address); + const tx = await sChain.erc20.withdraw( + this.originAddress, amountWei, { address: this.address } ); - const block = await this.sChain1.web3.eth.getBlock(tx.blockNumber); - this.updateState('transferDone', tx.transactionHash, block.timestamp); + const block = await sChain.provider.getBlock(tx.blockNumber); + this.updateState('transferDone', tx.hash, block.timestamp); externalEvents.transactionCompleted(tx, block.timestamp, this.chainName1, 'withdraw'); log('TransferERC20S2M:execute - tx completed %O', tx); - this.mainnet.waitERC20BalanceChange(destTokenContract, this.address, balanceOnDestination); + this.mainnet.waitERC20BalanceChange(this.destToken, this.address, balanceOnDestination); this.updateState('received'); log('TransferERC20S2M:execute - tokens received to destination chain'); externalEvents.transferComplete( - tx, + tx.hash, this.chainName1, this.chainName2, - this.tokenData.keyname, + this.token.keyname, false ); } async preAction() { - const tokenContract = this.sChain1.erc20.tokens[this.tokenData.keyname]; const checkResBalance = await checkERC20Balance( this.address, this.amount, - this.tokenData, - tokenContract + this.token, + this.sourceToken ); if (!checkResBalance.res) { this.setAmountErrorMessage(checkResBalance.msg); return } + this.setAmountErrorMessage(null); } } diff --git a/src/core/actions/erc721.ts b/src/core/actions/erc721.ts deleted file mode 100644 index 1f92c04..0000000 --- a/src/core/actions/erc721.ts +++ /dev/null @@ -1,236 +0,0 @@ -/** - * @license - * SKALE Metaport - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -/** - * @file erc721.ts - * @copyright SKALE Labs 2022-Present - */ - - -import debug from 'debug'; - -import { Action } from './action'; -import { TokenType } from '../dataclasses/TokenType'; -import { externalEvents } from '../events'; -import { checkERC721 } from './checks'; - - -debug.enable('*'); -const log = debug('metaport:actions:erc721'); - - -class ERC721Action extends Action { - isMeta(): boolean { return this.tokenData.type === TokenType.erc721meta; }; - mn() { return this.isMeta() ? this.mainnet.erc721meta : this.mainnet.erc721; }; - s1() { return this.isMeta() ? this.sChain1.erc721meta : this.sChain1.erc721; }; - s2() { return this.isMeta() ? this.sChain2.erc721meta : this.sChain2.erc721; }; -} - - -class ERC721Transfer extends ERC721Action { - static label = 'Transfer' - static buttonText = 'Transfer' - static loadingText = 'Transferring' - - transferComplete(tx): void { - externalEvents.transferComplete( - tx, - this.chainName1, - this.chainName2, - this.tokenData.keyname, - false - ); - } -} - - -class ERC721TransferS extends ERC721Transfer { - async approve(): Promise { - const checkRes = await checkERC721( - this.address, - this.s1().address, - this.tokenId, - this.s1().tokens[this.tokenData.keyname] - ); - this.setAmountErrorMessage(checkRes.msg); - if (!checkRes.approved) { - this.updateState('approve'); - log(`ERC721TransferS:execute - approving token ${this.tokenId} (${this.chainName1})`); - const approveTx = await this.s1().approve( - this.tokenData.keyname, - this.tokenId, - { address: this.address } - ); - const txBlock = await this.s1().web3.eth.getBlock(approveTx.blockNumber); - this.updateState('approveDone', approveTx.transactionHash, txBlock.timestamp); - externalEvents.transactionCompleted( - approveTx, txBlock.timestamp, this.chainName1, 'approve'); - log('ERC721TransferS:execute - approve tx completed: %O', approveTx); - } - } -} - - -class ERC721TransferM extends ERC721Transfer { - async approve(): Promise { - const checkRes = await checkERC721( - this.address, - this.mn().address, - this.tokenId, - this.mn().tokens[this.tokenData.keyname] - ); - this.setAmountErrorMessage(checkRes.msg); - if (!checkRes.approved) { - this.updateState('approve'); - log(`ERC721TransferM:execute - approving token ${this.tokenId} (${this.chainName1})`); - const approveTx = await this.mn().approve( - this.tokenData.keyname, - this.tokenId, - { address: this.address } - ) - const txBlock = await this.mn().web3.eth.getBlock(approveTx.blockNumber); - this.updateState('approveDone', approveTx.transactionHash, txBlock.timestamp); - externalEvents.transactionCompleted( - approveTx, txBlock.timestamp, this.chainName1, 'approve'); - log('ERC721TransferS:execute - approve tx completed: %O', approveTx); - } - } -} - - -export class TransferERC721M2S extends ERC721TransferM { - async execute() { - this.updateState('init'); - await this.approve(); - this.updateState('transfer'); - const destTokenContract = this.s2().tokens[this.tokenData.keyname] - const ownerOnDestination = await this.sChain2.getERC721OwnerOf( - destTokenContract, - this.tokenId - ); - const tx = await this.mn().deposit( - this.chainName2, - this.tokenData.keyname, - this.tokenId, - { address: this.address } - ); - const block = await this.mn().web3.eth.getBlock(tx.blockNumber); - this.updateState('transferDone', tx.transactionHash, block.timestamp); - externalEvents.transactionCompleted( - tx, block.timestamp, this.chainName1, 'deposit'); - log('TransferERC721M2S:execute - tx completed %O', tx); - await this.sChain2.waitERC721OwnerChange( - destTokenContract, this.tokenId, ownerOnDestination); - this.updateState('received'); - log('Token received to destination chain'); - this.transferComplete(tx); - } - - async preAction() { - const checkRes = await checkERC721( - this.address, - this.mn().address, - this.tokenId, - this.mn().tokens[this.tokenData.keyname] - ); - this.setAmountErrorMessage(checkRes.msg); - if (!checkRes.approved) this.setActiveStep(0); - } -} - - -export class TransferERC721S2M extends ERC721TransferS { - async execute() { - this.updateState('init'); - await this.approve(); - this.updateState('transfer'); - const destTokenContract = this.mn().tokens[this.tokenData.keyname]; - const ownerOnDestination = await this.mainnet.getERC721OwnerOf( - destTokenContract, - this.tokenId - ); - const tx = await this.s1().withdraw( - this.tokenData.originAddress, - this.tokenId, - { address: this.address } - ); - - const block = await this.s1().web3.eth.getBlock(tx.blockNumber); - this.updateState('transferDone', tx.transactionHash, block.timestamp); - externalEvents.transactionCompleted( - tx, block.timestamp, this.chainName1, 'withdraw'); - log('TransferERC721S2M:execute - tx completed %O', tx); - await this.mainnet.waitERC721OwnerChange( - destTokenContract, this.tokenId, ownerOnDestination); - this.updateState('received'); - log('TransferERC721S2M:execute - tokens received to destination chain'); - this.transferComplete(tx); - } - - async preAction() { - const checkRes = await checkERC721( - this.address, - this.s1().address, - this.tokenId, - this.s1().tokens[this.tokenData.keyname] - ); - this.setAmountErrorMessage(checkRes.msg); - if (!checkRes.approved) this.setActiveStep(0); - } -} - - -export class TransferERC721S2S extends ERC721TransferS { - async execute() { - this.updateState('init'); - await this.approve(); - this.updateState('transfer'); - const destTokenContract = this.s2().tokens[this.tokenData.keyname]; - const ownerOnDestination = await this.sChain2.getERC721OwnerOf( - destTokenContract, - this.tokenId - ); - const tx = await this.s1().transferToSchain( - this.chainName2, - this.tokenData.originAddress, - this.tokenId, - { address: this.address } - ); - const block = await this.s1().web3.eth.getBlock(tx.blockNumber); - this.updateState('transferDone', tx.transactionHash, block.timestamp); - externalEvents.transactionCompleted( - tx, block.timestamp, this.chainName1, 'transferToSchain'); - log('TransferERC721S2S:execute - tx completed %O', tx); - await this.sChain2.waitERC721OwnerChange( - destTokenContract, this.tokenId, ownerOnDestination); - this.updateState('received'); - log('TransferERC721S2S:execute - tokens received to destination chain'); - this.transferComplete(tx); - } - - async preAction() { - const checkRes = await checkERC721( - this.address, - this.s1().address, - this.tokenId, - this.s1().tokens[this.tokenData.keyname] - ); - this.setAmountErrorMessage(checkRes.msg); - if (!checkRes.approved) this.setActiveStep(0); - } -} \ No newline at end of file diff --git a/src/core/actions/eth.ts b/src/core/actions/eth.ts deleted file mode 100644 index 1832718..0000000 --- a/src/core/actions/eth.ts +++ /dev/null @@ -1,121 +0,0 @@ -/** - * @license - * SKALE Metaport - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -/** - * @file eth.ts - * @copyright SKALE Labs 2022-Present - */ - - -import debug from 'debug'; - -import { externalEvents } from '../events'; -import { toWei } from '../convertation'; -import { TransferAction, Action } from './action'; -import { checkEthBalance } from './checks'; - - -debug.enable('*'); -const log = debug('metaport:actions:eth'); - - -export class TransferEthM2S extends TransferAction { - async execute() { - log('TransferEthM2S: started'); - this.updateState('transferETH'); - const amountWei = toWei(this.amount, this.tokenData.decimals); - const sChainBalanceBefore = await this.sChain2.ethBalance(this.address); - const tx = await this.mainnet.eth.deposit( - this.chainName2, - { - address: this.address, - value: amountWei - } - ); - this.updateState('transferETHDone'); - const block = await this.mainnet.web3.eth.getBlock(tx.blockNumber); - externalEvents.transactionCompleted(tx, block.timestamp, this.chainName1, 'deposit'); - await this.sChain2.waitETHBalanceChange(this.address, sChainBalanceBefore); - this.updateState('receivedETH'); - externalEvents.transferComplete( - tx, this.chainName1, this.chainName2, this.tokenData.keyname); - } - - async preAction() { - const checkResBalance = await checkEthBalance( - this.mainnet, - this.address, - this.amount, - this.tokenData - ); - if (!checkResBalance.res) this.setAmountErrorMessage(checkResBalance.msg); - } -} - - -export class TransferEthS2M extends TransferAction { - async execute() { - log('TransferEthS2M: started'); - this.updateState('transferETH'); - const amountWei = toWei(this.amount, this.tokenData.decimals); - const lockedETHAmount = await this.mainnet.eth.lockedETHAmount(this.address); - const tx = await this.sChain1.eth.withdraw( - amountWei, - { address: this.address } - ); - this.updateState('transferETHDone'); - const block = await this.sChain1.web3.eth.getBlock(tx.blockNumber); - externalEvents.transactionCompleted(tx, block.timestamp, this.chainName1, 'withdraw'); - await this.mainnet.eth.waitLockedETHAmountChange(this.address, lockedETHAmount); - this.updateState('receivedETH'); - externalEvents.transferComplete( - tx, this.chainName1, this.chainName2, this.tokenData.keyname); - } - - async preAction() { - const checkResBalance = await checkEthBalance( - this.sChain1, - this.address, - this.amount, - this.tokenData - ); - if (!checkResBalance.res) this.setAmountErrorMessage(checkResBalance.msg); - } -} - - -export class UnlockEthM extends Action { - static label = 'Unlock ETH' - static buttonText = 'Unlock' - static loadingText = 'Unlocking' - - async execute() { - log('UnlockEthM: started'); - this.updateState('switch'); - await this.switchMetamaskChain(false); - this.updateState('unlock'); - const tx = await this.mainnet.eth.getMyEth( - { address: this.address } - ); - const block = await this.mainnet.web3.eth.getBlock(tx.blockNumber); - externalEvents.transactionCompleted(tx, block.timestamp, 'mainnet', 'getMyEth'); - this.updateState('unlockDone'); - externalEvents.ethUnlocked(tx); - } -} - diff --git a/src/core/actions/index.ts b/src/core/actions/index.ts index 7fd1742..875cc23 100644 --- a/src/core/actions/index.ts +++ b/src/core/actions/index.ts @@ -22,42 +22,25 @@ */ import debug from 'debug'; -import { - TransferEthM2S, - TransferEthS2M, - UnlockEthM -} from './eth'; + import { TransferERC20S2S, WrapERC20S, UnWrapERC20S, - UnWrapERC20S2S, TransferERC20M2S, - TransferERC20S2M, - WrapSFuelERC20S + TransferERC20S2M } from './erc20'; -import { - TransferERC721M2S, - TransferERC721S2M, - TransferERC721S2S -} from './erc721'; -import { - TransferERC1155M2S, - TransferERC1155S2M, - TransferERC1155S2S -} from './erc1155'; + +import { Action } from './action'; import { isMainnet } from '../helper'; -import TokenData from '../dataclasses/TokenData'; +import { ActionType, TokenType } from '../dataclasses'; import { S2S_POSTFIX, M2S_POSTFIX, S2M_POSTFIX, } from '../constants'; -import { View } from '../../core/dataclasses/View'; -import { TokenType } from 'core/dataclasses'; - debug.enable('*'); const log = debug('metaport:actions'); @@ -66,10 +49,8 @@ const log = debug('metaport:actions'); export function getActionName( chainName1: string, chainName2: string, - tokenType: TokenType, - view: View + tokenType: TokenType ): string { - if (chainName1 && view === View.UNWRAP) return 'erc20_unwrap'; if (!chainName1 || !chainName2 || !tokenType) return; log(`Getting action name: ${chainName1} ${chainName2} ${tokenType}`); let postfix = S2S_POSTFIX; @@ -81,54 +62,27 @@ export function getActionName( } -const wrapActions = [WrapERC20S]; -const unwrapActions = [UnWrapERC20S2S]; -const sFuelWrapActions = [WrapSFuelERC20S]; +export const ACTIONS: { [actionType in ActionType]: typeof Action; } = { + // eth_m2s: [TransferEthM2S], + // eth_s2m: [TransferEthS2M, UnlockEthM], + // eth_s2s: [], + wrap: WrapERC20S, + unwrap: UnWrapERC20S, -export const ACTIONS = { - eth_m2s: [TransferEthM2S], - eth_s2m: [TransferEthS2M, UnlockEthM], - eth_s2s: [], + erc20_m2s: TransferERC20M2S, + erc20_s2m: TransferERC20S2M, + erc20_s2s: TransferERC20S2S, - erc20_m2s: [TransferERC20M2S], - erc20_s2m: [TransferERC20S2M], - erc20_s2s: [TransferERC20S2S], + // erc721_m2s: [TransferERC721M2S], + // erc721_s2m: [TransferERC721S2M], + // erc721_s2s: [TransferERC721S2S], - erc20_unwrap: [UnWrapERC20S], + // erc721meta_m2s: [TransferERC721M2S], + // erc721meta_s2m: [TransferERC721S2M], + // erc721meta_s2s: [TransferERC721S2S], - erc721_m2s: [TransferERC721M2S], - erc721_s2m: [TransferERC721S2M], - erc721_s2s: [TransferERC721S2S], - - erc721meta_m2s: [TransferERC721M2S], - erc721meta_s2m: [TransferERC721S2M], - erc721meta_s2s: [TransferERC721S2S], - - erc1155_m2s: [TransferERC1155M2S], - erc1155_s2m: [TransferERC1155S2M], - erc1155_s2s: [TransferERC1155S2S] -} - - -export function getActionSteps( - actionName: string, - tokenData: TokenData -) { - log(`Getting action steps ${actionName}, ${tokenData.keyname}`); - const actionsList = []; - // TODO: tmp fix - if (tokenData.unwrappedSymbol && !tokenData.clone && actionName !== 'erc20_unwrap') { - actionsList.push(...wrapActions); - } - if (tokenData.wrapsSFuel && !tokenData.clone && actionName !== 'erc20_unwrap') { - actionsList.push(...sFuelWrapActions); - } - actionsList.push(...ACTIONS[actionName]); - if (tokenData.unwrappedSymbol && tokenData.clone) { - actionsList.push(...unwrapActions); - } - log('actionsList'); - log(actionsList); - return actionsList; -} + // erc1155_m2s: [TransferERC1155M2S], + // erc1155_s2m: [TransferERC1155S2M], + // erc1155_s2s: [TransferERC1155S2S] +} \ No newline at end of file diff --git a/src/core/chain_id.ts b/src/core/chain_id.ts new file mode 100644 index 0000000..7d3cf08 --- /dev/null +++ b/src/core/chain_id.ts @@ -0,0 +1,48 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/** + * @file chain_id.ts + * @copyright SKALE Labs 2023-Present + */ + +import { ethers } from 'ethers'; + + +export function remove0x(s: any) { + if (!s.startsWith('0x')) return s; + return s.slice(2); +} + + +function calcChainId(chainName: string): number { + let h = ethers.solidityPackedKeccak256(['string'], [chainName]); + // let h = soliditySha3(sChainName); + h = remove0x(h).toLowerCase(); + while (h.length < 64) + h = "0" + h; + h = h.substr(0, 13); + h = h.replace(/^0+/, ''); + return ethers.getNumber("0x" + h); +} + + +export function getChainId(chainName: string): number { + // if (chainName === MAINNET_CHAIN_NAME) return CHAIN_IDS[network]; + return calcChainId(chainName); +} diff --git a/src/core/community_pool.ts b/src/core/community_pool.ts index 5745fa7..958d5b2 100644 --- a/src/core/community_pool.ts +++ b/src/core/community_pool.ts @@ -22,84 +22,84 @@ */ -import debug from 'debug'; -import { MainnetChain, SChain } from '@skalenetwork/ima-js'; +// import debug from 'debug'; +// import { MainnetChain, SChain } from '@skalenetwork/ima-js'; -import { CommunityPoolData } from './interfaces'; -import { fromWei } from './convertation'; -import { - MAINNET_CHAIN_NAME, - DEFAULT_ERC20_DECIMALS, - RECHARGE_MULTIPLIER, - MINIMUM_RECHARGE_AMOUNT -} from './constants'; +// import { CommunityPoolData } from './interfaces'; +// import { fromWei } from './convertation'; +// import { +// MAINNET_CHAIN_NAME, +// DEFAULT_ERC20_DECIMALS, +// RECHARGE_MULTIPLIER, +// MINIMUM_RECHARGE_AMOUNT +// } from './constants'; -debug.enable('*'); -const log = debug('metaport:core:community_pool'); +// debug.enable('*'); +// const log = debug('metaport:core:community_pool'); -export function getEmptyCommunityPoolData(): CommunityPoolData { - return { - exitGasOk: null, - isActive: null, - balance: null, - accountBalance: null, - recommendedRechargeAmount: null, - originalRecommendedRechargeAmount: null - }; -} +// export function getEmptyCommunityPoolData(): CommunityPoolData { +// return { +// exitGasOk: null, +// isActive: null, +// balance: null, +// accountBalance: null, +// recommendedRechargeAmount: null, +// originalRecommendedRechargeAmount: null +// }; +// } -export async function getCommunityPoolData( - address: string, - chainName1: string, - chainName2: string, - mainnet: MainnetChain, - sChain: SChain -): Promise { +// export async function getCommunityPoolData( +// address: string, +// chainName1: string, +// chainName2: string, +// mainnet: MainnetChain, +// sChain: SChain +// ): Promise { - if (chainName2 !== MAINNET_CHAIN_NAME) { - log('not a S2M transfer, skipping community pool check'); - return { - exitGasOk: true, - isActive: null, - balance: null, - accountBalance: null, - recommendedRechargeAmount: null, - originalRecommendedRechargeAmount: null - } - } +// if (chainName2 !== MAINNET_CHAIN_NAME) { +// log('not a S2M transfer, skipping community pool check'); +// return { +// exitGasOk: true, +// isActive: null, +// balance: null, +// accountBalance: null, +// recommendedRechargeAmount: null, +// originalRecommendedRechargeAmount: null +// } +// } - log('Getting community pool data', address, chainName1); - const balanceWei = await mainnet.communityPool.balance(address, chainName1); - const accountBalanceWei = await mainnet.ethBalance(address); - const activeS = await sChain.communityLocker.contract.methods.activeUsers( - address - ).call(); - const chainHash = mainnet.web3.utils.soliditySha3(chainName1); - const activeM = await mainnet.communityPool.contract.methods.activeUsers( - address, - chainHash - ).call(); +// log('Getting community pool data', address, chainName1); +// const balanceWei = await mainnet.communityPool.balance(address, chainName1); +// const accountBalanceWei = await mainnet.ethBalance(address); +// const activeS = await sChain.communityLocker.contract.activeUsers( +// address +// ) +// const chainHash = mainnet.web3.utils.soliditySha3(chainName1); +// const activeM = await mainnet.communityPool.contract.activeUsers( +// address, +// chainHash +// ) - const rraWei = await mainnet.communityPool.contract.methods.getRecommendedRechargeAmount( - mainnet.web3.utils.soliditySha3(chainName1), - address - ).call(); - const rraEther = fromWei(rraWei as string, DEFAULT_ERC20_DECIMALS); +// const rraWei = await mainnet.communityPool.contract.getRecommendedRechargeAmount( +// mainnet.web3.utils.soliditySha3(chainName1), +// address +// ) +// const rraEther = fromWei(rraWei as string, DEFAULT_ERC20_DECIMALS); - let recommendedAmount = parseFloat(rraEther as string) * RECHARGE_MULTIPLIER; - if (recommendedAmount < MINIMUM_RECHARGE_AMOUNT) recommendedAmount = MINIMUM_RECHARGE_AMOUNT; +// let recommendedAmount = parseFloat(rraEther as string) * RECHARGE_MULTIPLIER; +// if (recommendedAmount < MINIMUM_RECHARGE_AMOUNT) recommendedAmount = MINIMUM_RECHARGE_AMOUNT; - const communityPoolData = { - exitGasOk: activeM && activeS && rraWei === '0', - isActive: activeM && activeS, - balance: balanceWei, - accountBalance: accountBalanceWei, - recommendedRechargeAmount: recommendedAmount.toString(), - originalRecommendedRechargeAmount: rraWei - } - log('communityPoolData:', communityPoolData); - return communityPoolData; -} \ No newline at end of file +// const communityPoolData = { +// exitGasOk: activeM && activeS && rraWei === '0', +// isActive: activeM && activeS, +// balance: balanceWei, +// accountBalance: accountBalanceWei, +// recommendedRechargeAmount: recommendedAmount.toString(), +// originalRecommendedRechargeAmount: rraWei +// } +// log('communityPoolData:', communityPoolData); +// return communityPoolData; +// } \ No newline at end of file diff --git a/src/core/constants.ts b/src/core/constants.ts index 89d3d89..80c77e8 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -47,13 +47,13 @@ export const HTTPS_PREFIX = 'https://'; export const MAINNET_EXPLORER_URLS: { [skaleNetwork: string]: string } = { mainnet: 'https://etherscan.io', - staging3: 'https://goerli.etherscan.io/', + staging: 'https://goerli.etherscan.io/', legacy: 'https://goerli.etherscan.io/' }; export const BASE_EXPLORER_URLS = { mainnet: "explorer.mainnet.skalenodes.com", - staging3: "explorer.staging-v3.skalenodes.com", + staging: "explorer.staging-v3.skalenodes.com", legacy: "explorer.staging-v3.skalenodes.com" }; @@ -100,4 +100,6 @@ export const COMMUNITY_POOL_WITHDRAW_GAS_LIMIT = '1500000'; export const BALANCE_UPDATE_INTERVAL_SECONDS = 10; -export const SFUEL_RESERVE_AMOUNT = 0.02; \ No newline at end of file +export const SFUEL_RESERVE_AMOUNT = 0.02; + +export const SUCCESS_EMOJIS = ['🎉', '👌', '✅', '🙌', '🎊']; \ No newline at end of file diff --git a/src/core/contracts.ts b/src/core/contracts.ts new file mode 100644 index 0000000..315400d --- /dev/null +++ b/src/core/contracts.ts @@ -0,0 +1,59 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/** + * @file contracts.ts + * @copyright SKALE Labs 2023-Present + */ + +import { CustomAbiTokenType, TokenType } from './dataclasses'; + +import erc20Abi from '../metadata/erc20_abi.json'; +import erc721Abi from '../metadata/erc721_abi.json'; +import erc721MetaAbi from '../metadata/erc721meta_abi.json'; +import erc1155Abi from '../metadata/erc1155_abi.json'; +import erc20WrapperAbi from '../metadata/erc20_wrapper_abi.json'; +import sFuelWrapperAbi from '../metadata/sfuel_wrapper_abi.json'; + +import mainnetAddresses from '../metadata/addresses/mainnet.json'; +import stagingAddresses from '../metadata/addresses/staging.json'; +import legacyAddresses from '../metadata/addresses/legacy.json'; + +import sChainAbi from '../metadata/schainAbi.json'; +import mainnetAbi from '../metadata/mainnetAbi.json'; + +export const ERC_ABIS: { [tokenType in CustomAbiTokenType | TokenType]: { ['abi']: any } } = { + eth: null, + erc20: erc20Abi, + erc20wrap: erc20WrapperAbi, + sfuelwrap: sFuelWrapperAbi, + erc721: erc721Abi, + erc721meta: erc721MetaAbi, + erc1155: erc1155Abi +} + +export const IMA_ADDRESSES = { + mainnet: mainnetAddresses, + staging: stagingAddresses, + legacy: legacyAddresses +} + +export const IMA_ABIS = { + mainnet: mainnetAbi, + schain: sChainAbi +} \ No newline at end of file diff --git a/src/core/convertation.ts b/src/core/convertation.ts index 70d7a67..81ca100 100644 --- a/src/core/convertation.ts +++ b/src/core/convertation.ts @@ -21,18 +21,14 @@ * @copyright SKALE Labs 2022-Present */ -import { Unit, toWei as _toWei, fromWei as _fromWei, unitMap, toBN } from 'web3-utils'; +import { formatUnits, parseUnits, BigNumberish } from 'ethers'; -export function toWei(value: string, decimals: string): string { - return _toWei(value, decimalsToUnit(decimals)); +export function toWei(value: string, decimals: string): bigint { + return parseUnits(value, parseInt(decimals as string)); } -export function fromWei(value: string, decimals: string): string { - return _fromWei(value, decimalsToUnit(decimals)); -} -function decimalsToUnit(decimals: string): Unit { - return Object.keys(unitMap).find( - key => unitMap[key] === toBN(10).pow(toBN(decimals)).toString()) as Unit; +export function fromWei(value: BigNumberish, decimals: string): string { + return formatUnits(value, parseInt(decimals as string)); } \ No newline at end of file diff --git a/src/core/core.ts b/src/core/core.ts deleted file mode 100644 index a8e72b7..0000000 --- a/src/core/core.ts +++ /dev/null @@ -1,225 +0,0 @@ -import Web3 from 'web3'; -import { soliditySha3, AbiItem } from 'web3-utils'; - -import debug from 'debug'; - -import { SChain, MainnetChain } from '@skalenetwork/ima-js'; - -import sChainAbi from '../metadata/schainAbi.json'; -import mainnetAbi from '../metadata/mainnetAbi.json'; -import proxyEndpoints from '../metadata/proxy.json'; -import { - schainNetworkParams, - mainnetNetworkParams, - changeMetamaskNetwork, - CHAIN_IDS -} from '../components/WalletConnector'; - - -import erc20Abi from '../metadata/erc20_abi.json'; -import erc721Abi from '../metadata/erc721_abi.json'; -import erc721MetaAbi from '../metadata/erc721meta_abi.json'; -import erc1155Abi from '../metadata/erc1155_abi.json'; -import erc20WrapperAbi from '../metadata/erc20_wrapper_abi.json'; -import sFuelWrapperAbi from '../metadata/sfuel_wrapper_abi.json'; - -import mainnetAddresses from '../metadata/addresses/mainnet.json'; -import stagingAddresses from '../metadata/addresses/staging.json'; -import staging3Addresses from '../metadata/addresses/staging3.json'; -import legacyAddresses from '../metadata/addresses/legacy.json'; - -import { getChainName } from './helper'; -import { MAINNET_CHAIN_NAME } from './constants'; -import { MetaportConfig } from './interfaces'; - - -const ERC_ABIS = { - 'erc20': erc20Abi, - 'erc20wrap': erc20WrapperAbi, - 'sfuelwrap': sFuelWrapperAbi, - 'erc721': erc721Abi, - 'erc721meta': erc721MetaAbi, - 'erc1155': erc1155Abi -} - - -debug.enable('*'); -const log = debug('metaport:core:core'); - - -export function initContract(tokenType: string, tokenAddress: string, web3: Web3) { - return new web3.eth.Contract(ERC_ABIS[tokenType].abi as AbiItem[], tokenAddress); -} - - -export function initERC20(tokenAddress: string, web3: Web3) { - return new web3.eth.Contract(erc20Abi.abi as AbiItem[], tokenAddress); -} - - -export function initERC20Wrapper(tokenAddress: string, web3: Web3) { - return new web3.eth.Contract(erc20WrapperAbi.abi as AbiItem[], tokenAddress); -} - - -export function initSChain(network: string, schainName: string) { - const endpoint = getSChainEndpoint(network, schainName); - const sChainWeb3 = new Web3(endpoint); - return new SChain(sChainWeb3, sChainAbi); -} - - -export async function switchMetamaskNetwork( // TODO: use new function - network: string, - chainName: string, - mainnetEndpoint: string, - chainsMetadata: any -) { - if (chainName === MAINNET_CHAIN_NAME) { - return await initMainnetMetamask(network, mainnetEndpoint); - } else { - return await initSChainMetamask(network, chainName, chainsMetadata); - } -} - - -export function getChainId(network: string, chainName: string): string { // TODO: use new function - if (chainName === MAINNET_CHAIN_NAME) return CHAIN_IDS[network]; - return calcChainId(chainName); -} - - -export async function initSChainMetamask(network: string, schainName: string, chainsMetadata: any) { - const endpoint = getSChainEndpoint(network, schainName); - const chainId = calcChainId(schainName); - const chainName = getChainName(chainsMetadata, schainName, network); - const networkParams = schainNetworkParams(chainName, endpoint, chainId); - await changeMetamaskNetwork(networkParams); - const sChainWeb3 = new Web3(window.ethereum); - return new SChain(sChainWeb3, sChainAbi); -} - -export function updateWeb3SChain(schain: SChain, network: string, schainName: string) { - const endpoint = getSChainEndpoint(network, schainName); - const sChainWeb3 = new Web3(endpoint); - schain.updateWeb3(sChainWeb3); -} - -export async function updateWeb3SChainMetamask( - schain: SChain, - network: string, - schainName: string, - chainsMetadata: any -): Promise { - const endpoint = getSChainEndpoint(network, schainName); - const chainId = calcChainId(schainName); - const chainName = getChainName(chainsMetadata, schainName, network); - const networkParams = schainNetworkParams(chainName, endpoint, chainId); - await changeMetamaskNetwork(networkParams); - const sChainWeb3 = new Web3(window.ethereum); - schain.updateWeb3(sChainWeb3); -} - - -export function updateWeb3Mainnet(mainnet: MainnetChain, mainnetEndpoint: string) { - const web3 = new Web3(mainnetEndpoint); - mainnet.updateWeb3(web3); -} - - -export async function updateWeb3MainnetMetamask( - mainnet: MainnetChain, - network: string, - mainnetEndpoint: string -): Promise { - const networkParams = mainnetNetworkParams(network, mainnetEndpoint); - await changeMetamaskNetwork(networkParams); - const web3 = new Web3(window.ethereum); - mainnet.updateWeb3(web3); -} - - -function getMainnetAbi(network: string) { - if (network === 'staging') { - return { ...mainnetAbi, ...stagingAddresses } - } - if (network === 'staging3') { - return { ...mainnetAbi, ...staging3Addresses } - } - if (network === 'legacy') { - return { ...mainnetAbi, ...legacyAddresses } - } - return { ...mainnetAbi, ...mainnetAddresses } -} - - -export function initMainnet(network: string, mainnetEndpoint: string): MainnetChain { - const web3 = new Web3(mainnetEndpoint); - return new MainnetChain(web3, getMainnetAbi(network)); -} - - -export async function initMainnetMetamask( - network: string, - mainnetEndpoint: string -): Promise { - const networkParams = mainnetNetworkParams(network, mainnetEndpoint); - await changeMetamaskNetwork(networkParams); - const web3 = new Web3(window.ethereum); - return new MainnetChain(web3, getMainnetAbi(network)); -} - - -function getSChainEndpoint(network: string, sChainName: string): string { - return getProxyEndpoint(network) + '/v1/' + sChainName; -} - - -function getProxyEndpoint(network: string) { - // todo: add network validation - return proxyEndpoints[network]; -} - - -function calcChainId(sChainName) { - let h = soliditySha3(sChainName); - h = remove0x(h).toLowerCase(); - while (h.length < 64) - h = "0" + h; - h = h.substr(0, 13); - h = h.replace(/^0+/, ''); - return "0x" + h; -} - - -export function remove0x(s: any) { - if (!s.startsWith('0x')) return s; - return s.slice(2); -} - - -// - -export function initChainWeb3(config: MetaportConfig, chainName: string): Web3 { - log(`Initializing web3 instance for ${chainName}`); - const endpoint = getChainEndpoint(chainName, config.mainnetEndpoint, config.skaleNetwork); - return initWeb3(endpoint); -} - - -export function initWeb3(endpoint: string) { - const provider = new Web3.providers.HttpProvider(endpoint); - return new Web3(provider); -} - - -export function getChainEndpoint( - chainName: string, - mainnetEndpoint: string, - skaleNetwork: string -): string { - if (chainName === MAINNET_CHAIN_NAME) { - return mainnetEndpoint; - } - return getProxyEndpoint(skaleNetwork) + '/v1/' + chainName; -} \ No newline at end of file diff --git a/src/core/dataclasses/ErrorMessage.ts b/src/core/dataclasses/ErrorMessage.ts new file mode 100644 index 0000000..3ecaff5 --- /dev/null +++ b/src/core/dataclasses/ErrorMessage.ts @@ -0,0 +1,74 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/** + * @file ErrorMessage.ts + * @copyright SKALE Labs 2022-Present + */ + + + +export class ErrorMessage { + + icon: string + text: string + btnText?: string + fallback?: Function + + constructor(fallback?: Function) { + this.fallback = fallback + } +} + + +export class NoTokenPairsMessage extends ErrorMessage { + constructor() { + super() + this.icon = 'link-off' + this.text = 'No token pairs for these chains' + } +} + + +export class WrongNetworkMessage extends ErrorMessage { + constructor(fallback: Function) { + super(fallback) + this.icon = 'public-off' + this.text = 'Looks like you are connected to the wrong network' + this.btnText = 'Switch network' + } +} + + +export class TransactionErrorMessage extends ErrorMessage { + constructor(text: string, fallback: Function) { + super(fallback) + this.icon = 'sentiment' + this.text = text + this.btnText = 'Try again' + } +} + + +export class CustomErrorMessage extends ErrorMessage { + constructor(text: string) { + super(undefined) + this.icon = 'error' + this.text = text + } +} diff --git a/src/core/dataclasses/EthTokenData.ts b/src/core/dataclasses/EthTokenData.ts index 664bff3..0b85bde 100644 --- a/src/core/dataclasses/EthTokenData.ts +++ b/src/core/dataclasses/EthTokenData.ts @@ -21,26 +21,26 @@ * @copyright SKALE Labs 2022-Present */ -import { ETH_ERC20_ADDRESS } from '../constants'; -import { TokenType } from './TokenType'; -import TokenData from './TokenData'; +// import { ETH_ERC20_ADDRESS } from '../constants'; +// import { TokenType } from './TokenType'; +import { TokenData } from './TokenData'; export default class EthTokenData extends TokenData { - constructor(clone: boolean) { - super( - ETH_ERC20_ADDRESS, - null, - TokenType.eth, - TokenType.eth, - TokenType.eth, - clone, - null, - null, - TokenType.eth, - null, - null, - null - ); - } + // constructor(clone: boolean) { + // super( + // ETH_ERC20_ADDRESS, + // null, + // TokenType.eth, + // TokenType.eth, + // TokenType.eth, + // clone, + // null, + // null, + // TokenType.eth, + // null, + // null, + // null + // ); + // } } \ No newline at end of file diff --git a/src/core/dataclasses/StepMetadata.ts b/src/core/dataclasses/StepMetadata.ts new file mode 100644 index 0000000..641cb3a --- /dev/null +++ b/src/core/dataclasses/StepMetadata.ts @@ -0,0 +1,107 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/** + * @file StepMetadata.ts + * @copyright SKALE Labs 2022-Present + */ + +import debug from 'debug'; + +import { TokenType } from './TokenType'; +import { isMainnet } from '../helper'; +import { + S2S_POSTFIX, + M2S_POSTFIX, + S2M_POSTFIX, +} from '../constants'; + + +debug.enable('*'); +const log = debug('metaport:actions'); + + +export enum ActionType { + erc20_m2s = 'erc20_m2s', + erc20_s2m = 'erc20_s2m', + erc20_s2s = 'erc20_s2s', + wrap = 'wrap', + unwrap = 'unwrap' +} + + +export function getActionType( + chainName1: string, + chainName2: string, + tokenType: TokenType +): ActionType { + if (!chainName1 || !chainName2 || !tokenType) return; + let postfix = S2S_POSTFIX; + if (isMainnet(chainName1)) { postfix = M2S_POSTFIX; }; + if (isMainnet(chainName2)) { postfix = S2M_POSTFIX; }; + const actionName = tokenType + '_' + postfix; + log('Action name: ' + actionName); + return actionName as ActionType; +} + + +export abstract class StepMetadata { + headline: string = ''; + text: string = ''; + btnText: string = ''; + btnLoadingText: string = ''; + + onSource: boolean = true; + + constructor(public type: ActionType, public from: string, public to: string) { } +} + + +export class TransferStepMetadata extends StepMetadata { + headline: string = 'Transfer to'; + text: string = 'You may need to approve first.'; + btnText: string = 'Transfer'; + btnLoadingText: string = 'Transferring'; + + onSource: boolean = false; +} + + +export class WrapStepMetadata extends StepMetadata { + headline: string = 'Wrap on'; + text: string = 'Tokens should be wrapped before transferring. Approval may be required.'; + btnText: string = 'Wrap'; + btnLoadingText: string = 'Wrapping'; + + constructor(public from: string, public to: string) { + super(ActionType.wrap, from, to) + } +} + + +export class UnwrapStepMetadata extends StepMetadata { + headline: string = 'Unwrap on'; + text: string = 'Tokens should be unwrapped after transferring.'; + btnText: string = 'Unwrap'; + btnLoadingText: string = 'Unwrapping'; + onSource: boolean = false; + + constructor(public from: string, public to: string) { + super(ActionType.unwrap, from, to) + } +} \ No newline at end of file diff --git a/src/core/dataclasses/TokenData.ts b/src/core/dataclasses/TokenData.ts index 27a7cc5..4408b47 100644 --- a/src/core/dataclasses/TokenData.ts +++ b/src/core/dataclasses/TokenData.ts @@ -22,68 +22,44 @@ */ import { DEFAULT_ERC20_DECIMALS } from '../constants'; +import { TokenMetadata, ConnectedChainMap } from '../interfaces'; import { TokenType } from './TokenType'; -export default class TokenData { - originAddress: string - cloneAddress: string - cloneSymbol: string - - name: string - symbol: string - keyname: string - - clone: boolean - type: TokenType - - balance: string - - iconUrl: string - decimals: string - - unwrappedSymbol: string - unwrappedAddress: string - unwrappedIconUrl: string - unwrappedBalance: string - - wrapsSFuel: boolean +export class TokenData { + address: string; + keyname: string; + type: TokenType; + meta: TokenMetadata; + connections: ConnectedChainMap; + chain: string; constructor( - cloneAddress: string, - originAddress: string, - name: string, - symbol: string, - cloneSymbol: string, - clone: boolean, - iconUrl: string, - decimals: string, + address: string, type: TokenType, - unwrappedSymbol: string, - unwrappedAddress: string, - unwrappedIconUrl: string, - wrapsSFuel: boolean = false + tokenKeyname: string, + metadata: TokenMetadata, + connections: ConnectedChainMap, + chain: string ) { - this.cloneAddress = cloneAddress; - this.cloneSymbol = cloneSymbol ? cloneSymbol : symbol; - this.originAddress = originAddress; - this.name = name; - this.symbol = symbol; - this.clone = clone; - this.iconUrl = iconUrl; - this.decimals = decimals ? decimals : DEFAULT_ERC20_DECIMALS; + this.address = address; + this.meta = metadata; + this.meta.decimals = this.meta.decimals ? this.meta.decimals : DEFAULT_ERC20_DECIMALS; + this.connections = connections; this.type = type; + this.keyname = tokenKeyname; + this.chain = chain; + } - this.keyname = getTokenKeyname(symbol, originAddress); - - this.unwrappedSymbol = unwrappedSymbol; - this.unwrappedAddress = unwrappedAddress; - this.unwrappedIconUrl = unwrappedIconUrl; - this.wrapsSFuel = wrapsSFuel; + wrapper(destChain: string): string | undefined { + return this.connections[destChain].wrapper } -} + isClone(destChain: string): boolean | undefined { + return this.connections[destChain].clone + } -export function getTokenKeyname(symbol: string, originAddress: string): string { - return `_${symbol}_${originAddress}`; -} + wrapsSFuel(destChain: string): boolean | undefined { + return this.connections[destChain].wrapsSFuel + } +} \ No newline at end of file diff --git a/src/core/dataclasses/TokenType.ts b/src/core/dataclasses/TokenType.ts index 9920285..31acdb5 100644 --- a/src/core/dataclasses/TokenType.ts +++ b/src/core/dataclasses/TokenType.ts @@ -28,4 +28,10 @@ export enum TokenType { erc721 = 'erc721', erc721meta = 'erc721meta', erc1155 = 'erc1155' +} + + +export enum CustomAbiTokenType { + erc20wrap = 'erc20wrap', + sfuelwrap = 'sfuelwrap' } \ No newline at end of file diff --git a/src/core/dataclasses/index.ts b/src/core/dataclasses/index.ts index 774734c..16b8139 100644 --- a/src/core/dataclasses/index.ts +++ b/src/core/dataclasses/index.ts @@ -22,5 +22,8 @@ */ export * from "./TokenType"; +export * from "./TokenData"; export * from "./Position"; export * from "./TransferRequestStatus"; +export * from "./StepMetadata"; +export * from "./ErrorMessage"; diff --git a/src/core/ethers.ts b/src/core/ethers.ts new file mode 100644 index 0000000..8460931 --- /dev/null +++ b/src/core/ethers.ts @@ -0,0 +1,47 @@ +import * as React from 'react' +import { type WalletClient, useWalletClient } from 'wagmi' +import { BrowserProvider, JsonRpcSigner, Eip1193Provider } from 'ethers' + +import { type PublicClient, usePublicClient } from 'wagmi' +import { FallbackProvider, JsonRpcProvider } from 'ethers' +import { type HttpTransport } from 'viem' + + +export function walletClientToSigner(walletClient: WalletClient) { + const { account, transport } = walletClient + const provider = new BrowserProvider(transport as Eip1193Provider, "any") + const signer = new JsonRpcSigner(provider, account.address) + return signer +} + +/** Hook to convert a viem Wallet Client to an ethers.js Signer. */ +export function useEthersSigner({ chainId }: { chainId?: number } = {}) { + const { data: walletClient } = useWalletClient({ chainId }) + return React.useMemo( + () => (walletClient ? walletClientToSigner(walletClient) : undefined), + [walletClient], + ) +} + +export function publicClientToProvider(publicClient: PublicClient) { + const { chain, transport } = publicClient + const network = { + chainId: chain.id, + name: chain.name, + ensAddress: chain.contracts?.ensRegistry?.address, + } + if (transport.type === 'fallback') { + const providers = (transport.transports as ReturnType[]).map( + ({ value }) => new JsonRpcProvider(value?.url, network), + ) + if (providers.length === 1) return providers[0] + return new FallbackProvider(providers) + } + return new JsonRpcProvider(transport.url, network) +} + +/** Hook to convert a viem Public Client to an ethers.js Provider. */ +export function useEthersProvider({ chainId }: { chainId?: number } = {}) { + const publicClient = usePublicClient({ chainId }) + return React.useMemo(() => publicClientToProvider(publicClient), [publicClient]) +} \ No newline at end of file diff --git a/src/core/events.ts b/src/core/events.ts index f3a9920..eff409f 100644 --- a/src/core/events.ts +++ b/src/core/events.ts @@ -95,7 +95,7 @@ export namespace externalEvents { chainName2: string, address: string, amount: string, - amountWei: string, + amountWei: bigint, tokenId: number }, transactionHash?: string, diff --git a/src/core/explorer.ts b/src/core/explorer.ts index 711f291..7e663ce 100644 --- a/src/core/explorer.ts +++ b/src/core/explorer.ts @@ -27,6 +27,7 @@ import { MAINNET_EXPLORER_URLS, BASE_EXPLORER_URLS } from './constants'; +import { SkaleNetwork } from './interfaces'; function getMainnetExplorerUrl(skaleNetwork: string) { @@ -37,13 +38,12 @@ function getSChainExplorerUrl(skaleNetwork: string) { return BASE_EXPLORER_URLS[skaleNetwork]; } -export function getExplorerUrl(chainName: string, skaleNetwork: string): string { +export function getExplorerUrl(skaleNetwork: SkaleNetwork, chainName: string): string { if (chainName === MAINNET_CHAIN_NAME) return getMainnetExplorerUrl(skaleNetwork); return HTTPS_PREFIX + chainName + '.' + getSChainExplorerUrl(skaleNetwork); } - -export function getTxUrl(chainName: string, skaleNetwork: string, txHash: string): string { - const explorerUrl = getExplorerUrl(chainName, skaleNetwork); +export function getTxUrl(chainName: string, skaleNetwork: SkaleNetwork, txHash: string): string { + const explorerUrl = getExplorerUrl(skaleNetwork, chainName); return `${explorerUrl}/tx/${txHash}`; } diff --git a/src/core/faucet.ts b/src/core/faucet.ts index 6d7b30d..738a246 100644 --- a/src/core/faucet.ts +++ b/src/core/faucet.ts @@ -21,31 +21,33 @@ * @copyright SKALE Labs 2023-Present */ -import { ZERO_ADDRESS, ZERO_FUNCSIG, FAUCET_DATA } from './constants'; -import Web3 from 'web3'; - - -function getAddress(chainName: string, skaleNetwork: string) { - if (!isFaucetAvailable(chainName, skaleNetwork)) return ZERO_ADDRESS; - const faucet: { [x: string]: { [x: string]: string } } = FAUCET_DATA[skaleNetwork]; - return faucet[chainName].address; -} - -function getFunc(chainName: string, skaleNetwork: string) { - if (!isFaucetAvailable(chainName, skaleNetwork)) return ZERO_FUNCSIG; - const faucet: { [x: string]: { [x: string]: string } } = FAUCET_DATA[skaleNetwork]; - return faucet[chainName].func; -} - -export function isFaucetAvailable(chainName: string, skaleNetwork: string) { - if (!FAUCET_DATA[skaleNetwork]) return false; - const keys = Object.keys(FAUCET_DATA[skaleNetwork]); - return keys.includes(chainName); -} - -export function getFuncData(web3: Web3, chainName: string, address: string, skaleNetwork: string) { - const faucetAddress = getAddress(chainName, skaleNetwork); - const functionSig = getFunc(chainName, skaleNetwork); - const functionParam = web3.eth.abi.encodeParameter('address', address); - return { to: faucetAddress, data: functionSig + functionParam.slice(2) }; -} \ No newline at end of file + +// TODO! + +// import { ZERO_ADDRESS, ZERO_FUNCSIG, FAUCET_DATA } from './constants'; + + +// function getAddress(chainName: string, skaleNetwork: string) { +// if (!isFaucetAvailable(chainName, skaleNetwork)) return ZERO_ADDRESS; +// const faucet: { [x: string]: { [x: string]: string } } = FAUCET_DATA[skaleNetwork]; +// return faucet[chainName].address; +// } + +// function getFunc(chainName: string, skaleNetwork: string) { +// if (!isFaucetAvailable(chainName, skaleNetwork)) return ZERO_FUNCSIG; +// const faucet: { [x: string]: { [x: string]: string } } = FAUCET_DATA[skaleNetwork]; +// return faucet[chainName].func; +// } + +// export function isFaucetAvailable(chainName: string, skaleNetwork: string) { +// if (!FAUCET_DATA[skaleNetwork]) return false; +// const keys = Object.keys(FAUCET_DATA[skaleNetwork]); +// return keys.includes(chainName); +// } + +// export function getFuncData(web3: Web3, chainName: string, address: string, skaleNetwork: string) { +// const faucetAddress = getAddress(chainName, skaleNetwork); +// const functionSig = getFunc(chainName, skaleNetwork); +// const functionParam = web3.eth.abi.encodeParameter('address', address); +// return { to: faucetAddress, data: functionSig + functionParam.slice(2) }; +// } \ No newline at end of file diff --git a/src/core/helper.ts b/src/core/helper.ts index 602ea6f..9336f41 100644 --- a/src/core/helper.ts +++ b/src/core/helper.ts @@ -21,10 +21,12 @@ * @copyright SKALE Labs 2022-Present */ +import { getAddress } from 'ethers'; import { MAINNET_CHAIN_NAME } from './constants'; -import utils from 'web3-utils'; +// import utils from 'web3-utils'; import { TransferRequestStatus } from './dataclasses'; +import { SkaleNetwork } from './interfaces'; import mainnetMeta from '../meta/mainnet/chains.json'; import stagingMeta from '../meta/staging/chains.json'; @@ -33,12 +35,12 @@ import legacyMeta from '../meta/legacy/chains.json'; export const CHAINS_META = { 'mainnet': mainnetMeta, - 'staging3': stagingMeta, + 'staging': stagingMeta, 'legacy': legacyMeta } -export function clsNames(...args: any): string { +export function cls(...args: any): string { const filteredArgs = args.map((clsName: any) => { if (typeof clsName === 'string') return clsName; if (Array.isArray(clsName) && clsName.length === 2 && clsName[1]) return clsName[0]; @@ -58,11 +60,11 @@ export function isMainnet(chainName: string): boolean { export function addressesEqual(address1: string, address2: string): boolean { - return utils.toChecksumAddress(address1) === utils.toChecksumAddress(address2); + return getAddress(address1) === getAddress(address2); } -export function isTransferRequestActive(transferRequestStatus: TransferRequestStatus) { +export default function isTransferRequestActive(transferRequestStatus: TransferRequestStatus) { return transferRequestStatus === TransferRequestStatus.IN_PROGRESS || transferRequestStatus === TransferRequestStatus.IN_PROGRESS_HUB; } @@ -71,27 +73,15 @@ export function delay(ms: number) { return new Promise(resolve => setTimeout(resolve, ms)); } -export function getChainName( - chainsMetadata: any, - chainName: string, - skaleNetwork: string, - app?: string -): string { + +export function getChainAlias(skaleNetwork: SkaleNetwork, chainName: string, app?: string): string { if (chainName === MAINNET_CHAIN_NAME) { - return 'Mainnet'; - } - if (chainsMetadata && chainsMetadata[chainName]) { - if (app && chainsMetadata[chainName].apps[app]) { - return chainsMetadata[chainName].apps[app].alias; + if (skaleNetwork != MAINNET_CHAIN_NAME) { + const network = skaleNetwork === 'staging' ? 'Goerli' : skaleNetwork; + return `Ethereum (${network})`; } - return chainsMetadata[chainName].alias; - } else { - return getChainNameMeta(chainName, skaleNetwork, app); + return 'Ethereum'; } -} - - -function getChainNameMeta(chainName: string, skaleNetwork: string, app?: string): string { if (CHAINS_META[skaleNetwork] && CHAINS_META[skaleNetwork][chainName]) { if (app && CHAINS_META[skaleNetwork][chainName].apps && CHAINS_META[skaleNetwork][chainName].apps[app]) { @@ -102,8 +92,12 @@ function getChainNameMeta(chainName: string, skaleNetwork: string, app?: string) return chainName; } -export function getChainAppsMeta(chainName: string, skaleNetwork: string) { +export function getChainAppsMeta(chainName: string, skaleNetwork: SkaleNetwork) { if (CHAINS_META[skaleNetwork][chainName] && CHAINS_META[skaleNetwork][chainName].apps) { return CHAINS_META[skaleNetwork][chainName].apps; } +} + +export function getRandom(list: Array) { + return list[Math.floor((Math.random() * list.length))]; } \ No newline at end of file diff --git a/src/core/index.ts b/src/core/index.ts deleted file mode 100644 index 8d119de..0000000 --- a/src/core/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./core"; diff --git a/src/core/interfaces/Config.ts b/src/core/interfaces/Config.ts index fed8d46..fc784c4 100644 --- a/src/core/interfaces/Config.ts +++ b/src/core/interfaces/Config.ts @@ -21,10 +21,9 @@ * @copyright SKALE Labs 2022-Present */ -import { MetaportTheme } from './Theme'; -import { ChainsMetadataMap } from './ChainsMetadata'; -import { TokensMap } from './Tokens'; +import { TokenConnectionsMap, TokenMetadataMap, MetaportTheme } from '.'; +export type SkaleNetwork = 'mainnet' | 'staging' | 'legacy' | 'regression'; export interface MetaportConfig { openOnLoad?: boolean; @@ -32,12 +31,12 @@ export interface MetaportConfig { autoLookup?: boolean; debug?: boolean; - skaleNetwork?: string; + skaleNetwork: SkaleNetwork; mainnetEndpoint?: string; chains?: string[]; - chainsMetadata?: ChainsMetadataMap; - tokens?: TokensMap; + tokens: TokenMetadataMap; + connections: TokenConnectionsMap; theme?: MetaportTheme; } diff --git a/src/core/interfaces/TokenDataMap.ts b/src/core/interfaces/TokenDataMap.ts index 3abcb56..693b85a 100644 --- a/src/core/interfaces/TokenDataMap.ts +++ b/src/core/interfaces/TokenDataMap.ts @@ -21,9 +21,10 @@ * @copyright SKALE Labs 2022-Present */ -import TokenData from '../../core/dataclasses/TokenData'; +import { TokenData } from '../../core/dataclasses/TokenData'; import EthTokenData from '../../core/dataclasses/EthTokenData'; import { TokenType } from '../../core/dataclasses/TokenType'; +import { Contract } from "ethers"; export interface TokenDataMap { [tokenSymbol: string]: TokenData; } @@ -37,3 +38,6 @@ export type TokenDataTypesMap = { [TokenType.erc721meta]: TokenDataMap [TokenType.erc1155]: TokenDataMap } + +export interface TokenContractsMap { [tokenKeyname: string]: Contract; }; +export interface TokenBalancesMap { [tokenKeyname: string]: bigint; }; \ No newline at end of file diff --git a/src/core/interfaces/TokenMetadata.ts b/src/core/interfaces/TokenMetadata.ts new file mode 100644 index 0000000..f9cdb74 --- /dev/null +++ b/src/core/interfaces/TokenMetadata.ts @@ -0,0 +1,31 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/** + * @file MetaportConfig.ts + * @copyright SKALE Labs 2022-Present + */ + +export interface TokenMetadata { + symbol: string, + name?: string, + iconUrl?: string, + decimals?: string +} + +export interface TokenMetadataMap { [tokenName: string]: TokenMetadata; } \ No newline at end of file diff --git a/src/core/interfaces/Tokens.ts b/src/core/interfaces/Tokens.ts index c8951f2..3695d2e 100644 --- a/src/core/interfaces/Tokens.ts +++ b/src/core/interfaces/Tokens.ts @@ -22,27 +22,23 @@ */ export interface EthToken { - chains: string[]; + chains: ConnectedChainMap } export interface Token { - symbol: string, - cloneSymbol?: string, - address: string, - name?: string, - iconUrl?: string, - decimals?: string, - wrapsSFuel?: boolean, - wraps?: WrapsData, + address?: string, + chains: ConnectedChainMap } -interface WrapsData { - symbol: string, - address: string, - iconUrl?: string +export interface ConnectedChain { + hub?: string + wrapper?: string + wrapsSFuel?: boolean + clone?: boolean } - +export interface ConnectedChainMap { [chainName: string]: ConnectedChain; } export interface ChainTokensMap { [tokenSymbol: string]: Token; } -export interface TokenTypeMap { [tokenType: string]: EthToken | ChainTokensMap; } -export interface TokensMap { [chainName: string]: TokenTypeMap; } +// export interface TokenTypeMap { [tokenType: string]: EthToken | ChainTokensMap; } +export interface TokenTypeMap { [tokenType: string]: ChainTokensMap; } +export interface TokenConnectionsMap { [chainName: string]: TokenTypeMap; } \ No newline at end of file diff --git a/src/core/interfaces/index.ts b/src/core/interfaces/index.ts index 2dcb5f1..945ebdf 100644 --- a/src/core/interfaces/index.ts +++ b/src/core/interfaces/index.ts @@ -30,3 +30,4 @@ export * from "./TransferParams"; export * from "./CheckRes"; export * from "./TransactionHistory"; export * from "./CommunityPoolData"; +export * from "./TokenMetadata"; diff --git a/src/components/TokenList/helper.ts b/src/core/metadata.ts similarity index 55% rename from src/components/TokenList/helper.ts rename to src/core/metadata.ts index 8904bfa..4a03908 100644 --- a/src/components/TokenList/helper.ts +++ b/src/core/metadata.ts @@ -17,24 +17,13 @@ */ /** - * @file helper.ts - * @copyright SKALE Labs 2022-Present + * @file metadata.ts + * @copyright SKALE Labs 2023-Present */ -import { MAINNET_CHAIN_NAME } from '../../core/constants'; -import TokenData from '../../core/dataclasses/TokenData'; - - -export function getTokenSymbol(token: TokenData): string { - let symbol = token.unwrappedSymbol ? token.unwrappedSymbol : token.symbol; - if (token.clone) symbol = token.cloneSymbol ? token.cloneSymbol : symbol; - return symbol; -} - - -export function getTokenName(token: TokenData): string { - return token.name ? token.name : getTokenSymbol(token); -} +import { TokenData } from './dataclasses'; +import { SkaleNetwork } from './interfaces'; +import { MAINNET_CHAIN_NAME } from './constants'; function importAll(r) { @@ -43,26 +32,16 @@ function importAll(r) { return images; } -const icons = importAll(require.context('../../icons', false, /\.(png|jpe?g|svg)$/)); -const CHAIN_ICONS = { - 'mainnet': importAll(require.context('../../meta/mainnet/icons', false, /\.(png|jpe?g|svg)$/)), - 'staging3': importAll(require.context('../../meta/staging/icons', false, /\.(png|jpe?g|svg)$/)), - 'legacy': importAll(require.context('../../meta/legacy/icons', false, /\.(png|jpe?g|svg)$/)) -} - -export function iconPath(name) { - if (!name) return; - const key = name.toLowerCase() + '.svg'; - if (icons[key]) { - return icons[key]; - } else { - return icons['eth.svg']; - } +const icons = importAll(require.context('../icons', false, /\.(png|jpe?g|svg)$/)); +const CHAIN_ICONS = { + 'mainnet': importAll(require.context('../meta/mainnet/icons', false, /\.(png|jpe?g|svg)$/)), + 'staging': importAll(require.context('../meta/staging/icons', false, /\.(png|jpe?g|svg)$/)), + 'legacy': importAll(require.context('../meta/legacy/icons', false, /\.(png|jpe?g|svg)$/)) } -export function chainIconPath(skaleNetwork: string, name: string, app?: string) { +export function chainIconPath(skaleNetwork: SkaleNetwork, name: string, app?: string) { if (!name) return; let filename = name.toLowerCase(); if (app) @@ -77,7 +56,22 @@ export function chainIconPath(skaleNetwork: string, name: string, app?: string) } -export function getIconSrc(token: TokenData): string { - if (token.unwrappedIconUrl) return token.unwrappedIconUrl; - return token.iconUrl ? token.iconUrl : iconPath(token.symbol); +export function tokenIcon(name: string): string { + if (!name) return; + const key = name.toLowerCase() + '.svg'; + if (icons[key]) { + return icons[key]; + } else { + return icons['eth.svg']; + } +} + + +export function tokenIconPath(token: TokenData): string { + return token.meta.iconUrl ?? tokenIcon(token.meta.symbol); } + + +export function getTokenName(token: TokenData): string { + return token.meta.name ?? token.meta.symbol; +} \ No newline at end of file diff --git a/src/core/metaport.ts b/src/core/metaport.ts new file mode 100644 index 0000000..8da24ec --- /dev/null +++ b/src/core/metaport.ts @@ -0,0 +1,237 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/** + * @file metaport.ts + * @copyright SKALE Labs 2023-Present + */ + +import { Provider, JsonRpcProvider, Contract } from "ethers"; + +import { MetaportConfig, TokenDataTypesMap, Token, TokenContractsMap, TokenBalancesMap } from './interfaces'; +import { TokenType, TokenData, CustomAbiTokenType } from './dataclasses'; + +import { getEmptyTokenDataMap } from './tokens/helper'; +import { getChainEndpoint, initIMA, initMainnet, initSChain } from './network'; +import { ERC_ABIS } from './contracts'; + + +import debug from 'debug'; +import { MainnetChain, SChain } from "@skalenetwork/ima-js"; + + + +const log = debug('ima:test:MainnetChain'); + + +export const createTokenData = ( + tokenKeyname: string, + chainName: string, + tokenType: TokenType, + config: MetaportConfig +): TokenData => { + const configToken: Token = config.connections[chainName][tokenType][tokenKeyname]; + return new TokenData( + configToken.address, + tokenType, + tokenKeyname, + config.tokens[tokenKeyname], + configToken.chains, + chainName + ); +} + + +export const addTokenData = ( + tokenKeyname: string, + chainName: string, + tokenType: TokenType, + config: MetaportConfig, + tokens: TokenDataTypesMap +) => { + tokens[tokenType][tokenKeyname] = createTokenData( + tokenKeyname, + chainName, + tokenType, + config + ) +} + +export const createTokensMap = ( + chainName1: string, + chainName2: string | null | undefined, + config: MetaportConfig +): TokenDataTypesMap => { + const tokens = getEmptyTokenDataMap(); + log(`updating tokens map for ${chainName1} -> ${chainName2}`); + if (chainName1) { + Object.values(TokenType).forEach(tokenType => { + if (config.connections[chainName1][tokenType]) { + Object.keys(config.connections[chainName1][tokenType]).forEach(tokenKeyname => { + const tokenInfo = config.connections[chainName1][tokenType][tokenKeyname]; + if (!chainName2 || (chainName2 && tokenInfo.chains.hasOwnProperty(chainName2))) { + addTokenData(tokenKeyname, chainName1, tokenType as TokenType, config, tokens); + } + }); + } + }); + } + return tokens; +} + + +export default class MetaportCore { + + private _config: MetaportConfig + + constructor(config: MetaportConfig) { + this._config = config; + } + + get config(): MetaportConfig { + return this._config; + } + + /** + * Generates available tokens for a given chain or a pair of the chains. + * + * @param {string} from - Source chain name. + * @param {string | null} [to] - Destination chain name. + * + * @returns {TokenDataTypesMap} - Returns a map of token data types for the given chains. + * + * @example + * + * // To get tokens for 'a' -> 'b' + * const tokens = mpc.tokens('a', 'b'); + * + * // To get all tokens from 'a' + * const tokens = mpc.tokens('a'); + */ + tokens( + from: string, + to?: string | null, + ): TokenDataTypesMap { + if (from === undefined || from === null || from === '') return getEmptyTokenDataMap(); + return createTokensMap(from, to, this._config); + } + + async tokenBalance( + tokenContract: Contract, + address: string + ): Promise { + return await tokenContract.balanceOf(address); + } + + async tokenBalances( + tokenContracts: TokenContractsMap, + address: string + ): Promise { + const balances: TokenBalancesMap = {}; + const tokenKeynames = Object.keys(tokenContracts); + for (const tokenKeyname of tokenKeynames) { + balances[tokenKeyname] = await tokenContracts[tokenKeyname].balanceOf(address); + } + return balances; + } + + tokenContracts( + tokens: TokenDataTypesMap, + tokenType: TokenType, + chainName: string, + provider: Provider + ): TokenContractsMap { + const contracts: TokenContractsMap = {}; + if (tokens[tokenType]) { + Object.keys(tokens[tokenType]).forEach(tokenKeyname => { + contracts[tokenKeyname] = this.tokenContract( + chainName, + tokenKeyname, + tokenType, + provider + ) + }); + } + return contracts; + } + + tokenContract( + chainName: string, + tokenKeyname: string, + tokenType: TokenType, + provider: Provider, + customAbiTokenType?: CustomAbiTokenType, + destChainName?: string + ): Contract { + const token = this._config.connections[chainName][tokenType][tokenKeyname]; + const abi = customAbiTokenType ? ERC_ABIS[customAbiTokenType].abi : ERC_ABIS[tokenType].abi; + const address = customAbiTokenType ? token.chains[destChainName].wrapper : token.address; + // TODO: add sFUEL address support! + return new Contract(address, abi, provider); + } + + originAddress( + chainName1: string, + chainName2: string, + tokenKeyname: string, + tokenType: TokenType + ) { + let token = this._config.connections[chainName1][tokenType][tokenKeyname]; + const isClone = token.chains[chainName2].clone; + if (isClone) { + token = this._config.connections[chainName2][tokenType][tokenKeyname]; + } + return token.chains[isClone ? chainName1 : chainName2].wrapper ?? token.address; + } + + endpoint( + chainName: string + ): string { + return getChainEndpoint( + this._config.mainnetEndpoint, + this._config.skaleNetwork, + chainName + ); + } + + ima(chainName: string): MainnetChain | SChain { + return initIMA( + this._config.mainnetEndpoint, + this._config.skaleNetwork, + chainName + ); + } + + mainnet(): MainnetChain { + return initMainnet( + this._config.mainnetEndpoint, + this._config.skaleNetwork, + ) + } + + schain(chainName: string): SChain { + return initSChain( + this._config.skaleNetwork, + chainName + ) + } + + provider(chainName: string): Provider { + return new JsonRpcProvider(this.endpoint(chainName)); + } +} diff --git a/src/core/network.ts b/src/core/network.ts new file mode 100644 index 0000000..e587145 --- /dev/null +++ b/src/core/network.ts @@ -0,0 +1,104 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/** + * @file network.ts + * @copyright SKALE Labs 2023-Present + */ + +import { MainnetChain, SChain } from '@skalenetwork/ima-js'; +import { JsonRpcProvider } from "ethers"; + + +import proxyEndpoints from '../metadata/proxy.json'; +import { MAINNET_CHAIN_NAME } from './constants'; +import { IMA_ADDRESSES, IMA_ABIS } from './contracts'; +import { SkaleNetwork } from './interfaces'; + + +const PROTOCOL: { [protocol in 'http' | 'ws']: string } = { + 'http': 'https://', + 'ws': 'wss://' +} + +export const CHAIN_IDS: { [network in SkaleNetwork]: number } = { + 'staging': 5, + 'legacy': 5, + 'regression': 5, + 'mainnet': 5 +} + +export function isMainnetChainId(chainId: number | BigInt, skaleNetwork: SkaleNetwork): boolean { + return Number(chainId) === CHAIN_IDS[skaleNetwork]; +} + +export function getChainEndpoint( + mainnetEndpoint: string, + network: SkaleNetwork, + chainName: string +): string { + if (chainName === MAINNET_CHAIN_NAME) return mainnetEndpoint; + return getSChainEndpoint(network, chainName); +} + +export function getSChainEndpoint( + network: SkaleNetwork, + sChainName: string, + protocol: 'http' | 'ws' = 'http' +): string { + return PROTOCOL[protocol] + getProxyEndpoint(network) + '/v1/' + (protocol === 'ws' ? 'ws/' : '') + sChainName; +} + +function getProxyEndpoint(network: SkaleNetwork) { + return proxyEndpoints[network]; +} + +export function getMainnetAbi(network: string) { + if (network === 'staging') { + return { ...IMA_ABIS.mainnet, ...IMA_ADDRESSES.staging } + } + if (network === 'legacy') { + return { ...IMA_ABIS.mainnet, ...IMA_ADDRESSES.legacy } + } + return { ...IMA_ABIS.mainnet, ...IMA_ADDRESSES.mainnet } +} + + +export function initIMA( + mainnetEndpoint: string, + network: SkaleNetwork, + chainName: string +): MainnetChain | SChain { + if (chainName === MAINNET_CHAIN_NAME) return initMainnet(mainnetEndpoint, network); + return initSChain(network, chainName); +} + +export function initMainnet(mainnetEndpoint: string, network: string): MainnetChain { + const provider = new JsonRpcProvider(mainnetEndpoint); + return new MainnetChain(provider, getMainnetAbi(network)); +} + +export function initSChain(network: SkaleNetwork, chainName: string): SChain { + const endpoint = getChainEndpoint( + null, + network, + chainName + ); + const provider = new JsonRpcProvider(endpoint); + return new SChain(provider, IMA_ABIS.schain); +} diff --git a/src/core/sfuel.ts b/src/core/sfuel.ts index 9c61ef3..c2c6f84 100644 --- a/src/core/sfuel.ts +++ b/src/core/sfuel.ts @@ -22,116 +22,118 @@ * @copyright SKALE Labs 2022-Present */ -import Web3 from 'web3'; -import debug from 'debug'; -import { AnonymousPoW } from "@skaleproject/pow-ethers"; - -import { getChainEndpoint, initWeb3 } from '../core/core'; -import { getFuncData, isFaucetAvailable } from '../core/faucet'; -import { DEFAULT_MIN_SFUEL_WEI, DEFAULT_FAUCET_URL, MAINNET_CHAIN_NAME } from '../core/constants'; - - -debug.enable('*'); -const log = debug('metaport:Widget'); - - -function getFaucetUrl(chainsMetadata: object, chainName: string): string { - if (chainsMetadata && chainsMetadata[chainName]) return chainsMetadata[chainName].faucetUrl; - return DEFAULT_FAUCET_URL; -} - - -function getMinSfuelWei(chainName: string, chainsMetadata?: object): string { - if (chainsMetadata && chainsMetadata[chainName] && chainsMetadata[chainName].minSfuelWei) { - return chainsMetadata[chainName].minSfuelWei; - } else { - return DEFAULT_MIN_SFUEL_WEI; - } -} - - -async function getSfuelBalance(web3: Web3, address: string): Promise { - return await web3.eth.getBalance(address); -} - - -export interface StationData { - faucetUrl: string; - minSfuelWei: string; - balance: string; - ok: boolean; -} - - -export interface StationPowRes { - message: string; - ok: boolean; -} - - -export class Station { - - endpoint: string; - web3: Web3; - - constructor( - public chainName: string, - public skaleNetwork: string, - public mainnetEndpoint?: string, - public chainsMetadata?: object - ) { - this.chainName = chainName; - this.skaleNetwork = skaleNetwork; - - this.endpoint = getChainEndpoint(chainName, mainnetEndpoint, skaleNetwork); - - this.web3 = initWeb3(this.endpoint); - this.chainsMetadata = chainsMetadata; - } - - async getData(address: string): Promise { - try { - const minSfuelWei = getMinSfuelWei(this.chainName, this.chainsMetadata); - const balance = await getSfuelBalance(this.web3, address); - return { - faucetUrl: getFaucetUrl(this.chainsMetadata, this.chainName), - minSfuelWei, - balance, - ok: Number(balance) >= Number(minSfuelWei) - } - } catch (e) { - log(`ERROR: getSFuelData for ${this.chainName} failed!`); - log(e); - return { - faucetUrl: undefined, minSfuelWei: undefined, balance: undefined, ok: undefined - }; - } - } - - async doPoW(address: string): Promise { - if (!this.chainName || !isFaucetAvailable(this.chainName, this.skaleNetwork)) { - log('WARNING: PoW is not available for this chain'); - if (this.chainName === MAINNET_CHAIN_NAME) { - return { ok: true, message: 'PoW is not available for Ethereum Mainnet' }; - } - return { ok: false, message: 'PoW is not available for this chain' }; - } - log('Mining sFUEL for ' + address + ' on ' + this.chainName + '...'); - try { - const endpoint = getChainEndpoint(this.chainName, undefined, this.skaleNetwork); - const web3 = initWeb3(endpoint); - const anon = new AnonymousPoW({ rpcUrl: endpoint }); - await (await anon.send(getFuncData( - web3, - this.chainName, - address, - this.skaleNetwork - ))).wait(); - return { ok: true, message: 'PoW finished successfully' } - } catch (e) { - log('ERROR: PoW failed!'); - log(e); - return { ok: false, message: e.message }; - } - } -} +// import debug from 'debug'; +// import { AnonymousPoW } from "@skaleproject/pow-ethers"; + +// import { getChainEndpoint, initWeb3 } from '../core/core'; +// import { getFuncData, isFaucetAvailable } from '../core/faucet'; +// import { DEFAULT_MIN_SFUEL_WEI, DEFAULT_FAUCET_URL, MAINNET_CHAIN_NAME } from '../core/constants'; + + +// debug.enable('*'); +// const log = debug('metaport:Widget'); + + +// function getFaucetUrl(chainsMetadata: object, chainName: string): string { +// if (chainsMetadata && chainsMetadata[chainName]) return chainsMetadata[chainName].faucetUrl; +// return DEFAULT_FAUCET_URL; +// } + + +// function getMinSfuelWei(chainName: string, chainsMetadata?: object): string { +// if (chainsMetadata && chainsMetadata[chainName] && chainsMetadata[chainName].minSfuelWei) { +// return chainsMetadata[chainName].minSfuelWei; +// } else { +// return DEFAULT_MIN_SFUEL_WEI; +// } +// } + + +// async function getSfuelBalance(web3: any, address: string): Promise { +// //return await provider.getBalance(address); +// // TODO! +// console.log(web3, address); +// return ''; +// } + + +// export interface StationData { +// faucetUrl: string; +// minSfuelWei: string; +// balance: string; +// ok: boolean; +// } + + +// export interface StationPowRes { +// message: string; +// ok: boolean; +// } + + +// export class Station { + +// endpoint: string; +// web3: any; // todo! + +// constructor( +// public chainName: string, +// public skaleNetwork: string, +// public mainnetEndpoint?: string, +// public chainsMetadata?: object +// ) { +// this.chainName = chainName; +// this.skaleNetwork = skaleNetwork; + +// this.endpoint = getChainEndpoint(chainName, mainnetEndpoint, skaleNetwork); + +// this.web3 = initWeb3(this.endpoint); +// this.chainsMetadata = chainsMetadata; +// } + +// async getData(address: string): Promise { +// try { +// const minSfuelWei = getMinSfuelWei(this.chainName, this.chainsMetadata); +// const balance = await getSfuelBalance(this.web3, address); +// return { +// faucetUrl: getFaucetUrl(this.chainsMetadata, this.chainName), +// minSfuelWei, +// balance, +// ok: Number(balance) >= Number(minSfuelWei) +// } +// } catch (e) { +// log(`ERROR: getSFuelData for ${this.chainName} failed!`); +// log(e); +// return { +// faucetUrl: undefined, minSfuelWei: undefined, balance: undefined, ok: undefined +// }; +// } +// } + +// async doPoW(address: string): Promise { +// if (!this.chainName || !isFaucetAvailable(this.chainName, this.skaleNetwork)) { +// log('WARNING: PoW is not available for this chain'); +// if (this.chainName === MAINNET_CHAIN_NAME) { +// return { ok: true, message: 'PoW is not available for Ethereum Mainnet' }; +// } +// return { ok: false, message: 'PoW is not available for this chain' }; +// } +// log('Mining sFUEL for ' + address + ' on ' + this.chainName + '...'); +// try { +// const endpoint = getChainEndpoint(this.chainName, undefined, this.skaleNetwork); +// const web3 = initWeb3(endpoint); +// const anon = new AnonymousPoW({ rpcUrl: endpoint }); +// await (await anon.send(getFuncData( +// web3, +// this.chainName, +// address, +// this.skaleNetwork +// ))).wait(); +// return { ok: true, message: 'PoW finished successfully' } +// } catch (e) { +// log('ERROR: PoW failed!'); +// log(e); +// return { ok: false, message: e.message }; +// } +// } +// } diff --git a/src/components/WidgetUI/Themes.ts b/src/core/themes.ts similarity index 85% rename from src/components/WidgetUI/Themes.ts rename to src/core/themes.ts index 7829906..729de92 100644 --- a/src/components/WidgetUI/Themes.ts +++ b/src/core/themes.ts @@ -17,26 +17,26 @@ */ /** - * @file Themes.ts + * @file themes.ts * @copyright SKALE Labs 2022-Present */ -import { Positions } from '../../core/dataclasses/Position'; -import { MetaportTheme } from '../../core/interfaces/Theme'; -import { DEFAULT_MP_Z_INDEX } from '../../core/constants'; +import { Positions } from './dataclasses/Position'; +import { MetaportTheme } from './interfaces/Theme'; +import { DEFAULT_MP_Z_INDEX } from './constants'; const defaultThemes = { 'dark': { - primary: 'rgb(217, 224, 33)', - background: '#0e0e0e', + primary: '#29FF94', + background: '#000000', mode: 'dark', position: Positions.bottomRight, zIndex: DEFAULT_MP_Z_INDEX }, 'light': { - primary: '#309676', - background: '#fbfbfb', + primary: '#173CFF', + background: '#EFEFEF', mode: 'light', position: Positions.bottomRight, zIndex: DEFAULT_MP_Z_INDEX diff --git a/src/core/tokens/erc20.ts b/src/core/tokens/erc20.ts deleted file mode 100644 index 1ef5cef..0000000 --- a/src/core/tokens/erc20.ts +++ /dev/null @@ -1,173 +0,0 @@ -/** - * @license - * SKALE Metaport - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -/** - * @file erc20.ts - * @copyright SKALE Labs 2022-Present - */ - -import debug from 'debug'; - -import { SChain, MainnetChain } from '@skalenetwork/ima-js'; - -import { initContract } from '../core'; -import { getEmptyTokenDataMap } from './helper'; -import { externalEvents } from '../events'; -import { MAINNET_CHAIN_NAME } from '../constants'; -import TokenData, { getTokenKeyname } from '../dataclasses/TokenData'; -import { TokenType } from '../dataclasses/TokenType'; -import * as interfaces from '../interfaces/index'; -import { fromWei } from '../convertation'; - - -debug.enable('*'); -const log = debug('metaport:tokens:erc20'); - - -export async function updateERC20TokenBalances( - availableTokens: interfaces.TokenDataTypesMap, - chainName: string, - mainnet: MainnetChain, - sChain1: SChain, - address: string -): Promise { - log('Getting ERC20 token balances...'); - for (const [symbol, tokenData] of Object.entries(availableTokens.erc20)) { - if (chainName === MAINNET_CHAIN_NAME) { - const balance = await getTokenBalance( - chainName, - mainnet, - symbol, - tokenData.decimals, - address - ); - availableTokens.erc20[symbol].balance = balance; - } else { - const balance = tokenData.wrapsSFuel && !tokenData.clone ? await getSFuelBalance( - chainName, - sChain1, - tokenData.decimals, - address - ) : await getTokenBalance( - chainName, - sChain1, - symbol, - tokenData.decimals, - address - ); - availableTokens.erc20[symbol].balance = balance; - if (availableTokens.erc20[symbol].unwrappedSymbol && - !availableTokens.erc20[symbol].clone) { - const wBalance = await getTokenBalance( - chainName, - sChain1, - availableTokens.erc20[symbol].unwrappedSymbol, - tokenData.decimals, - address - ); - availableTokens.erc20[symbol].unwrappedBalance = wBalance; - } - } - } -} - - -export async function getTokenBalance( - chainName: string, - chain: any, - tokenSymbol: string, - decimals: string, - address: string -): Promise { - const tokenContract = chain.erc20.tokens[tokenSymbol]; - const balance = await chain.getERC20Balance(tokenContract, address); - externalEvents.balance(tokenSymbol, chainName, balance); - return fromWei(balance, decimals); -} - - -export async function getSFuelBalance( - chainName: string, - chain: any, - decimals: string, - address: string -): Promise { - const balance = await chain.web3.eth.getBalance(address); - externalEvents.balance('sfuel', chainName, balance); - return fromWei(balance, decimals); -} - -export async function getWrappedTokens( - sChain: SChain, - chainName: string, - configTokens: interfaces.TokensMap, - address: string -): Promise { - log('Checking wrapped tokens...'); - const wrappedTokens: interfaces.TokenDataTypesMap = getEmptyTokenDataMap(); - if (configTokens && configTokens[chainName] && configTokens[chainName].erc20) { - for (const [_symbol, configToken] of Object.entries(configTokens[chainName].erc20)) { - if (!configToken.wraps && !configToken.wrapsSFuel) continue; - log(`getting wrapped token info configToken: ${JSON.stringify(configToken)}`) - const tokenKeyname = getTokenKeyname(configToken.symbol, configToken.address); - const tokenAbiType = configToken.wrapsSFuel ? 'sfuelwrap' : 'erc20wrap'; - const tokenContract = initContract(tokenAbiType, configToken.address, sChain.web3); - sChain.erc20.addToken( - tokenKeyname, - tokenContract - ); - const balance = await sChain.getERC20Balance( - tokenContract, - address - ); - log(`token ${tokenKeyname}, address: ${address}, balance: ${balance}`); - if (balance !== '0') { - let wrapsSymbol; - let wrapsAddress; - let wrapsIconUrl; - if (configToken.wraps) { - wrapsSymbol = configToken.wraps.symbol; - wrapsAddress = configToken.wraps.address; - wrapsIconUrl = configToken.wraps.iconUrl; - } - wrappedTokens.erc20[tokenKeyname] = new TokenData( - null, - configToken.address, - configToken.name, - configToken.symbol, - configToken.cloneSymbol, - false, - configToken.iconUrl, - configToken.decimals, - TokenType.erc20, - wrapsSymbol, - wrapsAddress, - wrapsIconUrl, - configToken.wrapsSFuel - ); - wrappedTokens.erc20[tokenKeyname].balance = fromWei( - balance, - wrappedTokens.erc20[tokenKeyname].decimals - ); - } - } - } - log('wrappedTokens'); - log(wrappedTokens); - return wrappedTokens; -} \ No newline at end of file diff --git a/src/core/tokens/eth.ts b/src/core/tokens/eth.ts deleted file mode 100644 index 61246d7..0000000 --- a/src/core/tokens/eth.ts +++ /dev/null @@ -1,91 +0,0 @@ -/** - * @license - * SKALE Metaport - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -/** - * @file eth.ts - * @copyright SKALE Labs 2022-Present - */ - - -import debug from 'debug'; - -import { SChain, MainnetChain } from '@skalenetwork/ima-js'; - -import { isMainnet } from '../helper'; -import { externalEvents } from '../events'; - -import EthTokenData from '../dataclasses/EthTokenData'; -import { TokenType } from '../dataclasses/TokenType'; -import * as interfaces from '../interfaces/index'; -import { MAINNET_CHAIN_NAME } from '../constants'; - - -debug.enable('*'); -const log = debug('metaport:tokens:eth'); - - -function ethInConfig(configTokens: interfaces.TokensMap): boolean { - return configTokens[MAINNET_CHAIN_NAME] !== undefined && - configTokens[MAINNET_CHAIN_NAME].eth !== undefined; -} - - -export async function addETHToken( - chainName1: string, - chainName2: string, - configTokens: interfaces.TokensMap, - availableTokens: interfaces.TokenDataTypesMap -): Promise { - - log('Checking ETH in the configTokens'); - if (!ethInConfig(configTokens)) return; - log('Adding ETH to token list'); - - let chains: string[] = []; - - if (configTokens[MAINNET_CHAIN_NAME][TokenType.eth]) { - chains = (configTokens[MAINNET_CHAIN_NAME][TokenType.eth].chains as string[]); - } - - if (chainName1 === MAINNET_CHAIN_NAME) { - if (chains.includes(chainName2)) { - availableTokens[TokenType.eth][TokenType.eth] = new EthTokenData(false); - } - } - - if (chainName2 === MAINNET_CHAIN_NAME) { - if (chains.includes(chainName1)) { - availableTokens[TokenType.eth][TokenType.eth] = new EthTokenData(true); - } - } -} - - -export async function getEthBalance( - mainnet: MainnetChain, - sChain: SChain, - chainName: string, - address: string -) { - log(`Getting ETH balance for ${address} on ${chainName}`); - const ethBalance = isMainnet(chainName) ? await mainnet.ethBalance(address) : - await sChain.ethBalance(address); - log('ETH balance for ' + address + ': ' + ethBalance + ' wei'); - externalEvents.balance('eth', chainName, ethBalance); - return mainnet ? mainnet.web3.utils.fromWei(ethBalance) : sChain.web3.utils.fromWei(ethBalance); -} diff --git a/src/core/tokens/helper.ts b/src/core/tokens/helper.ts index 4a95a11..e10604a 100644 --- a/src/core/tokens/helper.ts +++ b/src/core/tokens/helper.ts @@ -21,7 +21,7 @@ * @copyright SKALE Labs 2022-Present */ -import TokenData from '../dataclasses/TokenData'; +import { TokenData } from '../dataclasses/TokenData'; import * as interfaces from '../interfaces/index'; import { eqArrays } from '../helper'; @@ -45,7 +45,7 @@ export function getAvailableTokensTotal(availableTokens): number { export function getDefaultToken(availableTokens: interfaces.TokenDataTypesMap): TokenData { if (availableTokens === undefined) return; const availableTokenNumers = getAvailableTokenNumers(availableTokens); - if (eqArrays(availableTokenNumers, [1, 0, 0, 0, 0])) return availableTokens.eth.eth; + // if (eqArrays(availableTokenNumers, [1, 0, 0, 0, 0])) return availableTokens.eth.eth; if (eqArrays(availableTokenNumers, [0, 1, 0, 0, 0])) { return Object.values(availableTokens.erc20)[0]; } diff --git a/src/core/tokens/index.ts b/src/core/tokens/index.ts deleted file mode 100644 index 4681419..0000000 --- a/src/core/tokens/index.ts +++ /dev/null @@ -1,121 +0,0 @@ -/** - * @license - * SKALE Metaport - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -/** - * @file index.ts - * @copyright SKALE Labs 2022-Present - */ - -import debug from 'debug'; - -import { SChain, MainnetChain } from '@skalenetwork/ima-js'; - -import { addETHToken, getEthBalance } from './eth'; -import { updateERC20TokenBalances } from './erc20'; -import { addM2STokens } from './m2s'; -import { addS2STokens } from './s2s'; - -import { isMainnet } from '../helper'; -import { getEmptyTokenDataMap } from './helper'; - -import * as interfaces from '../interfaces/index'; - - -debug.enable('*'); -const log = debug('metaport:tokens'); - - -export async function getAvailableTokens( - mainnet: MainnetChain, - sChain1: SChain, - sChain2: SChain, - chainName1: string, - chainName2: string, - configTokens: interfaces.TokensMap, - autoLookup: boolean -): Promise { - log('Collecting available tokens for ' + chainName1 + ' → ' + chainName2); - const availableTokens = getEmptyTokenDataMap(); - try { - log('Adding ETH to availableTokens'); - await addETHToken( - chainName1, - chainName2, - configTokens, - availableTokens - ); - if (isMainnet(chainName1) || isMainnet(chainName2)) { - log('Going to add M2S ERC20 tokens') - const sChain = isMainnet(chainName1) ? sChain2 : sChain1; - const schainName = isMainnet(chainName1) ? chainName2 : chainName1; - await addM2STokens( - mainnet, - sChain, - schainName, - configTokens, - availableTokens, - autoLookup - ); - } else { - await addS2STokens( - sChain1, - sChain2, - chainName1, - chainName2, - configTokens, - availableTokens - ); - } - log('availableTokens'); - log(availableTokens); - } catch (e: unknown) { - log('ERROR: Something went wrong during getAvailableTokens procedure'); - if (typeof e === "string") { - log(e.toUpperCase()); - } else if (e instanceof Error) { - log(e.message); - } - } - return availableTokens; -} - - -export async function getTokenBalances( - availableTokens: interfaces.TokenDataTypesMap, - chainName: string, - mainnet: MainnetChain, - sChain1: SChain, - address: string -) { - log('Getting token balances...'); - if (availableTokens.eth && availableTokens.eth.eth) { - availableTokens.eth.eth.balance = await getEthBalance( - mainnet, - sChain1, - chainName, - address - ); - }; - await updateERC20TokenBalances( - availableTokens, - chainName, - mainnet, - sChain1, - address - ); -} \ No newline at end of file diff --git a/src/core/tokens/m2s.ts b/src/core/tokens/m2s.ts deleted file mode 100644 index 49c7eee..0000000 --- a/src/core/tokens/m2s.ts +++ /dev/null @@ -1,210 +0,0 @@ -/** - * @license - * SKALE Metaport - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -/** - * @file m2s.ts - * @copyright SKALE Labs 2022-Present - */ - - -import debug from 'debug'; - -import { SChain, MainnetChain } from '@skalenetwork/ima-js'; - -import { initContract } from '../core'; - -import * as interfaces from '../interfaces/index'; -import { TokenType } from '../dataclasses/TokenType'; -import TokenData, { getTokenKeyname } from '../dataclasses/TokenData'; -import { MAINNET_CHAIN_NAME, ZERO_ADDRESS } from '../constants'; -import { isMainnet } from '../helper'; - - -debug.enable('*'); -const log = debug('metaport:tokens:m2s'); - - -export async function addM2STokens( - mainnet: MainnetChain, - sChain: SChain, - schainName: string, - configTokens: interfaces.TokensMap, - availableTokens: interfaces.TokenDataTypesMap, - autoLookup: boolean -): Promise { - autoLookup ? await getM2STokensAutomatic( - mainnet, - sChain, - schainName, - configTokens, - availableTokens - ) : await getM2STokensManual( - mainnet, - sChain, - configTokens, - availableTokens - ); -} - - -async function getM2STokensAutomatic( - mainnet: MainnetChain, - sChain: SChain, - schainName: string, - configTokens: interfaces.TokensMap, - availableTokens: interfaces.TokenDataTypesMap -): Promise { - log('Starting automatic lookup for M2S tokens...'); - for (const tokenType in TokenType) { - await addM2STokensAutomatic( - tokenType, - mainnet, - sChain, - schainName, - configTokens, - availableTokens - ) - } -} - - -async function addM2STokensAutomatic( - tokenType: string, - mainnet: MainnetChain, - sChain: SChain, - destChainName: string, - configTokens: interfaces.TokensMap, - availableTokens: interfaces.TokenDataTypesMap -): Promise { - if (tokenType === TokenType.eth) return; - log(`Getting token pairs: ${tokenType}`); - const len = await mainnet[tokenType].getTokenMappingsLength(destChainName); - log(`Number of ${tokenType} token pairs: ${len}`); - if (len === '0') { - log('No linked tokens, exiting.') - return; - } - const tokenAddresses = await mainnet[tokenType].getTokenMappings( - destChainName, - 0, - len - ); // todo: optimize - for (const address of tokenAddresses) { - log(`Adding contract: ${address}`); - const contract = initContract(tokenType, address, mainnet.web3); - - const symbol = await contract.methods.symbol().call(); - const isClone = isMainnet(destChainName); - const name = await contract.methods.name().call(); - - let decimals: string; - - if (tokenType === TokenType.erc20) { - decimals = await contract.methods.decimals().call(); - } - - const cloneAddress = await sChain[tokenType].getTokenCloneAddress(address); - - const key = getTokenKeyname(symbol, address); - log('Adding token: ' + key); - - const tokenData = new TokenData( - cloneAddress, - address, - name, - symbol, - symbol, - isClone, - null, - decimals, - tokenType as TokenType, - null, - null, - null - ); - availableTokens[tokenType][key] = overrideTokenDataFromConfig( - configTokens, - tokenData, - tokenType - ); - mainnet[tokenType].addToken(key, contract); - sChain[tokenType].addToken(key, initContract(tokenType, cloneAddress, sChain.web3)); - } -} - -function overrideTokenDataFromConfig( - configTokens: interfaces.TokensMap, - tokenData: TokenData, - tokenType: string -): TokenData { - if (!configTokens[MAINNET_CHAIN_NAME]) return tokenData; - if (!configTokens[MAINNET_CHAIN_NAME][tokenType]) return tokenData; - if (!configTokens[MAINNET_CHAIN_NAME][tokenType][tokenData.keyname]) return tokenData; - - const configTokenData = configTokens[MAINNET_CHAIN_NAME][tokenType][tokenData.keyname]; - log(`Overriding token data from config ${tokenData.keyname}: ${configTokenData}`); - tokenData.iconUrl = configTokenData.iconUrl ? configTokenData.iconUrl : tokenData.iconUrl; - tokenData.decimals = configTokenData.decimals ? configTokenData.decimals : tokenData.decimals; - tokenData.name = configTokenData.name ? configTokenData.name : tokenData.name; - tokenData.symbol = configTokenData.symbol ? configTokenData.symbol : tokenData.symbol; - return tokenData; -} - - -async function getM2STokensManual( - mainnet: MainnetChain, - sChain: SChain, - configTokens: interfaces.TokensMap, - availableTokens: interfaces.TokenDataTypesMap -): Promise { - log('Starting manual lookup for M2S tokens...'); - if (!configTokens[MAINNET_CHAIN_NAME]) return; - for (const tokenType in configTokens[MAINNET_CHAIN_NAME]) { - if (tokenType === TokenType.eth) continue; - log(`Adding tokens for tokenType ${tokenType}`); - for (const tokenSymbol in configTokens[MAINNET_CHAIN_NAME][tokenType]) { - const tokenInfo = configTokens[MAINNET_CHAIN_NAME][tokenType][tokenSymbol]; - const cloneAddress = await sChain[tokenType].getTokenCloneAddress(tokenInfo.address); - const tokenKeyname = getTokenKeyname(tokenInfo.symbol, tokenInfo.address); - if (cloneAddress === ZERO_ADDRESS) { - log(`No token clone for ${tokenInfo.address}, skipping`); - continue; - } - - log(`Adding token: ${tokenKeyname}`); - availableTokens[tokenType][tokenKeyname] = new TokenData( - cloneAddress, - tokenInfo.address, - tokenInfo.name, - tokenInfo.symbol, - tokenInfo.cloneSymbol, - false, - tokenInfo.iconUrl, - tokenInfo.decimals, - tokenType as TokenType, - null, - null, - null - ); - mainnet[tokenType].addToken( - tokenKeyname, initContract(tokenType, tokenInfo.address, mainnet.web3)); - sChain[tokenType].addToken( - tokenKeyname, initContract(tokenType, cloneAddress, sChain.web3)); - } - } -} \ No newline at end of file diff --git a/src/core/tokens/s2s.ts b/src/core/tokens/s2s.ts deleted file mode 100644 index 7ac5bf9..0000000 --- a/src/core/tokens/s2s.ts +++ /dev/null @@ -1,187 +0,0 @@ -/** - * @license - * SKALE Metaport - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -/** - * @file s2s.ts - * @copyright SKALE Labs 2022-Present - */ - - -import debug from 'debug'; - -import { SChain } from '@skalenetwork/ima-js'; - -import { initContract } from '../core'; -import * as interfaces from '../interfaces/index'; -import { TokenType } from '../dataclasses/TokenType'; -import TokenData, { getTokenKeyname } from '../dataclasses/TokenData'; -import { ZERO_ADDRESS } from '../constants'; - - -debug.enable('*'); -const log = debug('metaport:tokens:s2s'); - - -export async function addS2STokens( - sChain1: SChain, - sChain2: SChain, - chainName1: string, - chainName2: string, - configTokens: interfaces.TokensMap, - availableTokens: interfaces.TokenDataTypesMap, -): Promise { - log('Add S2S Tokens'); - await collectS2STokens( - sChain1, - sChain2, - chainName1, - configTokens, - availableTokens, - false - ); - await collectS2STokens( - sChain1, - sChain2, - chainName2, - configTokens, - availableTokens, - true - ); -} - - -async function collectS2STokens( - sChain1: SChain, - sChain2: SChain, - chainName: string, - configTokens: interfaces.TokensMap, - availableTokens: interfaces.TokenDataTypesMap, - isClone: boolean -): Promise { - if (!configTokens[chainName]) return; - for (const tokenType in configTokens[chainName]) { - log(`Adding tokens for tokenType ${tokenType}`); - for (const tokenKeyname in configTokens[chainName][tokenType]) { - await addTokenData( - sChain1, - sChain2, - chainName, - configTokens[chainName][tokenType][tokenKeyname], - availableTokens, - isClone, - tokenType as TokenType - ); - } - } -} - - -async function addTokenData( - sChain1: SChain, - sChain2: SChain, - sChainName: string, - configToken: interfaces.Token, - availableTokens: interfaces.TokenDataTypesMap, - isClone: boolean, - tokenType: TokenType -): Promise { - const cloneAddress = await getCloneAddress( - isClone ? sChain1 : sChain2, - configToken.address, - sChainName, - tokenType - ); - if (!cloneAddress) { - log(`No token clone for ${configToken.address}, skipping`); - return; - } - let unwrappedSymbol; - let unwrappedAddress; - let unwrappedIconUrl; - if (configToken.wraps) { - unwrappedSymbol = configToken.wraps.symbol; - unwrappedAddress = configToken.wraps.address; - unwrappedIconUrl = configToken.wraps.iconUrl; - } - - const tokenKeyname = getTokenKeyname(configToken.symbol, configToken.address); - availableTokens[tokenType][tokenKeyname] = new TokenData( - cloneAddress, - configToken.address, - configToken.name, - configToken.symbol, - configToken.cloneSymbol, - isClone, - configToken.iconUrl, - configToken.decimals, - tokenType, - unwrappedSymbol, - unwrappedAddress, - unwrappedIconUrl, - configToken.wrapsSFuel - ); - addToken(sChain1, availableTokens[tokenType][tokenKeyname], true); - addToken(sChain2, availableTokens[tokenType][tokenKeyname], false); -} - - -async function getCloneAddress( - sChain: SChain, - originTokenAddress: string, - originChainName: string, - tokenType: TokenType -): Promise { - log(`Getting clone address for ${originTokenAddress} on a chain`); - try { - const tokenCloneAddress = await sChain[tokenType].getTokenCloneAddress( - originTokenAddress, - originChainName - ); - if (tokenCloneAddress === ZERO_ADDRESS) return; - return tokenCloneAddress; - } catch (e) { - log(`getCloneAddress for ${originTokenAddress} - ${originChainName} failed`); - log(e); - } -} - - -function addToken(sChain: SChain, token: TokenData, fromChain: boolean): void { - log(`Adding token to sChain object - ${token.keyname}`); - const isCloneAddress = (fromChain && token.clone) || (!fromChain && !token.clone); - const address = isCloneAddress ? token.cloneAddress : token.originAddress; - if (token.unwrappedSymbol) { - sChain[token.type].addToken( - token.keyname, - initContract('erc20wrap', address, sChain.web3) - ); - sChain[token.type].addToken( - token.unwrappedSymbol, - initContract(token.type, token.unwrappedAddress, sChain.web3) - ); - } else { - if (token.wrapsSFuel && !token.clone) { - sChain[token.type].addToken( - token.keyname, - initContract('sfuelwrap', address, sChain.web3) - ); - return; - } - sChain[token.type].addToken(token.keyname, initContract(token.type, address, sChain.web3)); - } -} diff --git a/src/core/transfer_steps.ts b/src/core/transfer_steps.ts index 73efb21..3e35b60 100644 --- a/src/core/transfer_steps.ts +++ b/src/core/transfer_steps.ts @@ -1,13 +1,40 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/** + * @file transfer_steps.ts + * @copyright SKALE Labs 2023-Present + */ import debug from 'debug'; -import TokenData from './dataclasses/TokenData'; -import * as interfaces from './interfaces/index'; +import { + TokenData, + WrapStepMetadata, + UnwrapStepMetadata, + TransferStepMetadata, + StepMetadata, + getActionType +} from './dataclasses'; + import { MetaportConfig } from './interfaces/index'; -import { getChainIcon } from '../components/ChainsList/helper'; -import { getChainName } from './helper'; import { MAINNET_CHAIN_NAME } from './constants'; @@ -15,187 +42,51 @@ debug.enable('*'); const log = debug('metaport:core:transferSteps'); -export function getTransferSteps( - trReq: interfaces.TransferParams, +export function getStepsMetadata( config: MetaportConfig, - theme: any, - token: TokenData -) { - - // TODO: refactor this function - - const steps = []; - - const toChain = trReq.route ? trReq.route.hub : trReq.chains[1]; - const toApp = trReq.route ? null : trReq.toApp; - - log('adding transfer step'); - steps.push(getTransferStep( - trReq.chains[0], - toChain, - trReq.fromApp, - toApp, - token.symbol, - config, - theme - )); - - if (trReq.route) { - if (!token.clone) { - log('adding wrap+transfer steps'); - steps.push(getWrapStep( - trReq.route.hub, - null, - config, - theme - )); - steps.push(getTransferStep( - trReq.route.hub, - trReq.chains[1], - null, - trReq.toApp, - token.symbol, - config, - theme - )); - - } else { - log('adding unwrap+transfer steps'); - steps.push(getUnwrapStep( - trReq.route.hub, - null, - config, - theme - )); - steps.push(getTransferStep( - trReq.route.hub, - trReq.chains[1], - null, - toApp, - token.symbol, - config, - theme - )); - } - } else { - if (token.unwrappedSymbol || token.wrapsSFuel) { - if (!token.clone) { - log('adding wrap step'); - steps.unshift(getWrapStep( - trReq.chains[0], - trReq.fromApp, - config, - theme - )); - } else { - log('adding unwrap step'); - if (!token.wrapsSFuel) { - steps.push(getUnwrapStep( - trReq.chains[1], - trReq.toApp, - config, - theme - )); - } - } - } - }; - if (trReq.chains[1] === MAINNET_CHAIN_NAME && - (trReq.tokenKeyname === 'eth' || (trReq.route && trReq.route.tokenKeyname === 'eth')) - ) { - log('adding unlock step'); - steps.push(getUnlockStep( - trReq.chains[1], - null, - config, - theme + token: TokenData, + to: string +): StepMetadata[] { + const steps: StepMetadata[] = []; + if (token === undefined || token === null || to === null || to === '') return steps; + + const toChain = token.connections[to].hub ?? to; + const hubTokenOptions = config.connections[toChain][token.type][token.keyname].chains[token.chain]; + const destTokenOptions = config.connections[to][token.type][token.keyname].chains[token.chain]; + const isCloneToClone = token.isClone(to) && destTokenOptions.clone; + + log(`Setting toChain: ${toChain}`); + + if (token.connections[toChain].wrapper) { + steps.push(new WrapStepMetadata( + token.chain, + to )) } - return steps; -} - - -function getWrapStep( - chain: string, - app: string, - config: MetaportConfig, - theme: any -) { - const chainName = getChainName(config.chainsMetadata, chain, config.skaleNetwork, app); - const chainIcon = getChainIcon(config.skaleNetwork, chain, theme.dark, app); - return { - chainName, - chainIcon, - headline: 'Wrap on', - text: `Wrap on ${chainName}. You may need to approve first.`, - btnText: 'Wrap', - btnLoadingText: 'Wrapping' + steps.push(new TransferStepMetadata( + getActionType(token.chain, toChain, token.type), + token.chain, + toChain + )); + if (hubTokenOptions.wrapper && !isCloneToClone) { + steps.push(new UnwrapStepMetadata(token.chain, toChain)); } -} - - -function getUnwrapStep( - chain: string, - app: string, - config: MetaportConfig, - theme: any -) { - const chainName = getChainName(config.chainsMetadata, chain, config.skaleNetwork, app); - const chainIcon = getChainIcon(config.skaleNetwork, chain, theme.dark, app); - return { - chainName, - chainIcon, - headline: 'Unwrap on', - text: `Unwrap on ${chainName}.`, - btnText: 'Unwrap', - btnLoadingText: 'Unwrapping' + if (token.connections[to].hub) { + const tokenOptionsHub = config.connections[toChain][token.type][token.keyname].chains[to]; + if (tokenOptionsHub.wrapper && !isCloneToClone) { + steps.push(new WrapStepMetadata(toChain, to)); + } + steps.push(new TransferStepMetadata( + getActionType(toChain, to, token.type), + toChain, + to + )); } -} - - -function getUnlockStep( - chain: string, - app: string, - config: MetaportConfig, - theme: any -) { - const chainName = getChainName(config.chainsMetadata, chain, config.skaleNetwork, app); - const chainIcon = getChainIcon(config.skaleNetwork, chain, theme.dark, app); - return { - chainName, - chainIcon, - headline: 'Unlock on', - text: `You have to unlock your assets to be able to use it on ${chainName}.`, - btnText: 'Unlock', - btnLoadingText: 'Unlocking' + if (to === MAINNET_CHAIN_NAME && token.keyname === 'eth') { + // todo: add unlock step! } -} - -function getTransferStep( - fromChain: string, - toChain: string, - fromApp: string, - toApp: string, - tokenSymbol: string, - config: MetaportConfig, - theme: any -) { - const fromChainName = getChainName( - config.chainsMetadata, - fromChain, - config.skaleNetwork, - fromApp - ); - const toChainName = getChainName(config.chainsMetadata, toChain, config.skaleNetwork, toApp); - const toChainIcon = getChainIcon(config.skaleNetwork, toChain, theme.dark, toApp); - return { - chainName: toChainName, - chainIcon: toChainIcon, - headline: 'Transfer to', - text: `Transfer ${tokenSymbol.toUpperCase()} from ${fromChainName} to ${toChainName}. - You may need to approve first.`, - btnText: 'Transfer', - btnLoadingText: 'Transferring' - } + log(`Action steps metadata:`); + log(steps); + return steps; } \ No newline at end of file diff --git a/src/core/views.ts b/src/core/views.ts index 407f32b..aa33581 100644 --- a/src/core/views.ts +++ b/src/core/views.ts @@ -35,6 +35,6 @@ export function isTransferRequestSummary(view: View) { } -export function isTransferRequestSteps(view: View) { +export function isStepsMetadata(view: View) { return view === View.TRANSFER_REQUEST_STEPS } diff --git a/src/core/wagmi_network.ts b/src/core/wagmi_network.ts new file mode 100644 index 0000000..5bbaab2 --- /dev/null +++ b/src/core/wagmi_network.ts @@ -0,0 +1,65 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/** + * @file wagmi_network.ts + * @copyright SKALE Labs 2023-Present + */ + +import { Chain } from 'wagmi' + +import { getSChainEndpoint } from './network'; +import { getExplorerUrl } from './explorer'; +import { getChainAlias } from './helper'; +import { getChainId } from './chain_id'; + +import { SkaleNetwork } from './interfaces'; + + +export function constructWagmiChain(network: SkaleNetwork, chainName: string): Chain { + const endpointHttp = getSChainEndpoint(network, chainName); + const endpointWs = getSChainEndpoint(network, chainName, 'ws'); + const explorerUrl = getExplorerUrl(network, chainName); + const name = getChainAlias(network, chainName); + const chainId = getChainId(chainName); + return { + id: chainId, + name: name, + network: `skale-${chainName}`, + nativeCurrency: { + decimals: 18, + name: 'sFUEL', + symbol: 'sFUEL', + }, + rpcUrls: { + public: { http: [endpointHttp], webSocket: [endpointWs] }, + default: { http: [endpointHttp], webSocket: [endpointWs] }, + }, + blockExplorers: { + etherscan: { name: 'SKALE Explorer', url: explorerUrl }, + default: { name: 'SKALE Explorer', url: explorerUrl }, + }, + contracts: {} + } as const satisfies Chain +} + + +export function getWebSocketUrl(chain: Chain): string { + // return chain.rpcUrls.default.webSocket ? chain.rpcUrls.default.webSocket[0] : ''; + return chain.rpcUrls.default.webSocket ? chain.rpcUrls.default.webSocket[0] : ''; // TODO - IP! +} \ No newline at end of file diff --git a/src/metadata/addresses/staging.json b/src/metadata/addresses/staging.json index 8192894..ef115e5 100644 --- a/src/metadata/addresses/staging.json +++ b/src/metadata/addresses/staging.json @@ -1,10 +1,10 @@ { - "message_proxy_mainnet_address": "0x656fb12abab353FB1875a4e3Dc4D70179CB85BA4", - "linker_address": "0xEa870bEF8cc1Ca6871AE960266ea0fDbCF06371d", - "community_pool_address": "0xb2BadB7f28075CB2C8BDBd730204750Db4C03f98", - "deposit_box_eth_address": "0x9910cF6ba22915C5afCe8b682f7c09d1c001FA59", - "deposit_box_erc20_address": "0xb3bf0c62f0924e5C8fdae9815355eA98Fba33C8E", - "deposit_box_erc721_address": "0x98937f91885dcCfF8082623a157296AA161a9917", - "deposit_box_erc1155_address": "0xa0EF1521f56641F9E0E43c46E0F6B20715E454c8", - "deposit_box_erc721_with_metadata_address": "0x4B85DD7d995D6ae445292939d7ebfabD7Cd088dA" + "message_proxy_mainnet_address": "0x08913E0DC2BA60A1626655581f701bCa84f42324", + "linker_address": "0xd081AC47D26baE9c07320AdB83867da28678959E", + "community_pool_address": "0x4957cF98336C0911E42100C8839dCd65DdDe88C9", + "deposit_box_eth_address": "0xD0C9019c517A6CEbb86527fd52F2bDD4Dc6A94Dd", + "deposit_box_erc20_address": "0x2F4B31e661955d41bd6ab5530b117758C26C8159", + "deposit_box_erc721_address": "0x3B1425c6EfD383BAA53F607DD43e5593c4DeBf8f", + "deposit_box_erc1155_address": "0x29DF2117459Dd2c692A1E86DE90371fBc0E3EC76", + "deposit_box_erc721_with_metadata_address": "0x01dd5b9a147c03336F37b7857248d9CDF27661e8" } \ No newline at end of file diff --git a/src/metadata/addresses/staging3.json b/src/metadata/addresses/staging3.json deleted file mode 100644 index ef115e5..0000000 --- a/src/metadata/addresses/staging3.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "message_proxy_mainnet_address": "0x08913E0DC2BA60A1626655581f701bCa84f42324", - "linker_address": "0xd081AC47D26baE9c07320AdB83867da28678959E", - "community_pool_address": "0x4957cF98336C0911E42100C8839dCd65DdDe88C9", - "deposit_box_eth_address": "0xD0C9019c517A6CEbb86527fd52F2bDD4Dc6A94Dd", - "deposit_box_erc20_address": "0x2F4B31e661955d41bd6ab5530b117758C26C8159", - "deposit_box_erc721_address": "0x3B1425c6EfD383BAA53F607DD43e5593c4DeBf8f", - "deposit_box_erc1155_address": "0x29DF2117459Dd2c692A1E86DE90371fBc0E3EC76", - "deposit_box_erc721_with_metadata_address": "0x01dd5b9a147c03336F37b7857248d9CDF27661e8" -} \ No newline at end of file diff --git a/src/metadata/faucet.json b/src/metadata/faucet.json index 8248998..d69a401 100644 --- a/src/metadata/faucet.json +++ b/src/metadata/faucet.json @@ -25,7 +25,7 @@ "func": "0x0c11dedd" } }, - "staging3": { + "staging": { "staging-perfect-parallel-gacrux": { "address": "0x4576d1B9eeaE16d6Ca643e55D21E0Dc00e8A7b6D", "func": "0x0c11dedd" diff --git a/src/metadata/metaportConfigStaging.json b/src/metadata/metaportConfigStaging.json new file mode 100644 index 0000000..db445c7 --- /dev/null +++ b/src/metadata/metaportConfigStaging.json @@ -0,0 +1,314 @@ +{ + "skaleNetwork": "staging", + "openOnLoad": true, + "openButton": true, + "debug": false, + "chains": [ + "mainnet", + "staging-legal-crazy-castor", + "staging-utter-unripe-menkar", + "staging-faint-slimy-achird", + "staging-perfect-parallel-gacrux", + "staging-severe-violet-wezen", + "staging-weepy-fitting-caph" + ], + "tokens": { + "eth": { + "symbol": "eth" + }, + "skl": { + "decimals": "18", + "name": "SKALE", + "symbol": "SKL" + }, + "usdc": { + "decimals": "6", + "symbol": "USDC", + "name": "USD Coin" + }, + "usdt": { + "decimals": "6", + "symbol": "USDT", + "name": "Tether USD" + }, + "wbtc": { + "decimals": "18", + "symbol": "WBTC", + "name": "WBTC" + }, + "_SPACE_1": { + "name": "SKALE Space", + "symbol": "SPACE", + "iconUrl": "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Rocket/3D/rocket_3d.png" + }, + "_SKALIENS_1": { + "name": "SKALIENS Collection", + "symbol": "SKALIENS", + "iconUrl": "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Alien/3D/alien_3d.png" + }, + "ruby": { + "name": "Ruby Token", + "iconUrl": "https://ruby.exchange/images/tokens/ruby-square.png", + "symbol": "RUBY" + }, + "dai": { + "name": "DAI Stablecoin", + "symbol": "DAI" + }, + "usdp": { + "name": "Pax Dollar", + "symbol": "USDP", + "iconUrl": "https://ruby.exchange/images/tokens/usdp-square.png" + }, + "hmt": { + "name": "Human Token", + "symbol": "HMT", + "iconUrl": "https://s2.coinmarketcap.com/static/img/coins/64x64/10347.png" + } + }, + "connections": { + "mainnet": { + "erc20": { + "skl": { + "address": "0x493D4442013717189C9963a2e275Ad33bfAFcE11", + "chains": { + "staging-legal-crazy-castor": {}, + "staging-utter-unripe-menkar": { + "hub": "staging-legal-crazy-castor" + }, + "staging-faint-slimy-achird": { + "hub": "staging-legal-crazy-castor" + } + } + }, + "ruby": { + "address": "0xd66641E25E9D36A995682572eaD74E24C11Bb422", + "chains": { + "staging-legal-crazy-castor": {} + } + }, + "dai": { + "address": "0x83B38f79cFFB47CF74f7eC8a5F8D7DD69349fBf7", + "chains": { + "staging-legal-crazy-castor": {} + } + }, + "usdp": { + "address": "0x66259E472f8d09083ecB51D42F9F872A61001426", + "chains": { + "staging-legal-crazy-castor": {} + } + }, + "usdt": { + "address": "0xD1E44e3afd6d3F155e7704c67705E3bAC2e491b6", + "chains": { + "staging-legal-crazy-castor": {} + } + }, + "usdc": { + "address": "0x85dedAA65D33210E15911Da5E9dc29F5C93a50A9", + "chains": { + "staging-legal-crazy-castor": {} + } + }, + "wbtc": { + "address": "0xd80BC0126A38c9F7b915e1B2B9f78280639cadb3", + "chains": { + "staging-legal-crazy-castor": {} + } + }, + "hmt": { + "address": "0x4058d058ff62ED347dB8a69c43Ae9C67268B50b0", + "chains": {} + } + }, + "erc721meta": { + "_SPACE_1": { + "address": "0x1b7729d7E1025A031aF9D6E68598b57f4C2adfF6", + "chains": {} + } + }, + "erc1155": { + "_SKALIENS_1": { + "address": "0x6cb73D413970ae9379560aA45c769b417Fbf33D6", + "chains": {} + } + } + }, + "staging-utter-unripe-menkar": { + "erc20": { + "skl": { + "address": "0x7E1B8750C21AebC3bb2a0bDf40be104C609a9852", + "chains": { + "staging-legal-crazy-castor": { + "clone": true + }, + "staging-faint-slimy-achird": { + "hub": "staging-legal-crazy-castor", + "clone": true + }, + "mainnet": { + "hub": "staging-legal-crazy-castor", + "clone": true + } + } + } + } + }, + "staging-faint-slimy-achird": { + "erc20": { + "skl": { + "address": "0x7F73B66d4e6e67bCdeaF277b9962addcDabBFC4d", + "chains": { + "staging-legal-crazy-castor": { + "clone": true + }, + "mainnet": { + "hub": "staging-legal-crazy-castor", + "clone": true + }, + "staging-utter-unripe-menkar": { + "hub": "staging-legal-crazy-castor", + "clone": true + } + } + } + } + }, + "staging-legal-crazy-castor": { + "erc20": { + "skl": { + "address": "0xbA1E9BA7CDd4815Da6a51586bE56e8643d1bEAb6", + "chains": { + "mainnet": { + "clone": true + }, + "staging-utter-unripe-menkar": { + "wrapper": "0x6a679eF80aF3fE01A646F858Ca1e26D58b5430B6" + }, + "staging-faint-slimy-achird": { + "wrapper": "0x6a679eF80aF3fE01A646F858Ca1e26D58b5430B6" + } + } + }, + "ruby": { + "address": "0xf06De9214B1Db39fFE9db2AebFA74E52f1e46e39", + "chains": { + "mainnet": { + "clone": true + } + } + }, + "dai": { + "address": "0x3595E2f313780cb2f23e197B8e297066fd410d30", + "chains": { + "mainnet": { + "clone": true + } + } + }, + "usdp": { + "address": "0xe0E2cb3A5d6f94a5bc2D00FAa3e64460A9D241E1", + "chains": { + "mainnet": { + "clone": true + } + } + }, + "usdt": { + "address": "0xa388F9783d8E5B0502548061c3b06bf4300Fc0E1", + "chains": { + "mainnet": { + "clone": true + } + } + }, + "usdc": { + "address": "0x5d42495D417fcd9ECf42F3EA8a55FcEf44eD9B33", + "chains": { + "mainnet": { + "clone": true + } + } + }, + "wbtc": { + "address": "0xf5E880E1066DDc90471B9BAE6f183D5344fd289F", + "chains": { + "mainnet": { + "clone": true + } + } + } + } + }, + "staging-perfect-parallel-gacrux": { + "erc20": { + "_ETH_0xBA3f8192e28224790978794102C0D7aaa65B7d70": { + "address": "0xBA3f8192e28224790978794102C0D7aaa65B7d70", + "name": "ETH", + "symbol": "ETH", + "cloneSymbol": "ETH", + "wraps": { + "address": "0xD2Aaa00700000000000000000000000000000000", + "symbol": "ETH", + "name": "aaaa" + } + }, + "_SKILL_0xb36A1DdaBf21161ad71013A34D502381DD1aa7BA": { + "address": "0xb36A1DdaBf21161ad71013A34D502381DD1aa7BA", + "name": "SKILL Token", + "symbol": "SKILL", + "iconUrl": "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Compass/3D/compass_3d.png" + }, + "DMT": { + "address": "0xb36A1DdaBf21161ad71013A34D502381DD1aa7BA", + "name": "DMT", + "symbol": "DMT", + "cloneSymbol": "DMTC", + "wraps": { + "address": "0x688f6d050B935BF06531b51B5e598318788fA7a5", + "symbol": "DMT", + "iconUrl": "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Compass/3D/compass_3d.png" + } + }, + "_SKL_0x099A46F35b627CABee27dc917eDA253fFbC55Be6": { + "address": "0x099A46F35b627CABee27dc917eDA253fFbC55Be6", + "decimals": "18", + "name": "SKL S2S", + "symbol": "SKL" + } + }, + "erc721": { + "_SPS_0x30216880A73B67133F37de35e769b8e1A943D35c": { + "address": "0x30216880A73B67133F37de35e769b8e1A943D35c", + "name": "SKALE Space S2S", + "symbol": "SPS", + "iconUrl": "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Glowing%20star/3D/glowing_star_3d.png" + } + }, + "erc1155": { + "skaliens": { + "address": "0xBA9fF38A2b22edDfa8e05805bD22C8f20c40546e", + "name": "SKALIENS Collection", + "symbol": "SKALIENS2S", + "iconUrl": "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Alien/3D/alien_3d.png" + }, + "medals": { + "address": "0x5D8bD602dC5468B3998e8514A1851bd5888E9639", + "name": "Medals", + "symbol": "MEDALS2S", + "iconUrl": "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/1st%20place%20medal/3D/1st_place_medal_3d.png" + }, + "_ANIMALS_0xDf87EEF0977148129969b01b329379b17756cdDE": { + "address": "0xDf87EEF0977148129969b01b329379b17756cdDE", + "name": "Funny Animals", + "symbol": "ANIMALS", + "iconUrl": "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Frog/3D/frog_3d.png" + } + } + } + }, + "theme": { + "mode": "dark" + } +} \ No newline at end of file diff --git a/src/metadata/proxy.json b/src/metadata/proxy.json index 3f749d1..a54c3bb 100644 --- a/src/metadata/proxy.json +++ b/src/metadata/proxy.json @@ -1,7 +1,6 @@ { - "mainnet": "https://mainnet.skalenodes.com", - "staging": "https://staging-v2.skalenodes.com", - "staging3": "https://staging-v3.skalenodes.com", - "legacy": "https://legacy-proxy.skalenodes.com/", - "qatestnet": "https://new-testnet-proxy.skalenodes.com" + "mainnet": "mainnet.skalenodes.com", + "staging": "staging-v3.skalenodes.com", + "legacy": "legacy-proxy.skalenodes.com/", + "qatestnet": "new-testnet-proxy.skalenodes.com" } \ No newline at end of file diff --git a/src/metadata/schainAbi.json b/src/metadata/schainAbi.json index 9e18540..cf9d056 100644 --- a/src/metadata/schainAbi.json +++ b/src/metadata/schainAbi.json @@ -1 +1 @@ -{"ERC1155OnChain_abi":[{"inputs":[{"internalType":"string","name":"uri","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"burnBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"mintBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}],"ERC20OnChain_abi":[{"inputs":[{"internalType":"string","name":"contractName","type":"string"},{"internalType":"string","name":"contractSymbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}],"ERC721OnChain_abi":[{"inputs":[{"internalType":"string","name":"contractName","type":"string"},{"internalType":"string","name":"contractSymbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"tokenUri","type":"string"}],"name":"setTokenURI","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}],"community_locker_abi":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"schainHash","type":"bytes32"},{"indexed":false,"internalType":"address","name":"user","type":"address"}],"name":"ActivateUser","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"constantHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"previousValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"ConstantUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"schainHash","type":"bytes32"},{"indexed":false,"internalType":"address","name":"user","type":"address"}],"name":"LockUser","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"CONSTANT_SETTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"activeUsers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"checkAllowedToSendMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"communityPool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasPriceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"newSchainName","type":"string"},{"internalType":"contract IMessageProxyForSchain","name":"newMessageProxy","type":"address"},{"internalType":"contract ITokenManagerLinker","name":"newTokenManagerLinker","type":"address"},{"internalType":"address","name":"newCommunityPool","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastMessageTimeStamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mainnetGasPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"messageProxy","outputs":[{"internalType":"contract IMessageProxyForSchain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"fromChainHash","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"postMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"schainHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"components":[{"internalType":"uint256[2]","name":"blsSignature","type":"uint256[2]"},{"internalType":"uint256","name":"hashA","type":"uint256"},{"internalType":"uint256","name":"hashB","type":"uint256"},{"internalType":"uint256","name":"counter","type":"uint256"}],"internalType":"struct IMessageProxy.Signature","name":"","type":"tuple"}],"name":"setGasPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newTimeLimitPerMessage","type":"uint256"}],"name":"setTimeLimitPerMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"timeLimitPerMessage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenManagerLinker","outputs":[{"internalType":"contract ITokenManagerLinker","name":"","type":"address"}],"stateMutability":"view","type":"function"}],"community_locker_address":"0xD2aaa00300000000000000000000000000000000","eth_erc20_abi":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"BURNER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"forceBurn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenManagerEthAddress","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}],"eth_erc20_address":"0xD2Aaa00700000000000000000000000000000000","key_storage_abi":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FN_NUM_GET_CONFIG_VARIABLE_UINT256","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FN_NUM_GET_CURRENT_BLS_PUBLIC_KEY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FREE_MEM_PTR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBlsCommonPublicKey","outputs":[{"components":[{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"b","type":"uint256"}],"internalType":"struct IFieldOperations.Fp2Point","name":"x","type":"tuple"},{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"b","type":"uint256"}],"internalType":"struct IFieldOperations.Fp2Point","name":"y","type":"tuple"}],"internalType":"struct IFieldOperations.G2Point","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"key_storage_address":"0xd2aaa00200000000000000000000000000000000","message_proxy_chain_abi":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":false,"internalType":"address","name":"contractAddress","type":"address"}],"name":"ExtraContractRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":false,"internalType":"address","name":"contractAddress","type":"address"}],"name":"ExtraContractRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"GasLimitWasChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"dstChainHash","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"msgCounter","type":"uint256"},{"indexed":true,"internalType":"address","name":"srcContract","type":"address"},{"indexed":false,"internalType":"address","name":"dstContract","type":"address"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"OutgoingMessage","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"msgCounter","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"}],"name":"PostMessageError","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"oldVersion","type":"string"},{"indexed":false,"internalType":"string","name":"newVersion","type":"string"}],"name":"VersionUpdated","type":"event"},{"inputs":[],"name":"CHAIN_CONNECTOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CONSTANT_SETTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ETHERBASE","outputs":[{"internalType":"contract IEtherbaseUpgradeable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXTRA_CONTRACT_REGISTRAR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MESSAGES_LENGTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINIMUM_BALANCE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REVERT_REASON_LENGTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"chainName","type":"string"}],"name":"addConnectedChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"connectedChains","outputs":[{"internalType":"uint256","name":"incomingMessageCounter","type":"uint256"},{"internalType":"uint256","name":"outgoingMessageCounter","type":"uint256"},{"internalType":"bool","name":"inited","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"schainHash","type":"bytes32"}],"name":"getContractRegisteredLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"schainHash","type":"bytes32"},{"internalType":"uint256","name":"from","type":"uint256"},{"internalType":"uint256","name":"to","type":"uint256"}],"name":"getContractRegisteredRange","outputs":[{"internalType":"address[]","name":"contractsInRange","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"fromSchainName","type":"string"}],"name":"getIncomingMessagesCounter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"targetSchainName","type":"string"}],"name":"getOutgoingMessagesCounter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IKeyStorage","name":"blsKeyStorage","type":"address"},{"internalType":"string","name":"schainName","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"internalType":"address[]","name":"contracts","type":"address[]"}],"name":"initializeAllRegisteredContracts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newGasLimit","type":"uint256"}],"name":"initializeMessageProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"isConnectedChain","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"schainHash","type":"bytes32"},{"internalType":"address","name":"contractAddress","type":"address"}],"name":"isContractRegistered","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keyStorage","outputs":[{"internalType":"contract IKeyStorage","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"messageInProgress","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"fromChainName","type":"string"},{"internalType":"uint256","name":"startingCounter","type":"uint256"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"destinationContract","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IMessageProxy.Message[]","name":"messages","type":"tuple[]"},{"components":[{"internalType":"uint256[2]","name":"blsSignature","type":"uint256[2]"},{"internalType":"uint256","name":"hashA","type":"uint256"},{"internalType":"uint256","name":"hashB","type":"uint256"},{"internalType":"uint256","name":"counter","type":"uint256"}],"internalType":"struct IMessageProxy.Signature","name":"signature","type":"tuple"}],"name":"postIncomingMessages","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"targetChainHash","type":"bytes32"},{"internalType":"address","name":"targetContract","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"postOutgoingMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"chainName","type":"string"},{"internalType":"address","name":"extraContract","type":"address"}],"name":"registerExtraContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"extraContract","type":"address"}],"name":"registerExtraContractForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"chainName","type":"string"}],"name":"removeConnectedChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"chainName","type":"string"},{"internalType":"address","name":"extraContract","type":"address"}],"name":"removeExtraContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"extraContract","type":"address"}],"name":"removeExtraContractForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"schainHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newGasLimit","type":"uint256"}],"name":"setNewGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newVersion","type":"string"}],"name":"setVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"dstChainHash","type":"bytes32"},{"internalType":"uint256","name":"msgCounter","type":"uint256"},{"internalType":"address","name":"srcContract","type":"address"},{"internalType":"address","name":"dstContract","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IMessageProxyForSchain.OutgoingMessageData","name":"message","type":"tuple"}],"name":"verifyOutgoingMessageData","outputs":[{"internalType":"bool","name":"isValidMessage","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hashedMessage","type":"bytes32"},{"components":[{"internalType":"uint256[2]","name":"blsSignature","type":"uint256[2]"},{"internalType":"uint256","name":"hashA","type":"uint256"},{"internalType":"uint256","name":"hashB","type":"uint256"},{"internalType":"uint256","name":"counter","type":"uint256"}],"internalType":"struct IMessageProxy.Signature","name":"signature","type":"tuple"}],"name":"verifySignature","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}],"message_proxy_chain_address":"0xd2AAa00100000000000000000000000000000000","proxy_admin_abi":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"contract TransparentUpgradeableProxy","name":"proxy","type":"address"},{"internalType":"address","name":"newAdmin","type":"address"}],"name":"changeProxyAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract TransparentUpgradeableProxy","name":"proxy","type":"address"}],"name":"getProxyAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract TransparentUpgradeableProxy","name":"proxy","type":"address"}],"name":"getProxyImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract TransparentUpgradeableProxy","name":"proxy","type":"address"},{"internalType":"address","name":"implementation","type":"address"}],"name":"upgrade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract TransparentUpgradeableProxy","name":"proxy","type":"address"},{"internalType":"address","name":"implementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeAndCall","outputs":[],"stateMutability":"payable","type":"function"}],"proxy_admin_address":"0xd2aAa00000000000000000000000000000000000","token_manager_erc1155_abi":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldValue","type":"address"},{"indexed":false,"internalType":"address","name":"newValue","type":"address"}],"name":"DepositBoxWasChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"erc1155OnMainnet","type":"address"},{"indexed":true,"internalType":"address","name":"erc1155OnSchain","type":"address"}],"name":"ERC1155TokenAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"erc1155OnMainnet","type":"address"},{"indexed":true,"internalType":"address","name":"erc1155OnSchain","type":"address"}],"name":"ERC1155TokenCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"contractOnMainnet","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"ERC1155TokenReady","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"erc1155OnMainnet","type":"address"},{"indexed":true,"internalType":"address","name":"erc1155OnSchain","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"ERC1155TokenReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"AUTOMATIC_DEPLOY_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN_REGISTRAR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"targetChainName","type":"string"},{"internalType":"address","name":"erc1155OnMainnet","type":"address"},{"internalType":"address","name":"erc1155OnSchain","type":"address"}],"name":"addERC1155TokenByOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"},{"internalType":"address","name":"newTokenManager","type":"address"}],"name":"addTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC1155OnChain","name":"","type":"address"}],"name":"addedClones","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"automaticDeploy","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"changeDepositBoxAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"}],"name":"clonesErc1155","outputs":[{"internalType":"contract ERC1155OnChain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"communityLocker","outputs":[{"internalType":"contract ICommunityLocker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositBox","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"deprecatedClonesErc1155","outputs":[{"internalType":"contract ERC1155OnChain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disableAutomaticDeploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enableAutomaticDeploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractOnMainnet","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"exitToMainERC1155","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractOnMainnet","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"exitToMainERC1155Batch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"hasTokenManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"newChainName","type":"string"},{"internalType":"contract IMessageProxyForSchain","name":"newMessageProxy","type":"address"},{"internalType":"contract ITokenManagerLinker","name":"newIMALinker","type":"address"},{"internalType":"contract ICommunityLocker","name":"newCommunityLocker","type":"address"},{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"contracts","type":"address[]"}],"name":"initializeAllClonesERC1155","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newSchainName","type":"string"},{"internalType":"contract IMessageProxyForSchain","name":"newMessageProxy","type":"address"},{"internalType":"contract ITokenManagerLinker","name":"newIMALinker","type":"address"},{"internalType":"contract ICommunityLocker","name":"newCommunityLocker","type":"address"},{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"initializeTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"messageProxy","outputs":[{"internalType":"contract IMessageProxyForSchain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"fromChainHash","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"postMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"removeTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"schainHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenManagerLinker","outputs":[{"internalType":"contract ITokenManagerLinker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"tokenManagers","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"targetSchainName","type":"string"},{"internalType":"address","name":"contractOnMainnet","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferToSchainERC1155","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"targetSchainName","type":"string"},{"internalType":"address","name":"contractOnMainnet","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"transferToSchainERC1155Batch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transferredAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}],"token_manager_erc1155_address":"0xD2aaA00900000000000000000000000000000000","token_manager_erc20_abi":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldValue","type":"address"},{"indexed":false,"internalType":"address","name":"newValue","type":"address"}],"name":"DepositBoxWasChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"erc20OnMainChain","type":"address"},{"indexed":true,"internalType":"address","name":"erc20OnSchain","type":"address"}],"name":"ERC20TokenAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"erc20OnMainChain","type":"address"},{"indexed":true,"internalType":"address","name":"erc20OnSchain","type":"address"}],"name":"ERC20TokenCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"contractOnMainnet","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ERC20TokenReady","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"erc20OnMainChain","type":"address"},{"indexed":true,"internalType":"address","name":"erc20OnSchain","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ERC20TokenReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"AUTOMATIC_DEPLOY_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN_REGISTRAR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"targetChainName","type":"string"},{"internalType":"address","name":"erc20OnMainChain","type":"address"},{"internalType":"address","name":"erc20OnSchain","type":"address"}],"name":"addERC20TokenByOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"},{"internalType":"address","name":"newTokenManager","type":"address"}],"name":"addTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20OnChain","name":"","type":"address"}],"name":"addedClones","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"automaticDeploy","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"changeDepositBoxAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"}],"name":"clonesErc20","outputs":[{"internalType":"contract ERC20OnChain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"communityLocker","outputs":[{"internalType":"contract ICommunityLocker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositBox","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"deprecatedClonesErc20","outputs":[{"internalType":"contract ERC20OnChain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disableAutomaticDeploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enableAutomaticDeploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractOnMainnet","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"exitToMainERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"hasTokenManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"newChainName","type":"string"},{"internalType":"contract IMessageProxyForSchain","name":"newMessageProxy","type":"address"},{"internalType":"contract ITokenManagerLinker","name":"newIMALinker","type":"address"},{"internalType":"contract ICommunityLocker","name":"newCommunityLocker","type":"address"},{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"contracts","type":"address[]"}],"name":"initializeAllClonesERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newSchainName","type":"string"},{"internalType":"contract IMessageProxyForSchain","name":"newMessageProxy","type":"address"},{"internalType":"contract ITokenManagerLinker","name":"newIMALinker","type":"address"},{"internalType":"contract ICommunityLocker","name":"newCommunityLocker","type":"address"},{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"initializeTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"messageProxy","outputs":[{"internalType":"contract IMessageProxyForSchain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"fromChainHash","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"postMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"removeTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"schainHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenManagerLinker","outputs":[{"internalType":"contract ITokenManagerLinker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"tokenManagers","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20Upgradeable","name":"","type":"address"}],"name":"totalSupplyOnMainnet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"targetSchainName","type":"string"},{"internalType":"address","name":"contractOnMainnet","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferToSchainERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"}],"name":"transferredAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}],"token_manager_erc20_address":"0xD2aAA00500000000000000000000000000000000","token_manager_erc721_abi":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldValue","type":"address"},{"indexed":false,"internalType":"address","name":"newValue","type":"address"}],"name":"DepositBoxWasChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"erc721OnMainChain","type":"address"},{"indexed":true,"internalType":"address","name":"erc721OnSchain","type":"address"}],"name":"ERC721TokenAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"erc721OnMainChain","type":"address"},{"indexed":true,"internalType":"address","name":"erc721OnSchain","type":"address"}],"name":"ERC721TokenCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"contractOnMainnet","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721TokenReady","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"erc721OnMainChain","type":"address"},{"indexed":true,"internalType":"address","name":"erc721OnSchain","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721TokenReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"AUTOMATIC_DEPLOY_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN_REGISTRAR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"targetChainName","type":"string"},{"internalType":"address","name":"erc721OnMainChain","type":"address"},{"internalType":"address","name":"erc721OnSchain","type":"address"}],"name":"addERC721TokenByOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"},{"internalType":"address","name":"newTokenManager","type":"address"}],"name":"addTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC721OnChain","name":"","type":"address"}],"name":"addedClones","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"automaticDeploy","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"changeDepositBoxAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"}],"name":"clonesErc721","outputs":[{"internalType":"contract ERC721OnChain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"communityLocker","outputs":[{"internalType":"contract ICommunityLocker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositBox","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"deprecatedClonesErc721","outputs":[{"internalType":"contract ERC721OnChain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disableAutomaticDeploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enableAutomaticDeploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractOnMainnet","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"exitToMainERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"hasTokenManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"newChainName","type":"string"},{"internalType":"contract IMessageProxyForSchain","name":"newMessageProxy","type":"address"},{"internalType":"contract ITokenManagerLinker","name":"newIMALinker","type":"address"},{"internalType":"contract ICommunityLocker","name":"newCommunityLocker","type":"address"},{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"contracts","type":"address[]"}],"name":"initializeAllClonesERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newSchainName","type":"string"},{"internalType":"contract IMessageProxyForSchain","name":"newMessageProxy","type":"address"},{"internalType":"contract ITokenManagerLinker","name":"newIMALinker","type":"address"},{"internalType":"contract ICommunityLocker","name":"newCommunityLocker","type":"address"},{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"initializeTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"messageProxy","outputs":[{"internalType":"contract IMessageProxyForSchain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"fromChainHash","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"postMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"removeTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"schainHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenManagerLinker","outputs":[{"internalType":"contract ITokenManagerLinker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"tokenManagers","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"targetSchainName","type":"string"},{"internalType":"address","name":"contractOnMainnet","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferToSchainERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transferredAmount","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"}],"token_manager_erc721_address":"0xD2aaa00600000000000000000000000000000000","token_manager_erc721_with_metadata_abi":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldValue","type":"address"},{"indexed":false,"internalType":"address","name":"newValue","type":"address"}],"name":"DepositBoxWasChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"erc721OnMainChain","type":"address"},{"indexed":true,"internalType":"address","name":"erc721OnSchain","type":"address"}],"name":"ERC721TokenAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"erc721OnMainChain","type":"address"},{"indexed":true,"internalType":"address","name":"erc721OnSchain","type":"address"}],"name":"ERC721TokenCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"contractOnMainnet","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721TokenReady","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"erc721OnMainChain","type":"address"},{"indexed":true,"internalType":"address","name":"erc721OnSchain","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721TokenReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"AUTOMATIC_DEPLOY_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN_REGISTRAR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"targetChainName","type":"string"},{"internalType":"address","name":"erc721OnMainChain","type":"address"},{"internalType":"address","name":"erc721OnSchain","type":"address"}],"name":"addERC721TokenByOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"},{"internalType":"address","name":"newTokenManager","type":"address"}],"name":"addTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC721OnChain","name":"","type":"address"}],"name":"addedClones","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"automaticDeploy","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"changeDepositBoxAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"}],"name":"clonesErc721","outputs":[{"internalType":"contract ERC721OnChain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"communityLocker","outputs":[{"internalType":"contract ICommunityLocker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositBox","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"deprecatedClonesErc721","outputs":[{"internalType":"contract ERC721OnChain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disableAutomaticDeploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enableAutomaticDeploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractOnMainnet","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"exitToMainERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"hasTokenManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"newChainName","type":"string"},{"internalType":"contract IMessageProxyForSchain","name":"newMessageProxy","type":"address"},{"internalType":"contract ITokenManagerLinker","name":"newIMALinker","type":"address"},{"internalType":"contract ICommunityLocker","name":"newCommunityLocker","type":"address"},{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"contracts","type":"address[]"}],"name":"initializeAllClonesERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newSchainName","type":"string"},{"internalType":"contract IMessageProxyForSchain","name":"newMessageProxy","type":"address"},{"internalType":"contract ITokenManagerLinker","name":"newIMALinker","type":"address"},{"internalType":"contract ICommunityLocker","name":"newCommunityLocker","type":"address"},{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"initializeTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"messageProxy","outputs":[{"internalType":"contract IMessageProxyForSchain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"fromChainHash","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"postMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"removeTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"schainHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenManagerLinker","outputs":[{"internalType":"contract ITokenManagerLinker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"tokenManagers","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"targetSchainName","type":"string"},{"internalType":"address","name":"contractOnMainnet","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferToSchainERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transferredAmount","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"}],"token_manager_erc721_with_metadata_address":"0xd2AaA00a00000000000000000000000000000000","token_manager_eth_abi":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldValue","type":"address"},{"indexed":false,"internalType":"address","name":"newValue","type":"address"}],"name":"DepositBoxWasChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"AUTOMATIC_DEPLOY_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN_REGISTRAR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"},{"internalType":"address","name":"newTokenManager","type":"address"}],"name":"addTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"automaticDeploy","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"changeDepositBoxAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"communityLocker","outputs":[{"internalType":"contract ICommunityLocker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositBox","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disableAutomaticDeploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enableAutomaticDeploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ethErc20","outputs":[{"internalType":"contract IEthErc20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"exitToMain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"hasTokenManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"newChainName","type":"string"},{"internalType":"contract IMessageProxyForSchain","name":"newMessageProxy","type":"address"},{"internalType":"contract ITokenManagerLinker","name":"newIMALinker","type":"address"},{"internalType":"contract ICommunityLocker","name":"newCommunityLocker","type":"address"},{"internalType":"address","name":"newDepositBox","type":"address"},{"internalType":"contract IEthErc20","name":"ethErc20Address","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newSchainName","type":"string"},{"internalType":"contract IMessageProxyForSchain","name":"newMessageProxy","type":"address"},{"internalType":"contract ITokenManagerLinker","name":"newIMALinker","type":"address"},{"internalType":"contract ICommunityLocker","name":"newCommunityLocker","type":"address"},{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"initializeTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"messageProxy","outputs":[{"internalType":"contract IMessageProxyForSchain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"fromChainHash","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"postMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"removeTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"schainHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IEthErc20","name":"newEthErc20Address","type":"address"}],"name":"setEthErc20Address","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenManagerLinker","outputs":[{"internalType":"contract ITokenManagerLinker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"tokenManagers","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}],"token_manager_eth_address":"0xd2AaA00400000000000000000000000000000000","token_manager_linker_abi":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REGISTRAR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"connectSchain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"disconnectSchain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"hasSchain","outputs":[{"internalType":"bool","name":"connected","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ITokenManager","name":"tokenManager","type":"address"}],"name":"hasTokenManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IMessageProxyForSchain","name":"newMessageProxyAddress","type":"address"},{"internalType":"address","name":"linker","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"linkerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"messageProxy","outputs":[{"internalType":"contract IMessageProxyForSchain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ITokenManager","name":"newTokenManager","type":"address"}],"name":"registerTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ITokenManager","name":"tokenManagerAddress","type":"address"}],"name":"removeTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenManagers","outputs":[{"internalType":"contract ITokenManager","name":"","type":"address"}],"stateMutability":"view","type":"function"}],"token_manager_linker_address":"0xD2aAA00800000000000000000000000000000000"} \ No newline at end of file +{"ERC1155OnChain_abi":[{"inputs":[{"internalType":"string","name":"uri","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"burnBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"mintBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}],"ERC20OnChain_abi":[{"inputs":[{"internalType":"string","name":"contractName","type":"string"},{"internalType":"string","name":"contractSymbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}],"ERC721OnChain_abi":[{"inputs":[{"internalType":"string","name":"contractName","type":"string"},{"internalType":"string","name":"contractSymbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"tokenUri","type":"string"}],"name":"setTokenURI","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}],"community_locker_abi":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"schainHash","type":"bytes32"},{"indexed":false,"internalType":"address","name":"user","type":"address"}],"name":"ActivateUser","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"constantHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"previousValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"ConstantUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"schainHash","type":"bytes32"},{"indexed":false,"internalType":"address","name":"user","type":"address"}],"name":"LockUser","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"CONSTANT_SETTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"activeUsers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"checkAllowedToSendMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"communityPool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasPriceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"newSchainName","type":"string"},{"internalType":"contract IMessageProxyForSchain","name":"newMessageProxy","type":"address"},{"internalType":"contract ITokenManagerLinker","name":"newTokenManagerLinker","type":"address"},{"internalType":"address","name":"newCommunityPool","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastMessageTimeStamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mainnetGasPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"messageProxy","outputs":[{"internalType":"contract IMessageProxyForSchain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"fromChainHash","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"postMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"schainHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"components":[{"internalType":"uint256[2]","name":"blsSignature","type":"uint256[2]"},{"internalType":"uint256","name":"hashA","type":"uint256"},{"internalType":"uint256","name":"hashB","type":"uint256"},{"internalType":"uint256","name":"counter","type":"uint256"}],"internalType":"struct IMessageProxy.Signature","name":"","type":"tuple"}],"name":"setGasPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newTimeLimitPerMessage","type":"uint256"}],"name":"setTimeLimitPerMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"timeLimitPerMessage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenManagerLinker","outputs":[{"internalType":"contract ITokenManagerLinker","name":"","type":"address"}],"stateMutability":"view","type":"function"}],"community_locker_address":"0xD2aaa00300000000000000000000000000000000","eth_erc20_abi":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"BURNER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"forceBurn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenManagerEthAddress","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}],"eth_erc20_address":"0xD2Aaa00700000000000000000000000000000000","key_storage_abi":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FN_NUM_GET_CONFIG_VARIABLE_UINT256","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FN_NUM_GET_CURRENT_BLS_PUBLIC_KEY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FREE_MEM_PTR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBlsCommonPublicKey","outputs":[{"components":[{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"b","type":"uint256"}],"internalType":"struct IFieldOperations.Fp2Point","name":"x","type":"tuple"},{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"b","type":"uint256"}],"internalType":"struct IFieldOperations.Fp2Point","name":"y","type":"tuple"}],"internalType":"struct IFieldOperations.G2Point","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"key_storage_address":"0xd2aaa00200000000000000000000000000000000","message_proxy_chain_abi":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":false,"internalType":"address","name":"contractAddress","type":"address"}],"name":"ExtraContractRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":false,"internalType":"address","name":"contractAddress","type":"address"}],"name":"ExtraContractRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"GasLimitWasChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"dstChainHash","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"msgCounter","type":"uint256"},{"indexed":true,"internalType":"address","name":"srcContract","type":"address"},{"indexed":false,"internalType":"address","name":"dstContract","type":"address"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"OutgoingMessage","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"msgCounter","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"}],"name":"PostMessageError","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"oldVersion","type":"string"},{"indexed":false,"internalType":"string","name":"newVersion","type":"string"}],"name":"VersionUpdated","type":"event"},{"inputs":[],"name":"CHAIN_CONNECTOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CONSTANT_SETTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ETHERBASE","outputs":[{"internalType":"contract IEtherbaseUpgradeable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXTRA_CONTRACT_REGISTRAR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MESSAGES_LENGTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINIMUM_BALANCE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REVERT_REASON_LENGTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"chainName","type":"string"}],"name":"addConnectedChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"connectedChains","outputs":[{"internalType":"uint256","name":"incomingMessageCounter","type":"uint256"},{"internalType":"uint256","name":"outgoingMessageCounter","type":"uint256"},{"internalType":"bool","name":"inited","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"schainHash","type":"bytes32"}],"name":"getContractRegisteredLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"schainHash","type":"bytes32"},{"internalType":"uint256","name":"from","type":"uint256"},{"internalType":"uint256","name":"to","type":"uint256"}],"name":"getContractRegisteredRange","outputs":[{"internalType":"address[]","name":"contractsInRange","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"fromSchainName","type":"string"}],"name":"getIncomingMessagesCounter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"targetSchainName","type":"string"}],"name":"getOutgoingMessagesCounter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IKeyStorage","name":"blsKeyStorage","type":"address"},{"internalType":"string","name":"schainName","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"internalType":"address[]","name":"contracts","type":"address[]"}],"name":"initializeAllRegisteredContracts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newGasLimit","type":"uint256"}],"name":"initializeMessageProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"isConnectedChain","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"schainHash","type":"bytes32"},{"internalType":"address","name":"contractAddress","type":"address"}],"name":"isContractRegistered","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keyStorage","outputs":[{"internalType":"contract IKeyStorage","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"messageInProgress","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"fromChainName","type":"string"},{"internalType":"uint256","name":"startingCounter","type":"uint256"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"destinationContract","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IMessageProxy.Message[]","name":"messages","type":"tuple[]"},{"components":[{"internalType":"uint256[2]","name":"blsSignature","type":"uint256[2]"},{"internalType":"uint256","name":"hashA","type":"uint256"},{"internalType":"uint256","name":"hashB","type":"uint256"},{"internalType":"uint256","name":"counter","type":"uint256"}],"internalType":"struct IMessageProxy.Signature","name":"signature","type":"tuple"}],"name":"postIncomingMessages","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"targetChainHash","type":"bytes32"},{"internalType":"address","name":"targetContract","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"postOutgoingMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"chainName","type":"string"},{"internalType":"address","name":"extraContract","type":"address"}],"name":"registerExtraContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"extraContract","type":"address"}],"name":"registerExtraContractForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"chainName","type":"string"}],"name":"removeConnectedChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"chainName","type":"string"},{"internalType":"address","name":"extraContract","type":"address"}],"name":"removeExtraContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"extraContract","type":"address"}],"name":"removeExtraContractForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"schainHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newGasLimit","type":"uint256"}],"name":"setNewGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newVersion","type":"string"}],"name":"setVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"dstChainHash","type":"bytes32"},{"internalType":"uint256","name":"msgCounter","type":"uint256"},{"internalType":"address","name":"srcContract","type":"address"},{"internalType":"address","name":"dstContract","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IMessageProxyForSchain.OutgoingMessageData","name":"message","type":"tuple"}],"name":"verifyOutgoingMessageData","outputs":[{"internalType":"bool","name":"isValidMessage","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hashedMessage","type":"bytes32"},{"components":[{"internalType":"uint256[2]","name":"blsSignature","type":"uint256[2]"},{"internalType":"uint256","name":"hashA","type":"uint256"},{"internalType":"uint256","name":"hashB","type":"uint256"},{"internalType":"uint256","name":"counter","type":"uint256"}],"internalType":"struct IMessageProxy.Signature","name":"signature","type":"tuple"}],"name":"verifySignature","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}],"message_proxy_chain_address":"0xd2AAa00100000000000000000000000000000000","proxy_admin_abi":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"contract TransparentUpgradeableProxy","name":"proxy","type":"address"},{"internalType":"address","name":"newAdmin","type":"address"}],"name":"changeProxyAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract TransparentUpgradeableProxy","name":"proxy","type":"address"}],"name":"getProxyAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract TransparentUpgradeableProxy","name":"proxy","type":"address"}],"name":"getProxyImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract TransparentUpgradeableProxy","name":"proxy","type":"address"},{"internalType":"address","name":"implementation","type":"address"}],"name":"upgrade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract TransparentUpgradeableProxy","name":"proxy","type":"address"},{"internalType":"address","name":"implementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeAndCall","outputs":[],"stateMutability":"payable","type":"function"}],"proxy_admin_address":"0xd2aAa00000000000000000000000000000000000","token_manager_erc1155_abi":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldValue","type":"address"},{"indexed":false,"internalType":"address","name":"newValue","type":"address"}],"name":"DepositBoxWasChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"erc1155OnMainnet","type":"address"},{"indexed":true,"internalType":"address","name":"erc1155OnSchain","type":"address"}],"name":"ERC1155TokenAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"erc1155OnMainnet","type":"address"},{"indexed":true,"internalType":"address","name":"erc1155OnSchain","type":"address"}],"name":"ERC1155TokenCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"contractOnMainnet","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"ERC1155TokenReady","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"erc1155OnMainnet","type":"address"},{"indexed":true,"internalType":"address","name":"erc1155OnSchain","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"ERC1155TokenReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"AUTOMATIC_DEPLOY_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN_REGISTRAR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"targetChainAlias","type":"string"},{"internalType":"address","name":"erc1155OnMainnet","type":"address"},{"internalType":"address","name":"erc1155OnSchain","type":"address"}],"name":"addERC1155TokenByOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"},{"internalType":"address","name":"newTokenManager","type":"address"}],"name":"addTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC1155OnChain","name":"","type":"address"}],"name":"addedClones","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"automaticDeploy","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"changeDepositBoxAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"}],"name":"clonesErc1155","outputs":[{"internalType":"contract ERC1155OnChain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"communityLocker","outputs":[{"internalType":"contract ICommunityLocker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositBox","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"deprecatedClonesErc1155","outputs":[{"internalType":"contract ERC1155OnChain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disableAutomaticDeploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enableAutomaticDeploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractOnMainnet","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"exitToMainERC1155","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractOnMainnet","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"exitToMainERC1155Batch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"hasTokenManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"newChainName","type":"string"},{"internalType":"contract IMessageProxyForSchain","name":"newMessageProxy","type":"address"},{"internalType":"contract ITokenManagerLinker","name":"newIMALinker","type":"address"},{"internalType":"contract ICommunityLocker","name":"newCommunityLocker","type":"address"},{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"contracts","type":"address[]"}],"name":"initializeAllClonesERC1155","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newSchainName","type":"string"},{"internalType":"contract IMessageProxyForSchain","name":"newMessageProxy","type":"address"},{"internalType":"contract ITokenManagerLinker","name":"newIMALinker","type":"address"},{"internalType":"contract ICommunityLocker","name":"newCommunityLocker","type":"address"},{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"initializeTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"messageProxy","outputs":[{"internalType":"contract IMessageProxyForSchain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"fromChainHash","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"postMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"removeTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"schainHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenManagerLinker","outputs":[{"internalType":"contract ITokenManagerLinker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"tokenManagers","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"targetSchainName","type":"string"},{"internalType":"address","name":"contractOnMainnet","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferToSchainERC1155","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"targetSchainName","type":"string"},{"internalType":"address","name":"contractOnMainnet","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"transferToSchainERC1155Batch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transferredAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}],"token_manager_erc1155_address":"0xD2aaA00900000000000000000000000000000000","token_manager_erc20_abi":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldValue","type":"address"},{"indexed":false,"internalType":"address","name":"newValue","type":"address"}],"name":"DepositBoxWasChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"erc20OnMainChain","type":"address"},{"indexed":true,"internalType":"address","name":"erc20OnSchain","type":"address"}],"name":"ERC20TokenAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"erc20OnMainChain","type":"address"},{"indexed":true,"internalType":"address","name":"erc20OnSchain","type":"address"}],"name":"ERC20TokenCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"contractOnMainnet","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ERC20TokenReady","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"erc20OnMainChain","type":"address"},{"indexed":true,"internalType":"address","name":"erc20OnSchain","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ERC20TokenReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"AUTOMATIC_DEPLOY_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN_REGISTRAR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"targetChainAlias","type":"string"},{"internalType":"address","name":"erc20OnMainChain","type":"address"},{"internalType":"address","name":"erc20OnSchain","type":"address"}],"name":"addERC20TokenByOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"},{"internalType":"address","name":"newTokenManager","type":"address"}],"name":"addTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20OnChain","name":"","type":"address"}],"name":"addedClones","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"automaticDeploy","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"changeDepositBoxAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"}],"name":"clonesErc20","outputs":[{"internalType":"contract ERC20OnChain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"communityLocker","outputs":[{"internalType":"contract ICommunityLocker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositBox","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"deprecatedClonesErc20","outputs":[{"internalType":"contract ERC20OnChain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disableAutomaticDeploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enableAutomaticDeploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractOnMainnet","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"exitToMainERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"hasTokenManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"newChainName","type":"string"},{"internalType":"contract IMessageProxyForSchain","name":"newMessageProxy","type":"address"},{"internalType":"contract ITokenManagerLinker","name":"newIMALinker","type":"address"},{"internalType":"contract ICommunityLocker","name":"newCommunityLocker","type":"address"},{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"contracts","type":"address[]"}],"name":"initializeAllClonesERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newSchainName","type":"string"},{"internalType":"contract IMessageProxyForSchain","name":"newMessageProxy","type":"address"},{"internalType":"contract ITokenManagerLinker","name":"newIMALinker","type":"address"},{"internalType":"contract ICommunityLocker","name":"newCommunityLocker","type":"address"},{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"initializeTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"messageProxy","outputs":[{"internalType":"contract IMessageProxyForSchain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"fromChainHash","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"postMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"removeTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"schainHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenManagerLinker","outputs":[{"internalType":"contract ITokenManagerLinker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"tokenManagers","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20Upgradeable","name":"","type":"address"}],"name":"totalSupplyOnMainnet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"targetSchainName","type":"string"},{"internalType":"address","name":"contractOnMainnet","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferToSchainERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"}],"name":"transferredAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}],"token_manager_erc20_address":"0xD2aAA00500000000000000000000000000000000","token_manager_erc721_abi":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldValue","type":"address"},{"indexed":false,"internalType":"address","name":"newValue","type":"address"}],"name":"DepositBoxWasChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"erc721OnMainChain","type":"address"},{"indexed":true,"internalType":"address","name":"erc721OnSchain","type":"address"}],"name":"ERC721TokenAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"erc721OnMainChain","type":"address"},{"indexed":true,"internalType":"address","name":"erc721OnSchain","type":"address"}],"name":"ERC721TokenCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"contractOnMainnet","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721TokenReady","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"erc721OnMainChain","type":"address"},{"indexed":true,"internalType":"address","name":"erc721OnSchain","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721TokenReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"AUTOMATIC_DEPLOY_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN_REGISTRAR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"targetChainAlias","type":"string"},{"internalType":"address","name":"erc721OnMainChain","type":"address"},{"internalType":"address","name":"erc721OnSchain","type":"address"}],"name":"addERC721TokenByOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"},{"internalType":"address","name":"newTokenManager","type":"address"}],"name":"addTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC721OnChain","name":"","type":"address"}],"name":"addedClones","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"automaticDeploy","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"changeDepositBoxAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"}],"name":"clonesErc721","outputs":[{"internalType":"contract ERC721OnChain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"communityLocker","outputs":[{"internalType":"contract ICommunityLocker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositBox","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"deprecatedClonesErc721","outputs":[{"internalType":"contract ERC721OnChain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disableAutomaticDeploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enableAutomaticDeploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractOnMainnet","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"exitToMainERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"hasTokenManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"newChainName","type":"string"},{"internalType":"contract IMessageProxyForSchain","name":"newMessageProxy","type":"address"},{"internalType":"contract ITokenManagerLinker","name":"newIMALinker","type":"address"},{"internalType":"contract ICommunityLocker","name":"newCommunityLocker","type":"address"},{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"contracts","type":"address[]"}],"name":"initializeAllClonesERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newSchainName","type":"string"},{"internalType":"contract IMessageProxyForSchain","name":"newMessageProxy","type":"address"},{"internalType":"contract ITokenManagerLinker","name":"newIMALinker","type":"address"},{"internalType":"contract ICommunityLocker","name":"newCommunityLocker","type":"address"},{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"initializeTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"messageProxy","outputs":[{"internalType":"contract IMessageProxyForSchain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"fromChainHash","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"postMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"removeTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"schainHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenManagerLinker","outputs":[{"internalType":"contract ITokenManagerLinker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"tokenManagers","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"targetSchainName","type":"string"},{"internalType":"address","name":"contractOnMainnet","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferToSchainERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transferredAmount","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"}],"token_manager_erc721_address":"0xD2aaa00600000000000000000000000000000000","token_manager_erc721_with_metadata_abi":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldValue","type":"address"},{"indexed":false,"internalType":"address","name":"newValue","type":"address"}],"name":"DepositBoxWasChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"erc721OnMainChain","type":"address"},{"indexed":true,"internalType":"address","name":"erc721OnSchain","type":"address"}],"name":"ERC721TokenAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"erc721OnMainChain","type":"address"},{"indexed":true,"internalType":"address","name":"erc721OnSchain","type":"address"}],"name":"ERC721TokenCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"contractOnMainnet","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721TokenReady","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"chainHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"erc721OnMainChain","type":"address"},{"indexed":true,"internalType":"address","name":"erc721OnSchain","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721TokenReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"AUTOMATIC_DEPLOY_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN_REGISTRAR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"targetChainAlias","type":"string"},{"internalType":"address","name":"erc721OnMainChain","type":"address"},{"internalType":"address","name":"erc721OnSchain","type":"address"}],"name":"addERC721TokenByOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"},{"internalType":"address","name":"newTokenManager","type":"address"}],"name":"addTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC721OnChain","name":"","type":"address"}],"name":"addedClones","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"automaticDeploy","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"changeDepositBoxAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"}],"name":"clonesErc721","outputs":[{"internalType":"contract ERC721OnChain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"communityLocker","outputs":[{"internalType":"contract ICommunityLocker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositBox","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"deprecatedClonesErc721","outputs":[{"internalType":"contract ERC721OnChain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disableAutomaticDeploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enableAutomaticDeploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractOnMainnet","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"exitToMainERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"hasTokenManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"newChainName","type":"string"},{"internalType":"contract IMessageProxyForSchain","name":"newMessageProxy","type":"address"},{"internalType":"contract ITokenManagerLinker","name":"newIMALinker","type":"address"},{"internalType":"contract ICommunityLocker","name":"newCommunityLocker","type":"address"},{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"contracts","type":"address[]"}],"name":"initializeAllClonesERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newSchainName","type":"string"},{"internalType":"contract IMessageProxyForSchain","name":"newMessageProxy","type":"address"},{"internalType":"contract ITokenManagerLinker","name":"newIMALinker","type":"address"},{"internalType":"contract ICommunityLocker","name":"newCommunityLocker","type":"address"},{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"initializeTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"messageProxy","outputs":[{"internalType":"contract IMessageProxyForSchain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"fromChainHash","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"postMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"removeTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"schainHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenManagerLinker","outputs":[{"internalType":"contract ITokenManagerLinker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"tokenManagers","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"targetSchainName","type":"string"},{"internalType":"address","name":"contractOnMainnet","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferToSchainERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transferredAmount","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"}],"token_manager_erc721_with_metadata_address":"0xd2AaA00a00000000000000000000000000000000","token_manager_eth_abi":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldValue","type":"address"},{"indexed":false,"internalType":"address","name":"newValue","type":"address"}],"name":"DepositBoxWasChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"AUTOMATIC_DEPLOY_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN_REGISTRAR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"},{"internalType":"address","name":"newTokenManager","type":"address"}],"name":"addTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"automaticDeploy","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"changeDepositBoxAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"communityLocker","outputs":[{"internalType":"contract ICommunityLocker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositBox","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disableAutomaticDeploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enableAutomaticDeploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ethErc20","outputs":[{"internalType":"contract IEthErc20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"exitToMain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"hasTokenManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"newChainName","type":"string"},{"internalType":"contract IMessageProxyForSchain","name":"newMessageProxy","type":"address"},{"internalType":"contract ITokenManagerLinker","name":"newIMALinker","type":"address"},{"internalType":"contract ICommunityLocker","name":"newCommunityLocker","type":"address"},{"internalType":"address","name":"newDepositBox","type":"address"},{"internalType":"contract IEthErc20","name":"ethErc20Address","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newSchainName","type":"string"},{"internalType":"contract IMessageProxyForSchain","name":"newMessageProxy","type":"address"},{"internalType":"contract ITokenManagerLinker","name":"newIMALinker","type":"address"},{"internalType":"contract ICommunityLocker","name":"newCommunityLocker","type":"address"},{"internalType":"address","name":"newDepositBox","type":"address"}],"name":"initializeTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"messageProxy","outputs":[{"internalType":"contract IMessageProxyForSchain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"fromChainHash","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"postMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"removeTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"schainHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IEthErc20","name":"newEthErc20Address","type":"address"}],"name":"setEthErc20Address","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenManagerLinker","outputs":[{"internalType":"contract ITokenManagerLinker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"tokenManagers","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}],"token_manager_eth_address":"0xd2AaA00400000000000000000000000000000000","token_manager_linker_abi":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINNET_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REGISTRAR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"connectSchain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"disconnectSchain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"schainName","type":"string"}],"name":"hasSchain","outputs":[{"internalType":"bool","name":"connected","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ITokenManager","name":"tokenManager","type":"address"}],"name":"hasTokenManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IMessageProxyForSchain","name":"newMessageProxyAddress","type":"address"},{"internalType":"address","name":"linker","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"linkerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"messageProxy","outputs":[{"internalType":"contract IMessageProxyForSchain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ITokenManager","name":"newTokenManager","type":"address"}],"name":"registerTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ITokenManager","name":"tokenManagerAddress","type":"address"}],"name":"removeTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenManagers","outputs":[{"internalType":"contract ITokenManager","name":"","type":"address"}],"stateMutability":"view","type":"function"}],"token_manager_linker_address":"0xD2aAA00800000000000000000000000000000000"} \ No newline at end of file diff --git a/src/store/MetaportState.ts b/src/store/MetaportState.ts new file mode 100644 index 0000000..a2bbc3a --- /dev/null +++ b/src/store/MetaportState.ts @@ -0,0 +1,326 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/** + * @file MetaportState.ts + * @copyright SKALE Labs 2023-Present + */ + +import debug from 'debug'; + +import { MainnetChain, SChain } from '@skalenetwork/ima-js' +import { create } from 'zustand' + +import MetaportCore from '../core/metaport' +import * as interfaces from '../core/interfaces'; +import * as dataclasses from '../core/dataclasses'; +import { getEmptyTokenDataMap } from '../core/tokens/helper'; +import { MAINNET_CHAIN_NAME, DEFAULT_ERROR_MSG } from '../core/constants'; +import { getStepsMetadata } from '../core/transfer_steps'; +import { ACTIONS } from '../core/actions'; +import { WalletClient } from 'viem'; + + +debug.enable('*'); +const log = debug('metaport:state'); + + +interface MetaportState { + mainnetChain: MainnetChain + setMainnetChain: (mainnet: MainnetChain) => void + sChain1: SChain + setSChain1: (schain: SChain) => void + sChain2: SChain + setSChain2: (schain: SChain) => void + + mpc: MetaportCore, + setMpc: (mpc: MetaportCore) => void + + amount: string + setAmount: (amount: string, address: `0x${string}`) => void + + tokenId: number + setTokenId: (tokenId: number) => void + + execute: ( + address: string, + switchNetwork: (chainId: number) => void, + walletClient: WalletClient + ) => void + check: (amount: string, address: `0x${string}`) => void + + currentStep: number + setCurrentStep: (currentStep: number) => void + + stepsMetadata: dataclasses.StepMetadata[] + setStepsMetadata: (steps: dataclasses.StepMetadata[]) => void + + chainName1: string, + chainName2: string, + + setChainName1: (name: string) => void + setChainName2: (name: string) => void + + tokens: interfaces.TokenDataTypesMap + + token: dataclasses.TokenData + setToken: (token: dataclasses.TokenData) => void + + tokenContracts: interfaces.TokenContractsMap + tokenBalances: interfaces.TokenBalancesMap + updateTokenBalances: (address: string) => Promise + + amountErrorMessage: string + setAmountErrorMessage: (amountErrorMessage: string) => void + + errorMessage: dataclasses.ErrorMessage + setErrorMessage: (amountErrorMessage: dataclasses.ErrorMessage) => void + + actionBtnDisabled: boolean + setActionBtnDisabled: (actionBtnDisabled: boolean) => void + + loading: boolean + setLoading: (loading: boolean) => void + + transferInProgress: boolean + setTransferInProgress: (loading: boolean) => void + + btnText: string + setBtnText: (btnText: string) => void + + errorMessageClosedFallback: () => void + startOver: () => void +} + + +export const useMetaportStore = create()((set, get) => ({ + mainnetChain: null, + setMainnetChain: (mainnet: MainnetChain) => set(() => ({ mainnetChain: mainnet })), + + sChain1: null, + setSChain1: (schain: SChain) => set(() => ({ sChain1: schain })), + + sChain2: null, + setSChain2: (schain: SChain) => set(() => ({ sChain2: schain })), + + mpc: null, + setMpc: (mpc: MetaportCore) => set(() => ({ mpc: mpc })), + + tokenId: null, + setTokenId: (tokenId: number) => set(() => { + return { + tokenId: tokenId + } + }), + + amount: '', + setAmount: (amount: string, address: `0x${string}`) => set((state) => { + state.check(amount, address); + return { + amount: amount + } + }), + + + execute: async (address: string, switchNetwork: any, walletClient: WalletClient) => { + log('Running execute'); + if (get().stepsMetadata[get().currentStep]) { + set({ + loading: true, + transferInProgress: true + }) + try { + const stepMetadata = get().stepsMetadata[get().currentStep]; + const actionClass = ACTIONS[stepMetadata.type]; + await new actionClass( + get().mpc, + stepMetadata.from, + stepMetadata.to, + address, + get().amount, + get().tokenId, + get().token, + get().setAmountErrorMessage, + get().setBtnText, + switchNetwork, + walletClient + ).execute(); + } catch (err) { + console.error(err); + const msg = err.message ? err.message : DEFAULT_ERROR_MSG; + set({ + errorMessage: new dataclasses.TransactionErrorMessage( + msg, + get().errorMessageClosedFallback + ) + }); + return; + } finally { + set({ loading: false }); + } + set({ + transferInProgress: get().currentStep + 1 !== get().stepsMetadata.length, + currentStep: get().currentStep + 1, + + }); + } + }, + + errorMessageClosedFallback() { + set({ + loading: false, + errorMessage: undefined, + transferInProgress: get().currentStep !== 0 + }); + }, + + startOver() { + set({ + loading: false, + errorMessage: undefined, + amount: '', + tokenId: null, + currentStep: 0, + transferInProgress: false + }); + }, + + check: async (amount: string, address: string) => { + if (get().stepsMetadata[get().currentStep]) { + set({ + 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(); + // console.log(); + // console.log('going to check amount!!!'); + } + set({ loading: false }); + }, + + currentStep: 0, + setCurrentStep: (currentStep: number) => set(() => ({ currentStep: currentStep })), + + stepsMetadata: [], + setStepsMetadata: (steps: dataclasses.StepMetadata[]) => set(() => ({ stepsMetadata: steps })), + + chainName1: '', + chainName2: '', + + setChainName1: (name: string) => set((state) => { + // updateState( + // name, + // state.chainName2 + // ) + + const updState = {}; + if (name === MAINNET_CHAIN_NAME) { + updState['mainnetChain'] = state.mpc.mainnet(); + } else { + updState['sChain1'] = state.mpc.schain(name); + } + const provider = updState['mainnetChain'] ? updState['mainnetChain'].provider : updState['sChain1'].provider; + const tokens = state.mpc.tokens(name); + const tokenContracts = state.mpc.tokenContracts( + tokens, + dataclasses.TokenType.erc20, + name, + provider + ); + return { + currentStep: 0, + token: null, + chainName1: name, + tokens: tokens, + tokenContracts: tokenContracts, + ...updState + } + }), + setChainName2: (name: string) => set((state) => { + const updState = {}; + if (name === MAINNET_CHAIN_NAME) { + updState['mainnetChain'] = state.mpc.mainnet(); + } else { + updState['sChain2'] = state.mpc.schain(name); + } + return { + currentStep: 0, + token: null, + chainName2: name, + tokens: state.mpc.tokens(state.chainName1, name), + stepsMetadata: getStepsMetadata( + get().mpc.config, + get().token, + name + ), + ...updState + } + }), + + tokens: getEmptyTokenDataMap(), + + token: null, + setToken: (token: dataclasses.TokenData) => set(() => ({ + token: token, + stepsMetadata: getStepsMetadata( + get().mpc.config, + token, + get().chainName2 + ) + })), + + tokenContracts: {}, + tokenBalances: {}, + + updateTokenBalances: async (address: string) => { + const tokenBalances = await get().mpc.tokenBalances(get().tokenContracts, address); + set({ tokenBalances: tokenBalances }); + }, + + amountErrorMessage: null, + setAmountErrorMessage: (em: string) => set(() => ({ amountErrorMessage: em })), + + errorMessage: null, + setErrorMessage: (em: dataclasses.ErrorMessage) => set(() => ({ errorMessage: em })), + + actionBtnDisabled: false, + setActionBtnDisabled: (disabled: boolean) => set(() => ({ actionBtnDisabled: disabled })), + + loading: false, + setLoading: (loading: boolean) => set(() => ({ loading: loading })), + + transferInProgress: false, + setTransferInProgress: (inProgress: boolean) => set(() => ({ transferInProgress: inProgress })), + + btnText: null, + setBtnText: (btnText: string) => set(() => ({ btnText: btnText })) +})); diff --git a/src/store/Store.ts b/src/store/Store.ts new file mode 100644 index 0000000..59e4aa2 --- /dev/null +++ b/src/store/Store.ts @@ -0,0 +1,75 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/** + * @file Store.ts + * @copyright SKALE Labs 2023-Present + */ + +import { create } from 'zustand' + +import * as interfaces from '../core/interfaces'; + +interface UIState { + theme: interfaces.MetaportTheme + setTheme: (theme: interfaces.MetaportTheme) => void + open: boolean, + setOpen: (isOpen: boolean) => void +} + + +export const useUIStore = create()((set) => ({ + theme: null, + setTheme: (theme: interfaces.MetaportTheme) => set(() => ({ theme: theme })), + open: false, + setOpen: (isOpen: boolean) => set(() => ({ open: isOpen })), +})); + + +interface CollapseState { + expandedFrom: string | false, + setExpandedFrom: (expanded: string | false) => void, + expandedTo: string | false, + setExpandedTo: (expanded: string | false) => void + + expandedTokens: string | false, + setExpandedTokens: (expanded: string | false) => void +} + + +export const useCollapseStore = create()((set) => ({ + expandedFrom: false, + setExpandedFrom: (expanded: string | false) => set(() => ({ + expandedFrom: expanded, + expandedTo: false, + expandedTokens: false + })), + expandedTo: false, + setExpandedTo: (expanded: string | false) => set(() => ({ + expandedTo: expanded, + expandedFrom: false, + expandedTokens: false + })), + expandedTokens: false, + setExpandedTokens: (expanded: string | false) => set(() => ({ + expandedTokens: expanded, + expandedFrom: false, + expandedTo: false + })) +})); + diff --git a/src/styles/_variables.scss b/src/styles/_variables.scss new file mode 100644 index 0000000..24f2eb1 --- /dev/null +++ b/src/styles/_variables.scss @@ -0,0 +1,14 @@ +$sk-border-radius-outter: 30px; +$sk-border-radius: 25px; + +$sk-paper-color: rgb(136 135 135 / 15%); +$sk-gray-background-color: rgba(161, 161, 161, 0.2); + + +$sk-btn-height: 47px; + +$sk-disabled-dark: rgba(255, 255, 255, 0.5); +$sk-disabled-light: rgba(0, 0, 0, 0.38); + +$sk-secondary-dark: rgb(255 255 255 / 65%); +$sk-secondary-light: rgb(0 0 0 / 65%); \ No newline at end of file diff --git a/src/styles/common.scss b/src/styles/common.scss new file mode 100644 index 0000000..e01c124 --- /dev/null +++ b/src/styles/common.scss @@ -0,0 +1,233 @@ +@import './variables'; + +.flex { + display: flex; + vertical-align: middle; +} + +.flexRight { + justify-content: end; +} + +.flexCentered { + align-items: center; + justify-content: center; +} + +.flexCenteredVert { + align-items: center; +} + +.flexGrow { + flex-grow: 1; +} + +.flexRow { + flex-direction: row; + flex-wrap: wrap; +} + +.marg10 { + margin: 10px !important; +} + +.padd10 { + padding: 10px !important; +} + + +.margTop10 { + margin-top: 10px !important; +} + +.margTop20 { + margin-top: 20px !important; +} + +.margTop40 { + margin-top: 40px !important; +} + + +.margLeft5 { + margin-left: 5px !important; +} + +.margLeft10 { + margin-left: 10px !important; +} + +.margLeft20 { + margin-left: 20px !important; +} + +.margRi20 { + margin-right: 20px !important; +} + +.margRi10 { + margin-right: 10px !important; +} + +.margRi5 { + margin-right: 5px !important; +} + +.margBottMin10 { + margin-bottom: -10px !important; +} + +.margBottMin15 { + margin-bottom: -15px !important; +} + +.marg-top-20 { + margin-top: 20px !important; +} + +.margTop20Pt { + margin-top: 20pt !important; +} + +.marg-top-30 { + margin-top: 30px !important; +} + +.margBott20 { + margin-bottom: 20px !important; +} + +.margBott40 { + margin-bottom: 40px !important; +} + +.margBott15 { + margin-bottom: 15px !important; +} + +.margBott10 { + margin-bottom: 10px !important; +} + +.marg-bott-40 { + margin-bottom: 40px !important; +} + +.margBott5 { + margin-bottom: 5px !important; +} + +.margTop5 { + margin-top: 5px !important; +} + +.noMargTop { + margin-top: 0 !important; +} + +.noMargBott { + margin-bottom: 0 !important; +} + +.noMarg { + margin: 0 !important; +} + +.paddTop10 { + padding-top: 10px !important; +} + +.paddBott10 { + padding-bottom: 10px !important; +} + +.noPadd { + padding: 0 !important; +} + +.capitalize { + text-transform: capitalize !important; +} + +// fonts + + +.p { + margin: 0; + text-transform: none; + line-height: 1.6 !important; + font-weight: 500; +} + +.p500 { + font-weight: 500 !important; +} + +.p600 { + font-weight: 600 !important; +} + +.uppercase { + text-transform: uppercase !important; +} + +.p1 { + font-size: 1.3rem !important; + letter-spacing: 0.03857em !important; +} + +.p2 { + font-size: 0.9025rem !important; + letter-spacing: 0.03857em !important; +} + +.p3 { + font-size: 0.8025rem !important; + letter-spacing: 0.02857em !important; +} + +.p4 { + font-size: 0.7025rem !important; + letter-spacing: 0.04857em !important; +} + +.darkTheme { + .pMain { + color: white !important; + } + + .pSecondary { + color: $sk-secondary-dark !important; + } + + .pDisabled { + color: $sk-disabled-dark !important; + } +} + +.lightTheme { + .pMain { + color: black !important; + } + + .pSecondary { + color: $sk-secondary-light !important; + } + + .pDisabled { + color: $sk-disabled-light !important; + } +} + +.fullWidth { + width: 100% !important; +} + +.textCentered { + text-align: center; +} + + +:global([rk-chain-button]) { + display: none !important; +} \ No newline at end of file diff --git a/src/styles/styles.scss b/src/styles/styles.scss new file mode 100644 index 0000000..f949f04 --- /dev/null +++ b/src/styles/styles.scss @@ -0,0 +1,262 @@ +@import './variables'; + +.paper { + padding: 10px; + border-radius: $sk-border-radius; +} + +.paperGrey { + // background-color: $sk-gray-background-color !important; + background-color: $sk-paper-color !important; +} + +.fullHeight { + height: 100%; +} + +.popper { + width: 390px; + max-height: calc(100vh - 110pt); + padding: 10pt; + border-radius: $sk-border-radius-outter; + border: 1px rgba(127, 127, 127, .2705882353) solid; + + :global(.Mui-disabled) { + :global(.MuiAccordionSummary-expandIconWrapper) { + display: none !important; + } + opacity: 1 !important; + } +} + +.darkTheme { + .skaleLogoSm { + filter: invert(1); + } + + .defaultChainIcon { + color: 'hsl(120deg 2% 88%)'; + } + + .sk__btnSwitch { + :global(.Mui-disabled) { + background-color: $sk-paper-color !important; + } + } + + :global .MuiIconButton-root { + svg { + color: #000000; + } + } + + :global(.MuiIconButton-root.Mui-disabled) { + svg { + color: rgba(255, 255, 255, 0.3); + } + } + + :global(.Mui-completed) { + color: $sk-disabled-dark; + } + +} + +.lightTheme { + .skaleLogoLg { + filter: invert(1); + } + + .defaultChainIcon { + color: 'hsl(120deg 2% 88%)'; + } + + .sk__btnSwitch { + :global(.Mui-disabled) { + background-color: rgb(224 224 224) !important; + } + } + + :global(.MuiIconButton-root) { + svg { + color: #ffffff; + } + } + + :global(.MuiIconButton-root.Mui-disabled) { + svg { + color: rgba(0, 0, 0, 0.26); + } + } + + :global(.Mui-completed) { + color: $sk-disabled-light; + } +} + +.skaleBtnHidden { + display: none !important; +} + +.skaleBtn { + border: 1px #7f7f7f45 solid; + box-shadow: none !important; +} + + +.skaleLogoSm { + width: 18pt; +} + + +button { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif !important; + -webkit-font-smoothing: antialiased; +} + + +.imaWidgetBody { + border-radius: $sk-border-radius-outter !important; + position: fixed; + + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif !important; + -webkit-font-smoothing: antialiased; + + :global(.MuiAccordion-root) { + background-color: transparent !important; + } + + :global(.MuiAccordionDetails-root) { + padding: 0 !important; + } + + :global(.MuiButton-root) { + font-weight: 600 !important; + box-shadow: none !important; + border-radius: $sk-border-radius !important; + } +} + +.chainIconxs { + width: 17px; + height: 17px; + + svg { + width: 17px; + height: 17px; + } +} + +.chainIconsm { + width: 26px; + height: 26px; + + svg { + width: 26px; + height: 26px; + } +} + +.chainIconmd { + width: 35px; + height: 35px; + + svg { + width: 35px; + height: 35px; + } +} + +.chainIconlg { + width: 45px; + height: 45px; +} + +.sk__chainApps { + + border-left: 1px #bdbdbd solid; + margin-left: 30px !important; + + // background-color: $sk-paper-color; + // border-radius: $sk-border-radius !important; + // padding: 5px; +} + + + +.sk__btnSwitch { + width: 100%; + text-align: center; + margin-top: -13pt; + margin-bottom: -13pt; + + button { + border: 13px #1a1a1a solid; + } + + :global(svg) { + width: 14pt; + height: 14pt; + } +} + +.btnSwitchAnimation { + transition: all 0.2s ease-in-out; +} + +.btnAction { + width: 100%; + text-transform: none !important; + font-size: 0.8025rem !important; + line-height: 1.6 !important; + letter-spacing: 0.02857em !important; + font-weight: 600 !important; + padding-top: 0.8em !important; + padding-bottom: 0.8em !important; + min-height: $sk-btn-height !important; +} + +.btnChain { + width: 100%; + text-align: left; + text-transform: none !important; + font-size: 0.6525rem !important; + line-height: 1.6; + letter-spacing: 0.02857em; +} + + +@keyframes resize { + + 0%, + 100% { + transform: scale(1); + /* Initial and final size: 100% (no change) */ + } + + 50% { + transform: scale(1.1); + /* At half-time, size becomes 110% (10% larger) */ + } +} + +.skMovingDiv { + animation: resize 3s infinite ease-in-out; +} + +.infoIcon { + svg { + height: 45pt; + width: 100%; + } +} + +:global(.spin) { + transform: rotate(360deg); +} + + + +.accordionSummary { + padding: 10px 26px !important; +} \ No newline at end of file diff --git a/src/types/custom.d.ts b/src/types/custom.d.ts index 3e6090d..9c9c4e8 100644 --- a/src/types/custom.d.ts +++ b/src/types/custom.d.ts @@ -13,4 +13,25 @@ declare module "*.png" { export default content; } -declare module '*.scss'; \ No newline at end of file +declare module '*.scss'; + +declare module 'node' { + interface NodeRequire { + context: ( + directory: string, + useSubdirectories: boolean, + regExp: RegExp, + mode?: string + ) => any; + } +} + +declare namespace NodeJS { + interface Global { + require: NodeRequire; + } +} + +interface NodeRequire { + context: (directory: string, useSubdirectories: boolean, regExp: RegExp, mode?: string) => any; +} diff --git a/test/TestTest.ts b/test/TestTest.ts new file mode 100644 index 0000000..5f6f3e9 --- /dev/null +++ b/test/TestTest.ts @@ -0,0 +1,105 @@ + +import { Wallet } from "ethers"; + +import MetaportCore from '../src/core/metaport' +import { TokenType } from "../src/core/dataclasses"; +import { MainnetChain } from "@skalenetwork/ima-js"; + + + +const METAPORT_CONFIG = require('../src/metadata/metaportConfigStaging.json'); +METAPORT_CONFIG.mainnetEndpoint = 'https://cloudflare-eth.com/'; + + +describe("BASE LIB Test", () => { + let wallet: Wallet; + + before(async () => { + + + }); + + it("Requests ETH balance for Mainnet chain", async () => { + const mpc = new MetaportCore(METAPORT_CONFIG); + + const chain1 = 'mainnet'; + const chain2 = 'elated-tan-skat'; + const token = '_SKL_1'; + const tokenType = TokenType.erc20; + + const address = ''; + + const tokens = mpc.tokens(chain1, chain2); + + console.log(tokens); + + // const provider1 = mpc.provider(chain1); + // const provider2 = mpc.provider(chain2); + + const endp1 = mpc.endpoint(chain1); + const endp2 = mpc.endpoint(chain2); + + const mainnetChain = mpc.mainnet(); + const sChain = mpc.schain(chain2); + + console.log('======'); + console.log(endp1); + console.log(endp2); + console.log('======'); + + const bnr1 = await mainnetChain.provider.getBlockNumber(); + const bnr2 = await sChain.provider.getBlockNumber(); + + // const contract2 = mpc.tokenContract( + // token.erc20[tokenKeyname], + // provider2 + // ); + + const contract2 = mpc.tokenContract( + chain2, + token, + tokenType, + sChain.provider + ); + + console.log('-----'); + console.log(bnr1); + console.log(bnr2); + console.log('-------') + console.log(await contract2.balanceOf(address)); + console.log('-----'); + + console.log('-----'); + console.log(tokens.erc20); + + const tokenContracts = mpc.tokenContracts( + tokens, + TokenType.erc20, + chain1, + mainnetChain.provider + ); + const tokenBalances = await mpc.tokenBalances( + tokenContracts, + address + ); + + const tokenContractsDest = mpc.tokenContracts( + tokens, + TokenType.erc20, + chain2, + sChain.provider + ); + const tokenBalancesDest = await mpc.tokenBalances( + tokenContractsDest, + address + ); + + console.log('BALANCES:'); + console.log(tokenBalances); + console.log(tokenBalancesDest); + + // console.log(await sChain.ethBalance(address)); + // console.log(await mainnetChain.ethBalance(address)); + }); + +}); \ No newline at end of file diff --git a/test/core/tokensTest.ts b/test/core/tokensTest.ts deleted file mode 100644 index 5fcbb3d..0000000 --- a/test/core/tokensTest.ts +++ /dev/null @@ -1,52 +0,0 @@ -import 'mocha'; -import { SChain, MainnetChain } from '@skalenetwork/ima-js'; - -import { initSChain } from '../../src/core/core'; -import { CHAIN_NAME_SCHAIN, CHAIN_NAME_SCHAIN_2, NETWORK_NAME } from '../test_utils'; - -import { getAvailableTokens } from '../../src/core/tokens'; - - -describe("Test for tokens core module", () => { - let sChainName1: string; - let sChainName2: string; - - let sChain1: SChain; - let sChain2: SChain; - let mainnet: MainnetChain; - - let tokens: Object; - - before(async () => { - sChain1 = initSChain(NETWORK_NAME, CHAIN_NAME_SCHAIN); - sChain2 = initSChain(NETWORK_NAME, CHAIN_NAME_SCHAIN_2); - - tokens = { - 'rapping-zuben-elakrab': { - 'erc20': { - 'skEth': { - 'address': '0xD8AA84EbC1CfafFa4968cDd493235A0ae0872b73', - 'name': 'skETH', - 'wraps': { - 'address': '0xD2Aaa00700000000000000000000000000000000', - 'symbol': 'ETHC' - } - } - } - } - } - }); - - it.only("Test getAvailableTokens", async () => { - const availableTokens = await getAvailableTokens( - mainnet, - sChain1, - sChain2, - CHAIN_NAME_SCHAIN, - CHAIN_NAME_SCHAIN_2, - tokens, - true - ); - console.log(availableTokens); - }) -}) \ No newline at end of file diff --git a/test/test_utils.ts b/test/test_utils.ts index a4f66d1..e69de29 100644 --- a/test/test_utils.ts +++ b/test/test_utils.ts @@ -1,14 +0,0 @@ -import Web3 from 'web3'; -import { SChain, MainnetChain } from '@skalenetwork/ima-js'; - -import * as dotenv from "dotenv"; - - -dotenv.config(); - -export const CHAIN_NAME_SCHAIN = (process.env["CHAIN_NAME_SCHAIN"] as string); -export const CHAIN_NAME_SCHAIN_2 = (process.env["CHAIN_NAME_SCHAIN_2"] as string); - -export const MAINNET_CHAIN_NAME = 'Mainnet'; - -export const NETWORK_NAME = (process.env["NETWORK_NAME"] as string); diff --git a/tsconfig.json b/tsconfig.json index 0cdd4da..65c9c45 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,7 +14,7 @@ "esModuleInterop": true, "baseUrl": "src", "types": ["node", "webpack-env", "mocha"], - "typeRoots": ["./src/types"], + "typeRoots": ["./src/types", "./node_modules/@types"], "noUnusedLocals": true, /* Report errors on unused locals. */ "noUnusedParameters": true /* Report errors on unused parameters. */ }, diff --git a/webpack.config.js b/webpack.config.js index 5ed46f0..a3417b5 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -54,31 +54,51 @@ module.exports = { // }, // ], // }, + { - test: /\.s[ac]ss$/i, - use: [ - - // Creates `style` nodes from JS strings - { - loader: 'style-loader', - options: { - esModule: false, - }, - }, - // Translates CSS into CommonJS - { - loader: 'css-loader', - options: { - modules: true, - sourceMap: true, - // importLoaders: 2, - // esModule: false - } - }, - // Compiles Sass to CSS - "sass-loader", - ], - } + test: /\.css$/, + use: ['style-loader', 'css-loader', 'postcss-loader'], + }, + { + test: /\.scss$/, + use: ["style-loader", { + loader: 'css-loader', + options: { + modules: true, + sourceMap: true, + importLoaders: 2, + esModule: false + } + }, "sass-loader"], + include: path.resolve(__dirname, "../") + }, + + + // { + // test: /\.s[ac]ss$/i, + // use: [ + + // // Creates `style` nodes from JS strings + // { + // loader: 'style-loader', + // options: { + // esModule: false, + // }, + // }, + // // Translates CSS into CommonJS + // { + // loader: 'css-loader', + // options: { + // modules: true, + // sourceMap: true, + // // importLoaders: 2, + // // esModule: false + // } + // }, + // // Compiles Sass to CSS + // "sass-loader", + // ], + // } ] }, resolve: { From 6e646b1b94f2616b29a1c9aaf7a2af6ad896020e Mon Sep 17 00:00:00 2001 From: Dmytro Date: Mon, 7 Aug 2023 19:51:08 +0100 Subject: [PATCH 02/54] Update skale-network --- skale-network | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skale-network b/skale-network index 84e54b4..5b00cae 160000 --- a/skale-network +++ b/skale-network @@ -1 +1 @@ -Subproject commit 84e54b423f920c42efaca79274e16789fc8cf0a7 +Subproject commit 5b00cae6736322f302c3a75331b19ee02b0a3596 From 517e45182ba94a0d7880e44fab4f02c721c6b784 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Mon, 7 Aug 2023 19:55:45 +0100 Subject: [PATCH 03/54] Fix path to regression icons --- src/core/metadata.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/metadata.ts b/src/core/metadata.ts index c43cf25..ca8d80d 100644 --- a/src/core/metadata.ts +++ b/src/core/metadata.ts @@ -39,7 +39,7 @@ const CHAIN_ICONS = { 'staging': importAll(require.context('../meta/staging/icons', false, /\.(png|jpe?g|svg)$/)), 'legacy': importAll(require.context('../meta/legacy/icons', false, /\.(png|jpe?g|svg)$/)), 'regression': importAll( - require.context('../../meta/regression/icons', false, /\.(png|jpe?g|svg)$/)) + require.context('../meta/regression/icons', false, /\.(png|jpe?g|svg)$/)) } From 186ba3b2d9b352b0554461031bac936a6616b2ee Mon Sep 17 00:00:00 2001 From: Dmytro Date: Mon, 7 Aug 2023 20:06:39 +0100 Subject: [PATCH 04/54] Comment out metamask wallet --- src/components/Widget/Widget.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/Widget/Widget.tsx b/src/components/Widget/Widget.tsx index e2df2f7..ee7fd86 100644 --- a/src/components/Widget/Widget.tsx +++ b/src/components/Widget/Widget.tsx @@ -36,8 +36,7 @@ import { connectorsForWallets } from '@rainbow-me/rainbowkit'; import { injectedWallet, - coinbaseWallet, - metaMaskWallet + coinbaseWallet } from '@rainbow-me/rainbowkit/wallets'; import { MetaportConfig } from "core/interfaces" @@ -84,7 +83,7 @@ const connectors = connectorsForWallets([ { groupName: 'Supported Wallets', wallets: [ - metaMaskWallet({ chains, projectId: '' }), + // metaMaskWallet({ chains, projectId: '' }), injectedWallet({ chains }), coinbaseWallet({ chains, appName: 'TEST' }) ], From e3e00253666641555411dc8f535a25b2ec6fff8d Mon Sep 17 00:00:00 2001 From: Dmytro Date: Tue, 8 Aug 2023 20:11:54 +0100 Subject: [PATCH 05/54] Update webpack-cli, move packages to dependencies, add regression --- package.json | 34 ++++++------ src/components/Widget/Widget.tsx | 8 ++- src/core/contracts.ts | 4 +- src/core/network.ts | 3 ++ src/core/wagmi_network.ts | 2 +- src/metadata/faucet.json | 1 - webpack.config.js | 93 +++++++++++--------------------- 7 files changed, 59 insertions(+), 86 deletions(-) diff --git a/package.json b/package.json index 01786cf..fb39f2e 100644 --- a/package.json +++ b/package.json @@ -34,19 +34,10 @@ "@babel/preset-env": "^7.21.4", "@babel/preset-react": "^7.18.6", "@babel/preset-typescript": "^7.21.4", - "@emotion/react": "^11.9.0", - "@emotion/styled": "^11.8.1", - "@fontsource/roboto": "^4.5.7", - "@mui/icons-material": "^5.8.0", - "@mui/lab": "^5.0.0-alpha.88", - "@mui/material": "^5.8.1", - "@rainbow-me/rainbowkit": "^1.0.6", "@rollup/plugin-commonjs": "^17.1.0", "@rollup/plugin-image": "^2.1.1", "@rollup/plugin-json": "^4.1.0", "@rollup/plugin-node-resolve": "^11.2.1", - "@skalenetwork/ima-js": "2.0.0-custom.5", - "@skaleproject/pow-ethers": "0.3.2", "@storybook/addon-essentials": "^7.1.0", "@storybook/addon-interactions": "^7.1.0", "@storybook/addon-links": "^7.1.0", @@ -75,6 +66,7 @@ "html-webpack-plugin": "^5.5.0", "https-browserify": "^1.0.0", "identity-obj-proxy": "^3.0.0", + "mini-css-extract-plugin": "^2.7.6", "mocha": "^9.2.2", "node-polyfill-webpack-plugin": "^1.1.4", "postcss": "^8.4.14", @@ -103,12 +95,22 @@ "ts-mocha": "^10.0.0", "ts-node": "^10.9.1", "typescript": "^5.1.6", - "viem": "^1.3.0", - "wagmi": "^1.3.9", - "webpack": "^5.73.0", - "webpack-cli": "^4.10.0", - "zustand": "^4.3.9" + "webpack": "^5.88.2", + "webpack-cli": "^5.1.4" }, "peerDependencies": {}, - "dependencies": {} -} + "dependencies": { + "@rainbow-me/rainbowkit": "^1.0.8", + "viem": "^1.5.3", + "wagmi": "^1.3.9", + "zustand": "^4.4.1", + "@skalenetwork/ima-js": "2.0.0-custom.5", + "@skaleproject/pow-ethers": "0.3.2", + "@emotion/react": "^11.9.0", + "@emotion/styled": "^11.8.1", + "@fontsource/roboto": "^4.5.7", + "@mui/icons-material": "^5.8.0", + "@mui/lab": "^5.0.0-alpha.88", + "@mui/material": "^5.8.1" + } +} \ No newline at end of file diff --git a/src/components/Widget/Widget.tsx b/src/components/Widget/Widget.tsx index ee7fd86..609180a 100644 --- a/src/components/Widget/Widget.tsx +++ b/src/components/Widget/Widget.tsx @@ -36,7 +36,8 @@ import { connectorsForWallets } from '@rainbow-me/rainbowkit'; import { injectedWallet, - coinbaseWallet + coinbaseWallet, + metaMaskWallet } from '@rainbow-me/rainbowkit/wallets'; import { MetaportConfig } from "core/interfaces" @@ -56,7 +57,6 @@ const { chains, webSocketPublicClient } = configureChains( [ mainnet, goerli, - constructWagmiChain('staging', "staging-legal-crazy-castor"), constructWagmiChain('staging', "staging-utter-unripe-menkar"), constructWagmiChain('staging', "staging-faint-slimy-achird"), @@ -83,7 +83,7 @@ const connectors = connectorsForWallets([ { groupName: 'Supported Wallets', wallets: [ - // metaMaskWallet({ chains, projectId: '' }), + metaMaskWallet({ chains, projectId: '' }), injectedWallet({ chains }), coinbaseWallet({ chains, appName: 'TEST' }) ], @@ -98,8 +98,6 @@ const wagmiConfig = createConfig({ }); - - export default function Widget(props: { config: MetaportConfig }) { diff --git a/src/core/contracts.ts b/src/core/contracts.ts index 315400d..f9e7b2c 100644 --- a/src/core/contracts.ts +++ b/src/core/contracts.ts @@ -33,6 +33,7 @@ import sFuelWrapperAbi from '../metadata/sfuel_wrapper_abi.json'; import mainnetAddresses from '../metadata/addresses/mainnet.json'; import stagingAddresses from '../metadata/addresses/staging.json'; import legacyAddresses from '../metadata/addresses/legacy.json'; +import regressionAddresses from '../metadata/addresses/regression.json'; import sChainAbi from '../metadata/schainAbi.json'; import mainnetAbi from '../metadata/mainnetAbi.json'; @@ -50,7 +51,8 @@ export const ERC_ABIS: { [tokenType in CustomAbiTokenType | TokenType]: { ['abi' export const IMA_ADDRESSES = { mainnet: mainnetAddresses, staging: stagingAddresses, - legacy: legacyAddresses + legacy: legacyAddresses, + regression: regressionAddresses } export const IMA_ABIS = { diff --git a/src/core/network.ts b/src/core/network.ts index e587145..b9a9363 100644 --- a/src/core/network.ts +++ b/src/core/network.ts @@ -75,6 +75,9 @@ export function getMainnetAbi(network: string) { if (network === 'legacy') { return { ...IMA_ABIS.mainnet, ...IMA_ADDRESSES.legacy } } + if (network === 'regression') { + return { ...IMA_ABIS.mainnet, ...IMA_ADDRESSES.regression } + } return { ...IMA_ABIS.mainnet, ...IMA_ADDRESSES.mainnet } } diff --git a/src/core/wagmi_network.ts b/src/core/wagmi_network.ts index 5bbaab2..fef4d33 100644 --- a/src/core/wagmi_network.ts +++ b/src/core/wagmi_network.ts @@ -61,5 +61,5 @@ export function constructWagmiChain(network: SkaleNetwork, chainName: string): C export function getWebSocketUrl(chain: Chain): string { // return chain.rpcUrls.default.webSocket ? chain.rpcUrls.default.webSocket[0] : ''; - return chain.rpcUrls.default.webSocket ? chain.rpcUrls.default.webSocket[0] : ''; // TODO - IP! + return chain.rpcUrls.default.webSocket ? chain.rpcUrls.default.webSocket[0] : 'wss://goerli-light.eth.linkpool.io/ws'; // TODO - IP! } \ No newline at end of file diff --git a/src/metadata/faucet.json b/src/metadata/faucet.json index f5b34bd..d40e6e5 100644 --- a/src/metadata/faucet.json +++ b/src/metadata/faucet.json @@ -35,7 +35,6 @@ "func": "0x0c11dedd" } }, - "staging": null, "legacy": null, "regression": null } \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index a3417b5..0db5dad 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -13,6 +13,8 @@ module.exports = { }, module: { rules: [ + { test: /\.m?js$/, type: 'javascript/auto' }, + { test: /\.m?js$/, resolve: { fullySpecified: false } }, { test: /\.(ts|tsx)$/, loader: require.resolve("babel-loader"), @@ -40,65 +42,38 @@ module.exports = { }, ], }, - // { - // test: /\.png$/, - // use: [ - // { - // loader: 'file-loader', - // options: { - // limit: 10000, - // outputPath: 'icons', - // publicPath: 'icons', - // name: '[name].[ext]', - // }, - // }, - // ], - // }, - { test: /\.css$/, - use: ['style-loader', 'css-loader', 'postcss-loader'], - }, - { - test: /\.scss$/, - use: ["style-loader", { - loader: 'css-loader', - options: { - modules: true, - sourceMap: true, - importLoaders: 2, - esModule: false + sideEffects: true, + use: [ + 'style-loader', + { + loader: 'css-loader', + options: { + importLoaders: 1 + } } - }, "sass-loader"], - include: path.resolve(__dirname, "../") + ] }, - - - // { - // test: /\.s[ac]ss$/i, - // use: [ - - // // Creates `style` nodes from JS strings - // { - // loader: 'style-loader', - // options: { - // esModule: false, - // }, - // }, - // // Translates CSS into CommonJS - // { - // loader: 'css-loader', - // options: { - // modules: true, - // sourceMap: true, - // // importLoaders: 2, - // // esModule: false - // } - // }, - // // Compiles Sass to CSS - // "sass-loader", - // ], - // } + { + test: /\.s[ac]ss$/i, + use: [ + { + loader: 'style-loader', + options: { + esModule: false, + }, + }, + { + loader: 'css-loader', + options: { + modules: true, + sourceMap: true + } + }, + "sass-loader", + ], + } ] }, resolve: { @@ -122,11 +97,5 @@ module.exports = { new webpack.ProvidePlugin({ process: 'process/browser', }), - ], - // optimization: { - // splitChunks: { - // chunks: 'all', - // } - // } - + ] }; \ No newline at end of file From c467f563a2708bea1a9131aa31017c4ce30882db Mon Sep 17 00:00:00 2001 From: Dmytro Date: Fri, 11 Aug 2023 11:45:13 +0100 Subject: [PATCH 06/54] Update webpack config --- package.json | 30 ++++++----------- rollup.config.js | 55 -------------------------------- src/Metaport.tsx | 9 ++++-- src/components/Widget/Widget.tsx | 2 +- webpack.config.js | 37 ++++++++++++++++----- 5 files changed, 47 insertions(+), 86 deletions(-) delete mode 100644 rollup.config.js diff --git a/package.json b/package.json index fb39f2e..d2496fe 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,11 @@ "author": "SKALE Labs", "license": "LGPL-3.0-only", "main": "build/index.js", + "types": "build/index.d.ts", + "source": "src/index.ts", "files": [ "build" ], - "types": "build/index.d.ts", "scripts": { "storybook": "storybook dev -p 6006", "build-storybook": "storybook build", @@ -34,10 +35,6 @@ "@babel/preset-env": "^7.21.4", "@babel/preset-react": "^7.18.6", "@babel/preset-typescript": "^7.21.4", - "@rollup/plugin-commonjs": "^17.1.0", - "@rollup/plugin-image": "^2.1.1", - "@rollup/plugin-json": "^4.1.0", - "@rollup/plugin-node-resolve": "^11.2.1", "@storybook/addon-essentials": "^7.1.0", "@storybook/addon-interactions": "^7.1.0", "@storybook/addon-links": "^7.1.0", @@ -63,25 +60,18 @@ "esm": "^3.2.25", "fast-glob": "^3.2.11", "html-webpack-inline-svg-plugin": "^2.3.0", - "html-webpack-plugin": "^5.5.0", "https-browserify": "^1.0.0", "identity-obj-proxy": "^3.0.0", "mini-css-extract-plugin": "^2.7.6", "mocha": "^9.2.2", "node-polyfill-webpack-plugin": "^1.1.4", - "postcss": "^8.4.14", + "postcss": "^8.4.27", "postcss-loader": "^7.3.3", "react": "^18.2.0", "react-dom": "^18.2.0", "react-jazzicon": "^1.0.4", "react-script": "^2.0.5", "react-svg-loader": "^3.0.3", - "rollup": "^2.56.3", - "rollup-plugin-copy": "^3.4.0", - "rollup-plugin-peer-deps-external": "^2.2.4", - "rollup-plugin-postcss": "^4.0.2", - "rollup-plugin-svg-import": "^1.6.0", - "rollup-plugin-typescript2": "^0.29.0", "sass": "^1.54.0", "sass-loader": "^13.0.0", "storybook": "^7.1.0", @@ -100,17 +90,17 @@ }, "peerDependencies": {}, "dependencies": { - "@rainbow-me/rainbowkit": "^1.0.8", - "viem": "^1.5.3", - "wagmi": "^1.3.9", - "zustand": "^4.4.1", - "@skalenetwork/ima-js": "2.0.0-custom.5", - "@skaleproject/pow-ethers": "0.3.2", "@emotion/react": "^11.9.0", "@emotion/styled": "^11.8.1", "@fontsource/roboto": "^4.5.7", "@mui/icons-material": "^5.8.0", "@mui/lab": "^5.0.0-alpha.88", - "@mui/material": "^5.8.1" + "@mui/material": "^5.8.1", + "@rainbow-me/rainbowkit": "^1.0.8", + "@skalenetwork/ima-js": "2.0.0-custom.5", + "@skaleproject/pow-ethers": "0.3.2", + "viem": "^1.5.3", + "wagmi": "^1.3.9", + "zustand": "^4.4.1" } } \ No newline at end of file diff --git a/rollup.config.js b/rollup.config.js deleted file mode 100644 index 371514c..0000000 --- a/rollup.config.js +++ /dev/null @@ -1,55 +0,0 @@ -import peerDepsExternal from "rollup-plugin-peer-deps-external"; -import resolve from "@rollup/plugin-node-resolve"; -import commonjs from "@rollup/plugin-commonjs"; -import typescript from "rollup-plugin-typescript2"; -import postcss from "rollup-plugin-postcss"; -import copy from "rollup-plugin-copy"; -import image from '@rollup/plugin-image'; -import json from '@rollup/plugin-json'; - - -const packageJson = require("./package.json"); - -export default { - input: "src/index.ts", - output: [ - { - file: packageJson.main, - format: "cjs", - sourcemap: true - }, - { - file: packageJson.module, - format: "esm", - sourcemap: true - } - ], - plugins: [ - json(), - image(), - peerDepsExternal(), - resolve(), - commonjs(), - typescript({ useTsconfigDeclarationDir: true }), - postcss(), - copy({ - targets: [ - { - src: "src/variables.scss", - dest: "build", - rename: "variables.scss" - }, - { - src: "src/typography.scss", - dest: "build", - rename: "typography.scss" - }, - { - src: "src/icons", - dest: "build", - rename: "icons" - } - ] - }) - ] -}; diff --git a/src/Metaport.tsx b/src/Metaport.tsx index 5fc667e..d6c16b0 100644 --- a/src/Metaport.tsx +++ b/src/Metaport.tsx @@ -41,7 +41,12 @@ export class Metaport { if (config.autoLookup === undefined) config.autoLookup = true; if (config.skaleNetwork === undefined) config.skaleNetwork = 'mainnet'; if (config.debug === undefined) config.debug = false; - createRoot(document.getElementById('metaport')).render(); + const el = document.getElementById('metaport'); + if (el) { + createRoot(el).render(); + } else { + console.log('div with id="metaport" does not exist') + } } transfer(params: interfaces.TransferParams): void { @@ -53,7 +58,7 @@ export class Metaport { // updateParams(params) { internalEvents.updateParams(params) } // requestBalance(params) { internalEvents.requestBalance(params) } - setTheme(theme) { internalEvents.setTheme(theme) } + setTheme(theme: any) { internalEvents.setTheme(theme) } close() { internalEvents.close() } open() { internalEvents.open() } reset() { internalEvents.reset() } diff --git a/src/components/Widget/Widget.tsx b/src/components/Widget/Widget.tsx index 609180a..5d35b9b 100644 --- a/src/components/Widget/Widget.tsx +++ b/src/components/Widget/Widget.tsx @@ -40,7 +40,7 @@ import { metaMaskWallet } from '@rainbow-me/rainbowkit/wallets'; -import { MetaportConfig } from "core/interfaces" +import { MetaportConfig } from "../../core/interfaces" import WidgetUI from '../WidgetUI' import { useUIStore } from '../../store/Store' diff --git a/webpack.config.js b/webpack.config.js index 0db5dad..edbe161 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,22 +1,26 @@ const path = require('path'); const webpack = require("webpack"); + module.exports = { entry: path.join(__dirname, '/src/index.ts'), mode: 'production', output: { filename: 'index.js', - publicPath: '', + // publicPath: '', path: path.join(__dirname, 'build'), - libraryTarget: 'commonjs', - //chunkFilename: '[id].[chunkhash].js' + library: { + type: 'commonjs' + }, + // chunkFilename: '[id].[chunkhash].js' }, module: { rules: [ - { test: /\.m?js$/, type: 'javascript/auto' }, - { test: /\.m?js$/, resolve: { fullySpecified: false } }, + // { test: /\.m?js$/, type: 'javascript/auto' }, + // { test: /\.m?js$/, resolve: { fullySpecified: false } }, { - test: /\.(ts|tsx)$/, + test: /\.(js|ts|tsx)$/, + exclude: /node_modules/, // excludes node_modules directory loader: require.resolve("babel-loader"), options: { presets: [["react-app", { @@ -96,6 +100,23 @@ module.exports = { }), new webpack.ProvidePlugin({ process: 'process/browser', - }), - ] + }) + ], + optimization: { + splitChunks: { + cacheGroups: { + default: false, + vendors: false, + // Merge all the chunks into one. + single: { + name: 'main', + chunks: 'all', + minChunks: 1, + reuseExistingChunk: true, + enforce: true + } + } + }, + runtimeChunk: false + } }; \ No newline at end of file From 1a28ee3c72a0b966f19853c39c9fc9bbb71a377b Mon Sep 17 00:00:00 2001 From: Dmytro Date: Fri, 11 Aug 2023 13:28:33 +0100 Subject: [PATCH 07/54] Update React imports --- src/Metaport.tsx | 2 ++ src/components/AmountErrorMessage/AmountErrorMessage.tsx | 1 + src/components/ChainApps/ChainApps.tsx | 1 + src/components/ChainIcon/ChainIcon.tsx | 1 + src/components/ErrorMessage/ErrorMessage.tsx | 1 + src/components/SkConnect/SkConnect.tsx | 1 + src/components/SkPaper/SkPaper.tsx | 2 +- src/components/SkeletonLoader/SkeletonLoader.tsx | 1 + src/components/Stepper/SkStepper.tsx | 2 +- src/components/SwitchDirection/SwitchDirection.tsx | 2 +- src/components/TokenIcon/TokenIcon.tsx | 1 + src/components/TokenList/TokenBalance.tsx | 1 + src/components/TokenListSection/TokenListSection.tsx | 1 + src/components/Widget/Widget.tsx | 2 +- src/components/WidgetBody/WidgetBody.tsx | 1 + src/index.ts | 2 +- tsconfig.json | 2 +- 17 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/Metaport.tsx b/src/Metaport.tsx index d6c16b0..7d4c0ea 100644 --- a/src/Metaport.tsx +++ b/src/Metaport.tsx @@ -32,6 +32,8 @@ import * as interfaces from './core/interfaces/index'; export * as dataclasses from './core/dataclasses/index'; export * as interfaces from './core/interfaces/index'; +export * as ChainIcon from './components/ChainIcon'; + // export * as sfuel from './core/sfuel'; diff --git a/src/components/AmountErrorMessage/AmountErrorMessage.tsx b/src/components/AmountErrorMessage/AmountErrorMessage.tsx index bc2a838..f8d9d1a 100644 --- a/src/components/AmountErrorMessage/AmountErrorMessage.tsx +++ b/src/components/AmountErrorMessage/AmountErrorMessage.tsx @@ -1,3 +1,4 @@ +import React from 'react'; import Collapse from '@mui/material/Collapse'; import { cls } from '../../core/helper'; diff --git a/src/components/ChainApps/ChainApps.tsx b/src/components/ChainApps/ChainApps.tsx index 94c228e..79abdf3 100644 --- a/src/components/ChainApps/ChainApps.tsx +++ b/src/components/ChainApps/ChainApps.tsx @@ -1,3 +1,4 @@ +import React from 'react'; import { cls, getChainAppsMeta, getChainAlias } from '../../core/helper'; import styles from "../../styles/styles.scss"; diff --git a/src/components/ChainIcon/ChainIcon.tsx b/src/components/ChainIcon/ChainIcon.tsx index 2488da8..a1d4694 100644 --- a/src/components/ChainIcon/ChainIcon.tsx +++ b/src/components/ChainIcon/ChainIcon.tsx @@ -1,3 +1,4 @@ +import React from 'react'; import OfflineBoltRoundedIcon from '@mui/icons-material/OfflineBoltRounded'; import { SkaleNetwork } from '../../core/interfaces'; import { chainIconPath } from '../../core/metadata'; diff --git a/src/components/ErrorMessage/ErrorMessage.tsx b/src/components/ErrorMessage/ErrorMessage.tsx index ce79b02..7ad3b48 100644 --- a/src/components/ErrorMessage/ErrorMessage.tsx +++ b/src/components/ErrorMessage/ErrorMessage.tsx @@ -1,3 +1,4 @@ +import React from 'react'; import Button from '@mui/material/Button'; import { cls } from '../../core/helper'; diff --git a/src/components/SkConnect/SkConnect.tsx b/src/components/SkConnect/SkConnect.tsx index 126052b..f2d8c4e 100644 --- a/src/components/SkConnect/SkConnect.tsx +++ b/src/components/SkConnect/SkConnect.tsx @@ -20,6 +20,7 @@ * @copyright SKALE Labs 2023-Present */ +import React from 'react'; import { ConnectButton } from '@rainbow-me/rainbowkit'; import Jazzicon, { jsNumberForAddress } from 'react-jazzicon' diff --git a/src/components/SkPaper/SkPaper.tsx b/src/components/SkPaper/SkPaper.tsx index 84ed4e6..f799cc0 100644 --- a/src/components/SkPaper/SkPaper.tsx +++ b/src/components/SkPaper/SkPaper.tsx @@ -21,7 +21,7 @@ * @copyright SKALE Labs 2023-Present */ -import { ReactElement } from 'react'; +import React, { ReactElement } from 'react'; import { cls } from '../../core/helper'; import styles from "../../styles/styles.scss"; diff --git a/src/components/SkeletonLoader/SkeletonLoader.tsx b/src/components/SkeletonLoader/SkeletonLoader.tsx index ad7d6de..8a4bc8c 100644 --- a/src/components/SkeletonLoader/SkeletonLoader.tsx +++ b/src/components/SkeletonLoader/SkeletonLoader.tsx @@ -1,3 +1,4 @@ +import React from 'react'; import Skeleton from '@mui/material/Skeleton'; export default function SkeletonLoader(props) { diff --git a/src/components/Stepper/SkStepper.tsx b/src/components/Stepper/SkStepper.tsx index 9ae61e0..1504eb6 100644 --- a/src/components/Stepper/SkStepper.tsx +++ b/src/components/Stepper/SkStepper.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import Box from '@mui/material/Box'; import Stepper from '@mui/material/Stepper'; diff --git a/src/components/SwitchDirection/SwitchDirection.tsx b/src/components/SwitchDirection/SwitchDirection.tsx index 0eb2930..555e3b6 100644 --- a/src/components/SwitchDirection/SwitchDirection.tsx +++ b/src/components/SwitchDirection/SwitchDirection.tsx @@ -1,4 +1,4 @@ -import { useRef } from 'react'; +import React, { useRef } from 'react'; import IconButton from '@mui/material/IconButton'; import ArrowDownwardRoundedIcon from '@mui/icons-material/ArrowDownwardRounded'; diff --git a/src/components/TokenIcon/TokenIcon.tsx b/src/components/TokenIcon/TokenIcon.tsx index 2332518..0ae8cff 100644 --- a/src/components/TokenIcon/TokenIcon.tsx +++ b/src/components/TokenIcon/TokenIcon.tsx @@ -21,6 +21,7 @@ * @copyright SKALE Labs 2023-Present */ +import React from 'react'; import TollRoundedIcon from '@mui/icons-material/TollRounded'; import { TokenData } from '../../core/dataclasses'; import { tokenIconPath } from '../../core/metadata'; diff --git a/src/components/TokenList/TokenBalance.tsx b/src/components/TokenList/TokenBalance.tsx index ca02b24..d8902fd 100644 --- a/src/components/TokenList/TokenBalance.tsx +++ b/src/components/TokenList/TokenBalance.tsx @@ -1,3 +1,4 @@ +import React from 'react'; import { formatUnits } from 'ethers'; import { TokenType, TokenData } from '../../core/dataclasses'; diff --git a/src/components/TokenListSection/TokenListSection.tsx b/src/components/TokenListSection/TokenListSection.tsx index d1804a7..fae7b85 100644 --- a/src/components/TokenListSection/TokenListSection.tsx +++ b/src/components/TokenListSection/TokenListSection.tsx @@ -1,3 +1,4 @@ +import React from 'react'; import Button from '@mui/material/Button'; import { TokenData, TokenType } from '../../core/dataclasses'; diff --git a/src/components/Widget/Widget.tsx b/src/components/Widget/Widget.tsx index 5d35b9b..32dc876 100644 --- a/src/components/Widget/Widget.tsx +++ b/src/components/Widget/Widget.tsx @@ -21,7 +21,7 @@ * @copyright SKALE Labs 2023-Present */ -import { useEffect } from 'react'; +import React, { useEffect } from 'react'; import { RainbowKitProvider, diff --git a/src/components/WidgetBody/WidgetBody.tsx b/src/components/WidgetBody/WidgetBody.tsx index 249eb00..73d8967 100644 --- a/src/components/WidgetBody/WidgetBody.tsx +++ b/src/components/WidgetBody/WidgetBody.tsx @@ -1,3 +1,4 @@ +import React from 'react'; import { useCollapseStore } from '../../store/Store' import { useMetaportStore } from '../../store/MetaportState' diff --git a/src/index.ts b/src/index.ts index 4205b85..037d2b1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1 +1 @@ -export { Metaport, interfaces, dataclasses } from "./Metaport"; +export { Metaport, ChainIcon, interfaces, dataclasses } from "./Metaport"; diff --git a/tsconfig.json b/tsconfig.json index 65c9c45..14717e2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,7 +7,7 @@ "target": "es6", "lib": ["es6", "dom", "es2016", "es2017"], "sourceMap": true, - "jsx": "react-jsx", + "jsx": "react", "moduleResolution": "node", "allowSyntheticDefaultImports": true, "resolveJsonModule": true, From 4fea232fd6d040ebfa046a7c16e91f0e50e0a9b1 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Mon, 14 Aug 2023 18:18:40 +0100 Subject: [PATCH 08/54] Migrate builder to rollup.js --- .babelrc.json | 16 -- .eslintrc.js | 20 +++ .prettierrc | 7 + .storybook/main.ts | 84 ++-------- .storybook/manager.js | 7 - .storybook/preview.ts | 9 +- .storybook/vite.config.ts | 16 ++ package.json | 155 +++++++++--------- prepare_meta.sh | 23 --- src/Metaport.tsx | 12 +- .../AmountErrorMessage/AmountErrorMessage.tsx | 2 +- ...ountInput.scss => AmountInput.module.scss} | 0 .../AmountInput/AmountInput.module.scss.d.ts | 9 + src/components/AmountInput/AmountInput.tsx | 4 +- src/components/ChainApps/ChainApps.tsx | 4 +- src/components/ChainIcon/ChainIcon.tsx | 2 +- src/components/ChainsList/ChainsList.tsx | 4 +- src/components/ErrorMessage/ErrorMessage.tsx | 4 +- src/components/SkConnect/SkConnect.tsx | 8 +- src/components/SkPaper/SkPaper.tsx | 4 +- .../{SkStepper.scss => SkStepper.module.scss} | 0 .../Stepper/SkStepper.module.scss.d.ts | 16 ++ src/components/Stepper/SkStepper.tsx | 6 +- .../SwitchDirection/SwitchDirection.tsx | 4 +- src/components/TokenIcon/TokenIcon.tsx | 2 +- src/components/TokenList/TokenBalance.tsx | 2 +- src/components/TokenList/TokenList.tsx | 4 +- .../TokenListSection/TokenListSection.tsx | 2 +- src/components/WidgetBody/WidgetBody.tsx | 2 +- src/components/WidgetUI/WidgetUI.tsx | 4 +- src/core/metadata.ts | 11 +- src/index.ts | 2 +- src/styles/_variables.scss | 6 +- .../{common.scss => common.module.scss} | 0 src/styles/common.module.scss.d.ts | 55 +++++++ .../{styles.scss => styles.module.scss} | 2 +- src/vite-env.d.ts | 1 + test/TestTest.ts | 105 ------------ test/test_utils.ts | 0 tsconfig.json | 37 ++--- tsconfig.test.json | 14 -- tslint.json | 22 --- vite.config.ts | 47 ++++++ webpack.config.js | 122 -------------- 44 files changed, 332 insertions(+), 524 deletions(-) delete mode 100644 .babelrc.json create mode 100644 .eslintrc.js create mode 100644 .prettierrc delete mode 100644 .storybook/manager.js create mode 100644 .storybook/vite.config.ts delete mode 100644 prepare_meta.sh rename src/components/AmountInput/{AmountInput.scss => AmountInput.module.scss} (100%) create mode 100644 src/components/AmountInput/AmountInput.module.scss.d.ts rename src/components/Stepper/{SkStepper.scss => SkStepper.module.scss} (100%) create mode 100644 src/components/Stepper/SkStepper.module.scss.d.ts rename src/styles/{common.scss => common.module.scss} (100%) create mode 100644 src/styles/common.module.scss.d.ts rename src/styles/{styles.scss => styles.module.scss} (98%) create mode 100644 src/vite-env.d.ts delete mode 100644 test/TestTest.ts delete mode 100644 test/test_utils.ts delete mode 100644 tsconfig.test.json delete mode 100644 tslint.json create mode 100644 vite.config.ts delete mode 100644 webpack.config.js diff --git a/.babelrc.json b/.babelrc.json deleted file mode 100644 index b5cf683..0000000 --- a/.babelrc.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "sourceType": "unambiguous", - "presets": [ - [ - "@babel/preset-env", - { - "targets": { - "chrome": 100 - } - } - ], - "@babel/preset-typescript", - "@babel/preset-react" - ], - "plugins": [] -} \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..988ec8b --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,20 @@ +module.exports = { + env: { + browser: true, + es2021: true, + }, + extends: ['plugin:react/recommended', 'standard-with-typescript', 'prettier', 'plugin:storybook/recommended'], + overrides: [], + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + }, + plugins: ['react'], + rules: { + 'react/jsx-key': 'off', + 'react/react-in-jsx-scope': 'off', + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': 'warn', + 'no-console': 'warn', + }, +} diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..b13587a --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "semi": false, + "trailingComma": "all", + "singleQuote": true, + "printWidth": 120, + "endOfLine": "auto" +} \ No newline at end of file diff --git a/.storybook/main.ts b/.storybook/main.ts index 79487d7..c8af2c6 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -1,74 +1,22 @@ - -const path = require("path"); -/** @type { import('@storybook/react-webpack5').StorybookConfig } */ -const config = { - stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"], - staticDirs: ["../build"], +import type { StorybookConfig } from '@storybook/react-vite' +const config: StorybookConfig = { + stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], addons: [ - "@storybook/addon-links", - "@storybook/addon-essentials", - "@storybook/addon-interactions", - // "storybook-css-modules", - // { - // name: '@storybook/addon-styling', - // options: { - // sass: { - // // Require your Sass preprocessor here - // implementation: require('sass'), - // }, - // }, - // } + '@storybook/addon-links', + '@storybook/addon-essentials', + '@storybook/addon-interactions', + '@storybook/addon-styling', ], framework: { - name: "@storybook/react-webpack5", - options: {}, + name: '@storybook/react-vite', + options: { + builder: { + viteConfigPath: '.storybook/vite.config.ts', + }, + }, }, docs: { - autodocs: "tag", + autodocs: 'tag', }, - webpackFinal: async config => { - if (config.resolve && config.resolve.alias) { - const { - global, - ...alias - } = config.resolve.alias; - config.resolve.alias['browser'] = false; - // const { ...alias } = config.resolve.alias - config.resolve.alias = alias; - } - if (config.resolve && config.resolve.fallback) { - config.resolve.fallback = { - path: require.resolve('path-browserify'), - os: "os-browserify/browser", - "fs": false, - "browser": false, - "https": require.resolve("https-browserify"), - "http": require.resolve("stream-http"), - "crypto": require.resolve("crypto-browserify"), - "stream": require.resolve("stream-browserify"), - "buffer": require.resolve("buffer"), - "constants": require.resolve("constants-browserify") - //...config.resolve.fallback, - }; - } - if (config.module && config.module.rules) { - config.module.rules.push({ - test: /\.scss$/, - use: ["style-loader", { - loader: 'css-loader', - options: { - modules: true, - sourceMap: true, - importLoaders: 2, - esModule: false - } - }, "sass-loader"], - include: path.resolve(__dirname, "../") - }); - } - - return config; - } -}; -export default config; - +} +export default config diff --git a/.storybook/manager.js b/.storybook/manager.js deleted file mode 100644 index c233e6f..0000000 --- a/.storybook/manager.js +++ /dev/null @@ -1,7 +0,0 @@ -// .storybook/manager.js - -import { addons } from '@storybook/manager-api'; - -addons.setConfig({ - panelPosition: 'right' -}); \ No newline at end of file diff --git a/.storybook/preview.ts b/.storybook/preview.ts index 1c372b6..76fc315 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.ts @@ -1,8 +1,9 @@ -import type { Preview } from "@storybook/react"; +import type { Preview } from '@storybook/react' +import '../src/lib/tailwind/theme.css' const preview: Preview = { parameters: { - actions: { argTypesRegex: "^on[A-Z].*" }, + actions: { argTypesRegex: '^on[A-Z].*' }, controls: { matchers: { color: /(background|color)$/i, @@ -10,6 +11,6 @@ const preview: Preview = { }, }, }, -}; +} -export default preview; +export default preview diff --git a/.storybook/vite.config.ts b/.storybook/vite.config.ts new file mode 100644 index 0000000..218663b --- /dev/null +++ b/.storybook/vite.config.ts @@ -0,0 +1,16 @@ +import react from '@vitejs/plugin-react' +import { defineConfig } from 'vitest/config' +import { UserConfigExport } from 'vite' + +const app = async (): Promise => { + return defineConfig({ + plugins: [react()], + css: { + postcss: { + plugins: [], + }, + }, + }) +} +// https://vitejs.dev/config/ +export default app diff --git a/package.json b/package.json index d2496fe..05d80c2 100644 --- a/package.json +++ b/package.json @@ -9,86 +9,71 @@ ], "author": "SKALE Labs", "license": "LGPL-3.0-only", - "main": "build/index.js", - "types": "build/index.d.ts", - "source": "src/index.ts", - "files": [ - "build" - ], - "scripts": { - "storybook": "storybook dev -p 6006", - "build-storybook": "storybook build", - "serve-storybook": "serve storybook-static", - "prepublish": "npm run build", - "build": "NODE_ENV=production webpack --mode=production", - "build-stats": " webpack --json > stats.json", - "test": "TS_NODE_PROJECT=\"tsconfig.test.json\" mocha -t 300000 -r ts-node/register test/**/*Test.ts", - "test-ts": "ts-mocha -n loader=ts-node/esm -p tsconfig.json test/**/*Test.ts", - "lint": "tslint -c tslint.json 'src/**/*.ts'", - "version": "node -e \"console.log(require('./package.json').version);\"" + "main": "./dist/metaport.umd.js", + "module": "./dist/metaport.es.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/@skalenetwork/metaport.es.js", + "require": "./dist/@skalenetwork/metaport.umd.js" + }, + "./dist/style.css": "./dist/style.css" }, - "resolutions": { - "webpack": "^5" + "engines": { + "node": "18" + }, + "scripts": { + "dev": "storybook dev -p 6006", + "build": "storybook build", + "build:lib": "tsc && vite build", + "lint": "eslint --ext .js,.jsx,.ts,.tsx --fix", + "prettier": "prettier --write \"src/**/*.{ts,tsx,js,mdx}\"", + "test": "vitest", + "test:cov": "vitest run --coverage", + "prepack": "json -f package.json -I -e \"delete this.devDependencies; delete this.dependencies\"" }, "devDependencies": { - "@babel/core": "^7.15.0", - "@babel/preset-env": "^7.21.4", - "@babel/preset-react": "^7.18.6", - "@babel/preset-typescript": "^7.21.4", - "@storybook/addon-essentials": "^7.1.0", - "@storybook/addon-interactions": "^7.1.0", - "@storybook/addon-links": "^7.1.0", - "@storybook/addon-mdx-gfm": "^7.1.0", - "@storybook/addon-styling": "^1.3.4", - "@storybook/blocks": "^7.1.0", - "@storybook/react": "^7.1.0", - "@storybook/react-webpack5": "^7.1.0", - "@svgr/webpack": "^7.0.0", - "@types/babel__core": "^7.1.19", - "@types/mocha": "^9.1.1", - "@types/node": "^17.0.38", - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.11", - "@types/webpack-env": "^1.18.0", - "babel-loader": "^8.2.2", - "babel-preset-react-app": "^10.0.0", - "coingecko-api-v3": "0.0.13", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.12.0", - "css-loader": "^6.7.1", - "debug": "^4.3.4", - "esm": "^3.2.25", - "fast-glob": "^3.2.11", - "html-webpack-inline-svg-plugin": "^2.3.0", - "https-browserify": "^1.0.0", - "identity-obj-proxy": "^3.0.0", - "mini-css-extract-plugin": "^2.7.6", - "mocha": "^9.2.2", - "node-polyfill-webpack-plugin": "^1.1.4", - "postcss": "^8.4.27", - "postcss-loader": "^7.3.3", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-jazzicon": "^1.0.4", - "react-script": "^2.0.5", - "react-svg-loader": "^3.0.3", - "sass": "^1.54.0", - "sass-loader": "^13.0.0", - "storybook": "^7.1.0", - "storybook-css-modules": "^1.0.8", - "stream-browserify": "^3.0.0", - "stream-http": "^3.2.0", - "style-loader": "^3.3.1", - "svg-inline-loader": "^0.8.2", - "svg-url-loader": "^8.0.0", - "ts-loader": "^9.3.0", - "ts-mocha": "^10.0.0", - "ts-node": "^10.9.1", - "typescript": "^5.1.6", - "webpack": "^5.88.2", - "webpack-cli": "^5.1.4" + "@babel/core": "7.22.10", + "@storybook/addon-essentials": "7.2.2", + "@storybook/addon-interactions": "7.2.2", + "@storybook/addon-links": "7.2.2", + "@storybook/addon-styling": "1.3.6", + "@storybook/blocks": "7.2.2", + "@storybook/react": "7.2.2", + "@storybook/react-vite": "7.2.2", + "@storybook/testing-library": "0.2.0", + "@testing-library/react": "14.0.0", + "@types/node": "20.4.9", + "@types/react": "18.2.20", + "@types/react-dom": "18.2.7", + "@typescript-eslint/eslint-plugin": "5.60.0", + "@vitejs/plugin-react": "4.0.4", + "@vitest/coverage-v8": "0.34.1", + "autoprefixer": "10.4.14", + "babel-loader": "9.1.3", + "eslint": "8.46.0", + "eslint-config-prettier": "9.0.0", + "eslint-config-standard-with-typescript": "37.0.0", + "eslint-plugin-import": "2.28.0", + "eslint-plugin-n": "16.0.1", + "eslint-plugin-promise": "6.1.1", + "eslint-plugin-react": "7.33.1", + "eslint-plugin-storybook": "0.6.13", + "jsdom": "22.1.0", + "json": "11.0.0", + "lint-staged": "13.2.3", + "postcss": "8.4.27", + "prettier": "3.0.1", + "prop-types": "15.8.1", + "sass": "^1.65.1", + "storybook": "7.2.2", + "typescript": "5.1.6", + "vite": "4.4.9", + "vite-plugin-dts": "3.5.1", + "vite-plugin-sass-dts": "^1.3.9", + "vitest": "0.34.1" }, - "peerDependencies": {}, "dependencies": { "@emotion/react": "^11.9.0", "@emotion/styled": "^11.8.1", @@ -97,10 +82,24 @@ "@mui/lab": "^5.0.0-alpha.88", "@mui/material": "^5.8.1", "@rainbow-me/rainbowkit": "^1.0.8", - "@skalenetwork/ima-js": "2.0.0-custom.5", + "@skalenetwork/ima-js": "2.0.0-experimental.1", "@skaleproject/pow-ethers": "0.3.2", + "coingecko-api-v3": "^0.0.28", + "react-jazzicon": "^1.0.4", "viem": "^1.5.3", "wagmi": "^1.3.9", "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": "18.2.0", + "react-dom": "18.2.0" + }, + "files": [ + "dist" + ], + "lint-staged": { + "*.{ts,tsx,js,jsx,json,css,md}": [ + "prettier -w" + ] } -} \ No newline at end of file +} diff --git a/prepare_meta.sh b/prepare_meta.sh deleted file mode 100644 index 749b6ba..0000000 --- a/prepare_meta.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -set -e - -export DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" - -META_DIR_EXTERNAL=$DIR/skale-network/metadata/ -META_DIR=$DIR/src/meta/ - -if [ -d "$META_DIR" ]; then - echo "Removing ${META_DIR}..." - rm -rf $META_DIR -else - echo "${META_DIR} not found, skipping" -fi - -if [ -d "$META_DIR_EXTERNAL" ]; then - echo "Copying ${META_DIR_EXTERNAL} -> ${META_DIR}..." - cp -R $META_DIR_EXTERNAL $META_DIR -else - cp -R $DIR/skale-network/metadata/mainnet/ $META_DIR - echo "${META_DIR_EXTERNAL} not found, copying Mainnet meta" -fi diff --git a/src/Metaport.tsx b/src/Metaport.tsx index 7d4c0ea..6f13564 100644 --- a/src/Metaport.tsx +++ b/src/Metaport.tsx @@ -23,7 +23,7 @@ // @ts-ignore import React from 'react'; -import { createRoot } from 'react-dom/client'; +// import { createRoot } from 'react-dom/client'; import Widget from './components/Widget'; import { internalEvents } from './core/events'; @@ -32,7 +32,13 @@ import * as interfaces from './core/interfaces/index'; export * as dataclasses from './core/dataclasses/index'; export * as interfaces from './core/interfaces/index'; -export * as ChainIcon from './components/ChainIcon'; +import ChainIcon from './components/ChainIcon'; +export { ChainIcon }; + + +import WidgetUI from './components/WidgetUI'; +export { WidgetUI }; + // export * as sfuel from './core/sfuel'; @@ -45,7 +51,7 @@ export class Metaport { if (config.debug === undefined) config.debug = false; const el = document.getElementById('metaport'); if (el) { - createRoot(el).render(); + // createRoot(el).render(); } else { console.log('div with id="metaport" does not exist') } diff --git a/src/components/AmountErrorMessage/AmountErrorMessage.tsx b/src/components/AmountErrorMessage/AmountErrorMessage.tsx index f8d9d1a..531e1c0 100644 --- a/src/components/AmountErrorMessage/AmountErrorMessage.tsx +++ b/src/components/AmountErrorMessage/AmountErrorMessage.tsx @@ -2,7 +2,7 @@ import React from 'react'; import Collapse from '@mui/material/Collapse'; import { cls } from '../../core/helper'; -import common from '../../styles/common.scss'; +import common from '../../styles/common.module.scss'; import { useMetaportStore } from '../../store/MetaportState' diff --git a/src/components/AmountInput/AmountInput.scss b/src/components/AmountInput/AmountInput.module.scss similarity index 100% rename from src/components/AmountInput/AmountInput.scss rename to src/components/AmountInput/AmountInput.module.scss diff --git a/src/components/AmountInput/AmountInput.module.scss.d.ts b/src/components/AmountInput/AmountInput.module.scss.d.ts new file mode 100644 index 0000000..4653d00 --- /dev/null +++ b/src/components/AmountInput/AmountInput.module.scss.d.ts @@ -0,0 +1,9 @@ +import globalClassNames from '../../style.d' +declare const classNames: typeof globalClassNames & { + readonly mp__inputAmount: 'mp__inputAmount' + readonly tokenSymbol: 'tokenSymbol' + readonly tokenSymbolPlaceholder: 'tokenSymbolPlaceholder' + readonly 'MuiInput-root': 'MuiInput-root' + readonly 'MuiFormControl-root': 'MuiFormControl-root' +} +export = classNames diff --git a/src/components/AmountInput/AmountInput.tsx b/src/components/AmountInput/AmountInput.tsx index c59e4df..2524f3a 100644 --- a/src/components/AmountInput/AmountInput.tsx +++ b/src/components/AmountInput/AmountInput.tsx @@ -4,8 +4,8 @@ import { useAccount } from 'wagmi' import TextField from '@mui/material/TextField'; import { cls } from '../../core/helper'; -import common from '../../styles/common.scss'; -import localStyles from './AmountInput.scss'; +import common from '../../styles/common.module.scss'; +import localStyles from './AmountInput.module.scss'; import { useMetaportStore } from '../../store/MetaportState' diff --git a/src/components/ChainApps/ChainApps.tsx b/src/components/ChainApps/ChainApps.tsx index 79abdf3..c00eac4 100644 --- a/src/components/ChainApps/ChainApps.tsx +++ b/src/components/ChainApps/ChainApps.tsx @@ -1,8 +1,8 @@ import React from 'react'; import { cls, getChainAppsMeta, getChainAlias } from '../../core/helper'; -import styles from "../../styles/styles.scss"; -import common from "../../styles/common.scss"; +import styles from "../../styles/styles.module.scss"; +import common from "../../styles/common.module.scss"; import { SkaleNetwork } from '../../core/interfaces'; import ChainIcon from '../ChainIcon'; diff --git a/src/components/ChainIcon/ChainIcon.tsx b/src/components/ChainIcon/ChainIcon.tsx index a1d4694..b18a301 100644 --- a/src/components/ChainIcon/ChainIcon.tsx +++ b/src/components/ChainIcon/ChainIcon.tsx @@ -4,7 +4,7 @@ import { SkaleNetwork } from '../../core/interfaces'; import { chainIconPath } from '../../core/metadata'; import { cls } from '../../core/helper'; -import styles from "../../styles/styles.scss"; +import styles from "../../styles/styles.module.scss"; export default function ChainIcon(props: { diff --git a/src/components/ChainsList/ChainsList.tsx b/src/components/ChainsList/ChainsList.tsx index b36e98f..28c6e4f 100644 --- a/src/components/ChainsList/ChainsList.tsx +++ b/src/components/ChainsList/ChainsList.tsx @@ -14,8 +14,8 @@ import ChainIcon from '../ChainIcon'; import { MetaportConfig } from '../../core/interfaces'; import { cls, getChainAlias } from '../../core/helper'; -import common from "../../styles/common.scss"; -import styles from "../../styles/styles.scss"; +import common from "../../styles/common.module.scss"; +import styles from "../../styles/styles.module.scss"; export default function ChainsList(props: { diff --git a/src/components/ErrorMessage/ErrorMessage.tsx b/src/components/ErrorMessage/ErrorMessage.tsx index 7ad3b48..dd2f691 100644 --- a/src/components/ErrorMessage/ErrorMessage.tsx +++ b/src/components/ErrorMessage/ErrorMessage.tsx @@ -2,8 +2,8 @@ import React from 'react'; import Button from '@mui/material/Button'; import { cls } from '../../core/helper'; -import common from "../../styles/common.scss"; -import styles from "../../styles/styles.scss"; +import common from "../../styles/common.module.scss"; +import styles from "../../styles/styles.module.scss"; import { ErrorMessage } from '../../core/dataclasses'; diff --git a/src/components/SkConnect/SkConnect.tsx b/src/components/SkConnect/SkConnect.tsx index f2d8c4e..4c1b552 100644 --- a/src/components/SkConnect/SkConnect.tsx +++ b/src/components/SkConnect/SkConnect.tsx @@ -29,10 +29,10 @@ import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import { cls } from '../../core/helper'; -import styles from "../../styles/styles.scss"; -import common from "../../styles/common.scss"; +import styles from "../../styles/styles.module.scss"; +import common from "../../styles/common.module.scss"; -import skaleLogoFull from '../WidgetUI/skale_logo.svg'; +// import skaleLogoFull from '../WidgetUI/skale_logo.svg'; import { useMetaportStore } from '../../store/MetaportState'; import ChainIcon from "../ChainIcon"; @@ -80,7 +80,7 @@ export default function SkConnect() { common.margTop20, common.margBott20, )}> - + {/* */}
diff --git a/test/TestTest.ts b/test/TestTest.ts deleted file mode 100644 index 5f6f3e9..0000000 --- a/test/TestTest.ts +++ /dev/null @@ -1,105 +0,0 @@ - -import { Wallet } from "ethers"; - -import MetaportCore from '../src/core/metaport' -import { TokenType } from "../src/core/dataclasses"; -import { MainnetChain } from "@skalenetwork/ima-js"; - - - -const METAPORT_CONFIG = require('../src/metadata/metaportConfigStaging.json'); -METAPORT_CONFIG.mainnetEndpoint = 'https://cloudflare-eth.com/'; - - -describe("BASE LIB Test", () => { - let wallet: Wallet; - - before(async () => { - - - }); - - it("Requests ETH balance for Mainnet chain", async () => { - const mpc = new MetaportCore(METAPORT_CONFIG); - - const chain1 = 'mainnet'; - const chain2 = 'elated-tan-skat'; - const token = '_SKL_1'; - const tokenType = TokenType.erc20; - - const address = ''; - - const tokens = mpc.tokens(chain1, chain2); - - console.log(tokens); - - // const provider1 = mpc.provider(chain1); - // const provider2 = mpc.provider(chain2); - - const endp1 = mpc.endpoint(chain1); - const endp2 = mpc.endpoint(chain2); - - const mainnetChain = mpc.mainnet(); - const sChain = mpc.schain(chain2); - - console.log('======'); - console.log(endp1); - console.log(endp2); - console.log('======'); - - const bnr1 = await mainnetChain.provider.getBlockNumber(); - const bnr2 = await sChain.provider.getBlockNumber(); - - // const contract2 = mpc.tokenContract( - // token.erc20[tokenKeyname], - // provider2 - // ); - - const contract2 = mpc.tokenContract( - chain2, - token, - tokenType, - sChain.provider - ); - - console.log('-----'); - console.log(bnr1); - console.log(bnr2); - console.log('-------') - console.log(await contract2.balanceOf(address)); - console.log('-----'); - - console.log('-----'); - console.log(tokens.erc20); - - const tokenContracts = mpc.tokenContracts( - tokens, - TokenType.erc20, - chain1, - mainnetChain.provider - ); - const tokenBalances = await mpc.tokenBalances( - tokenContracts, - address - ); - - const tokenContractsDest = mpc.tokenContracts( - tokens, - TokenType.erc20, - chain2, - sChain.provider - ); - const tokenBalancesDest = await mpc.tokenBalances( - tokenContractsDest, - address - ); - - console.log('BALANCES:'); - console.log(tokenBalances); - console.log(tokenBalancesDest); - - // console.log(await sChain.ethBalance(address)); - // console.log(await mainnetChain.ethBalance(address)); - }); - -}); \ No newline at end of file diff --git a/test/test_utils.ts b/test/test_utils.ts deleted file mode 100644 index e69de29..0000000 diff --git a/tsconfig.json b/tsconfig.json index 14717e2..99dcac8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,29 +1,22 @@ { "compilerOptions": { - "rootDir": "src", - "declaration": true, - "declarationDir": "build", - "module": "esnext", - "target": "es6", - "lib": ["es6", "dom", "es2016", "es2017"], - "sourceMap": true, - "jsx": "react", - "moduleResolution": "node", + "target": "ESNext", + "useDefineForClassFields": true, + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": false, "allowSyntheticDefaultImports": true, + "strict": false, + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "moduleResolution": "Node", "resolveJsonModule": true, - "esModuleInterop": true, - "baseUrl": "src", - "types": ["node", "webpack-env", "mocha"], + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", "typeRoots": ["./src/types", "./node_modules/@types"], - "noUnusedLocals": true, /* Report errors on unused locals. */ - "noUnusedParameters": true /* Report errors on unused parameters. */ }, - "include": ["src/**/*", "index.ts", "src/types/custom.d.ts"], - "exclude": [ - "node_modules", - "build", - "storybook-static", - "src/**/*.stories.tsx", - "src/**/*.test.tsx" - ] + "include": ["./src/**/*.ts", "./src/**/*.tsx"], + "exclude": ["./src/**/*.stories.*"] } diff --git a/tsconfig.test.json b/tsconfig.test.json deleted file mode 100644 index 5f10f9d..0000000 --- a/tsconfig.test.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es6", - "resolveJsonModule": true, - "esModuleInterop": true, - "jsx": "react-jsx", - "typeRoots": ["./node_modules/@types", "./src/types"] - }, - "include": [ - "tests/*.ts" - ], - "exclude": ["src/components/**/*.ts"] -} \ No newline at end of file diff --git a/tslint.json b/tslint.json deleted file mode 100644 index 5ea890a..0000000 --- a/tslint.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "defaultSeverity": "error", - "extends": [ - "tslint:recommended" - ], - "jsRules": {}, - "rules": { - "no-namespace": false, - "max-classes-per-file": false, - "forin": false, - "max-line-length": [ - true, - { - "limit": 100, - "ignore-pattern": "^import |^export {(.*?)}", - "check-strings": true, - "check-regex": true - } - ] - }, - "rulesDirectory": [] -} \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..6606745 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,47 @@ +import react from '@vitejs/plugin-react' +import path from 'node:path' +import { defineConfig } from 'vitest/config' +import dts from 'vite-plugin-dts' +import { UserConfigExport } from 'vite' +import { name } from './package.json' + + +const app = async (): Promise => { + return defineConfig({ + css: { + postcss: { + plugins: [], + }, + }, + plugins: [ + react(), + dts({ + insertTypesEntry: true, + }) + ], + build: { + lib: { + entry: path.resolve(__dirname, 'src/index.ts'), + name, + formats: ['es', 'umd'], + fileName: (format) => `${name}.${format}.js`, + }, + rollupOptions: { + external: ['react', 'react/jsx-runtime', 'react-dom'], + output: { + globals: { + react: 'React', + 'react/jsx-runtime': 'react/jsx-runtime', + 'react-dom': 'ReactDOM' + }, + }, + }, + }, + test: { + globals: true, + environment: 'jsdom', + }, + }) +} +// https://vitejs.dev/config/ +export default app diff --git a/webpack.config.js b/webpack.config.js deleted file mode 100644 index edbe161..0000000 --- a/webpack.config.js +++ /dev/null @@ -1,122 +0,0 @@ -const path = require('path'); -const webpack = require("webpack"); - - -module.exports = { - entry: path.join(__dirname, '/src/index.ts'), - mode: 'production', - output: { - filename: 'index.js', - // publicPath: '', - path: path.join(__dirname, 'build'), - library: { - type: 'commonjs' - }, - // chunkFilename: '[id].[chunkhash].js' - }, - module: { - rules: [ - // { test: /\.m?js$/, type: 'javascript/auto' }, - // { test: /\.m?js$/, resolve: { fullySpecified: false } }, - { - test: /\.(js|ts|tsx)$/, - exclude: /node_modules/, // excludes node_modules directory - loader: require.resolve("babel-loader"), - options: { - presets: [["react-app", { - flow: false, - typescript: true - }]] - } - }, - { - test: /\.tsx?$/, - loader: 'ts-loader', - // include: path.resolve(__dirname, 'src'), - exclude: /node_modules/ - }, - { - test: /\.svg$/, - use: [ - { - loader: 'svg-url-loader', - options: { - limit: 200000, - }, - }, - ], - }, - { - test: /\.css$/, - sideEffects: true, - use: [ - 'style-loader', - { - loader: 'css-loader', - options: { - importLoaders: 1 - } - } - ] - }, - { - test: /\.s[ac]ss$/i, - use: [ - { - loader: 'style-loader', - options: { - esModule: false, - }, - }, - { - loader: 'css-loader', - options: { - modules: true, - sourceMap: true - } - }, - "sass-loader", - ], - } - ] - }, - resolve: { - extensions: [".tsx", ".ts", ".js", ".css", ".scss"], - fallback: { - // make sure you `npm install path-browserify` to use this - path: require.resolve('path-browserify'), - os: "os-browserify/browser", - "fs": false, - "https": require.resolve("https-browserify"), - "http": require.resolve("stream-http"), - "crypto": require.resolve("crypto-browserify"), - "stream": require.resolve("stream-browserify"), - "buffer": require.resolve("buffer") - } - }, - plugins: [ - new webpack.ProvidePlugin({ - Buffer: ['buffer', 'Buffer'], - }), - new webpack.ProvidePlugin({ - process: 'process/browser', - }) - ], - optimization: { - splitChunks: { - cacheGroups: { - default: false, - vendors: false, - // Merge all the chunks into one. - single: { - name: 'main', - chunks: 'all', - minChunks: 1, - reuseExistingChunk: true, - enforce: true - } - } - }, - runtimeChunk: false - } -}; \ No newline at end of file From b7b85e7df74c01df56bc37812310b6ea4f16c0cb Mon Sep 17 00:00:00 2001 From: Dmytro Date: Mon, 14 Aug 2023 18:35:08 +0100 Subject: [PATCH 09/54] Split injected metaport and mp component --- src/Metaport.tsx | 4 +- src/components/Metaport/Metaport.tsx | 109 +++++++++++++++++++++++++++ src/components/Metaport/index.ts | 1 + src/components/WidgetUI/WidgetUI.tsx | 27 ++++++- 4 files changed, 137 insertions(+), 4 deletions(-) create mode 100644 src/components/Metaport/Metaport.tsx create mode 100644 src/components/Metaport/index.ts diff --git a/src/Metaport.tsx b/src/Metaport.tsx index 6f13564..4113907 100644 --- a/src/Metaport.tsx +++ b/src/Metaport.tsx @@ -39,11 +39,13 @@ export { ChainIcon }; import WidgetUI from './components/WidgetUI'; export { WidgetUI }; +import Metaport from './components/Metaport'; +export { Metaport }; // export * as sfuel from './core/sfuel'; -export class Metaport { +export class InjectedMetaport { constructor(config: interfaces.MetaportConfig) { if (config.openButton === undefined) config.openButton = true; if (config.autoLookup === undefined) config.autoLookup = true; diff --git a/src/components/Metaport/Metaport.tsx b/src/components/Metaport/Metaport.tsx new file mode 100644 index 0000000..b96960c --- /dev/null +++ b/src/components/Metaport/Metaport.tsx @@ -0,0 +1,109 @@ + +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +/** + * @file Metaport.ts + * @copyright SKALE Labs 2023-Present + */ + +import { + RainbowKitProvider +} from '@rainbow-me/rainbowkit'; +import { configureChains, createConfig, WagmiConfig } from 'wagmi'; +import { mainnet, goerli } from 'wagmi/chains'; +import { jsonRpcProvider } from 'wagmi/providers/jsonRpc'; +import { connectorsForWallets } from '@rainbow-me/rainbowkit'; + +import { + injectedWallet, + coinbaseWallet, + metaMaskWallet +} from '@rainbow-me/rainbowkit/wallets'; + +import { MetaportConfig } from "../../core/interfaces" + +import WidgetUI from '../WidgetUI' + +import '@rainbow-me/rainbowkit/styles.css'; + +import { constructWagmiChain, getWebSocketUrl } from '../../core/wagmi_network'; + + +const { chains, webSocketPublicClient } = configureChains( + [ + mainnet, + goerli, + constructWagmiChain('staging', "staging-legal-crazy-castor"), + constructWagmiChain('staging', "staging-utter-unripe-menkar"), + constructWagmiChain('staging', "staging-faint-slimy-achird"), + constructWagmiChain('staging', "staging-perfect-parallel-gacrux"), + constructWagmiChain('staging', "staging-severe-violet-wezen"), + constructWagmiChain('staging', "staging-weepy-fitting-caph"), + + constructWagmiChain('mainnet', 'honorable-steel-rasalhague'), + constructWagmiChain('mainnet', 'elated-tan-skat'), + constructWagmiChain('mainnet', 'affectionate-immediate-pollux') + ], + [ + jsonRpcProvider({ + rpc: chain => ({ + http: chain.rpcUrls.default.http[0], + webSocket: getWebSocketUrl(chain) + }), + }) + ] +); + + +const connectors = connectorsForWallets([ + { + groupName: 'Supported Wallets', + wallets: [ + metaMaskWallet({ chains, projectId: '' }), + injectedWallet({ chains }), + coinbaseWallet({ chains, appName: 'TEST' }) + ], + } +]); + + +const wagmiConfig = createConfig({ + autoConnect: true, + connectors, + publicClient: webSocketPublicClient +}); + + +export default function Widget(props: { + config: MetaportConfig +}) { + return ( + + + + + + ) +} \ No newline at end of file diff --git a/src/components/Metaport/index.ts b/src/components/Metaport/index.ts new file mode 100644 index 0000000..293cae0 --- /dev/null +++ b/src/components/Metaport/index.ts @@ -0,0 +1 @@ +export { default } from "./Metaport"; diff --git a/src/components/WidgetUI/WidgetUI.tsx b/src/components/WidgetUI/WidgetUI.tsx index 6fce788..e71b370 100644 --- a/src/components/WidgetUI/WidgetUI.tsx +++ b/src/components/WidgetUI/WidgetUI.tsx @@ -20,7 +20,7 @@ * @copyright SKALE Labs 2023-Present */ -import React from 'react'; +import React, { useEffect } from 'react'; import { StyledEngineProvider } from '@mui/material/styles'; import { useAccount } from 'wagmi'; @@ -47,17 +47,38 @@ import styles from "../../styles/styles.module.scss"; import common from "../../styles/common.module.scss"; import { PaletteMode } from '@mui/material'; +import { getWidgetTheme } from '../../core/themes'; + import SkConnect from '../SkConnect'; import ErrorMessage from '../ErrorMessage'; +import { MetaportConfig } from '../../core/interfaces'; +import MetaportCore from '../../core/metaport' + + +export function WidgetUI(props: { config: MetaportConfig }) { + + const widgetTheme = getWidgetTheme(props.config.theme); + const setTheme = useUIStore((state) => state.setTheme); + const setMpc = useMetaportStore((state) => state.setMpc); + const setOpen = useUIStore((state) => state.setOpen); + + useEffect(() => { + setOpen(props.config.openOnLoad); + }, []); -export function WidgetUI(props) { + useEffect(() => { + setTheme(widgetTheme); + }, [setTheme]); + + useEffect(() => { + setMpc(new MetaportCore(props.config)); + }, [setMpc]); const { address } = useAccount(); const metaportTheme = useUIStore((state) => state.theme); const isOpen = useUIStore((state) => state.open); - const setOpen = useUIStore((state) => state.setOpen); const errorMessage = useMetaportStore((state) => state.errorMessage); From fda6a4b6ac545afe25931f0a63cac662699f5ec1 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Mon, 14 Aug 2023 19:08:19 +0100 Subject: [PATCH 10/54] Add chain icons support for vite --- generate-imports.js | 44 ++++++++++++++++++++ src/components/ChainIcon/ChainIcon.tsx | 2 +- src/core/metadata.ts | 28 ++++++------- src/metadata/metaportConfigStaging.json | 53 ++----------------------- 4 files changed, 61 insertions(+), 66 deletions(-) create mode 100644 generate-imports.js diff --git a/generate-imports.js b/generate-imports.js new file mode 100644 index 0000000..d19ba1c --- /dev/null +++ b/generate-imports.js @@ -0,0 +1,44 @@ +const fs = require('fs'); +const path = require('path'); + +const rootDir = process.argv[2]; + +if (!rootDir) { + console.error('Please provide a root directory as an argument.'); + process.exit(1); +} + +const getSvgFilesInDir = (dir) => { + return fs.readdirSync(dir).filter(file => path.extname(file) === '.svg').map(file => path.join(dir, file)); +}; + +const generateNamespaceExportsForDir = (dir) => { + const svgFiles = getSvgFilesInDir(dir); + + if (svgFiles.length === 0) return; // Skip folders without SVGs + + const namespaceExports = svgFiles.map(file => { + const variableName = path.basename(file, '.svg').replace(/-([a-z])/g, (_, g) => g.toUpperCase()); // Convert kebab-case to camelCase + return `export * as ${variableName} from './${path.basename(file)}';`; + }).join('\n'); + + const outputPath = path.join(dir, 'index.ts'); + fs.writeFileSync(outputPath, namespaceExports, 'utf-8'); +}; + +const walkDirectories = (dir) => { + const items = fs.readdirSync(dir); + + for (const item of items) { + const itemPath = path.join(dir, item); + const stat = fs.statSync(itemPath); + + if (stat && stat.isDirectory()) { + generateNamespaceExportsForDir(itemPath); + walkDirectories(itemPath); + } + } +}; + +generateNamespaceExportsForDir(rootDir); // Generate for rootDir itself +walkDirectories(rootDir); // Then walk its subdirectories diff --git a/src/components/ChainIcon/ChainIcon.tsx b/src/components/ChainIcon/ChainIcon.tsx index b18a301..702e8c7 100644 --- a/src/components/ChainIcon/ChainIcon.tsx +++ b/src/components/ChainIcon/ChainIcon.tsx @@ -23,7 +23,7 @@ export default function ChainIcon(props: { const className = styles[`chainIcon${size}`] + ' ' + props.className; if (iconPath !== undefined) { if (iconPath.default) { - return ; + return ; } return ; } diff --git a/src/core/metadata.ts b/src/core/metadata.ts index a219e73..a0512c3 100644 --- a/src/core/metadata.ts +++ b/src/core/metadata.ts @@ -25,32 +25,28 @@ import { TokenData } from './dataclasses'; import { SkaleNetwork } from './interfaces'; import { MAINNET_CHAIN_NAME } from './constants'; - -function importAll(r) { - const images = {}; - r.keys().map((item, _) => { images[item.replace('./', '')] = r(item); }); - return images; -} - +import * as MAINNET_CHAIN_ICONS from '../meta/mainnet/icons'; +import * as STAGING_CHAIN_ICONS from '../meta/staging/icons'; +import * as LEGACY_CHAIN_ICONS from '../meta/legacy/icons'; +import * as REGRESSION_CHAIN_ICONS from '../meta/regression/icons'; const icons = {}; const CHAIN_ICONS = { - 'mainnet': {}, - 'staging': {}, - 'legacy': {}, - 'regression': {} + 'mainnet': MAINNET_CHAIN_ICONS, + 'staging': STAGING_CHAIN_ICONS, + 'legacy': LEGACY_CHAIN_ICONS, + 'regression': REGRESSION_CHAIN_ICONS } export function chainIconPath(skaleNetwork: SkaleNetwork, name: string, app?: string) { if (!name) return; - let filename = name.toLowerCase(); - if (app) - filename += `-${app}`; - filename += '.svg'; + let filename = name.toLowerCase() + if (app) filename += `-${app}`; if (name === MAINNET_CHAIN_NAME) { - return icons['eth.svg']; + return CHAIN_ICONS[skaleNetwork]['mainnet']; } + filename = filename.replace(/-([a-z])/g, (_, g) => g.toUpperCase()) if (CHAIN_ICONS[skaleNetwork][filename]) { return CHAIN_ICONS[skaleNetwork][filename]; } diff --git a/src/metadata/metaportConfigStaging.json b/src/metadata/metaportConfigStaging.json index db445c7..eaa3f7a 100644 --- a/src/metadata/metaportConfigStaging.json +++ b/src/metadata/metaportConfigStaging.json @@ -243,67 +243,22 @@ }, "staging-perfect-parallel-gacrux": { "erc20": { - "_ETH_0xBA3f8192e28224790978794102C0D7aaa65B7d70": { - "address": "0xBA3f8192e28224790978794102C0D7aaa65B7d70", - "name": "ETH", - "symbol": "ETH", - "cloneSymbol": "ETH", - "wraps": { - "address": "0xD2Aaa00700000000000000000000000000000000", - "symbol": "ETH", - "name": "aaaa" - } - }, - "_SKILL_0xb36A1DdaBf21161ad71013A34D502381DD1aa7BA": { - "address": "0xb36A1DdaBf21161ad71013A34D502381DD1aa7BA", - "name": "SKILL Token", - "symbol": "SKILL", - "iconUrl": "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Compass/3D/compass_3d.png" - }, - "DMT": { - "address": "0xb36A1DdaBf21161ad71013A34D502381DD1aa7BA", - "name": "DMT", - "symbol": "DMT", - "cloneSymbol": "DMTC", - "wraps": { - "address": "0x688f6d050B935BF06531b51B5e598318788fA7a5", - "symbol": "DMT", - "iconUrl": "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Compass/3D/compass_3d.png" - } - }, - "_SKL_0x099A46F35b627CABee27dc917eDA253fFbC55Be6": { - "address": "0x099A46F35b627CABee27dc917eDA253fFbC55Be6", - "decimals": "18", - "name": "SKL S2S", - "symbol": "SKL" - } }, "erc721": { - "_SPS_0x30216880A73B67133F37de35e769b8e1A943D35c": { - "address": "0x30216880A73B67133F37de35e769b8e1A943D35c", - "name": "SKALE Space S2S", - "symbol": "SPS", - "iconUrl": "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Glowing%20star/3D/glowing_star_3d.png" - } + }, "erc1155": { "skaliens": { "address": "0xBA9fF38A2b22edDfa8e05805bD22C8f20c40546e", - "name": "SKALIENS Collection", - "symbol": "SKALIENS2S", - "iconUrl": "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Alien/3D/alien_3d.png" + "chains": {} }, "medals": { "address": "0x5D8bD602dC5468B3998e8514A1851bd5888E9639", - "name": "Medals", - "symbol": "MEDALS2S", - "iconUrl": "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/1st%20place%20medal/3D/1st_place_medal_3d.png" + "chains": {} }, "_ANIMALS_0xDf87EEF0977148129969b01b329379b17756cdDE": { "address": "0xDf87EEF0977148129969b01b329379b17756cdDE", - "name": "Funny Animals", - "symbol": "ANIMALS", - "iconUrl": "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Frog/3D/frog_3d.png" + "chains": {} } } } From 476a9d46f9f071b9f40b136f454421e8334c6aae Mon Sep 17 00:00:00 2001 From: Dmytro Date: Mon, 14 Aug 2023 19:21:07 +0100 Subject: [PATCH 11/54] Add token icons in vite build --- .gitignore | 1 + src/components/TokenIcon/TokenIcon.tsx | 8 +- src/core/metadata.ts | 12 +- src/icons/{0xbtc.svg => _0xbtc.svg} | 0 src/icons/{2give.svg => _2give.svg} | 0 src/icons/index.ts | 471 +++++++++++++++++++++++++ src/icons/{$pac.svg => pac.svg} | 0 7 files changed, 485 insertions(+), 7 deletions(-) rename src/icons/{0xbtc.svg => _0xbtc.svg} (100%) rename src/icons/{2give.svg => _2give.svg} (100%) create mode 100644 src/icons/index.ts rename src/icons/{$pac.svg => pac.svg} (100%) diff --git a/.gitignore b/.gitignore index 3c31b63..13d7e0d 100644 --- a/.gitignore +++ b/.gitignore @@ -53,6 +53,7 @@ test.mjs src/meta/ +src/icons/index.ts metaportConfig.json metaportConfigMainnet.json diff --git a/src/components/TokenIcon/TokenIcon.tsx b/src/components/TokenIcon/TokenIcon.tsx index b373568..fd5290c 100644 --- a/src/components/TokenIcon/TokenIcon.tsx +++ b/src/components/TokenIcon/TokenIcon.tsx @@ -37,7 +37,11 @@ export default function TokenIcon(props: { const className = styles[`chainIcon${size}`]; if (props.token === undefined || props.token === null) { return - // return } - return + + const iconPath = tokenIconPath(props.token); + if (iconPath.default) { + return ; + } + return ; } \ No newline at end of file diff --git a/src/core/metadata.ts b/src/core/metadata.ts index a0512c3..e150fda 100644 --- a/src/core/metadata.ts +++ b/src/core/metadata.ts @@ -30,7 +30,9 @@ import * as STAGING_CHAIN_ICONS from '../meta/staging/icons'; import * as LEGACY_CHAIN_ICONS from '../meta/legacy/icons'; import * as REGRESSION_CHAIN_ICONS from '../meta/regression/icons'; -const icons = {}; +import * as icons from '../icons'; + + const CHAIN_ICONS = { 'mainnet': MAINNET_CHAIN_ICONS, 'staging': STAGING_CHAIN_ICONS, @@ -53,18 +55,18 @@ export function chainIconPath(skaleNetwork: SkaleNetwork, name: string, app?: st } -export function tokenIcon(name: string): string { +export function tokenIcon(name: string) { if (!name) return; - const key = name.toLowerCase() + '.svg'; + const key = name.toLowerCase() if (icons[key]) { return icons[key]; } else { - return icons['eth.svg']; + return icons['eth']; } } -export function tokenIconPath(token: TokenData): string { +export function tokenIconPath(token: TokenData) { return token.meta.iconUrl ?? tokenIcon(token.meta.symbol); } diff --git a/src/icons/0xbtc.svg b/src/icons/_0xbtc.svg similarity index 100% rename from src/icons/0xbtc.svg rename to src/icons/_0xbtc.svg diff --git a/src/icons/2give.svg b/src/icons/_2give.svg similarity index 100% rename from src/icons/2give.svg rename to src/icons/_2give.svg diff --git a/src/icons/index.ts b/src/icons/index.ts new file mode 100644 index 0000000..5b947a4 --- /dev/null +++ b/src/icons/index.ts @@ -0,0 +1,471 @@ +export * as _0xbtc from './_0xbtc.svg'; +export * as _2give from './_2give.svg'; +export * as aave from './aave.svg'; +export * as abt from './abt.svg'; +export * as act from './act.svg'; +export * as actn from './actn.svg'; +export * as ada from './ada.svg'; +export * as add from './add.svg'; +export * as adx from './adx.svg'; +export * as ae from './ae.svg'; +export * as aeon from './aeon.svg'; +export * as aeur from './aeur.svg'; +export * as agi from './agi.svg'; +export * as agrs from './agrs.svg'; +export * as aion from './aion.svg'; +export * as algo from './algo.svg'; +export * as amb from './amb.svg'; +export * as amp from './amp.svg'; +export * as ampl from './ampl.svg'; +export * as ankr from './ankr.svg'; +export * as ant from './ant.svg'; +export * as apex from './apex.svg'; +export * as appc from './appc.svg'; +export * as ardr from './ardr.svg'; +export * as arg from './arg.svg'; +export * as ark from './ark.svg'; +export * as arn from './arn.svg'; +export * as arnx from './arnx.svg'; +export * as ary from './ary.svg'; +export * as ast from './ast.svg'; +export * as atm from './atm.svg'; +export * as atom from './atom.svg'; +export * as audr from './audr.svg'; +export * as auto from './auto.svg'; +export * as aywa from './aywa.svg'; +export * as bab from './bab.svg'; +export * as bal from './bal.svg'; +export * as band from './band.svg'; +export * as bat from './bat.svg'; +export * as bay from './bay.svg'; +export * as bcbc from './bcbc.svg'; +export * as bcc from './bcc.svg'; +export * as bcd from './bcd.svg'; +export * as bch from './bch.svg'; +export * as bcio from './bcio.svg'; +export * as bcn from './bcn.svg'; +export * as bco from './bco.svg'; +export * as bcpt from './bcpt.svg'; +export * as bdl from './bdl.svg'; +export * as beam from './beam.svg'; +export * as bela from './bela.svg'; +export * as bix from './bix.svg'; +export * as blcn from './blcn.svg'; +export * as blk from './blk.svg'; +export * as block from './block.svg'; +export * as blz from './blz.svg'; +export * as bnb from './bnb.svg'; +export * as bnt from './bnt.svg'; +export * as bnty from './bnty.svg'; +export * as booty from './booty.svg'; +export * as bos from './bos.svg'; +export * as bpt from './bpt.svg'; +export * as bq from './bq.svg'; +export * as brd from './brd.svg'; +export * as bsd from './bsd.svg'; +export * as bsv from './bsv.svg'; +export * as btc from './btc.svg'; +export * as btcd from './btcd.svg'; +export * as btch from './btch.svg'; +export * as btcp from './btcp.svg'; +export * as btcz from './btcz.svg'; +export * as btdx from './btdx.svg'; +export * as btg from './btg.svg'; +export * as btm from './btm.svg'; +export * as bts from './bts.svg'; +export * as btt from './btt.svg'; +export * as btx from './btx.svg'; +export * as burst from './burst.svg'; +export * as bze from './bze.svg'; +export * as call from './call.svg'; +export * as cc from './cc.svg'; +export * as cdn from './cdn.svg'; +export * as cdt from './cdt.svg'; +export * as cenz from './cenz.svg'; +export * as chain from './chain.svg'; +export * as chat from './chat.svg'; +export * as chips from './chips.svg'; +export * as chsb from './chsb.svg'; +export * as cix from './cix.svg'; +export * as clam from './clam.svg'; +export * as cloak from './cloak.svg'; +export * as cmm from './cmm.svg'; +export * as cmt from './cmt.svg'; +export * as cnd from './cnd.svg'; +export * as cnx from './cnx.svg'; +export * as cny from './cny.svg'; +export * as cob from './cob.svg'; +export * as colx from './colx.svg'; +export * as comp from './comp.svg'; +export * as coqui from './coqui.svg'; +export * as cred from './cred.svg'; +export * as crpt from './crpt.svg'; +export * as crv from './crv.svg'; +export * as crw from './crw.svg'; +export * as cs from './cs.svg'; +export * as ctr from './ctr.svg'; +export * as ctxc from './ctxc.svg'; +export * as cvc from './cvc.svg'; +export * as dai from './dai.svg'; +export * as dash from './dash.svg'; +export * as dat from './dat.svg'; +export * as data from './data.svg'; +export * as dbc from './dbc.svg'; +export * as dcn from './dcn.svg'; +export * as dcr from './dcr.svg'; +export * as deez from './deez.svg'; +export * as dent from './dent.svg'; +export * as dew from './dew.svg'; +export * as dgb from './dgb.svg'; +export * as dgd from './dgd.svg'; +export * as dlt from './dlt.svg'; +export * as dnt from './dnt.svg'; +export * as dock from './dock.svg'; +export * as doge from './doge.svg'; +export * as dot from './dot.svg'; +export * as drgn from './drgn.svg'; +export * as drop from './drop.svg'; +export * as dta from './dta.svg'; +export * as dth from './dth.svg'; +export * as dtr from './dtr.svg'; +export * as ebst from './ebst.svg'; +export * as eca from './eca.svg'; +export * as edg from './edg.svg'; +export * as edo from './edo.svg'; +export * as edoge from './edoge.svg'; +export * as ela from './ela.svg'; +export * as elec from './elec.svg'; +export * as elf from './elf.svg'; +export * as elix from './elix.svg'; +export * as ella from './ella.svg'; +export * as emb from './emb.svg'; +export * as emc from './emc.svg'; +export * as emc2 from './emc2.svg'; +export * as eng from './eng.svg'; +export * as enj from './enj.svg'; +export * as entrp from './entrp.svg'; +export * as eon from './eon.svg'; +export * as eop from './eop.svg'; +export * as eos from './eos.svg'; +export * as eqli from './eqli.svg'; +export * as equa from './equa.svg'; +export * as etc from './etc.svg'; +export * as eth from './eth.svg'; +export * as eth_white from './eth_white.svg'; +export * as ethos from './ethos.svg'; +export * as etn from './etn.svg'; +export * as etp from './etp.svg'; +export * as eur from './eur.svg'; +export * as evx from './evx.svg'; +export * as exmo from './exmo.svg'; +export * as exp from './exp.svg'; +export * as fair from './fair.svg'; +export * as fct from './fct.svg'; +export * as fil from './fil.svg'; +export * as fjc from './fjc.svg'; +export * as fldc from './fldc.svg'; +export * as flo from './flo.svg'; +export * as flux from './flux.svg'; +export * as fsn from './fsn.svg'; +export * as ftc from './ftc.svg'; +export * as fuel from './fuel.svg'; +export * as fun from './fun.svg'; +export * as game from './game.svg'; +export * as gas from './gas.svg'; +export * as gbp from './gbp.svg'; +export * as gbx from './gbx.svg'; +export * as gbyte from './gbyte.svg'; +export * as generic from './generic.svg'; +export * as gin from './gin.svg'; +export * as glxt from './glxt.svg'; +export * as gmr from './gmr.svg'; +export * as gno from './gno.svg'; +export * as gnt from './gnt.svg'; +export * as gold from './gold.svg'; +export * as grc from './grc.svg'; +export * as grin from './grin.svg'; +export * as grs from './grs.svg'; +export * as grt from './grt.svg'; +export * as gsc from './gsc.svg'; +export * as gto from './gto.svg'; +export * as gup from './gup.svg'; +export * as gusd from './gusd.svg'; +export * as gvt from './gvt.svg'; +export * as gxs from './gxs.svg'; +export * as gzr from './gzr.svg'; +export * as hight from './hight.svg'; +export * as hns from './hns.svg'; +export * as hodl from './hodl.svg'; +export * as hot from './hot.svg'; +export * as hpb from './hpb.svg'; +export * as hsr from './hsr.svg'; +export * as ht from './ht.svg'; +export * as html from './html.svg'; +export * as huc from './huc.svg'; +export * as husd from './husd.svg'; +export * as hush from './hush.svg'; +export * as icn from './icn.svg'; +export * as icp from './icp.svg'; +export * as icx from './icx.svg'; +export * as ignis from './ignis.svg'; +export * as ilk from './ilk.svg'; +export * as ink from './ink.svg'; +export * as ins from './ins.svg'; +export * as ion from './ion.svg'; +export * as iop from './iop.svg'; +export * as iost from './iost.svg'; +export * as iotx from './iotx.svg'; +export * as iq from './iq.svg'; +export * as itc from './itc.svg'; +export * as jnt from './jnt.svg'; +export * as jpy from './jpy.svg'; +export * as kcs from './kcs.svg'; +export * as kin from './kin.svg'; +export * as klown from './klown.svg'; +export * as kmd from './kmd.svg'; +export * as knc from './knc.svg'; +export * as krb from './krb.svg'; +export * as ksm from './ksm.svg'; +export * as lbc from './lbc.svg'; +export * as lend from './lend.svg'; +export * as leo from './leo.svg'; +export * as link from './link.svg'; +export * as lkk from './lkk.svg'; +export * as loom from './loom.svg'; +export * as lpt from './lpt.svg'; +export * as lrc from './lrc.svg'; +export * as lsk from './lsk.svg'; +export * as ltc from './ltc.svg'; +export * as lun from './lun.svg'; +export * as maid from './maid.svg'; +export * as mana from './mana.svg'; +export * as matic from './matic.svg'; +export * as max from './max.svg'; +export * as mcap from './mcap.svg'; +export * as mco from './mco.svg'; +export * as mda from './mda.svg'; +export * as mds from './mds.svg'; +export * as med from './med.svg'; +export * as meetone from './meetone.svg'; +export * as mft from './mft.svg'; +export * as miota from './miota.svg'; +export * as mith from './mith.svg'; +export * as mkr from './mkr.svg'; +export * as mln from './mln.svg'; +export * as mnx from './mnx.svg'; +export * as mnz from './mnz.svg'; +export * as moac from './moac.svg'; +export * as mod from './mod.svg'; +export * as mona from './mona.svg'; +export * as msr from './msr.svg'; +export * as mth from './mth.svg'; +export * as mtl from './mtl.svg'; +export * as music from './music.svg'; +export * as mzc from './mzc.svg'; +export * as nano from './nano.svg'; +export * as nas from './nas.svg'; +export * as nav from './nav.svg'; +export * as ncash from './ncash.svg'; +export * as ndz from './ndz.svg'; +export * as nebl from './nebl.svg'; +export * as neo from './neo.svg'; +export * as neos from './neos.svg'; +export * as neu from './neu.svg'; +export * as nexo from './nexo.svg'; +export * as ngc from './ngc.svg'; +export * as nio from './nio.svg'; +export * as nkn from './nkn.svg'; +export * as nlc2 from './nlc2.svg'; +export * as nlg from './nlg.svg'; +export * as nmc from './nmc.svg'; +export * as nmr from './nmr.svg'; +export * as npxs from './npxs.svg'; +export * as ntbc from './ntbc.svg'; +export * as nuls from './nuls.svg'; +export * as nxs from './nxs.svg'; +export * as nxt from './nxt.svg'; +export * as oax from './oax.svg'; +export * as ok from './ok.svg'; +export * as omg from './omg.svg'; +export * as omni from './omni.svg'; +export * as one from './one.svg'; +export * as ong from './ong.svg'; +export * as ont from './ont.svg'; +export * as oot from './oot.svg'; +export * as ost from './ost.svg'; +export * as ox from './ox.svg'; +export * as oxt from './oxt.svg'; +export * as pac from './pac.svg'; +export * as part from './part.svg'; +export * as pasc from './pasc.svg'; +export * as pasl from './pasl.svg'; +export * as pax from './pax.svg'; +export * as paxg from './paxg.svg'; +export * as pay from './pay.svg'; +export * as payx from './payx.svg'; +export * as pink from './pink.svg'; +export * as pirl from './pirl.svg'; +export * as pivx from './pivx.svg'; +export * as plr from './plr.svg'; +export * as poa from './poa.svg'; +export * as poe from './poe.svg'; +export * as polis from './polis.svg'; +export * as poly from './poly.svg'; +export * as pot from './pot.svg'; +export * as powr from './powr.svg'; +export * as ppc from './ppc.svg'; +export * as ppp from './ppp.svg'; +export * as ppt from './ppt.svg'; +export * as pre from './pre.svg'; +export * as prl from './prl.svg'; +export * as pungo from './pungo.svg'; +export * as pura from './pura.svg'; +export * as qash from './qash.svg'; +export * as qiwi from './qiwi.svg'; +export * as qlc from './qlc.svg'; +export * as qrl from './qrl.svg'; +export * as qsp from './qsp.svg'; +export * as qtum from './qtum.svg'; +export * as r from './r.svg'; +export * as rads from './rads.svg'; +export * as rap from './rap.svg'; +export * as rcn from './rcn.svg'; +export * as rdd from './rdd.svg'; +export * as rdn from './rdn.svg'; +export * as ren from './ren.svg'; +export * as rep from './rep.svg'; +export * as repv2 from './repv2.svg'; +export * as req from './req.svg'; +export * as rhoc from './rhoc.svg'; +export * as ric from './ric.svg'; +export * as rise from './rise.svg'; +export * as rlc from './rlc.svg'; +export * as rpx from './rpx.svg'; +export * as rub from './rub.svg'; +export * as rvn from './rvn.svg'; +export * as ryo from './ryo.svg'; +export * as safe from './safe.svg'; +export * as safemoon from './safemoon.svg'; +export * as sai from './sai.svg'; +export * as salt from './salt.svg'; +export * as san from './san.svg'; +export * as sand from './sand.svg'; +export * as sbd from './sbd.svg'; +export * as sberbank from './sberbank.svg'; +export * as sc from './sc.svg'; +export * as shift from './shift.svg'; +export * as sib from './sib.svg'; +export * as sin from './sin.svg'; +export * as skl from './skl.svg'; +export * as sky from './sky.svg'; +export * as slr from './slr.svg'; +export * as sls from './sls.svg'; +export * as smart from './smart.svg'; +export * as sngls from './sngls.svg'; +export * as snm from './snm.svg'; +export * as snt from './snt.svg'; +export * as snx from './snx.svg'; +export * as soc from './soc.svg'; +export * as sol from './sol.svg'; +export * as spacehbit from './spacehbit.svg'; +export * as spank from './spank.svg'; +export * as sphtx from './sphtx.svg'; +export * as srn from './srn.svg'; +export * as stak from './stak.svg'; +export * as start from './start.svg'; +export * as steem from './steem.svg'; +export * as storj from './storj.svg'; +export * as storm from './storm.svg'; +export * as stox from './stox.svg'; +export * as stq from './stq.svg'; +export * as strat from './strat.svg'; +export * as stx from './stx.svg'; +export * as sub from './sub.svg'; +export * as sumo from './sumo.svg'; +export * as sushi from './sushi.svg'; +export * as sys from './sys.svg'; +export * as taas from './taas.svg'; +export * as tau from './tau.svg'; +export * as tbx from './tbx.svg'; +export * as tel from './tel.svg'; +export * as ten from './ten.svg'; +export * as tern from './tern.svg'; +export * as tgch from './tgch.svg'; +export * as theta from './theta.svg'; +export * as tix from './tix.svg'; +export * as tkn from './tkn.svg'; +export * as tks from './tks.svg'; +export * as tnb from './tnb.svg'; +export * as tnc from './tnc.svg'; +export * as tnt from './tnt.svg'; +export * as tomo from './tomo.svg'; +export * as tpay from './tpay.svg'; +export * as trig from './trig.svg'; +export * as trtl from './trtl.svg'; +export * as trx from './trx.svg'; +export * as tusd from './tusd.svg'; +export * as tzc from './tzc.svg'; +export * as ubq from './ubq.svg'; +export * as uma from './uma.svg'; +export * as uni from './uni.svg'; +export * as unity from './unity.svg'; +export * as usd from './usd.svg'; +export * as usdc from './usdc.svg'; +export * as usdt from './usdt.svg'; +export * as utk from './utk.svg'; +export * as veri from './veri.svg'; +export * as vet from './vet.svg'; +export * as via from './via.svg'; +export * as vib from './vib.svg'; +export * as vibe from './vibe.svg'; +export * as vivo from './vivo.svg'; +export * as vrc from './vrc.svg'; +export * as vrsc from './vrsc.svg'; +export * as vtc from './vtc.svg'; +export * as vtho from './vtho.svg'; +export * as wabi from './wabi.svg'; +export * as wan from './wan.svg'; +export * as waves from './waves.svg'; +export * as wax from './wax.svg'; +export * as wbtc from './wbtc.svg'; +export * as wgr from './wgr.svg'; +export * as wicc from './wicc.svg'; +export * as wings from './wings.svg'; +export * as wpr from './wpr.svg'; +export * as wtc from './wtc.svg'; +export * as x from './x.svg'; +export * as xas from './xas.svg'; +export * as xbc from './xbc.svg'; +export * as xbp from './xbp.svg'; +export * as xby from './xby.svg'; +export * as xcp from './xcp.svg'; +export * as xdn from './xdn.svg'; +export * as xem from './xem.svg'; +export * as xin from './xin.svg'; +export * as xlm from './xlm.svg'; +export * as xmcc from './xmcc.svg'; +export * as xmg from './xmg.svg'; +export * as xmo from './xmo.svg'; +export * as xmr from './xmr.svg'; +export * as xmy from './xmy.svg'; +export * as xp from './xp.svg'; +export * as xpa from './xpa.svg'; +export * as xpm from './xpm.svg'; +export * as xpr from './xpr.svg'; +export * as xrp from './xrp.svg'; +export * as xsg from './xsg.svg'; +export * as xtz from './xtz.svg'; +export * as xuc from './xuc.svg'; +export * as xvc from './xvc.svg'; +export * as xvg from './xvg.svg'; +export * as xzc from './xzc.svg'; +export * as yfi from './yfi.svg'; +export * as yoyow from './yoyow.svg'; +export * as zcl from './zcl.svg'; +export * as zec from './zec.svg'; +export * as zel from './zel.svg'; +export * as zen from './zen.svg'; +export * as zest from './zest.svg'; +export * as zil from './zil.svg'; +export * as zilla from './zilla.svg'; +export * as zrx from './zrx.svg'; \ No newline at end of file diff --git a/src/icons/$pac.svg b/src/icons/pac.svg similarity index 100% rename from src/icons/$pac.svg rename to src/icons/pac.svg From dc2dce76df8a4f8f53f6f30199b38c07bef5f420 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Mon, 14 Aug 2023 19:22:13 +0100 Subject: [PATCH 12/54] Add prepare_meta script --- prepare_meta.sh | 26 +++ src/icons/index.ts | 471 --------------------------------------------- 2 files changed, 26 insertions(+), 471 deletions(-) create mode 100644 prepare_meta.sh delete mode 100644 src/icons/index.ts diff --git a/prepare_meta.sh b/prepare_meta.sh new file mode 100644 index 0000000..957542d --- /dev/null +++ b/prepare_meta.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -e + +export DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +META_DIR_EXTERNAL=$DIR/skale-network/metadata/ +META_DIR=$DIR/src/meta/ + +if [ -d "$META_DIR" ]; then + echo "Removing ${META_DIR}..." + rm -rf $META_DIR +else + echo "${META_DIR} not found, skipping" +fi + +if [ -d "$META_DIR_EXTERNAL" ]; then + echo "Copying ${META_DIR_EXTERNAL} -> ${META_DIR}..." + cp -R $META_DIR_EXTERNAL $META_DIR +else + cp -R $DIR/skale-network/metadata/mainnet/ $META_DIR + echo "${META_DIR_EXTERNAL} not found, copying Mainnet meta" +fi + +node generate-imports.js ./src/meta +node generate-imports.js ./src/icons \ No newline at end of file diff --git a/src/icons/index.ts b/src/icons/index.ts deleted file mode 100644 index 5b947a4..0000000 --- a/src/icons/index.ts +++ /dev/null @@ -1,471 +0,0 @@ -export * as _0xbtc from './_0xbtc.svg'; -export * as _2give from './_2give.svg'; -export * as aave from './aave.svg'; -export * as abt from './abt.svg'; -export * as act from './act.svg'; -export * as actn from './actn.svg'; -export * as ada from './ada.svg'; -export * as add from './add.svg'; -export * as adx from './adx.svg'; -export * as ae from './ae.svg'; -export * as aeon from './aeon.svg'; -export * as aeur from './aeur.svg'; -export * as agi from './agi.svg'; -export * as agrs from './agrs.svg'; -export * as aion from './aion.svg'; -export * as algo from './algo.svg'; -export * as amb from './amb.svg'; -export * as amp from './amp.svg'; -export * as ampl from './ampl.svg'; -export * as ankr from './ankr.svg'; -export * as ant from './ant.svg'; -export * as apex from './apex.svg'; -export * as appc from './appc.svg'; -export * as ardr from './ardr.svg'; -export * as arg from './arg.svg'; -export * as ark from './ark.svg'; -export * as arn from './arn.svg'; -export * as arnx from './arnx.svg'; -export * as ary from './ary.svg'; -export * as ast from './ast.svg'; -export * as atm from './atm.svg'; -export * as atom from './atom.svg'; -export * as audr from './audr.svg'; -export * as auto from './auto.svg'; -export * as aywa from './aywa.svg'; -export * as bab from './bab.svg'; -export * as bal from './bal.svg'; -export * as band from './band.svg'; -export * as bat from './bat.svg'; -export * as bay from './bay.svg'; -export * as bcbc from './bcbc.svg'; -export * as bcc from './bcc.svg'; -export * as bcd from './bcd.svg'; -export * as bch from './bch.svg'; -export * as bcio from './bcio.svg'; -export * as bcn from './bcn.svg'; -export * as bco from './bco.svg'; -export * as bcpt from './bcpt.svg'; -export * as bdl from './bdl.svg'; -export * as beam from './beam.svg'; -export * as bela from './bela.svg'; -export * as bix from './bix.svg'; -export * as blcn from './blcn.svg'; -export * as blk from './blk.svg'; -export * as block from './block.svg'; -export * as blz from './blz.svg'; -export * as bnb from './bnb.svg'; -export * as bnt from './bnt.svg'; -export * as bnty from './bnty.svg'; -export * as booty from './booty.svg'; -export * as bos from './bos.svg'; -export * as bpt from './bpt.svg'; -export * as bq from './bq.svg'; -export * as brd from './brd.svg'; -export * as bsd from './bsd.svg'; -export * as bsv from './bsv.svg'; -export * as btc from './btc.svg'; -export * as btcd from './btcd.svg'; -export * as btch from './btch.svg'; -export * as btcp from './btcp.svg'; -export * as btcz from './btcz.svg'; -export * as btdx from './btdx.svg'; -export * as btg from './btg.svg'; -export * as btm from './btm.svg'; -export * as bts from './bts.svg'; -export * as btt from './btt.svg'; -export * as btx from './btx.svg'; -export * as burst from './burst.svg'; -export * as bze from './bze.svg'; -export * as call from './call.svg'; -export * as cc from './cc.svg'; -export * as cdn from './cdn.svg'; -export * as cdt from './cdt.svg'; -export * as cenz from './cenz.svg'; -export * as chain from './chain.svg'; -export * as chat from './chat.svg'; -export * as chips from './chips.svg'; -export * as chsb from './chsb.svg'; -export * as cix from './cix.svg'; -export * as clam from './clam.svg'; -export * as cloak from './cloak.svg'; -export * as cmm from './cmm.svg'; -export * as cmt from './cmt.svg'; -export * as cnd from './cnd.svg'; -export * as cnx from './cnx.svg'; -export * as cny from './cny.svg'; -export * as cob from './cob.svg'; -export * as colx from './colx.svg'; -export * as comp from './comp.svg'; -export * as coqui from './coqui.svg'; -export * as cred from './cred.svg'; -export * as crpt from './crpt.svg'; -export * as crv from './crv.svg'; -export * as crw from './crw.svg'; -export * as cs from './cs.svg'; -export * as ctr from './ctr.svg'; -export * as ctxc from './ctxc.svg'; -export * as cvc from './cvc.svg'; -export * as dai from './dai.svg'; -export * as dash from './dash.svg'; -export * as dat from './dat.svg'; -export * as data from './data.svg'; -export * as dbc from './dbc.svg'; -export * as dcn from './dcn.svg'; -export * as dcr from './dcr.svg'; -export * as deez from './deez.svg'; -export * as dent from './dent.svg'; -export * as dew from './dew.svg'; -export * as dgb from './dgb.svg'; -export * as dgd from './dgd.svg'; -export * as dlt from './dlt.svg'; -export * as dnt from './dnt.svg'; -export * as dock from './dock.svg'; -export * as doge from './doge.svg'; -export * as dot from './dot.svg'; -export * as drgn from './drgn.svg'; -export * as drop from './drop.svg'; -export * as dta from './dta.svg'; -export * as dth from './dth.svg'; -export * as dtr from './dtr.svg'; -export * as ebst from './ebst.svg'; -export * as eca from './eca.svg'; -export * as edg from './edg.svg'; -export * as edo from './edo.svg'; -export * as edoge from './edoge.svg'; -export * as ela from './ela.svg'; -export * as elec from './elec.svg'; -export * as elf from './elf.svg'; -export * as elix from './elix.svg'; -export * as ella from './ella.svg'; -export * as emb from './emb.svg'; -export * as emc from './emc.svg'; -export * as emc2 from './emc2.svg'; -export * as eng from './eng.svg'; -export * as enj from './enj.svg'; -export * as entrp from './entrp.svg'; -export * as eon from './eon.svg'; -export * as eop from './eop.svg'; -export * as eos from './eos.svg'; -export * as eqli from './eqli.svg'; -export * as equa from './equa.svg'; -export * as etc from './etc.svg'; -export * as eth from './eth.svg'; -export * as eth_white from './eth_white.svg'; -export * as ethos from './ethos.svg'; -export * as etn from './etn.svg'; -export * as etp from './etp.svg'; -export * as eur from './eur.svg'; -export * as evx from './evx.svg'; -export * as exmo from './exmo.svg'; -export * as exp from './exp.svg'; -export * as fair from './fair.svg'; -export * as fct from './fct.svg'; -export * as fil from './fil.svg'; -export * as fjc from './fjc.svg'; -export * as fldc from './fldc.svg'; -export * as flo from './flo.svg'; -export * as flux from './flux.svg'; -export * as fsn from './fsn.svg'; -export * as ftc from './ftc.svg'; -export * as fuel from './fuel.svg'; -export * as fun from './fun.svg'; -export * as game from './game.svg'; -export * as gas from './gas.svg'; -export * as gbp from './gbp.svg'; -export * as gbx from './gbx.svg'; -export * as gbyte from './gbyte.svg'; -export * as generic from './generic.svg'; -export * as gin from './gin.svg'; -export * as glxt from './glxt.svg'; -export * as gmr from './gmr.svg'; -export * as gno from './gno.svg'; -export * as gnt from './gnt.svg'; -export * as gold from './gold.svg'; -export * as grc from './grc.svg'; -export * as grin from './grin.svg'; -export * as grs from './grs.svg'; -export * as grt from './grt.svg'; -export * as gsc from './gsc.svg'; -export * as gto from './gto.svg'; -export * as gup from './gup.svg'; -export * as gusd from './gusd.svg'; -export * as gvt from './gvt.svg'; -export * as gxs from './gxs.svg'; -export * as gzr from './gzr.svg'; -export * as hight from './hight.svg'; -export * as hns from './hns.svg'; -export * as hodl from './hodl.svg'; -export * as hot from './hot.svg'; -export * as hpb from './hpb.svg'; -export * as hsr from './hsr.svg'; -export * as ht from './ht.svg'; -export * as html from './html.svg'; -export * as huc from './huc.svg'; -export * as husd from './husd.svg'; -export * as hush from './hush.svg'; -export * as icn from './icn.svg'; -export * as icp from './icp.svg'; -export * as icx from './icx.svg'; -export * as ignis from './ignis.svg'; -export * as ilk from './ilk.svg'; -export * as ink from './ink.svg'; -export * as ins from './ins.svg'; -export * as ion from './ion.svg'; -export * as iop from './iop.svg'; -export * as iost from './iost.svg'; -export * as iotx from './iotx.svg'; -export * as iq from './iq.svg'; -export * as itc from './itc.svg'; -export * as jnt from './jnt.svg'; -export * as jpy from './jpy.svg'; -export * as kcs from './kcs.svg'; -export * as kin from './kin.svg'; -export * as klown from './klown.svg'; -export * as kmd from './kmd.svg'; -export * as knc from './knc.svg'; -export * as krb from './krb.svg'; -export * as ksm from './ksm.svg'; -export * as lbc from './lbc.svg'; -export * as lend from './lend.svg'; -export * as leo from './leo.svg'; -export * as link from './link.svg'; -export * as lkk from './lkk.svg'; -export * as loom from './loom.svg'; -export * as lpt from './lpt.svg'; -export * as lrc from './lrc.svg'; -export * as lsk from './lsk.svg'; -export * as ltc from './ltc.svg'; -export * as lun from './lun.svg'; -export * as maid from './maid.svg'; -export * as mana from './mana.svg'; -export * as matic from './matic.svg'; -export * as max from './max.svg'; -export * as mcap from './mcap.svg'; -export * as mco from './mco.svg'; -export * as mda from './mda.svg'; -export * as mds from './mds.svg'; -export * as med from './med.svg'; -export * as meetone from './meetone.svg'; -export * as mft from './mft.svg'; -export * as miota from './miota.svg'; -export * as mith from './mith.svg'; -export * as mkr from './mkr.svg'; -export * as mln from './mln.svg'; -export * as mnx from './mnx.svg'; -export * as mnz from './mnz.svg'; -export * as moac from './moac.svg'; -export * as mod from './mod.svg'; -export * as mona from './mona.svg'; -export * as msr from './msr.svg'; -export * as mth from './mth.svg'; -export * as mtl from './mtl.svg'; -export * as music from './music.svg'; -export * as mzc from './mzc.svg'; -export * as nano from './nano.svg'; -export * as nas from './nas.svg'; -export * as nav from './nav.svg'; -export * as ncash from './ncash.svg'; -export * as ndz from './ndz.svg'; -export * as nebl from './nebl.svg'; -export * as neo from './neo.svg'; -export * as neos from './neos.svg'; -export * as neu from './neu.svg'; -export * as nexo from './nexo.svg'; -export * as ngc from './ngc.svg'; -export * as nio from './nio.svg'; -export * as nkn from './nkn.svg'; -export * as nlc2 from './nlc2.svg'; -export * as nlg from './nlg.svg'; -export * as nmc from './nmc.svg'; -export * as nmr from './nmr.svg'; -export * as npxs from './npxs.svg'; -export * as ntbc from './ntbc.svg'; -export * as nuls from './nuls.svg'; -export * as nxs from './nxs.svg'; -export * as nxt from './nxt.svg'; -export * as oax from './oax.svg'; -export * as ok from './ok.svg'; -export * as omg from './omg.svg'; -export * as omni from './omni.svg'; -export * as one from './one.svg'; -export * as ong from './ong.svg'; -export * as ont from './ont.svg'; -export * as oot from './oot.svg'; -export * as ost from './ost.svg'; -export * as ox from './ox.svg'; -export * as oxt from './oxt.svg'; -export * as pac from './pac.svg'; -export * as part from './part.svg'; -export * as pasc from './pasc.svg'; -export * as pasl from './pasl.svg'; -export * as pax from './pax.svg'; -export * as paxg from './paxg.svg'; -export * as pay from './pay.svg'; -export * as payx from './payx.svg'; -export * as pink from './pink.svg'; -export * as pirl from './pirl.svg'; -export * as pivx from './pivx.svg'; -export * as plr from './plr.svg'; -export * as poa from './poa.svg'; -export * as poe from './poe.svg'; -export * as polis from './polis.svg'; -export * as poly from './poly.svg'; -export * as pot from './pot.svg'; -export * as powr from './powr.svg'; -export * as ppc from './ppc.svg'; -export * as ppp from './ppp.svg'; -export * as ppt from './ppt.svg'; -export * as pre from './pre.svg'; -export * as prl from './prl.svg'; -export * as pungo from './pungo.svg'; -export * as pura from './pura.svg'; -export * as qash from './qash.svg'; -export * as qiwi from './qiwi.svg'; -export * as qlc from './qlc.svg'; -export * as qrl from './qrl.svg'; -export * as qsp from './qsp.svg'; -export * as qtum from './qtum.svg'; -export * as r from './r.svg'; -export * as rads from './rads.svg'; -export * as rap from './rap.svg'; -export * as rcn from './rcn.svg'; -export * as rdd from './rdd.svg'; -export * as rdn from './rdn.svg'; -export * as ren from './ren.svg'; -export * as rep from './rep.svg'; -export * as repv2 from './repv2.svg'; -export * as req from './req.svg'; -export * as rhoc from './rhoc.svg'; -export * as ric from './ric.svg'; -export * as rise from './rise.svg'; -export * as rlc from './rlc.svg'; -export * as rpx from './rpx.svg'; -export * as rub from './rub.svg'; -export * as rvn from './rvn.svg'; -export * as ryo from './ryo.svg'; -export * as safe from './safe.svg'; -export * as safemoon from './safemoon.svg'; -export * as sai from './sai.svg'; -export * as salt from './salt.svg'; -export * as san from './san.svg'; -export * as sand from './sand.svg'; -export * as sbd from './sbd.svg'; -export * as sberbank from './sberbank.svg'; -export * as sc from './sc.svg'; -export * as shift from './shift.svg'; -export * as sib from './sib.svg'; -export * as sin from './sin.svg'; -export * as skl from './skl.svg'; -export * as sky from './sky.svg'; -export * as slr from './slr.svg'; -export * as sls from './sls.svg'; -export * as smart from './smart.svg'; -export * as sngls from './sngls.svg'; -export * as snm from './snm.svg'; -export * as snt from './snt.svg'; -export * as snx from './snx.svg'; -export * as soc from './soc.svg'; -export * as sol from './sol.svg'; -export * as spacehbit from './spacehbit.svg'; -export * as spank from './spank.svg'; -export * as sphtx from './sphtx.svg'; -export * as srn from './srn.svg'; -export * as stak from './stak.svg'; -export * as start from './start.svg'; -export * as steem from './steem.svg'; -export * as storj from './storj.svg'; -export * as storm from './storm.svg'; -export * as stox from './stox.svg'; -export * as stq from './stq.svg'; -export * as strat from './strat.svg'; -export * as stx from './stx.svg'; -export * as sub from './sub.svg'; -export * as sumo from './sumo.svg'; -export * as sushi from './sushi.svg'; -export * as sys from './sys.svg'; -export * as taas from './taas.svg'; -export * as tau from './tau.svg'; -export * as tbx from './tbx.svg'; -export * as tel from './tel.svg'; -export * as ten from './ten.svg'; -export * as tern from './tern.svg'; -export * as tgch from './tgch.svg'; -export * as theta from './theta.svg'; -export * as tix from './tix.svg'; -export * as tkn from './tkn.svg'; -export * as tks from './tks.svg'; -export * as tnb from './tnb.svg'; -export * as tnc from './tnc.svg'; -export * as tnt from './tnt.svg'; -export * as tomo from './tomo.svg'; -export * as tpay from './tpay.svg'; -export * as trig from './trig.svg'; -export * as trtl from './trtl.svg'; -export * as trx from './trx.svg'; -export * as tusd from './tusd.svg'; -export * as tzc from './tzc.svg'; -export * as ubq from './ubq.svg'; -export * as uma from './uma.svg'; -export * as uni from './uni.svg'; -export * as unity from './unity.svg'; -export * as usd from './usd.svg'; -export * as usdc from './usdc.svg'; -export * as usdt from './usdt.svg'; -export * as utk from './utk.svg'; -export * as veri from './veri.svg'; -export * as vet from './vet.svg'; -export * as via from './via.svg'; -export * as vib from './vib.svg'; -export * as vibe from './vibe.svg'; -export * as vivo from './vivo.svg'; -export * as vrc from './vrc.svg'; -export * as vrsc from './vrsc.svg'; -export * as vtc from './vtc.svg'; -export * as vtho from './vtho.svg'; -export * as wabi from './wabi.svg'; -export * as wan from './wan.svg'; -export * as waves from './waves.svg'; -export * as wax from './wax.svg'; -export * as wbtc from './wbtc.svg'; -export * as wgr from './wgr.svg'; -export * as wicc from './wicc.svg'; -export * as wings from './wings.svg'; -export * as wpr from './wpr.svg'; -export * as wtc from './wtc.svg'; -export * as x from './x.svg'; -export * as xas from './xas.svg'; -export * as xbc from './xbc.svg'; -export * as xbp from './xbp.svg'; -export * as xby from './xby.svg'; -export * as xcp from './xcp.svg'; -export * as xdn from './xdn.svg'; -export * as xem from './xem.svg'; -export * as xin from './xin.svg'; -export * as xlm from './xlm.svg'; -export * as xmcc from './xmcc.svg'; -export * as xmg from './xmg.svg'; -export * as xmo from './xmo.svg'; -export * as xmr from './xmr.svg'; -export * as xmy from './xmy.svg'; -export * as xp from './xp.svg'; -export * as xpa from './xpa.svg'; -export * as xpm from './xpm.svg'; -export * as xpr from './xpr.svg'; -export * as xrp from './xrp.svg'; -export * as xsg from './xsg.svg'; -export * as xtz from './xtz.svg'; -export * as xuc from './xuc.svg'; -export * as xvc from './xvc.svg'; -export * as xvg from './xvg.svg'; -export * as xzc from './xzc.svg'; -export * as yfi from './yfi.svg'; -export * as yoyow from './yoyow.svg'; -export * as zcl from './zcl.svg'; -export * as zec from './zec.svg'; -export * as zel from './zel.svg'; -export * as zen from './zen.svg'; -export * as zest from './zest.svg'; -export * as zil from './zil.svg'; -export * as zilla from './zilla.svg'; -export * as zrx from './zrx.svg'; \ No newline at end of file From 1f201fb3a2f012ae11ccac3505a63e4240b11950 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Mon, 14 Aug 2023 19:59:49 +0100 Subject: [PATCH 13/54] Run prettier --- src/Metaport.tsx | 52 +- .../AmountErrorMessage/AmountErrorMessage.tsx | 40 +- src/components/AmountErrorMessage/index.ts | 2 +- src/components/AmountInput/AmountInput.tsx | 52 +- src/components/AmountInput/index.ts | 2 +- src/components/ChainApps/ChainApps.tsx | 52 +- src/components/ChainApps/index.ts | 2 +- src/components/ChainIcon/ChainIcon.tsx | 39 +- src/components/ChainIcon/index.ts | 2 +- src/components/ChainsList/ChainsList.tsx | 171 ++--- src/components/ChainsList/index.ts | 2 +- src/components/ErrorMessage/ErrorMessage.tsx | 110 ++-- src/components/ErrorMessage/index.ts | 2 +- src/components/Metaport/Metaport.tsx | 137 ++-- src/components/Metaport/index.ts | 2 +- src/components/SkConnect/SkConnect.tsx | 330 +++++----- src/components/SkConnect/index.ts | 2 +- src/components/SkPaper/SkPaper.tsx | 48 +- src/components/SkPaper/index.ts | 2 +- .../SkeletonLoader/SkeletonLoader.tsx | 4 +- src/components/SkeletonLoader/index.ts | 2 +- src/components/Stepper/SkStepper.tsx | 202 +++--- src/components/Stepper/index.ts | 2 +- .../SwitchDirection/SwitchDirection.tsx | 70 +-- src/components/SwitchDirection/index.ts | 2 +- src/components/TokenIcon/TokenIcon.tsx | 28 +- src/components/TokenIcon/index.ts | 2 +- src/components/TokenList/TokenBalance.tsx | 50 +- src/components/TokenList/TokenList.tsx | 113 ++-- src/components/TokenList/index.ts | 2 +- .../TokenListSection/TokenListSection.tsx | 73 +-- src/components/TokenListSection/index.ts | 2 +- src/components/Widget/Widget.mdx | 15 +- src/components/Widget/Widget.stories.tsx | 24 +- src/components/Widget/Widget.tsx | 190 +++--- src/components/Widget/index.ts | 2 +- src/components/WidgetBody/WidgetBody.tsx | 59 +- src/components/WidgetBody/index.ts | 2 +- src/components/WidgetUI/WidgetUI.tsx | 154 +++-- src/components/WidgetUI/index.ts | 2 +- src/core/actions/action.ts | 448 +++++++------ src/core/actions/actionState.ts | 78 +-- src/core/actions/checks.ts | 291 ++++----- src/core/actions/erc20.ts | 594 ++++++++---------- src/core/actions/index.ts | 103 ++- src/core/chain_id.ts | 28 +- src/core/community_pool.ts | 6 +- src/core/constants.ts | 105 ++-- src/core/contracts.ts | 54 +- src/core/convertation.ts | 10 +- src/core/dataclasses/ErrorMessage.ts | 65 +- src/core/dataclasses/EthTokenData.ts | 37 +- src/core/dataclasses/Position.ts | 26 +- src/core/dataclasses/StepMetadata.ts | 129 ++-- src/core/dataclasses/TokenData.ts | 71 ++- src/core/dataclasses/TokenType.ts | 18 +- src/core/dataclasses/TransferRequestStatus.ts | 15 +- src/core/dataclasses/View.ts | 13 +- src/core/dataclasses/index.ts | 12 +- src/core/ethers.ts | 50 +- src/core/events.ts | 325 +++++----- src/core/explorer.ts | 22 +- src/core/faucet.ts | 4 +- src/core/fee_calculator.ts | 46 +- src/core/gas_station.ts | 11 +- src/core/helper.ts | 90 ++- src/core/interfaces/ChainsMetadata.ts | 24 +- src/core/interfaces/CheckRes.ts | 9 +- src/core/interfaces/CommunityPoolData.ts | 15 +- src/core/interfaces/Config.ts | 24 +- src/core/interfaces/RouteParams.ts | 11 +- src/core/interfaces/Theme.ts | 18 +- src/core/interfaces/TokenDataMap.ts | 36 +- src/core/interfaces/TokenMetadata.ts | 12 +- src/core/interfaces/Tokens.ts | 30 +- src/core/interfaces/TransactionHistory.ts | 17 +- src/core/interfaces/TransferParams.ts | 27 +- src/core/interfaces/index.ts | 20 +- src/core/metadata.ts | 69 +- src/core/metaport.ts | 323 ++++------ src/core/network.ts | 93 ++- src/core/sfuel.ts | 8 - src/core/themes.ts | 65 +- src/core/tokens/helper.ts | 46 +- src/core/transfer_steps.ts | 98 ++- src/core/views.ts | 12 +- src/core/wagmi_network.ts | 66 +- src/index.ts | 4 +- src/store/MetaportState.ts | 484 +++++++------- src/store/Store.ts | 73 ++- src/types/custom.d.ts | 39 +- src/types/index.d.ts | 6 +- src/types/react-app-env.d.ts | 5 +- 93 files changed, 2932 insertions(+), 3402 deletions(-) diff --git a/src/Metaport.tsx b/src/Metaport.tsx index 4113907..e85d3a5 100644 --- a/src/Metaport.tsx +++ b/src/Metaport.tsx @@ -22,36 +22,34 @@ */ // @ts-ignore -import React from 'react'; +import React from 'react' // import { createRoot } from 'react-dom/client'; -import Widget from './components/Widget'; -import { internalEvents } from './core/events'; +import Widget from './components/Widget' +import { internalEvents } from './core/events' -import * as interfaces from './core/interfaces/index'; -export * as dataclasses from './core/dataclasses/index'; -export * as interfaces from './core/interfaces/index'; +import * as interfaces from './core/interfaces/index' +export * as dataclasses from './core/dataclasses/index' +export * as interfaces from './core/interfaces/index' -import ChainIcon from './components/ChainIcon'; -export { ChainIcon }; +import ChainIcon from './components/ChainIcon' +export { ChainIcon } +import WidgetUI from './components/WidgetUI' +export { WidgetUI } -import WidgetUI from './components/WidgetUI'; -export { WidgetUI }; - -import Metaport from './components/Metaport'; -export { Metaport }; +import Metaport from './components/Metaport' +export { Metaport } // export * as sfuel from './core/sfuel'; - export class InjectedMetaport { constructor(config: interfaces.MetaportConfig) { - if (config.openButton === undefined) config.openButton = true; - if (config.autoLookup === undefined) config.autoLookup = true; - if (config.skaleNetwork === undefined) config.skaleNetwork = 'mainnet'; - if (config.debug === undefined) config.debug = false; - const el = document.getElementById('metaport'); + if (config.openButton === undefined) config.openButton = true + if (config.autoLookup === undefined) config.autoLookup = true + if (config.skaleNetwork === undefined) config.skaleNetwork = 'mainnet' + if (config.debug === undefined) config.debug = false + const el = document.getElementById('metaport') if (el) { // createRoot(el).render(); } else { @@ -68,8 +66,16 @@ export class InjectedMetaport { // updateParams(params) { internalEvents.updateParams(params) } // requestBalance(params) { internalEvents.requestBalance(params) } - setTheme(theme: any) { internalEvents.setTheme(theme) } - close() { internalEvents.close() } - open() { internalEvents.open() } - reset() { internalEvents.reset() } + setTheme(theme: any) { + internalEvents.setTheme(theme) + } + close() { + internalEvents.close() + } + open() { + internalEvents.open() + } + reset() { + internalEvents.reset() + } } diff --git a/src/components/AmountErrorMessage/AmountErrorMessage.tsx b/src/components/AmountErrorMessage/AmountErrorMessage.tsx index 531e1c0..40b2c67 100644 --- a/src/components/AmountErrorMessage/AmountErrorMessage.tsx +++ b/src/components/AmountErrorMessage/AmountErrorMessage.tsx @@ -1,28 +1,30 @@ -import React from 'react'; -import Collapse from '@mui/material/Collapse'; +import React from 'react' +import Collapse from '@mui/material/Collapse' -import { cls } from '../../core/helper'; -import common from '../../styles/common.module.scss'; +import { cls } from '../../core/helper' +import common from '../../styles/common.module.scss' import { useMetaportStore } from '../../store/MetaportState' - export default function AmountErrorMessage() { - const amountErrorMessage = useMetaportStore((state) => state.amountErrorMessage); + const amountErrorMessage = useMetaportStore((state) => state.amountErrorMessage) return ( - -

+ +

🔴 {amountErrorMessage}

-
) + + ) } diff --git a/src/components/AmountErrorMessage/index.ts b/src/components/AmountErrorMessage/index.ts index adc7ed2..0944661 100644 --- a/src/components/AmountErrorMessage/index.ts +++ b/src/components/AmountErrorMessage/index.ts @@ -1 +1 @@ -export { default } from "./AmountErrorMessage"; \ No newline at end of file +export { default } from './AmountErrorMessage' diff --git a/src/components/AmountInput/AmountInput.tsx b/src/components/AmountInput/AmountInput.tsx index 2524f3a..5a84f29 100644 --- a/src/components/AmountInput/AmountInput.tsx +++ b/src/components/AmountInput/AmountInput.tsx @@ -1,31 +1,29 @@ -import React from "react"; +import React from 'react' import { useAccount } from 'wagmi' -import TextField from '@mui/material/TextField'; +import TextField from '@mui/material/TextField' -import { cls } from '../../core/helper'; -import common from '../../styles/common.module.scss'; -import localStyles from './AmountInput.module.scss'; +import { cls } from '../../core/helper' +import common from '../../styles/common.module.scss' +import localStyles from './AmountInput.module.scss' import { useMetaportStore } from '../../store/MetaportState' - export default function AmountInput() { - const { address } = useAccount() - const token = useMetaportStore((state) => state.token); - const transferInProgress = useMetaportStore((state) => state.transferInProgress); - const setAmount = useMetaportStore((state) => state.setAmount); - const amount = useMetaportStore((state) => state.amount); + const token = useMetaportStore((state) => state.token) + const transferInProgress = useMetaportStore((state) => state.transferInProgress) + const setAmount = useMetaportStore((state) => state.setAmount) + const amount = useMetaportStore((state) => state.amount) const handleChange = (event: React.ChangeEvent) => { if (parseFloat(event.target.value) < 0) { - setAmount('', address); - return; + setAmount('', address) + return } - setAmount(event.target.value, address); - }; + setAmount(event.target.value, address) + } // const setMaxAmount = () => { // if (token && !token.clone && @@ -43,7 +41,7 @@ export default function AmountInput() { // } // } - if (!token) return; + if (!token) return return (
@@ -57,16 +55,18 @@ export default function AmountInput() { />
-
+
{token.meta.symbol}
diff --git a/src/components/AmountInput/index.ts b/src/components/AmountInput/index.ts index 0315fc8..28f19b1 100644 --- a/src/components/AmountInput/index.ts +++ b/src/components/AmountInput/index.ts @@ -1 +1 @@ -export { default } from "./AmountInput"; +export { default } from './AmountInput' diff --git a/src/components/ChainApps/ChainApps.tsx b/src/components/ChainApps/ChainApps.tsx index c00eac4..ba9356a 100644 --- a/src/components/ChainApps/ChainApps.tsx +++ b/src/components/ChainApps/ChainApps.tsx @@ -1,44 +1,36 @@ -import React from 'react'; -import { cls, getChainAppsMeta, getChainAlias } from '../../core/helper'; +import React from 'react' +import { cls, getChainAppsMeta, getChainAlias } from '../../core/helper' -import styles from "../../styles/styles.module.scss"; -import common from "../../styles/common.module.scss"; -import { SkaleNetwork } from '../../core/interfaces'; +import styles from '../../styles/styles.module.scss' +import common from '../../styles/common.module.scss' +import { SkaleNetwork } from '../../core/interfaces' -import ChainIcon from '../ChainIcon'; +import ChainIcon from '../ChainIcon' - -export default function ChainApps(props: { - skaleNetwork: SkaleNetwork, - chain: string -}) { - - const apps = getChainAppsMeta(props.chain, props.skaleNetwork); - if (!apps || !Object.keys(apps) || Object.keys(apps).length === 0) return
; +export default function ChainApps(props: { skaleNetwork: SkaleNetwork; chain: string }) { + const apps = getChainAppsMeta(props.chain, props.skaleNetwork) + if (!apps || !Object.keys(apps) || Object.keys(apps).length === 0) return
return ( -
+
{Object.keys(apps).map((key, _) => ( -
+

{getChainAlias(props.skaleNetwork, props.chain, key)} @@ -48,4 +40,4 @@ export default function ChainApps(props: {

) -} \ No newline at end of file +} diff --git a/src/components/ChainApps/index.ts b/src/components/ChainApps/index.ts index 625df1e..47b61bd 100644 --- a/src/components/ChainApps/index.ts +++ b/src/components/ChainApps/index.ts @@ -1 +1 @@ -export { default } from "./ChainApps"; +export { default } from './ChainApps' diff --git a/src/components/ChainIcon/ChainIcon.tsx b/src/components/ChainIcon/ChainIcon.tsx index 702e8c7..739ef13 100644 --- a/src/components/ChainIcon/ChainIcon.tsx +++ b/src/components/ChainIcon/ChainIcon.tsx @@ -1,31 +1,26 @@ -import React from 'react'; -import OfflineBoltRoundedIcon from '@mui/icons-material/OfflineBoltRounded'; -import { SkaleNetwork } from '../../core/interfaces'; -import { chainIconPath } from '../../core/metadata'; - -import { cls } from '../../core/helper'; -import styles from "../../styles/styles.module.scss"; +import React from 'react' +import OfflineBoltRoundedIcon from '@mui/icons-material/OfflineBoltRounded' +import { SkaleNetwork } from '../../core/interfaces' +import { chainIconPath } from '../../core/metadata' +import { cls } from '../../core/helper' +import styles from '../../styles/styles.module.scss' export default function ChainIcon(props: { - skaleNetwork: SkaleNetwork, - chainName: string, - className?: string, - app?: string, + skaleNetwork: SkaleNetwork + chainName: string + className?: string + app?: string size?: 'xs' | 'sm' | 'md' | 'lg' }) { - const iconPath = chainIconPath( - props.skaleNetwork, - props.chainName, - props.app - ) - const size = props.size ?? 'sm'; - const className = styles[`chainIcon${size}`] + ' ' + props.className; + const iconPath = chainIconPath(props.skaleNetwork, props.chainName, props.app) + const size = props.size ?? 'sm' + const className = styles[`chainIcon${size}`] + ' ' + props.className if (iconPath !== undefined) { if (iconPath.default) { - return ; + return } - return ; + return } - return (); -} \ No newline at end of file + return +} diff --git a/src/components/ChainIcon/index.ts b/src/components/ChainIcon/index.ts index 78b7638..afe24d4 100644 --- a/src/components/ChainIcon/index.ts +++ b/src/components/ChainIcon/index.ts @@ -1 +1 @@ -export { default } from "./ChainIcon"; +export { default } from './ChainIcon' diff --git a/src/components/ChainsList/ChainsList.tsx b/src/components/ChainsList/ChainsList.tsx index 28c6e4f..04cf519 100644 --- a/src/components/ChainsList/ChainsList.tsx +++ b/src/components/ChainsList/ChainsList.tsx @@ -1,49 +1,46 @@ -import React from 'react'; -import Accordion from '@mui/material/Accordion'; -import AccordionDetails from '@mui/material/AccordionDetails'; -import AccordionSummary from '@mui/material/AccordionSummary'; -import Typography from '@mui/material/Typography'; -import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; -import Tooltip from '@mui/material/Tooltip'; -import Button from '@mui/material/Button'; +import React from 'react' +import Accordion from '@mui/material/Accordion' +import AccordionDetails from '@mui/material/AccordionDetails' +import AccordionSummary from '@mui/material/AccordionSummary' +import Typography from '@mui/material/Typography' +import ExpandMoreIcon from '@mui/icons-material/ExpandMore' +import Tooltip from '@mui/material/Tooltip' +import Button from '@mui/material/Button' +import ChainApps from '../ChainApps' +import ChainIcon from '../ChainIcon' -import ChainApps from '../ChainApps'; -import ChainIcon from '../ChainIcon'; - -import { MetaportConfig } from '../../core/interfaces'; - -import { cls, getChainAlias } from '../../core/helper'; -import common from "../../styles/common.module.scss"; -import styles from "../../styles/styles.module.scss"; +import { MetaportConfig } from '../../core/interfaces' +import { cls, getChainAlias } from '../../core/helper' +import common from '../../styles/common.module.scss' +import styles from '../../styles/styles.module.scss' export default function ChainsList(props: { - config: MetaportConfig, - expanded: string | false, - setExpanded: (expanded: string | false) => void, - setChain: (chain: string) => void, - chain: string, - disabledChain: string, - from?: boolean, + config: MetaportConfig + expanded: string | false + setExpanded: (expanded: string | false) => void + setChain: (chain: string) => void + chain: string + disabledChain: string + from?: boolean disabled?: boolean }) { - const handleChange = - (panel: string) => (_: React.SyntheticEvent, isExpanded: boolean) => { - props.setExpanded(isExpanded ? panel : false); - }; + const handleChange = (panel: string) => (_: React.SyntheticEvent, isExpanded: boolean) => { + props.setExpanded(isExpanded ? panel : false) + } - const schainNames = []; + const schainNames = [] for (let chain of props.config.chains) { if (chain != props.disabledChain && chain != props.chain) { - schainNames.push(chain); + schainNames.push(chain) } } function handle(schainName) { - props.setExpanded(false); - props.setChain(schainName); + props.setExpanded(false) + props.setChain(schainName) } return ( @@ -63,20 +60,10 @@ export default function ChainsList(props: { {props.chain ? (
- +
-

+

{getChainAlias(props.config.skaleNetwork, props.chain)}

@@ -91,74 +78,56 @@ export default function ChainsList(props: { ) : (
- +
-

+

Transfer {props.from ? 'from' : 'to'}...

- ) - } + )} -
+
- +
{schainNames.map((name) => ( -
- +
-
))}
-
+
) -} \ No newline at end of file +} diff --git a/src/components/ChainsList/index.ts b/src/components/ChainsList/index.ts index b0a2431..04f8e63 100644 --- a/src/components/ChainsList/index.ts +++ b/src/components/ChainsList/index.ts @@ -1 +1 @@ -export { default } from "./ChainsList"; +export { default } from './ChainsList' diff --git a/src/components/ErrorMessage/ErrorMessage.tsx b/src/components/ErrorMessage/ErrorMessage.tsx index dd2f691..3305422 100644 --- a/src/components/ErrorMessage/ErrorMessage.tsx +++ b/src/components/ErrorMessage/ErrorMessage.tsx @@ -1,25 +1,23 @@ -import React from 'react'; -import Button from '@mui/material/Button'; +import React from 'react' +import Button from '@mui/material/Button' -import { cls } from '../../core/helper'; -import common from "../../styles/common.module.scss"; -import styles from "../../styles/styles.module.scss"; +import { cls } from '../../core/helper' +import common from '../../styles/common.module.scss' +import styles from '../../styles/styles.module.scss' -import { ErrorMessage } from '../../core/dataclasses'; - -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 { ErrorMessage } from '../../core/dataclasses' +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' const ERROR_ICONS = { 'link-off': , 'public-off': , - 'sentiment': , - 'error': -}; - + sentiment: , + error: , +} export default function Error(props: { errorMessage: ErrorMessage }) { if (!props.errorMessage) return @@ -28,49 +26,63 @@ export default function Error(props: { errorMessage: ErrorMessage }) {
{ERROR_ICONS[props.errorMessage.icon]}
-

- Error occured -

-

- Please check logs in developer console -

-
-

+ )} + > + Error occured +

+

+ Please check logs in developer console +

+
+

{props.errorMessage.text}

- {props.errorMessage.fallback ? () : null} + {props.errorMessage.fallback ? ( + + ) : null}
) } diff --git a/src/components/ErrorMessage/index.ts b/src/components/ErrorMessage/index.ts index 26f0b73..e4f7f45 100644 --- a/src/components/ErrorMessage/index.ts +++ b/src/components/ErrorMessage/index.ts @@ -1 +1 @@ -export { default } from "./ErrorMessage"; \ No newline at end of file +export { default } from './ErrorMessage' diff --git a/src/components/Metaport/Metaport.tsx b/src/components/Metaport/Metaport.tsx index b96960c..8540da0 100644 --- a/src/components/Metaport/Metaport.tsx +++ b/src/components/Metaport/Metaport.tsx @@ -1,4 +1,3 @@ - /** * @license * SKALE Metaport @@ -21,89 +20,77 @@ * @copyright SKALE Labs 2023-Present */ -import { - RainbowKitProvider -} from '@rainbow-me/rainbowkit'; -import { configureChains, createConfig, WagmiConfig } from 'wagmi'; -import { mainnet, goerli } from 'wagmi/chains'; -import { jsonRpcProvider } from 'wagmi/providers/jsonRpc'; -import { connectorsForWallets } from '@rainbow-me/rainbowkit'; +import { RainbowKitProvider } from '@rainbow-me/rainbowkit' +import { configureChains, createConfig, WagmiConfig } from 'wagmi' +import { mainnet, goerli } from 'wagmi/chains' +import { jsonRpcProvider } from 'wagmi/providers/jsonRpc' +import { connectorsForWallets } from '@rainbow-me/rainbowkit' -import { - injectedWallet, - coinbaseWallet, - metaMaskWallet -} from '@rainbow-me/rainbowkit/wallets'; +import { injectedWallet, coinbaseWallet, metaMaskWallet } from '@rainbow-me/rainbowkit/wallets' -import { MetaportConfig } from "../../core/interfaces" +import { MetaportConfig } from '../../core/interfaces' import WidgetUI from '../WidgetUI' -import '@rainbow-me/rainbowkit/styles.css'; - -import { constructWagmiChain, getWebSocketUrl } from '../../core/wagmi_network'; +import '@rainbow-me/rainbowkit/styles.css' +import { constructWagmiChain, getWebSocketUrl } from '../../core/wagmi_network' const { chains, webSocketPublicClient } = configureChains( - [ - mainnet, - goerli, - constructWagmiChain('staging', "staging-legal-crazy-castor"), - constructWagmiChain('staging', "staging-utter-unripe-menkar"), - constructWagmiChain('staging', "staging-faint-slimy-achird"), - constructWagmiChain('staging', "staging-perfect-parallel-gacrux"), - constructWagmiChain('staging', "staging-severe-violet-wezen"), - constructWagmiChain('staging', "staging-weepy-fitting-caph"), - - constructWagmiChain('mainnet', 'honorable-steel-rasalhague'), - constructWagmiChain('mainnet', 'elated-tan-skat'), - constructWagmiChain('mainnet', 'affectionate-immediate-pollux') - ], - [ - jsonRpcProvider({ - rpc: chain => ({ - http: chain.rpcUrls.default.http[0], - webSocket: getWebSocketUrl(chain) - }), - }) - ] -); - + [ + mainnet, + goerli, + constructWagmiChain('staging', 'staging-legal-crazy-castor'), + constructWagmiChain('staging', 'staging-utter-unripe-menkar'), + constructWagmiChain('staging', 'staging-faint-slimy-achird'), + constructWagmiChain('staging', 'staging-perfect-parallel-gacrux'), + constructWagmiChain('staging', 'staging-severe-violet-wezen'), + constructWagmiChain('staging', 'staging-weepy-fitting-caph'), + + constructWagmiChain('mainnet', 'honorable-steel-rasalhague'), + constructWagmiChain('mainnet', 'elated-tan-skat'), + constructWagmiChain('mainnet', 'affectionate-immediate-pollux'), + ], + [ + jsonRpcProvider({ + rpc: (chain) => ({ + http: chain.rpcUrls.default.http[0], + webSocket: getWebSocketUrl(chain), + }), + }), + ], +) const connectors = connectorsForWallets([ - { - groupName: 'Supported Wallets', - wallets: [ - metaMaskWallet({ chains, projectId: '' }), - injectedWallet({ chains }), - coinbaseWallet({ chains, appName: 'TEST' }) - ], - } -]); - + { + groupName: 'Supported Wallets', + wallets: [ + metaMaskWallet({ chains, projectId: '' }), + injectedWallet({ chains }), + coinbaseWallet({ chains, appName: 'TEST' }), + ], + }, +]) const wagmiConfig = createConfig({ - autoConnect: true, - connectors, - publicClient: webSocketPublicClient -}); - - -export default function Widget(props: { - config: MetaportConfig -}) { - return ( - - - - - - ) -} \ No newline at end of file + autoConnect: true, + connectors, + publicClient: webSocketPublicClient, +}) + +export default function Widget(props: { config: MetaportConfig }) { + return ( + + + + + + ) +} diff --git a/src/components/Metaport/index.ts b/src/components/Metaport/index.ts index 293cae0..d2d1941 100644 --- a/src/components/Metaport/index.ts +++ b/src/components/Metaport/index.ts @@ -1 +1 @@ -export { default } from "./Metaport"; +export { default } from './Metaport' diff --git a/src/components/SkConnect/SkConnect.tsx b/src/components/SkConnect/SkConnect.tsx index 4c1b552..a286ead 100644 --- a/src/components/SkConnect/SkConnect.tsx +++ b/src/components/SkConnect/SkConnect.tsx @@ -20,196 +20,174 @@ * @copyright SKALE Labs 2023-Present */ -import React from 'react'; -import { ConnectButton } from '@rainbow-me/rainbowkit'; +import React from 'react' +import { ConnectButton } from '@rainbow-me/rainbowkit' import Jazzicon, { jsNumberForAddress } from 'react-jazzicon' -import Button from '@mui/material/Button'; -import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; +import Button from '@mui/material/Button' +import ExpandMoreIcon from '@mui/icons-material/ExpandMore' -import { cls } from '../../core/helper'; +import { cls } from '../../core/helper' -import styles from "../../styles/styles.module.scss"; -import common from "../../styles/common.module.scss"; +import styles from '../../styles/styles.module.scss' +import common from '../../styles/common.module.scss' // import skaleLogoFull from '../WidgetUI/skale_logo.svg'; -import { useMetaportStore } from '../../store/MetaportState'; +import { useMetaportStore } from '../../store/MetaportState' -import ChainIcon from "../ChainIcon"; +import ChainIcon from '../ChainIcon' export default function SkConnect() { - const transferInProgress = useMetaportStore((state) => state.transferInProgress); - return ( - - {({ - account, - chain, - openAccountModal, - openChainModal, - openConnectModal, - authenticationStatus, - mounted, - }) => { - // Note: If your app doesn't use authentication, you - // can remove all 'authenticationStatus' checks - const ready = mounted && authenticationStatus !== 'loading'; - const connected = - ready && - account && - chain && - (!authenticationStatus || - authenticationStatus === 'authenticated'); + const transferInProgress = useMetaportStore((state) => state.transferInProgress) + return ( + + {({ account, chain, openAccountModal, openChainModal, openConnectModal, authenticationStatus, mounted }) => { + // Note: If your app doesn't use authentication, you + // can remove all 'authenticationStatus' checks + const ready = mounted && authenticationStatus !== 'loading' + const connected = + ready && account && chain && (!authenticationStatus || authenticationStatus === 'authenticated') + return ( +
+ {(() => { + if (!connected) { return ( -
+
+ {/* */} +
+
+ + + + + + + + +
+

- {(() => { - if (!connected) { - return ( -

-
- {/* */} -
-
- - - - - - - - -
-

Connect a wallet to use SKALE Metaport

- -
- - ); - } - if (chain.unsupported) { - return ( - - - - ); - } - return ( -
-
- {/* + +
+ ) + } + if (chain.unsupported) { + return ( + + ) + } + return ( +
+
+ {/* */} -
-
-
+
+ -
- -
- ); - })()} -
- ); - }} - ) -}; \ No newline at end of file + + +
+
+ ) + })()} +
+ ) + }} + + ) +} diff --git a/src/components/SkConnect/index.ts b/src/components/SkConnect/index.ts index 03890dd..1395555 100644 --- a/src/components/SkConnect/index.ts +++ b/src/components/SkConnect/index.ts @@ -1 +1 @@ -export { default } from "./SkConnect"; +export { default } from './SkConnect' diff --git a/src/components/SkPaper/SkPaper.tsx b/src/components/SkPaper/SkPaper.tsx index 537686d..5d6cd95 100644 --- a/src/components/SkPaper/SkPaper.tsx +++ b/src/components/SkPaper/SkPaper.tsx @@ -19,37 +19,41 @@ /** * @file SkPaper.ts * @copyright SKALE Labs 2023-Present -*/ + */ -import React, { ReactElement } from 'react'; -import { cls } from '../../core/helper'; +import React, { ReactElement } from 'react' +import { cls } from '../../core/helper' -import styles from "../../styles/styles.module.scss"; -import common from "../../styles/common.module.scss"; +import styles from '../../styles/styles.module.scss' +import common from '../../styles/common.module.scss' import { useUIStore } from '../../store/Store' - export default function SkPaper(props: { - className?: string, - children?: ReactElement | ReactElement[], - background?: string, - gray?: boolean, - rounded?: boolean, - fullHeight?: boolean, - margTop?: boolean + className?: string + children?: ReactElement | ReactElement[] + background?: string + gray?: boolean + rounded?: boolean + fullHeight?: boolean + margTop?: boolean }) { - const metaportTheme = useUIStore((state) => state.theme); - const localStyle = { - 'background': props.background ?? metaportTheme.background - }; - return (
state.theme) + const localStyle = { + background: props.background ?? metaportTheme.background, + } + return ( +
- {props.children} -
) -} \ No newline at end of file + )} + > + {props.children} +
+ ) +} diff --git a/src/components/SkPaper/index.ts b/src/components/SkPaper/index.ts index d565a0d..bee60c9 100644 --- a/src/components/SkPaper/index.ts +++ b/src/components/SkPaper/index.ts @@ -1 +1 @@ -export { default } from "./SkPaper"; +export { default } from './SkPaper' diff --git a/src/components/SkeletonLoader/SkeletonLoader.tsx b/src/components/SkeletonLoader/SkeletonLoader.tsx index 8a4bc8c..bb91a3b 100644 --- a/src/components/SkeletonLoader/SkeletonLoader.tsx +++ b/src/components/SkeletonLoader/SkeletonLoader.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import Skeleton from '@mui/material/Skeleton'; +import React from 'react' +import Skeleton from '@mui/material/Skeleton' export default function SkeletonLoader(props) { return ( diff --git a/src/components/SkeletonLoader/index.ts b/src/components/SkeletonLoader/index.ts index de11545..0d3d587 100644 --- a/src/components/SkeletonLoader/index.ts +++ b/src/components/SkeletonLoader/index.ts @@ -1 +1 @@ -export { default } from "./SkeletonLoader"; +export { default } from './SkeletonLoader' diff --git a/src/components/Stepper/SkStepper.tsx b/src/components/Stepper/SkStepper.tsx index 2851325..2047ed1 100644 --- a/src/components/Stepper/SkStepper.tsx +++ b/src/components/Stepper/SkStepper.tsx @@ -1,131 +1,135 @@ -import React, { useEffect, useState } from 'react'; - -import Box from '@mui/material/Box'; -import Stepper from '@mui/material/Stepper'; -import Step from '@mui/material/Step'; -import StepLabel from '@mui/material/StepLabel'; -import StepContent from '@mui/material/StepContent'; -import Button from '@mui/material/Button'; -import LoadingButton from '@mui/lab/LoadingButton'; - -import { cls, getChainAlias, getRandom } from '../../core/helper'; -import common from '../../styles/common.module.scss'; -import styles from '../../styles/styles.module.scss'; -import localStyles from './SkStepper.module.scss'; -import ChainIcon from "../ChainIcon"; -import SkPaper from "../SkPaper"; +import React, { useEffect, useState } from 'react' + +import Box from '@mui/material/Box' +import Stepper from '@mui/material/Stepper' +import Step from '@mui/material/Step' +import StepLabel from '@mui/material/StepLabel' +import StepContent from '@mui/material/StepContent' +import Button from '@mui/material/Button' +import LoadingButton from '@mui/lab/LoadingButton' + +import { cls, getChainAlias, getRandom } from '../../core/helper' +import common from '../../styles/common.module.scss' +import styles from '../../styles/styles.module.scss' +import localStyles from './SkStepper.module.scss' +import ChainIcon from '../ChainIcon' +import SkPaper from '../SkPaper' import { useMetaportStore } from '../../store/MetaportState' -import { Collapse } from '@mui/material'; -import { SkaleNetwork } from '../../core/interfaces'; +import { Collapse } from '@mui/material' +import { SkaleNetwork } from '../../core/interfaces' import { useWalletClient } from 'wagmi' - -import SettingsBackupRestoreRoundedIcon from '@mui/icons-material/SettingsBackupRestoreRounded'; +import SettingsBackupRestoreRoundedIcon from '@mui/icons-material/SettingsBackupRestoreRounded' import { useSwitchNetwork, useAccount } from 'wagmi' -import { SUCCESS_EMOJIS } from '../../core/constants'; - - -export default function SkStepper(props: { - skaleNetwork: SkaleNetwork -}) { +import { SUCCESS_EMOJIS } from '../../core/constants' +export default function SkStepper(props: { skaleNetwork: SkaleNetwork }) { const { address } = useAccount() const { switchNetworkAsync } = useSwitchNetwork() const { data: walletClient } = useWalletClient() - const stepsMetadata = useMetaportStore((state) => state.stepsMetadata); - const currentStep = useMetaportStore((state) => state.currentStep); - const amountErrorMessage = useMetaportStore((state) => state.amountErrorMessage); - const actionBtnDisabled = useMetaportStore((state) => state.actionBtnDisabled); - const loading = useMetaportStore((state) => state.loading); - const btnText = useMetaportStore((state) => state.btnText); + const stepsMetadata = useMetaportStore((state) => state.stepsMetadata) + const currentStep = useMetaportStore((state) => state.currentStep) + const amountErrorMessage = useMetaportStore((state) => state.amountErrorMessage) + const actionBtnDisabled = useMetaportStore((state) => state.actionBtnDisabled) + const loading = useMetaportStore((state) => state.loading) + const btnText = useMetaportStore((state) => state.btnText) - const execute = useMetaportStore((state) => state.execute); - const startOver = useMetaportStore((state) => state.startOver); + const execute = useMetaportStore((state) => state.execute) + const startOver = useMetaportStore((state) => state.startOver) - const [emoji, setEmoji] = useState(); + const [emoji, setEmoji] = useState() useEffect(() => { - setEmoji(getRandom(SUCCESS_EMOJIS)); - }, []); + setEmoji(getRandom(SUCCESS_EMOJIS)) + }, []) - if (stepsMetadata.length === 0) return (
); + if (stepsMetadata.length === 0) return
return ( - {stepsMetadata.map((step, i) => ( - -
+ {stepsMetadata.map((step, i) => ( + +
-

{step.headline}

-
- +
+

{step.headline}

+
+ +
+

+ {getChainAlias(props.skaleNetwork, step.onSource ? step.from : step.to)} +

-

{getChainAlias( - props.skaleNetwork, - step.onSource ? step.from : step.to - )}

-
-
- - -

- {step.text} -

-
- {loading ? ( - - {btnText} - {/* {props.loadingTokens ? 'Loading...' : step.btnLoadingText} */} - - ) : ( - - )} -
-
-
-
))} + + + +

+ {step.text} +

+
+ {loading ? ( + + {btnText} + {/* {props.loadingTokens ? 'Loading...' : step.btnLoadingText} */} + + ) : ( + + )} +
+
+
+ + ))} - {currentStep === stepsMetadata.length && (
-

+

{emoji} Transfer completed

@@ -139,11 +143,9 @@ export default function SkStepper(props: { Start over
- )} - - ); -} \ No newline at end of file + ) +} diff --git a/src/components/Stepper/index.ts b/src/components/Stepper/index.ts index e3595f4..8a38c36 100644 --- a/src/components/Stepper/index.ts +++ b/src/components/Stepper/index.ts @@ -1 +1 @@ -export { default } from "./SkStepper"; +export { default } from './SkStepper' diff --git a/src/components/SwitchDirection/SwitchDirection.tsx b/src/components/SwitchDirection/SwitchDirection.tsx index e0b1855..6d5138c 100644 --- a/src/components/SwitchDirection/SwitchDirection.tsx +++ b/src/components/SwitchDirection/SwitchDirection.tsx @@ -1,73 +1,69 @@ -import React, { useRef } from 'react'; +import React, { useRef } from 'react' -import IconButton from '@mui/material/IconButton'; -import ArrowDownwardRoundedIcon from '@mui/icons-material/ArrowDownwardRounded'; -import styles from '../../styles/styles.module.scss'; -import common from '../../styles/common.module.scss'; -import { cls } from '../../core/helper'; +import IconButton from '@mui/material/IconButton' +import ArrowDownwardRoundedIcon from '@mui/icons-material/ArrowDownwardRounded' +import styles from '../../styles/styles.module.scss' +import common from '../../styles/common.module.scss' +import { cls } from '../../core/helper' import { useUIStore } from '../../store/Store' import { useMetaportStore } from '../../store/MetaportState' - export default function SwitchDirection() { + const myElement = useRef(null) - const myElement = useRef(null); - - const metaportTheme = useUIStore((state) => state.theme); + const metaportTheme = useUIStore((state) => state.theme) - const chainName1 = useMetaportStore((state) => state.chainName1); - const chainName2 = useMetaportStore((state) => state.chainName2); + const chainName1 = useMetaportStore((state) => state.chainName1) + const chainName2 = useMetaportStore((state) => state.chainName2) - const setChainName1 = useMetaportStore((state) => state.setChainName1); - const setChainName2 = useMetaportStore((state) => state.setChainName2); - const startOver = useMetaportStore((state) => state.startOver); - const loading = useMetaportStore((state) => state.loading); - const transferInProgress = useMetaportStore((state) => state.transferInProgress); + const setChainName1 = useMetaportStore((state) => state.setChainName1) + const setChainName2 = useMetaportStore((state) => state.setChainName2) + const startOver = useMetaportStore((state) => state.startOver) + const loading = useMetaportStore((state) => state.loading) + const transferInProgress = useMetaportStore((state) => state.transferInProgress) return (
-
-
+
+ borderRadius: '50%', + }} + > { - const element = myElement.current; + const element = myElement.current const rotate = () => { if (element) { - element.classList.add('spin'); + element.classList.add('spin') setTimeout(() => { - element.classList.remove('spin'); - }, 400); + element.classList.remove('spin') + }, 400) } - }; + } rotate() - let chain1 = chainName1; - setChainName1(chainName2); - setChainName2(chain1); - startOver(); - }}> + let chain1 = chainName1 + setChainName1(chainName2) + setChainName2(chain1) + startOver() + }} + >
-
-
- - +
) -} \ No newline at end of file +} diff --git a/src/components/SwitchDirection/index.ts b/src/components/SwitchDirection/index.ts index b86abe8..0540fc4 100644 --- a/src/components/SwitchDirection/index.ts +++ b/src/components/SwitchDirection/index.ts @@ -1 +1 @@ -export { default } from "./SwitchDirection"; +export { default } from './SwitchDirection' diff --git a/src/components/TokenIcon/TokenIcon.tsx b/src/components/TokenIcon/TokenIcon.tsx index fd5290c..4722c48 100644 --- a/src/components/TokenIcon/TokenIcon.tsx +++ b/src/components/TokenIcon/TokenIcon.tsx @@ -21,27 +21,23 @@ * @copyright SKALE Labs 2023-Present */ -import React from 'react'; -import TollRoundedIcon from '@mui/icons-material/TollRounded'; -import { TokenData } from '../../core/dataclasses'; -import { tokenIconPath } from '../../core/metadata'; +import React from 'react' +import TollRoundedIcon from '@mui/icons-material/TollRounded' +import { TokenData } from '../../core/dataclasses' +import { tokenIconPath } from '../../core/metadata' -import styles from "../../styles/styles.module.scss"; +import styles from '../../styles/styles.module.scss' - -export default function TokenIcon(props: { - token?: TokenData, - size?: 'xs' | 'sm' | 'md' | 'lg' -}) { - const size = props.size ?? 'sm'; - const className = styles[`chainIcon${size}`]; +export default function TokenIcon(props: { token?: TokenData; size?: 'xs' | 'sm' | 'md' | 'lg' }) { + const size = props.size ?? 'sm' + const className = styles[`chainIcon${size}`] if (props.token === undefined || props.token === null) { return } - const iconPath = tokenIconPath(props.token); + const iconPath = tokenIconPath(props.token) if (iconPath.default) { - return ; + return } - return ; -} \ No newline at end of file + return +} diff --git a/src/components/TokenIcon/index.ts b/src/components/TokenIcon/index.ts index 6412a21..2440af5 100644 --- a/src/components/TokenIcon/index.ts +++ b/src/components/TokenIcon/index.ts @@ -1 +1 @@ -export { default } from "./TokenIcon"; +export { default } from './TokenIcon' diff --git a/src/components/TokenList/TokenBalance.tsx b/src/components/TokenList/TokenBalance.tsx index 802f5e1..559efc9 100644 --- a/src/components/TokenList/TokenBalance.tsx +++ b/src/components/TokenList/TokenBalance.tsx @@ -1,39 +1,27 @@ -import React from 'react'; -import { formatUnits } from 'ethers'; +import React from 'react' +import { formatUnits } from 'ethers' -import { TokenType, TokenData } from '../../core/dataclasses'; -import { TokenBalancesMap } from '../../core/interfaces'; - -import { cls } from '../../core/helper'; -import common from "../../styles/common.module.scss"; +import { TokenType, TokenData } from '../../core/dataclasses' +import { TokenBalancesMap } from '../../core/interfaces' +import { cls } from '../../core/helper' +import common from '../../styles/common.module.scss' function formatBalance(balance: bigint, token: TokenData): string { - return formatUnits(balance, parseInt(token.meta.decimals)); + return formatUnits(balance, parseInt(token.meta.decimals)) } +export default function TokenBalance(props: { token: TokenData; tokenBalances: TokenBalancesMap }) { + if ([TokenType.erc721, TokenType.erc721meta, TokenType.erc1155].includes(props.token.type)) return -export default function TokenBalance(props: { - token: TokenData, - tokenBalances: TokenBalancesMap -}) { - if ([TokenType.erc721, TokenType.erc721meta, TokenType.erc1155].includes(props.token.type)) return; - - const balance = props.tokenBalances[props.token.keyname]; + const balance = props.tokenBalances[props.token.keyname] - if (balance === undefined || balance === null) return; - return ( -
-

- {formatBalance(balance, props.token)} {props.token.meta.symbol} -

-
- ) -} \ No newline at end of file + if (balance === undefined || balance === null) return + return ( +
+

+ {formatBalance(balance, props.token)} {props.token.meta.symbol} +

+
+ ) +} diff --git a/src/components/TokenList/TokenList.tsx b/src/components/TokenList/TokenList.tsx index 72a5f93..3f0d7ee 100644 --- a/src/components/TokenList/TokenList.tsx +++ b/src/components/TokenList/TokenList.tsx @@ -1,82 +1,75 @@ -import { useEffect } from 'react'; -import React from 'react'; +import { useEffect } from 'react' +import React from 'react' import { useAccount } from 'wagmi' -import Accordion from '@mui/material/Accordion'; -import AccordionDetails from '@mui/material/AccordionDetails'; -import AccordionSummary from '@mui/material/AccordionSummary'; +import Accordion from '@mui/material/Accordion' +import AccordionDetails from '@mui/material/AccordionDetails' +import AccordionSummary from '@mui/material/AccordionSummary' -import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; +import ExpandMoreIcon from '@mui/icons-material/ExpandMore' -import { getAvailableTokensTotal, getDefaultToken } from '../../core/tokens/helper'; +import { getAvailableTokensTotal, getDefaultToken } from '../../core/tokens/helper' -import { cls } from '../../core/helper'; +import { cls } from '../../core/helper' -import ErrorMessage from '../ErrorMessage'; +import ErrorMessage from '../ErrorMessage' -import TokenListSection from '../TokenListSection'; -import TokenBalance from './TokenBalance'; -import TokenIcon from "../TokenIcon"; +import TokenListSection from '../TokenListSection' +import TokenBalance from './TokenBalance' +import TokenIcon from '../TokenIcon' -import styles from "../../styles/styles.module.scss"; -import common from "../../styles/common.module.scss"; -import { getTokenName } from "../../core/metadata"; - -import { useCollapseStore } from '../../store/Store'; -import { useMetaportStore } from '../../store/MetaportState'; -import { TokenType, NoTokenPairsMessage } from '../../core/dataclasses'; +import styles from '../../styles/styles.module.scss' +import common from '../../styles/common.module.scss' +import { getTokenName } from '../../core/metadata' +import { useCollapseStore } from '../../store/Store' +import { useMetaportStore } from '../../store/MetaportState' +import { TokenType, NoTokenPairsMessage } from '../../core/dataclasses' export default function TokenList() { + const token = useMetaportStore((state) => state.token) + const tokens = useMetaportStore((state) => state.tokens) + const setToken = useMetaportStore((state) => state.setToken) + const updateTokenBalances = useMetaportStore((state) => state.updateTokenBalances) + const tokenContracts = useMetaportStore((state) => state.tokenContracts) - const token = useMetaportStore((state) => state.token); - const tokens = useMetaportStore((state) => state.tokens); - const setToken = useMetaportStore((state) => state.setToken); - const updateTokenBalances = useMetaportStore((state) => state.updateTokenBalances); - const tokenContracts = useMetaportStore((state) => state.tokenContracts); - - const tokenBalances = useMetaportStore((state) => state.tokenBalances); - const transferInProgress = useMetaportStore((state) => state.transferInProgress); - - const expandedTokens = useCollapseStore((state) => state.expandedTokens); - const setExpandedTokens = useCollapseStore((state) => state.setExpandedTokens); + const tokenBalances = useMetaportStore((state) => state.tokenBalances) + const transferInProgress = useMetaportStore((state) => state.transferInProgress) - const { address } = useAccount(); + const expandedTokens = useCollapseStore((state) => state.expandedTokens) + const setExpandedTokens = useCollapseStore((state) => state.setExpandedTokens) + const { address } = useAccount() useEffect(() => { - updateTokenBalances(address); // Fetch users immediately on component mount + updateTokenBalances(address) // Fetch users immediately on component mount const intervalId = setInterval(() => { - updateTokenBalances(address); + updateTokenBalances(address) }, 10000) // Fetch users every 10 seconds return () => { clearInterval(intervalId) // Clear interval on component unmount } - }, [updateTokenBalances, tokenContracts, address]); + }, [updateTokenBalances, tokenContracts, address]) useEffect(() => { - const defaultToken = getDefaultToken(tokens); + const defaultToken = getDefaultToken(tokens) if (defaultToken) { - setToken(defaultToken); + setToken(defaultToken) } - }, [tokens]); + }, [tokens]) + let availableTokensTotal = getAvailableTokensTotal(tokens) + let disabled = availableTokensTotal === 1 + let noTokens = availableTokensTotal === 0 - let availableTokensTotal = getAvailableTokensTotal(tokens); - let disabled = availableTokensTotal === 1; - let noTokens = availableTokensTotal === 0; - - const handleChange = - (panel: string) => (_: React.SyntheticEvent, isExpanded: boolean) => { - setExpandedTokens(isExpanded ? panel : false); - }; + const handleChange = (panel: string) => (_: React.SyntheticEvent, isExpanded: boolean) => { + setExpandedTokens(isExpanded ? panel : false) + } if (noTokens) { - return () + return } return ( @@ -92,21 +85,23 @@ export default function TokenList() { aria-controls="panel1bh-content" id="panel1bh-header" className={styles.accordionSummary} - style={{paddingTop: '0'}} + style={{ paddingTop: '0' }} >
-

+

{token ? getTokenName(token) : 'Select token'}

@@ -150,4 +145,4 @@ export default function TokenList() {
) -} \ No newline at end of file +} diff --git a/src/components/TokenList/index.ts b/src/components/TokenList/index.ts index 152b99b..ba9b61b 100644 --- a/src/components/TokenList/index.ts +++ b/src/components/TokenList/index.ts @@ -1 +1 @@ -export { default } from "./TokenList"; +export { default } from './TokenList' diff --git a/src/components/TokenListSection/TokenListSection.tsx b/src/components/TokenListSection/TokenListSection.tsx index 791797a..131f213 100644 --- a/src/components/TokenListSection/TokenListSection.tsx +++ b/src/components/TokenListSection/TokenListSection.tsx @@ -1,36 +1,33 @@ -import React from 'react'; -import Button from '@mui/material/Button'; +import React from 'react' +import Button from '@mui/material/Button' -import { TokenData, TokenType } from '../../core/dataclasses'; -import { TokenBalancesMap, TokenDataMap } from '../../core/interfaces'; -import { cls } from '../../core/helper'; +import { TokenData, TokenType } from '../../core/dataclasses' +import { TokenBalancesMap, TokenDataMap } from '../../core/interfaces' +import { cls } from '../../core/helper' -import TokenBalance from '../TokenList/TokenBalance'; -import TokenIcon from '../TokenIcon'; +import TokenBalance from '../TokenList/TokenBalance' +import TokenIcon from '../TokenIcon' -import common from "../../styles/common.module.scss"; - -import { getTokenName } from "../../core/metadata"; +import common from '../../styles/common.module.scss' +import { getTokenName } from '../../core/metadata' export default function TokenListSection(props: { - setExpanded: (expanded: string | false) => void, - setToken: (token: TokenData) => void, - tokens: TokenDataMap, - type: TokenType, + setExpanded: (expanded: string | false) => void + setToken: (token: TokenData) => void + tokens: TokenDataMap + type: TokenType tokenBalances?: TokenBalancesMap }) { - function handle(tokenData: TokenData): void { - props.setExpanded(false); - props.setToken(tokenData); + props.setExpanded(false) + props.setToken(tokenData) } - if (Object.keys(props.tokens).length === 0) return; + if (Object.keys(props.tokens).length === 0) return return ( -
+

@@ -53,26 +50,24 @@ export default function TokenListSection(props: { className={common.fullWidth} onClick={() => handle(props.tokens[key])} > -

+
-

+

{getTokenName(props.tokens[key])}

@@ -83,4 +78,4 @@ export default function TokenListSection(props: { ))}
) -} \ No newline at end of file +} diff --git a/src/components/TokenListSection/index.ts b/src/components/TokenListSection/index.ts index e177cb9..76e5a12 100644 --- a/src/components/TokenListSection/index.ts +++ b/src/components/TokenListSection/index.ts @@ -1 +1 @@ -export { default } from "./TokenListSection"; +export { default } from './TokenListSection' diff --git a/src/components/Widget/Widget.mdx b/src/components/Widget/Widget.mdx index bdf93cc..425c0a4 100644 --- a/src/components/Widget/Widget.mdx +++ b/src/components/Widget/Widget.mdx @@ -1,14 +1,13 @@ -import { useState } from "react"; +import { useState } from 'react' -import { Canvas, Story, ArgsTable } from "@storybook/blocks"; +import { Canvas, Story, ArgsTable } from '@storybook/blocks' -import Grid from "@mui/material/Grid"; -import TextField from "@mui/material/TextField"; -import Button from "@mui/material/Button"; - -import { internalEvents } from "../../core/events"; -import * as WidgetStories from "./Widget.stories"; +import Grid from '@mui/material/Grid' +import TextField from '@mui/material/TextField' +import Button from '@mui/material/Button' +import { internalEvents } from '../../core/events' +import * as WidgetStories from './Widget.stories' # Functional Metaport Demo diff --git a/src/components/Widget/Widget.stories.tsx b/src/components/Widget/Widget.stories.tsx index c052ee8..1d9405d 100644 --- a/src/components/Widget/Widget.stories.tsx +++ b/src/components/Widget/Widget.stories.tsx @@ -1,23 +1,21 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import Widget from "./Widget"; +import type { Meta, StoryObj } from '@storybook/react' +import Widget from './Widget' // import { storyDecorator } from "../WidgetUI/StorybookHelper"; -const METAPORT_CONFIG = require('../../metadata/metaportConfigStaging.json'); -METAPORT_CONFIG.mainnetEndpoint = process.env.STORYBOOK_MAINNET_ENDPOINT; - +const METAPORT_CONFIG = require('../../metadata/metaportConfigStaging.json') +METAPORT_CONFIG.mainnetEndpoint = process.env.STORYBOOK_MAINNET_ENDPOINT const meta: Meta = { - title: "Functional/Widget", + title: 'Functional/Widget', component: Widget, // decorators: [storyDecorator], -}; - -export default meta; -type Story = StoryObj; +} +export default meta +type Story = StoryObj export const WidgetDemo: Story = { args: { - config: METAPORT_CONFIG - } -}; \ No newline at end of file + config: METAPORT_CONFIG, + }, +} diff --git a/src/components/Widget/Widget.tsx b/src/components/Widget/Widget.tsx index 32dc876..12fbec2 100644 --- a/src/components/Widget/Widget.tsx +++ b/src/components/Widget/Widget.tsx @@ -1,4 +1,3 @@ - /** * @license * SKALE Metaport @@ -21,121 +20,106 @@ * @copyright SKALE Labs 2023-Present */ -import React, { useEffect } from 'react'; - -import { - RainbowKitProvider, - darkTheme, - lightTheme -} from '@rainbow-me/rainbowkit'; -import { configureChains, createConfig, WagmiConfig } from 'wagmi'; -import { mainnet, goerli } from 'wagmi/chains'; -import { jsonRpcProvider } from 'wagmi/providers/jsonRpc'; -import { connectorsForWallets } from '@rainbow-me/rainbowkit'; +import React, { useEffect } from 'react' +import { RainbowKitProvider, darkTheme, lightTheme } from '@rainbow-me/rainbowkit' +import { configureChains, createConfig, WagmiConfig } from 'wagmi' +import { mainnet, goerli } from 'wagmi/chains' +import { jsonRpcProvider } from 'wagmi/providers/jsonRpc' +import { connectorsForWallets } from '@rainbow-me/rainbowkit' -import { - injectedWallet, - coinbaseWallet, - metaMaskWallet -} from '@rainbow-me/rainbowkit/wallets'; +import { injectedWallet, coinbaseWallet, metaMaskWallet } from '@rainbow-me/rainbowkit/wallets' -import { MetaportConfig } from "../../core/interfaces" +import { MetaportConfig } from '../../core/interfaces' import WidgetUI from '../WidgetUI' import { useUIStore } from '../../store/Store' import { useMetaportStore } from '../../store/MetaportState' -import { getWidgetTheme } from '../../core/themes'; +import { getWidgetTheme } from '../../core/themes' import MetaportCore from '../../core/metaport' -import '@rainbow-me/rainbowkit/styles.css'; - -import { constructWagmiChain, getWebSocketUrl } from '../../core/wagmi_network'; +import '@rainbow-me/rainbowkit/styles.css' +import { constructWagmiChain, getWebSocketUrl } from '../../core/wagmi_network' const { chains, webSocketPublicClient } = configureChains( - [ - mainnet, - goerli, - constructWagmiChain('staging', "staging-legal-crazy-castor"), - constructWagmiChain('staging', "staging-utter-unripe-menkar"), - constructWagmiChain('staging', "staging-faint-slimy-achird"), - constructWagmiChain('staging', "staging-perfect-parallel-gacrux"), - constructWagmiChain('staging', "staging-severe-violet-wezen"), - constructWagmiChain('staging', "staging-weepy-fitting-caph"), - - constructWagmiChain('mainnet', 'honorable-steel-rasalhague'), - constructWagmiChain('mainnet', 'elated-tan-skat'), - constructWagmiChain('mainnet', 'affectionate-immediate-pollux') - ], - [ - jsonRpcProvider({ - rpc: chain => ({ - http: chain.rpcUrls.default.http[0], - webSocket: getWebSocketUrl(chain) - }), - }) - ] -); - + [ + mainnet, + goerli, + constructWagmiChain('staging', 'staging-legal-crazy-castor'), + constructWagmiChain('staging', 'staging-utter-unripe-menkar'), + constructWagmiChain('staging', 'staging-faint-slimy-achird'), + constructWagmiChain('staging', 'staging-perfect-parallel-gacrux'), + constructWagmiChain('staging', 'staging-severe-violet-wezen'), + constructWagmiChain('staging', 'staging-weepy-fitting-caph'), + + constructWagmiChain('mainnet', 'honorable-steel-rasalhague'), + constructWagmiChain('mainnet', 'elated-tan-skat'), + constructWagmiChain('mainnet', 'affectionate-immediate-pollux'), + ], + [ + jsonRpcProvider({ + rpc: (chain) => ({ + http: chain.rpcUrls.default.http[0], + webSocket: getWebSocketUrl(chain), + }), + }), + ], +) const connectors = connectorsForWallets([ - { - groupName: 'Supported Wallets', - wallets: [ - metaMaskWallet({ chains, projectId: '' }), - injectedWallet({ chains }), - coinbaseWallet({ chains, appName: 'TEST' }) - ], - } -]); - + { + groupName: 'Supported Wallets', + wallets: [ + metaMaskWallet({ chains, projectId: '' }), + injectedWallet({ chains }), + coinbaseWallet({ chains, appName: 'TEST' }), + ], + }, +]) const wagmiConfig = createConfig({ - autoConnect: true, - connectors, - publicClient: webSocketPublicClient -}); - - -export default function Widget(props: { - config: MetaportConfig -}) { - const widgetTheme = getWidgetTheme(props.config.theme); - const theme = widgetTheme.mode === 'dark' ? darkTheme() : lightTheme(); - - const setTheme = useUIStore((state) => state.setTheme); - const setMpc = useMetaportStore((state) => state.setMpc); - const setOpen = useUIStore((state) => state.setOpen); - - theme.colors.connectButtonInnerBackground = widgetTheme.background; - theme.colors.connectButtonBackground = widgetTheme.background; - - useEffect(() => { - setOpen(props.config.openOnLoad); - }, []); - - useEffect(() => { - setTheme(widgetTheme); - }, [setTheme]); - - useEffect(() => { - setMpc(new MetaportCore(props.config)); - }, [setMpc]); - - return ( - - - - - - ) -} \ No newline at end of file + autoConnect: true, + connectors, + publicClient: webSocketPublicClient, +}) + +export default function Widget(props: { config: MetaportConfig }) { + const widgetTheme = getWidgetTheme(props.config.theme) + const theme = widgetTheme.mode === 'dark' ? darkTheme() : lightTheme() + + const setTheme = useUIStore((state) => state.setTheme) + const setMpc = useMetaportStore((state) => state.setMpc) + const setOpen = useUIStore((state) => state.setOpen) + + theme.colors.connectButtonInnerBackground = widgetTheme.background + theme.colors.connectButtonBackground = widgetTheme.background + + useEffect(() => { + setOpen(props.config.openOnLoad) + }, []) + + useEffect(() => { + setTheme(widgetTheme) + }, [setTheme]) + + useEffect(() => { + setMpc(new MetaportCore(props.config)) + }, [setMpc]) + + return ( + + + + + + ) +} diff --git a/src/components/Widget/index.ts b/src/components/Widget/index.ts index 820393d..81db243 100644 --- a/src/components/Widget/index.ts +++ b/src/components/Widget/index.ts @@ -1 +1 @@ -export { default } from "./Widget"; +export { default } from './Widget' diff --git a/src/components/WidgetBody/WidgetBody.tsx b/src/components/WidgetBody/WidgetBody.tsx index ae621f2..fa7f668 100644 --- a/src/components/WidgetBody/WidgetBody.tsx +++ b/src/components/WidgetBody/WidgetBody.tsx @@ -1,56 +1,51 @@ -import React from 'react'; +import React from 'react' import { useCollapseStore } from '../../store/Store' import { useMetaportStore } from '../../store/MetaportState' -import TokenList from '../TokenList'; -import ChainsList from '../ChainsList'; -import AmountInput from '../AmountInput'; -import SkStepper from '../Stepper'; -import SkPaper from '../SkPaper'; -import AmountErrorMessage from '../AmountErrorMessage'; -import SwitchDirection from '../SwitchDirection'; - -import common from '../../styles/common.module.scss'; -import { cls } from '../../core/helper'; -import { Collapse } from '@mui/material'; +import TokenList from '../TokenList' +import ChainsList from '../ChainsList' +import AmountInput from '../AmountInput' +import SkStepper from '../Stepper' +import SkPaper from '../SkPaper' +import AmountErrorMessage from '../AmountErrorMessage' +import SwitchDirection from '../SwitchDirection' +import common from '../../styles/common.module.scss' +import { cls } from '../../core/helper' +import { Collapse } from '@mui/material' export function WidgetBody(props) { + const expandedFrom = useCollapseStore((state) => state.expandedFrom) + const setExpandedFrom = useCollapseStore((state) => state.setExpandedFrom) - const expandedFrom = useCollapseStore((state) => state.expandedFrom); - const setExpandedFrom = useCollapseStore((state) => state.setExpandedFrom); - - const expandedTo = useCollapseStore((state) => state.expandedTo); - const setExpandedTo = useCollapseStore((state) => state.setExpandedTo); + const expandedTo = useCollapseStore((state) => state.expandedTo) + const setExpandedTo = useCollapseStore((state) => state.setExpandedTo) - const token = useMetaportStore((state) => state.token); - const chainName1 = useMetaportStore((state) => state.chainName1); - const chainName2 = useMetaportStore((state) => state.chainName2); + const token = useMetaportStore((state) => state.token) + const chainName1 = useMetaportStore((state) => state.chainName1) + const chainName2 = useMetaportStore((state) => state.chainName2) - const setChainName1 = useMetaportStore((state) => state.setChainName1); - const setChainName2 = useMetaportStore((state) => state.setChainName2); + const setChainName1 = useMetaportStore((state) => state.setChainName1) + const setChainName2 = useMetaportStore((state) => state.setChainName2) - const transferInProgress = useMetaportStore((state) => state.transferInProgress); + const transferInProgress = useMetaportStore((state) => state.transferInProgress) return (
- + -
+
@@ -70,7 +65,6 @@ export function WidgetBody(props) { setExpanded={setExpandedTo} chain={chainName2} setChain={setChainName2} - disabledChain={chainName1} disabled={transferInProgress} /> @@ -83,14 +77,11 @@ export function WidgetBody(props) { {token ? : null}
*/} -
- - ); + ) } - -export default WidgetBody; +export default WidgetBody diff --git a/src/components/WidgetBody/index.ts b/src/components/WidgetBody/index.ts index f10e885..9480734 100644 --- a/src/components/WidgetBody/index.ts +++ b/src/components/WidgetBody/index.ts @@ -1 +1 @@ -export { default } from "./WidgetBody"; +export { default } from './WidgetBody' diff --git a/src/components/WidgetUI/WidgetUI.tsx b/src/components/WidgetUI/WidgetUI.tsx index e71b370..ea7402a 100644 --- a/src/components/WidgetUI/WidgetUI.tsx +++ b/src/components/WidgetUI/WidgetUI.tsx @@ -20,67 +20,64 @@ * @copyright SKALE Labs 2023-Present */ -import React, { useEffect } from 'react'; -import { StyledEngineProvider } from '@mui/material/styles'; +import React, { useEffect } from 'react' +import { StyledEngineProvider } from '@mui/material/styles' -import { useAccount } from 'wagmi'; +import { useAccount } from 'wagmi' -import Collapse from '@mui/material/Collapse'; -import Fab from '@mui/material/Fab'; -import CloseIcon from '@mui/icons-material/Close'; +import Collapse from '@mui/material/Collapse' +import Fab from '@mui/material/Fab' +import CloseIcon from '@mui/icons-material/Close' -import { createTheme, ThemeProvider } from '@mui/material/styles'; -import { getMuiZIndex } from '../../core/themes'; +import { createTheme, ThemeProvider } from '@mui/material/styles' +import { getMuiZIndex } from '../../core/themes' -import skaleLogo from './skale_logo_short.svg'; +import skaleLogo from './skale_logo_short.svg' import { useUIStore } from '../../store/Store' import { useMetaportStore } from '../../store/MetaportState' -import SkPaper from '../SkPaper'; +import SkPaper from '../SkPaper' -import WidgetBody from '../WidgetBody'; +import WidgetBody from '../WidgetBody' +import { cls } from '../../core/helper' -import { cls } from '../../core/helper'; +import styles from '../../styles/styles.module.scss' +import common from '../../styles/common.module.scss' +import { PaletteMode } from '@mui/material' -import styles from "../../styles/styles.module.scss"; -import common from "../../styles/common.module.scss"; -import { PaletteMode } from '@mui/material'; +import { getWidgetTheme } from '../../core/themes' -import { getWidgetTheme } from '../../core/themes'; - -import SkConnect from '../SkConnect'; -import ErrorMessage from '../ErrorMessage'; -import { MetaportConfig } from '../../core/interfaces'; +import SkConnect from '../SkConnect' +import ErrorMessage from '../ErrorMessage' +import { MetaportConfig } from '../../core/interfaces' import MetaportCore from '../../core/metaport' - export function WidgetUI(props: { config: MetaportConfig }) { + const widgetTheme = getWidgetTheme(props.config.theme) - const widgetTheme = getWidgetTheme(props.config.theme); - - const setTheme = useUIStore((state) => state.setTheme); - const setMpc = useMetaportStore((state) => state.setMpc); - const setOpen = useUIStore((state) => state.setOpen); + const setTheme = useUIStore((state) => state.setTheme) + const setMpc = useMetaportStore((state) => state.setMpc) + const setOpen = useUIStore((state) => state.setOpen) useEffect(() => { - setOpen(props.config.openOnLoad); - }, []); + setOpen(props.config.openOnLoad) + }, []) useEffect(() => { - setTheme(widgetTheme); - }, [setTheme]); + setTheme(widgetTheme) + }, [setTheme]) useEffect(() => { - setMpc(new MetaportCore(props.config)); - }, [setMpc]); + setMpc(new MetaportCore(props.config)) + }, [setMpc]) - const { address } = useAccount(); + const { address } = useAccount() - const metaportTheme = useUIStore((state) => state.theme); - const isOpen = useUIStore((state) => state.open); + const metaportTheme = useUIStore((state) => state.theme) + const isOpen = useUIStore((state) => state.open) - const errorMessage = useMetaportStore((state) => state.errorMessage); + const errorMessage = useMetaportStore((state) => state.errorMessage) if (!metaportTheme) return
@@ -89,55 +86,55 @@ export function WidgetUI(props: { config: MetaportConfig }) { palette: { mode: metaportTheme.mode as PaletteMode, background: { - paper: metaportTheme.background + paper: metaportTheme.background, }, primary: { main: metaportTheme.primary, }, secondary: { - main: metaportTheme.background + main: metaportTheme.background, }, }, - }); + }) const handleClick = (_: React.MouseEvent) => { - setOpen(isOpen ? false : true); - }; + setOpen(isOpen ? false : true) + } - const themeCls = metaportTheme.mode === 'dark' ? styles.darkTheme : styles.lightTheme; - const commonThemeCls = metaportTheme.mode === 'dark' ? common.darkTheme : common.lightTheme; + const themeCls = metaportTheme.mode === 'dark' ? styles.darkTheme : styles.lightTheme + const commonThemeCls = metaportTheme.mode === 'dark' ? common.darkTheme : common.lightTheme - let fabTop: boolean = false; - let fabLeft: boolean = false; + let fabTop: boolean = false + let fabLeft: boolean = false if (metaportTheme) { - fabTop = metaportTheme.position.bottom === 'auto'; - fabLeft = metaportTheme.position.right === 'auto'; + fabTop = metaportTheme.position.bottom === 'auto' + fabLeft = metaportTheme.position.right === 'auto' } - const fabButton = (
-
-
- - {isOpen ? ( - - ) : () - } - + const fabButton = ( +
+
+
+ + {isOpen ? ( + + ) : ( + + )} + +
-
); + ) return ( @@ -146,9 +143,7 @@ export function WidgetUI(props: { config: MetaportConfig }) { className={cls(styles.imaWidgetBody, themeCls, commonThemeCls)} style={metaportTheme ? { ...metaportTheme.position, zIndex: metaportTheme.zIndex } : null} > -
- {fabTop ? fabButton : null} -
+
{fabTop ? fabButton : null}
@@ -156,19 +151,14 @@ export function WidgetUI(props: { config: MetaportConfig }) { - - {address ? :
} -
+ {address ? :
}
-
- {fabTop ? null : fabButton} -
+
{fabTop ? null : fabButton}
- ); + ) } - -export default WidgetUI; +export default WidgetUI diff --git a/src/components/WidgetUI/index.ts b/src/components/WidgetUI/index.ts index aedb06f..6a13aef 100644 --- a/src/components/WidgetUI/index.ts +++ b/src/components/WidgetUI/index.ts @@ -1 +1 @@ -export { default } from "./WidgetUI"; +export { default } from './WidgetUI' diff --git a/src/core/actions/action.ts b/src/core/actions/action.ts index 2332845..353f1bc 100644 --- a/src/core/actions/action.ts +++ b/src/core/actions/action.ts @@ -21,255 +21,235 @@ * @copyright SKALE Labs 2022-Present */ -import debug from 'debug'; +import debug from 'debug' -import { Chain } from '@wagmi/core'; -import { WalletClient } from 'viem'; -import { Contract, Provider } from 'ethers'; +import { Chain } from '@wagmi/core' +import { WalletClient } from 'viem' +import { Contract, Provider } from 'ethers' -import { MainnetChain, SChain } from '@skalenetwork/ima-js'; -import { TokenData, CustomAbiTokenType } from '../dataclasses'; -import MetaportCore, { createTokenData } from '../metaport'; -import { externalEvents } from '../events'; -import { toWei } from '../convertation'; -import { ActionState, LOADING_BUTTON_TEXT } from './actionState'; -import { isMainnet } from '../helper'; +import { MainnetChain, SChain } from '@skalenetwork/ima-js' +import { TokenData, CustomAbiTokenType } from '../dataclasses' +import MetaportCore, { createTokenData } from '../metaport' +import { externalEvents } from '../events' +import { toWei } from '../convertation' +import { ActionState, LOADING_BUTTON_TEXT } from './actionState' +import { isMainnet } from '../helper' -import { IMA_ABIS } from '../contracts'; -import { isMainnetChainId, getMainnetAbi } from '../network'; +import { IMA_ABIS } from '../contracts' +import { isMainnetChainId, getMainnetAbi } from '../network' -import { walletClientToSigner } from '../ethers'; +import { walletClientToSigner } from '../ethers' -debug.enable('*'); -const log = debug('metaport:actions'); +debug.enable('*') +const log = debug('metaport:actions') +export type ActionType = typeof Action -export type ActionType = typeof Action; +export class Action { + execute(): void { + return + } + preAction(): void { + return + } + + mpc: MetaportCore + + mainnet: MainnetChain + sChain1: SChain + sChain2: SChain + + chainName1: string + chainName2: string + address: string + amount: string + amountWei: bigint + tokenId: number + token: TokenData + + walletClient: WalletClient + + sourceToken: Contract + destToken: Contract + unwrappedToken: Contract | undefined + + originAddress: string + + activeStep: number + setActiveStep: React.Dispatch> + + setAmountErrorMessage: React.Dispatch> + setBtnText: (btnText: string) => void + + _switchNetwork: (chainId: number | bigint) => Chain | undefined + + constructor( + mpc: MetaportCore, + // mainnet: MainnetChain, + // sChain1: SChain, + // sChain2: SChain, + chainName1: string, + chainName2: string, + address: string, + amount: string, + tokenId: number, + token: TokenData, + setAmountErrorMessage: (amountErrorMessage: string) => void, + setBtnText: (btnText: string) => void, + switchNetwork: (chainId: number | bigint) => Chain | undefined, + walletClient: WalletClient, + ) { + this.mpc = mpc + // this.mainnet = mainnet; + // this.sChain1 = sChain1; + // this.sChain2 = sChain2; + this.chainName1 = chainName1 + 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) + //! todo: init token here!!!!!, do not pass !!! + + // todo: init token contracts! + + if (isMainnet(chainName1)) { + this.mainnet = this.mpc.mainnet() + } else { + this.sChain1 = this.mpc.schain(this.chainName1) + } + if (isMainnet(chainName2)) { + this.mainnet = this.mpc.mainnet() + } else { + this.sChain2 = this.mpc.schain(this.chainName2) + } + const provider1 = isMainnet(chainName1) ? this.mainnet.provider : this.sChain1.provider + const provider2 = isMainnet(chainName2) ? this.mainnet.provider : this.sChain2.provider -export class Action { - execute(): void { return; }; - preAction(): void { return; }; - - mpc: MetaportCore - - mainnet: MainnetChain - sChain1: SChain - sChain2: SChain - - chainName1: string - chainName2: string - address: string - amount: string - amountWei: bigint - tokenId: number - token: TokenData - - walletClient: WalletClient - - sourceToken: Contract - destToken: Contract - unwrappedToken: Contract | undefined - - originAddress: string - - activeStep: number - setActiveStep: React.Dispatch> - - setAmountErrorMessage: React.Dispatch> - setBtnText: (btnText: string) => void - - _switchNetwork: (chainId: number | bigint) => Chain | undefined - - constructor( - mpc: MetaportCore, - // mainnet: MainnetChain, - // sChain1: SChain, - // sChain2: SChain, - chainName1: string, - chainName2: string, - address: string, - amount: string, - tokenId: number, - token: TokenData, - setAmountErrorMessage: (amountErrorMessage: string) => void, - setBtnText: (btnText: string) => void, - switchNetwork: (chainId: number | bigint) => Chain | undefined, - walletClient: WalletClient - ) { - this.mpc = mpc; - // this.mainnet = mainnet; - // this.sChain1 = sChain1; - // this.sChain2 = sChain2; - this.chainName1 = chainName1; - 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); - //! todo: init token here!!!!!, do not pass !!! - - // todo: init token contracts! - - if (isMainnet(chainName1)) { - this.mainnet = this.mpc.mainnet() - } else { - this.sChain1 = this.mpc.schain(this.chainName1) - } - if (isMainnet(chainName2)) { - this.mainnet = this.mpc.mainnet() - } else { - this.sChain2 = this.mpc.schain(this.chainName2) - } - - const provider1 = isMainnet(chainName1) ? this.mainnet.provider : this.sChain1.provider; - const provider2 = isMainnet(chainName2) ? this.mainnet.provider : this.sChain2.provider; - - this.sourceToken = mpc.tokenContract( - chainName1, - token.keyname, - token.type, - provider1, - this.token.wrapper(this.chainName2) ? CustomAbiTokenType.erc20wrap : null, - this.token.wrapper(this.chainName2) ? this.chainName2 : null - ); - - this.originAddress = this.mpc.originAddress( - chainName1, chainName2, token.keyname, token.type); - - - console.log('----') - console.log(this.chainName2) - console.log(token) - console.log(token.wrapper(this.chainName2)) - console.log('----') - - if (this.token.wrapper(this.chainName2)) { - this.unwrappedToken = mpc.tokenContract( - chainName1, - token.keyname, - token.type, - provider1 - ); - } - - // todo: use wrapper address! - const destWrapperAddress = this.mpc.config.connections[this.chainName2][this.token.type][this.token.keyname].chains[this.chainName1].wrapper; - if (this.token.isClone(this.chainName2) && destWrapperAddress) { - this.destToken = mpc.tokenContract( - chainName2, - token.keyname, - token.type, - provider2, - CustomAbiTokenType.erc20wrap, - this.chainName1 - ) - } else { - this.destToken = mpc.tokenContract( - chainName2, - token.keyname, - token.type, - provider2 - ) - } - - // this.switchMetamaskChain = switchMetamaskChain; - - // this.setActiveStep = setActiveStep; - // this.activeStep = activeStep; - - this.setAmountErrorMessage = setAmountErrorMessage; - this.setBtnText = setBtnText; - this._switchNetwork = switchNetwork; - this.walletClient = walletClient; - - // if (this.tokenData) this.wrap = !!this.token.unwrappedSymbol && !this.token.clone; + this.sourceToken = mpc.tokenContract( + chainName1, + token.keyname, + token.type, + provider1, + this.token.wrapper(this.chainName2) ? CustomAbiTokenType.erc20wrap : null, + this.token.wrapper(this.chainName2) ? this.chainName2 : null, + ) + + this.originAddress = this.mpc.originAddress(chainName1, chainName2, token.keyname, token.type) + + console.log('----') + console.log(this.chainName2) + console.log(token) + console.log(token.wrapper(this.chainName2)) + console.log('----') + + if (this.token.wrapper(this.chainName2)) { + this.unwrappedToken = mpc.tokenContract(chainName1, token.keyname, token.type, provider1) } - // tokenContract( - // provider: Provider, - // source: boolean = true - // ): Contract { - // return this.mpc.tokenContract( - // source ? this.chainName1 : this.chainName2, - // this.token.keyname, - // this.token.type, - // provider - // ) - // } - - updateState( - currentState: ActionState, - transactionHash?: string, - timestamp?: string | number - ) { - log(`actionStateUpd: ${this.constructor.name} - ${currentState} - ${this.token.keyname} \ -- ${this.chainName1} -> ${this.chainName2}`); - externalEvents.actionStateUpdated( - this.constructor.name, - currentState, - { - chainName1: this.chainName1, - chainName2: this.chainName2, - address: this.address, - amount: this.amount, - amountWei: this.amountWei, - tokenId: this.tokenId - }, - transactionHash, - timestamp - ); - this.setBtnText(LOADING_BUTTON_TEXT[currentState]); + // todo: use wrapper address! + const destWrapperAddress = + this.mpc.config.connections[this.chainName2][this.token.type][this.token.keyname].chains[this.chainName1].wrapper + if (this.token.isClone(this.chainName2) && destWrapperAddress) { + this.destToken = mpc.tokenContract( + chainName2, + token.keyname, + token.type, + provider2, + CustomAbiTokenType.erc20wrap, + this.chainName1, + ) + } else { + this.destToken = mpc.tokenContract(chainName2, token.keyname, token.type, provider2) } - async getConnectedChain( - provider: Provider, - customAbiTokenType?: CustomAbiTokenType, - destChainName?: string - ): Promise { - let chain: MainnetChain | SChain; - this.updateState('switch'); - const currentChainId = this.walletClient.chain.id; - const { chainId } = await provider.getNetwork(); - log(`Current chainId: ${currentChainId}, required chainId: ${chainId} `); - if (currentChainId !== Number(chainId)) { - log(`Switching network to ${chainId}...`); - const chain = await this._switchNetwork(Number(chainId)); - if (!chain) { - throw new Error(`Failed to switch from ${currentChainId} to ${chainId} `); - } - log(`Network switched to ${chainId}...`); - } - const signer = walletClientToSigner(this.walletClient) - if (isMainnetChainId(chainId, this.mpc.config.skaleNetwork)) { - chain = new MainnetChain(signer.provider, getMainnetAbi(this.mpc.config.skaleNetwork)); - } else { - chain = new SChain(signer.provider, IMA_ABIS.schain); - } - const token = this.mpc.tokenContract( - destChainName === this.chainName1 ? this.chainName2 : this.chainName1, - this.token.keyname, - this.token.type, - chain.provider, - customAbiTokenType, - destChainName - ); - chain.erc20.addToken(this.token.keyname, token); - return chain; + // this.switchMetamaskChain = switchMetamaskChain; + + // this.setActiveStep = setActiveStep; + // this.activeStep = activeStep; + + this.setAmountErrorMessage = setAmountErrorMessage + this.setBtnText = setBtnText + this._switchNetwork = switchNetwork + this.walletClient = walletClient + + // if (this.tokenData) this.wrap = !!this.token.unwrappedSymbol && !this.token.clone; + } + + // tokenContract( + // provider: Provider, + // source: boolean = true + // ): Contract { + // return this.mpc.tokenContract( + // source ? this.chainName1 : this.chainName2, + // this.token.keyname, + // this.token.type, + // provider + // ) + // } + + updateState(currentState: ActionState, transactionHash?: string, timestamp?: string | number) { + log(`actionStateUpd: ${this.constructor.name} - ${currentState} - ${this.token.keyname} \ +- ${this.chainName1} -> ${this.chainName2}`) + externalEvents.actionStateUpdated( + this.constructor.name, + currentState, + { + chainName1: this.chainName1, + chainName2: this.chainName2, + address: this.address, + amount: this.amount, + amountWei: this.amountWei, + tokenId: this.tokenId, + }, + transactionHash, + timestamp, + ) + this.setBtnText(LOADING_BUTTON_TEXT[currentState]) + } + + async getConnectedChain( + provider: Provider, + customAbiTokenType?: CustomAbiTokenType, + destChainName?: string, + ): Promise { + let chain: MainnetChain | SChain + this.updateState('switch') + const currentChainId = this.walletClient.chain.id + const { chainId } = await provider.getNetwork() + log(`Current chainId: ${currentChainId}, required chainId: ${chainId} `) + if (currentChainId !== Number(chainId)) { + log(`Switching network to ${chainId}...`) + const chain = await this._switchNetwork(Number(chainId)) + if (!chain) { + throw new Error(`Failed to switch from ${currentChainId} to ${chainId} `) + } + log(`Network switched to ${chainId}...`) + } + const signer = walletClientToSigner(this.walletClient) + if (isMainnetChainId(chainId, this.mpc.config.skaleNetwork)) { + chain = new MainnetChain(signer.provider, getMainnetAbi(this.mpc.config.skaleNetwork)) + } else { + chain = new SChain(signer.provider, IMA_ABIS.schain) } + const token = this.mpc.tokenContract( + destChainName === this.chainName1 ? this.chainName2 : this.chainName1, + this.token.keyname, + this.token.type, + chain.provider, + customAbiTokenType, + destChainName, + ) + chain.erc20.addToken(this.token.keyname, token) + return chain + } } - export abstract class TransferAction extends Action { - transferComplete(tx): void { - externalEvents.transferComplete( - tx, - this.chainName1, - this.chainName2, - this.token.keyname, - false - ); - } + transferComplete(tx): void { + externalEvents.transferComplete(tx, this.chainName1, this.chainName2, this.token.keyname, false) + } } diff --git a/src/core/actions/actionState.ts b/src/core/actions/actionState.ts index 09f98c5..415e888 100644 --- a/src/core/actions/actionState.ts +++ b/src/core/actions/actionState.ts @@ -22,46 +22,46 @@ */ export type ActionState = - | 'init' - | 'approve' - | 'approveDone' - | 'transfer' - | 'transferDone' - | 'received' - | 'transferETH' - | 'transferETHDone' - | 'receivedETH' - | 'approveWrap' - | 'approveWrapDone' - | 'wrap' - | 'wrapDone' - | 'unwrap' - | 'unwrapDone' - | 'switch' - | 'unlock' - | 'unlockDone'; + | 'init' + | 'approve' + | 'approveDone' + | 'transfer' + | 'transferDone' + | 'received' + | 'transferETH' + | 'transferETHDone' + | 'receivedETH' + | 'approveWrap' + | 'approveWrapDone' + | 'wrap' + | 'wrapDone' + | 'unwrap' + | 'unwrapDone' + | 'switch' + | 'unlock' + | 'unlockDone' type LoadingButtonTextMap = { - [key in ActionState]: string; -}; + [key in ActionState]: string +} export const LOADING_BUTTON_TEXT: LoadingButtonTextMap = { - init: 'Initializing', - approve: 'Approving transfer', - approveDone: 'Transfer approved', - transfer: 'Transferring tokens', - transferDone: 'Waiting for tokens to be received', - received: 'Tokens received', - transferETH: 'Transferring ETH', - transferETHDone: 'Waiting for ETH to be received', - receivedETH: 'ETH received', - approveWrap: 'Approving wrap', - approveWrapDone: 'Wrap approved', - wrap: 'Wrapping tokens', - wrapDone: 'Tokens wrapped', - unwrap: 'Unwrapping tokens', - unwrapDone: 'Tokens unwrapped', - switch: 'Waiting for network switch', - unlock: 'Unlocking ETH', - unlockDone: 'ETH unlocked' -}; + init: 'Initializing', + approve: 'Approving transfer', + approveDone: 'Transfer approved', + transfer: 'Transferring tokens', + transferDone: 'Waiting for tokens to be received', + received: 'Tokens received', + transferETH: 'Transferring ETH', + transferETHDone: 'Waiting for ETH to be received', + receivedETH: 'ETH received', + approveWrap: 'Approving wrap', + approveWrapDone: 'Wrap approved', + wrap: 'Wrapping tokens', + wrapDone: 'Tokens wrapped', + unwrap: 'Unwrapping tokens', + unwrapDone: 'Tokens unwrapped', + switch: 'Waiting for network switch', + unlock: 'Unlocking ETH', + unlockDone: 'ETH unlocked', +} diff --git a/src/core/actions/checks.ts b/src/core/actions/checks.ts index f971539..0e6a83c 100644 --- a/src/core/actions/checks.ts +++ b/src/core/actions/checks.ts @@ -21,185 +21,168 @@ * @copyright SKALE Labs 2022-Present */ +import debug from 'debug' +import { Contract } from 'ethers' +import { MainnetChain, SChain } from '@skalenetwork/ima-js' -import debug from 'debug'; -import { Contract } from "ethers"; -import { MainnetChain, SChain } from '@skalenetwork/ima-js'; - -import { fromWei } from '../convertation'; -import { TokenData } from '../dataclasses/TokenData'; -import * as interfaces from '../interfaces'; -import { addressesEqual } from '../helper'; -import { DEFAULT_ERC20_DECIMALS, SFUEL_RESERVE_AMOUNT } from '../constants'; - - -debug.enable('*'); -const log = debug('metaport:actions:checks'); +import { fromWei } from '../convertation' +import { TokenData } from '../dataclasses/TokenData' +import * as interfaces from '../interfaces' +import { addressesEqual } from '../helper' +import { DEFAULT_ERC20_DECIMALS, SFUEL_RESERVE_AMOUNT } from '../constants' +debug.enable('*') +const log = debug('metaport:actions:checks') export async function checkEthBalance( // TODO: optimize balance checks - chain: MainnetChain | SChain, - address: string, - amount: string, - tokenData: TokenData, + chain: MainnetChain | SChain, + address: string, + amount: string, + tokenData: TokenData, ): Promise { - const checkRes: interfaces.CheckRes = { res: false }; - - try { - const balance = await chain.ethBalance(address); - log(`address: ${address}, eth balance: ${balance}, amount: ${amount}`); - const balanceEther = fromWei(balance, tokenData.meta.decimals); - if (Number(amount) + SFUEL_RESERVE_AMOUNT > Number(balanceEther)) { - checkRes.msg = `Current balance: ${balanceEther} ${tokenData.meta.symbol}. \ - ${SFUEL_RESERVE_AMOUNT} ETH will be reserved to cover transfer costs.`; - } else { - checkRes.res = true; - } - return checkRes; - } catch (err) { - log(err); - checkRes.msg = 'Something went wrong, check developer console'; - return checkRes; + const checkRes: interfaces.CheckRes = { res: false } + + try { + const balance = await chain.ethBalance(address) + log(`address: ${address}, eth balance: ${balance}, amount: ${amount}`) + const balanceEther = fromWei(balance, tokenData.meta.decimals) + if (Number(amount) + SFUEL_RESERVE_AMOUNT > Number(balanceEther)) { + checkRes.msg = `Current balance: ${balanceEther} ${tokenData.meta.symbol}. \ + ${SFUEL_RESERVE_AMOUNT} ETH will be reserved to cover transfer costs.` + } else { + checkRes.res = true } + return checkRes + } catch (err) { + log(err) + checkRes.msg = 'Something went wrong, check developer console' + return checkRes + } } - export async function checkERC20Balance( - address: string, - amount: string, - tokenData: TokenData, - tokenContract: Contract + address: string, + amount: string, + tokenData: TokenData, + tokenContract: Contract, ): Promise { - const checkRes: interfaces.CheckRes = { res: false }; - if (!amount || Number(amount) === 0) return checkRes; - try { - const balance = await tokenContract.balanceOf(address); - log(`address: ${address}, balanceWei: ${balance}, amount: ${amount}`); - const balanceEther = fromWei(balance, tokenData.meta.decimals); - if (Number(amount) > Number(balanceEther)) { - checkRes.msg = `Insufficient balance: ${balanceEther} ${tokenData.meta.symbol}`; - } else { - checkRes.res = true; - } - return checkRes; - } catch (err) { - log(err); - checkRes.msg = 'Something went wrong, check developer console'; - return checkRes; + const checkRes: interfaces.CheckRes = { res: false } + if (!amount || Number(amount) === 0) return checkRes + try { + const balance = await tokenContract.balanceOf(address) + log(`address: ${address}, balanceWei: ${balance}, amount: ${amount}`) + const balanceEther = fromWei(balance, tokenData.meta.decimals) + if (Number(amount) > Number(balanceEther)) { + checkRes.msg = `Insufficient balance: ${balanceEther} ${tokenData.meta.symbol}` + } else { + checkRes.res = true } + return checkRes + } catch (err) { + log(err) + checkRes.msg = 'Something went wrong, check developer console' + return checkRes + } } -export async function checkSFuelBalance( - address: string, - amount: string, - sChain: SChain -): Promise { - const checkRes: interfaces.CheckRes = { res: false }; - if (!amount || Number(amount) === 0) return checkRes; - try { - const balance = await sChain.provider.getBalance(address); - log(`address: ${address}, balanceWei: ${balance}, amount: ${amount}`); - const balanceEther = fromWei(balance, DEFAULT_ERC20_DECIMALS); - if (Number(amount) + SFUEL_RESERVE_AMOUNT > Number(balanceEther)) { - checkRes.msg = `Current balance: ${balanceEther}. \ - ${SFUEL_RESERVE_AMOUNT} sFUEL will be reserved for transfers.`; - } else { - checkRes.res = true; - } - return checkRes; - } catch (err) { - log(err); - checkRes.msg = 'Something went wrong, check developer console'; - return checkRes; +export async function checkSFuelBalance(address: string, amount: string, sChain: SChain): Promise { + const checkRes: interfaces.CheckRes = { res: false } + if (!amount || Number(amount) === 0) return checkRes + try { + const balance = await sChain.provider.getBalance(address) + log(`address: ${address}, balanceWei: ${balance}, amount: ${amount}`) + const balanceEther = fromWei(balance, DEFAULT_ERC20_DECIMALS) + if (Number(amount) + SFUEL_RESERVE_AMOUNT > Number(balanceEther)) { + checkRes.msg = `Current balance: ${balanceEther}. \ + ${SFUEL_RESERVE_AMOUNT} sFUEL will be reserved for transfers.` + } else { + checkRes.res = true } + return checkRes + } catch (err) { + log(err) + checkRes.msg = 'Something went wrong, check developer console' + return checkRes + } } - export async function checkERC20Allowance( - address: string, - approvalAddress: string, - amount: string, - tokenData: TokenData, - tokenContract: Contract + address: string, + approvalAddress: string, + amount: string, + tokenData: TokenData, + tokenContract: Contract, ): Promise { - const checkRes: interfaces.CheckRes = { res: false }; - if (!amount || Number(amount) === 0) return checkRes; - try { - const allowance = await tokenContract.allowance( - address, - approvalAddress - ) - const allowanceEther = fromWei(allowance, tokenData.meta.decimals); - log(`allowanceEther: ${allowanceEther}, amount: ${amount}`); - checkRes.res = Number(allowanceEther) >= Number(amount); - return checkRes; - } catch (err) { - log(err); - checkRes.msg = 'Something went wrong, check developer console'; - return checkRes; - } + const checkRes: interfaces.CheckRes = { res: false } + if (!amount || Number(amount) === 0) return checkRes + try { + const allowance = await tokenContract.allowance(address, approvalAddress) + const allowanceEther = fromWei(allowance, tokenData.meta.decimals) + log(`allowanceEther: ${allowanceEther}, amount: ${amount}`) + checkRes.res = Number(allowanceEther) >= Number(amount) + return checkRes + } catch (err) { + log(err) + checkRes.msg = 'Something went wrong, check developer console' + return checkRes + } } - export async function checkERC721( - address: string, - approvalAddress: string, - tokenId: number, - tokenContract: Contract + address: string, + approvalAddress: string, + tokenId: number, + tokenContract: Contract, ): Promise { - let approvedAddress: string; - const checkRes: interfaces.CheckRes = { res: true, approved: false }; - if (!tokenId) return checkRes; - try { - approvedAddress = await tokenContract.getApproved(tokenId) - log(`approvedAddress: ${approvedAddress}, address: ${address}`); - } catch (err) { - log(err); - checkRes.msg = 'tokenId does not exist, try again' - return checkRes; - } - try { - const currentOwner = await tokenContract.ownerOf(tokenId); - log(`currentOwner: ${currentOwner}, address: ${address}`); - if (!addressesEqual(currentOwner, address)) { - checkRes.msg = 'This account is not an owner of this tokenId'; - return checkRes; - } - } catch (err) { - log(err); - checkRes.msg = 'Something went wrong, check developer console'; - return checkRes; + let approvedAddress: string + const checkRes: interfaces.CheckRes = { res: true, approved: false } + if (!tokenId) return checkRes + try { + approvedAddress = await tokenContract.getApproved(tokenId) + log(`approvedAddress: ${approvedAddress}, address: ${address}`) + } catch (err) { + log(err) + checkRes.msg = 'tokenId does not exist, try again' + return checkRes + } + try { + const currentOwner = await tokenContract.ownerOf(tokenId) + log(`currentOwner: ${currentOwner}, address: ${address}`) + if (!addressesEqual(currentOwner, address)) { + checkRes.msg = 'This account is not an owner of this tokenId' + return checkRes } - checkRes.approved = addressesEqual(approvedAddress, approvalAddress); - return checkRes; + } catch (err) { + log(err) + checkRes.msg = 'Something went wrong, check developer console' + return checkRes + } + checkRes.approved = addressesEqual(approvedAddress, approvalAddress) + return checkRes } - export async function checkERC1155( - address: string, - approvalAddress: string, - tokenId: number, - amount: string, - tokenData: TokenData, - tokenContract: Contract + address: string, + approvalAddress: string, + tokenId: number, + amount: string, + tokenData: TokenData, + tokenContract: Contract, ): Promise { - const checkRes: interfaces.CheckRes = { res: true, approved: false }; - if (!tokenId || !amount) return checkRes; - - try { - const balance = await tokenContract.balanceOf(address, tokenId) - log(`address: ${address}, balanceEther: ${balance}, amount: ${amount}`); - if (Number(amount) > Number(balance)) { - checkRes.msg = `Current balance: ${balance} ${tokenData.meta.symbol}`; - } - checkRes.approved = await tokenContract.isApprovedForAll( - address, - approvalAddress - ) - } catch (err) { - log(err); - checkRes.msg = 'Something went wrong, check developer console'; - return checkRes; + const checkRes: interfaces.CheckRes = { res: true, approved: false } + if (!tokenId || !amount) return checkRes + + try { + const balance = await tokenContract.balanceOf(address, tokenId) + log(`address: ${address}, balanceEther: ${balance}, amount: ${amount}`) + if (Number(amount) > Number(balance)) { + checkRes.msg = `Current balance: ${balance} ${tokenData.meta.symbol}` } - return checkRes; -} \ No newline at end of file + checkRes.approved = await tokenContract.isApprovedForAll(address, approvalAddress) + } catch (err) { + log(err) + checkRes.msg = 'Something went wrong, check developer console' + return checkRes + } + return checkRes +} diff --git a/src/core/actions/erc20.ts b/src/core/actions/erc20.ts index 18b549e..fc19744 100644 --- a/src/core/actions/erc20.ts +++ b/src/core/actions/erc20.ts @@ -21,204 +21,157 @@ * @copyright SKALE Labs 2022-Present */ +import debug from 'debug' -import debug from 'debug'; +import { MainnetChain, SChain } from '@skalenetwork/ima-js' -import { MainnetChain, SChain } from '@skalenetwork/ima-js'; +import { externalEvents } from '../events' +import { toWei } from '../convertation' +import { MAX_APPROVE_AMOUNT } from '../constants' -import { externalEvents } from '../events'; -import { toWei } from '../convertation'; -import { MAX_APPROVE_AMOUNT } from '../constants'; - -import { TransferAction, Action } from '../actions/action'; -import { checkERC20Balance, checkERC20Allowance, checkSFuelBalance } from './checks'; -import { CustomAbiTokenType } from '../dataclasses'; - - -debug.enable('*'); -const log = debug('metaport:actions:erc20'); +import { TransferAction, Action } from '../actions/action' +import { checkERC20Balance, checkERC20Allowance, checkSFuelBalance } from './checks' +import { CustomAbiTokenType } from '../dataclasses' +debug.enable('*') +const log = debug('metaport:actions:erc20') export class TransferERC20S2S extends TransferAction { - async execute() { - this.updateState('init'); - const checkResAllowance = await checkERC20Allowance( - this.address, - this.sChain1.erc20.address, - this.amount, - this.token, - this.sourceToken - ); - const sChain = await this.getConnectedChain( - this.sChain1.provider, - this.token.wrapper(this.chainName2) ? CustomAbiTokenType.erc20wrap : null, - this.token.wrapper(this.chainName2) ? this.chainName2 : null - ) as SChain; - if (!checkResAllowance.res) { - this.updateState('approve'); - const approveTx = await sChain.erc20.approve( - this.token.keyname, - MAX_APPROVE_AMOUNT, - sChain.erc20.address, - { address: this.address } - ); - const txBlock = await sChain.provider.getBlock(approveTx.blockNumber); - this.updateState('approveDone', approveTx.hash, txBlock.timestamp); - externalEvents.transactionCompleted( - approveTx, txBlock.timestamp, this.chainName1, 'approve'); - log('ApproveERC20S:execute - tx completed: %O', approveTx); - } + async execute() { + this.updateState('init') + const checkResAllowance = await checkERC20Allowance( + this.address, + this.sChain1.erc20.address, + this.amount, + this.token, + this.sourceToken, + ) + const sChain = (await this.getConnectedChain( + this.sChain1.provider, + this.token.wrapper(this.chainName2) ? CustomAbiTokenType.erc20wrap : null, + this.token.wrapper(this.chainName2) ? this.chainName2 : null, + )) as SChain + if (!checkResAllowance.res) { + this.updateState('approve') + const approveTx = await sChain.erc20.approve(this.token.keyname, MAX_APPROVE_AMOUNT, sChain.erc20.address, { + address: this.address, + }) + const txBlock = await sChain.provider.getBlock(approveTx.blockNumber) + this.updateState('approveDone', approveTx.hash, txBlock.timestamp) + externalEvents.transactionCompleted(approveTx, txBlock.timestamp, this.chainName1, 'approve') + log('ApproveERC20S:execute - tx completed: %O', approveTx) + } - // main transfer + // main transfer - this.updateState('transfer'); + this.updateState('transfer') - const amountWei = toWei(this.amount, this.token.meta.decimals); + const amountWei = toWei(this.amount, this.token.meta.decimals) - let balanceOnDestination; + let balanceOnDestination - const tokenConnection = this.token.connections[this.chainName2]; + const tokenConnection = this.token.connections[this.chainName2] - const isDestinationSFuel = tokenConnection.wrapsSFuel && tokenConnection.clone; // TODO! + const isDestinationSFuel = tokenConnection.wrapsSFuel && tokenConnection.clone // TODO! - if (isDestinationSFuel) { - balanceOnDestination = await this.sChain2.provider.getBalance(this.address); - } else { - balanceOnDestination = await this.sChain2.getERC20Balance( - this.destToken, - this.address - ); - } - const tx = await sChain.erc20.transferToSchain( - this.chainName2, - this.originAddress, - amountWei, - { address: this.address } - ); - const block = await sChain.provider.getBlock(tx.blockNumber); - this.updateState('transferDone', tx.hash, block.timestamp); - if (isDestinationSFuel) { - await this.sChain2.waitETHBalanceChange( - this.address, - balanceOnDestination - ); - } else { - await this.sChain2.waitERC20BalanceChange( - this.destToken, - this.address, - balanceOnDestination - ); - } - this.updateState('received'); + if (isDestinationSFuel) { + balanceOnDestination = await this.sChain2.provider.getBalance(this.address) + } else { + balanceOnDestination = await this.sChain2.getERC20Balance(this.destToken, this.address) } - - async preAction() { - const checkResBalance = await checkERC20Balance( - this.address, - this.amount, - this.token, - this.sourceToken - ); - if (!checkResBalance.res) { - this.setAmountErrorMessage(checkResBalance.msg); - return - } - this.setAmountErrorMessage(null); + const tx = await sChain.erc20.transferToSchain(this.chainName2, this.originAddress, amountWei, { + address: this.address, + }) + const block = await sChain.provider.getBlock(tx.blockNumber) + this.updateState('transferDone', tx.hash, block.timestamp) + if (isDestinationSFuel) { + await this.sChain2.waitETHBalanceChange(this.address, balanceOnDestination) + } else { + await this.sChain2.waitERC20BalanceChange(this.destToken, this.address, balanceOnDestination) } + this.updateState('received') + } + + async preAction() { + const checkResBalance = await checkERC20Balance(this.address, this.amount, this.token, this.sourceToken) + if (!checkResBalance.res) { + this.setAmountErrorMessage(checkResBalance.msg) + return + } + this.setAmountErrorMessage(null) + } } - export class WrapSFuelERC20S extends Action { - async execute() { - log('WrapSFuelERC20S:execute - starting'); - this.updateState('wrap'); - const tx = await this.sChain1.erc20.fundExit( - this.token.keyname, - { - address: this.address, - value: this.amountWei - } - ); - const block = await this.sChain1.provider.getBlock(tx.blockNumber); - this.updateState('wrapDone', tx.hash, block.timestamp); - externalEvents.transactionCompleted(tx, block.timestamp, this.chainName1, 'wrapsfuel'); - log('WrapSFuelERC20S:execute - tx completed %O', tx); - } - - async preAction() { - log('WrapSFuelERC20S:preAction - starting'); - const checkResBalance = await checkSFuelBalance( - this.address, - this.amount, - this.sChain1 - ); - if (!checkResBalance.res) { - this.setAmountErrorMessage(checkResBalance.msg); - return - } - this.setAmountErrorMessage(null); + async execute() { + log('WrapSFuelERC20S:execute - starting') + this.updateState('wrap') + const tx = await this.sChain1.erc20.fundExit(this.token.keyname, { + address: this.address, + value: this.amountWei, + }) + const block = await this.sChain1.provider.getBlock(tx.blockNumber) + this.updateState('wrapDone', tx.hash, block.timestamp) + externalEvents.transactionCompleted(tx, block.timestamp, this.chainName1, 'wrapsfuel') + log('WrapSFuelERC20S:execute - tx completed %O', tx) + } + + async preAction() { + log('WrapSFuelERC20S:preAction - starting') + const checkResBalance = await checkSFuelBalance(this.address, this.amount, this.sChain1) + if (!checkResBalance.res) { + this.setAmountErrorMessage(checkResBalance.msg) + return } + this.setAmountErrorMessage(null) + } } - export class WrapERC20S extends Action { - async execute() { - this.updateState('init'); - const checkResAllowance = await checkERC20Allowance( - this.address, - this.token.connections[this.chainName2].wrapper, - this.amount, - this.token, - this.unwrappedToken - ); - const sChain = await this.getConnectedChain(this.sChain1.provider) as SChain; - const wrapperToken = this.mpc.tokenContract( - this.chainName1, - this.token.keyname, - this.token.type, - sChain.provider, - CustomAbiTokenType.erc20wrap, - this.chainName2 - ); - sChain.erc20.addToken(`wrap_${this.token.keyname}`, wrapperToken); - if (!checkResAllowance.res) { - this.updateState('approveWrap'); - const approveTx = await sChain.erc20.approve( - this.token.keyname, - MAX_APPROVE_AMOUNT, - this.token.address, - { address: this.address } - ); - const txBlock = await this.sChain1.provider.getBlock(approveTx.blockNumber); - this.updateState('approveWrapDone', approveTx.hash, txBlock.timestamp); - } - this.updateState('wrap'); - const amountWei = toWei(this.amount, this.token.meta.decimals); - const tx = await sChain.erc20.wrap( - `wrap_${this.token.keyname}`, - amountWei, - { address: this.address } - ); - const block = await this.sChain1.provider.getBlock(tx.blockNumber); - this.updateState('wrapDone', tx.hash, block.timestamp); + async execute() { + this.updateState('init') + const checkResAllowance = await checkERC20Allowance( + this.address, + this.token.connections[this.chainName2].wrapper, + this.amount, + this.token, + this.unwrappedToken, + ) + const sChain = (await this.getConnectedChain(this.sChain1.provider)) as SChain + const wrapperToken = this.mpc.tokenContract( + this.chainName1, + this.token.keyname, + this.token.type, + sChain.provider, + CustomAbiTokenType.erc20wrap, + this.chainName2, + ) + sChain.erc20.addToken(`wrap_${this.token.keyname}`, wrapperToken) + if (!checkResAllowance.res) { + this.updateState('approveWrap') + const approveTx = await sChain.erc20.approve(this.token.keyname, MAX_APPROVE_AMOUNT, this.token.address, { + address: this.address, + }) + const txBlock = await this.sChain1.provider.getBlock(approveTx.blockNumber) + this.updateState('approveWrapDone', approveTx.hash, txBlock.timestamp) } - - async preAction() { - const checkResBalance = await checkERC20Balance( - this.address, - this.amount, - this.token, - this.unwrappedToken - ); - if (!checkResBalance.res) { - this.setAmountErrorMessage(checkResBalance.msg); - return - } - this.setAmountErrorMessage(null); + this.updateState('wrap') + const amountWei = toWei(this.amount, this.token.meta.decimals) + const tx = await sChain.erc20.wrap(`wrap_${this.token.keyname}`, amountWei, { address: this.address }) + const block = await this.sChain1.provider.getBlock(tx.blockNumber) + this.updateState('wrapDone', tx.hash, block.timestamp) + } + + async preAction() { + const checkResBalance = await checkERC20Balance(this.address, this.amount, this.token, this.unwrappedToken) + if (!checkResBalance.res) { + this.setAmountErrorMessage(checkResBalance.msg) + return } + this.setAmountErrorMessage(null) + } } - // export class UnWrapERC20S2S123 extends Action { // static label = 'Unwrap' // static buttonText = 'Unwrap' @@ -262,194 +215,137 @@ export class WrapERC20S extends Action { // } // } - export class UnWrapERC20S extends Action { - async execute() { - const sChain = await this.getConnectedChain( - this.sChain2.provider, - CustomAbiTokenType.erc20wrap, - this.chainName1 - ) as SChain; - // const token = this.mpc.tokenContract( - // this.chainName2, - // this.token.keyname, - // this.token.type, - // sChain.provider, - // CustomAbiTokenType.erc20wrap, - // this.chainName1 - // ); - // sChain.erc20.addToken(this.token.keyname, token); - this.updateState('unwrap'); - let tx; - if (this.token.connections[this.chainName2].wrapsSFuel) { - tx = await sChain.erc20.undoExit( - this.token.keyname, - { address: this.address } - ); - } else { - const amountWei = toWei(this.amount, this.token.meta.decimals); - tx = await sChain.erc20.unwrap( - this.token.keyname, - amountWei, - { address: this.address } - ); - } - log('UnWrapERC20S:execute - tx completed %O', tx); - const block = await sChain.provider.getBlock(tx.blockNumber); - this.updateState('unwrapDone', tx.hash, block.timestamp); - externalEvents.transactionCompleted(tx, block.timestamp, this.chainName1, 'unwrap'); - externalEvents.unwrapComplete(tx, this.chainName2, this.token.keyname); + async execute() { + const sChain = (await this.getConnectedChain( + this.sChain2.provider, + CustomAbiTokenType.erc20wrap, + this.chainName1, + )) as SChain + // const token = this.mpc.tokenContract( + // this.chainName2, + // this.token.keyname, + // this.token.type, + // sChain.provider, + // CustomAbiTokenType.erc20wrap, + // this.chainName1 + // ); + // sChain.erc20.addToken(this.token.keyname, token); + this.updateState('unwrap') + let tx + if (this.token.connections[this.chainName2].wrapsSFuel) { + tx = await sChain.erc20.undoExit(this.token.keyname, { address: this.address }) + } else { + const amountWei = toWei(this.amount, this.token.meta.decimals) + tx = await sChain.erc20.unwrap(this.token.keyname, amountWei, { address: this.address }) } - - async preAction() { - log('preAction: UnWrapERC20S'); - const tokenContract = this.sChain1.erc20.tokens[this.token.keyname]; - const checkResBalance = await checkERC20Balance( - this.address, - this.amount, - this.token, - tokenContract - ); - if (!checkResBalance.res) { - this.setAmountErrorMessage(checkResBalance.msg); - return - } + log('UnWrapERC20S:execute - tx completed %O', tx) + const block = await sChain.provider.getBlock(tx.blockNumber) + this.updateState('unwrapDone', tx.hash, block.timestamp) + externalEvents.transactionCompleted(tx, block.timestamp, this.chainName1, 'unwrap') + externalEvents.unwrapComplete(tx, this.chainName2, this.token.keyname) + } + + async preAction() { + log('preAction: UnWrapERC20S') + const tokenContract = this.sChain1.erc20.tokens[this.token.keyname] + const checkResBalance = await checkERC20Balance(this.address, this.amount, this.token, tokenContract) + if (!checkResBalance.res) { + this.setAmountErrorMessage(checkResBalance.msg) + return } + } } - export class TransferERC20M2S extends TransferAction { - async execute() { - this.updateState('init'); - - // check approve + approve - const checkResAllowance = await checkERC20Allowance( - this.address, - this.mainnet.erc20.address, - this.amount, - this.token, - this.sourceToken - ); - const mainnet = await this.getConnectedChain(this.mainnet.provider) as MainnetChain; - if (!checkResAllowance.res) { - this.updateState('approve'); - const approveTx = await mainnet.erc20.approve( - this.token.keyname, - MAX_APPROVE_AMOUNT, - { address: this.address } - ); - const txBlock = await mainnet.provider.getBlock(approveTx.blockNumber); - this.updateState('approveDone', approveTx.hash, txBlock.timestamp); - } - this.updateState('transfer'); - const amountWei = toWei(this.amount, this.token.meta.decimals); - // const destTokenContract = this.sChain2.erc20.tokens[this.token.keyname]; - const balanceOnDestination = await this.sChain2.getERC20Balance( - this.destToken, - this.address - ); - const tx = await await mainnet.erc20.deposit( - this.chainName2, - this.token.keyname, - amountWei, - { address: this.address } - ); - const block = await mainnet.provider.getBlock(tx.blockNumber); - this.updateState('transferDone', tx.hash, block.timestamp); - externalEvents.transactionCompleted(tx, block.timestamp, this.chainName1, 'deposit'); - log('TransferERC20M2S:execute - tx completed %O', tx); - await this.sChain2.waitERC20BalanceChange( - this.destToken, this.address, balanceOnDestination); - this.updateState('received'); - log('TransferERC20M2S:execute - tokens received to destination chain'); - externalEvents.transferComplete( - tx.hash, - this.chainName1, - this.chainName2, - this.token.keyname, - false - ); + async execute() { + this.updateState('init') + + // check approve + approve + const checkResAllowance = await checkERC20Allowance( + this.address, + this.mainnet.erc20.address, + this.amount, + this.token, + this.sourceToken, + ) + const mainnet = (await this.getConnectedChain(this.mainnet.provider)) as MainnetChain + if (!checkResAllowance.res) { + this.updateState('approve') + const approveTx = await mainnet.erc20.approve(this.token.keyname, MAX_APPROVE_AMOUNT, { address: this.address }) + const txBlock = await mainnet.provider.getBlock(approveTx.blockNumber) + this.updateState('approveDone', approveTx.hash, txBlock.timestamp) } - - async preAction() { - const checkResBalance = await checkERC20Balance( - this.address, - this.amount, - this.token, - this.sourceToken - ); - if (!checkResBalance.res) { - this.setAmountErrorMessage(checkResBalance.msg); - return - } - this.setAmountErrorMessage(null); + this.updateState('transfer') + const amountWei = toWei(this.amount, this.token.meta.decimals) + // const destTokenContract = this.sChain2.erc20.tokens[this.token.keyname]; + const balanceOnDestination = await this.sChain2.getERC20Balance(this.destToken, this.address) + const tx = await await mainnet.erc20.deposit(this.chainName2, this.token.keyname, amountWei, { + address: this.address, + }) + const block = await mainnet.provider.getBlock(tx.blockNumber) + this.updateState('transferDone', tx.hash, block.timestamp) + externalEvents.transactionCompleted(tx, block.timestamp, this.chainName1, 'deposit') + log('TransferERC20M2S:execute - tx completed %O', tx) + await this.sChain2.waitERC20BalanceChange(this.destToken, this.address, balanceOnDestination) + this.updateState('received') + log('TransferERC20M2S:execute - tokens received to destination chain') + externalEvents.transferComplete(tx.hash, this.chainName1, this.chainName2, this.token.keyname, false) + } + + async preAction() { + const checkResBalance = await checkERC20Balance(this.address, this.amount, this.token, this.sourceToken) + if (!checkResBalance.res) { + this.setAmountErrorMessage(checkResBalance.msg) + return } + this.setAmountErrorMessage(null) + } } - export class TransferERC20S2M extends TransferAction { - async execute() { - this.updateState('init'); - // check approve + approve - - const checkResAllowance = await checkERC20Allowance( - this.address, - this.sChain1.erc20.address, - this.amount, - this.token, - this.sourceToken - ); - const sChain = await this.getConnectedChain(this.sChain1.provider) as SChain; - if (!checkResAllowance.res) { - this.updateState('approve'); - const approveTx = await sChain.erc20.approve( - this.token.keyname, - MAX_APPROVE_AMOUNT, - sChain.erc20.address, - { address: this.address } - ); - const txBlock = await sChain.provider.getBlock(approveTx.blockNumber); - this.updateState('approveDone', approveTx.hash, txBlock.timestamp); - externalEvents.transactionCompleted( - approveTx, txBlock.timestamp, this.chainName1, 'approve'); - log('ApproveERC20S:execute - tx completed: %O', approveTx); - } - this.updateState('transfer'); - const amountWei = toWei(this.amount, this.token.meta.decimals); - const balanceOnDestination = await this.mainnet.getERC20Balance( - this.destToken, this.address); - const tx = await sChain.erc20.withdraw( - this.originAddress, - amountWei, - { address: this.address } - ); - const block = await sChain.provider.getBlock(tx.blockNumber); - this.updateState('transferDone', tx.hash, block.timestamp); - externalEvents.transactionCompleted(tx, block.timestamp, this.chainName1, 'withdraw'); - log('TransferERC20S2M:execute - tx completed %O', tx); - this.mainnet.waitERC20BalanceChange(this.destToken, this.address, balanceOnDestination); - this.updateState('received'); - log('TransferERC20S2M:execute - tokens received to destination chain'); - externalEvents.transferComplete( - tx.hash, - this.chainName1, - this.chainName2, - this.token.keyname, - false - ); + async execute() { + this.updateState('init') + // check approve + approve + + const checkResAllowance = await checkERC20Allowance( + this.address, + this.sChain1.erc20.address, + this.amount, + this.token, + this.sourceToken, + ) + const sChain = (await this.getConnectedChain(this.sChain1.provider)) as SChain + if (!checkResAllowance.res) { + this.updateState('approve') + const approveTx = await sChain.erc20.approve(this.token.keyname, MAX_APPROVE_AMOUNT, sChain.erc20.address, { + address: this.address, + }) + const txBlock = await sChain.provider.getBlock(approveTx.blockNumber) + this.updateState('approveDone', approveTx.hash, txBlock.timestamp) + externalEvents.transactionCompleted(approveTx, txBlock.timestamp, this.chainName1, 'approve') + log('ApproveERC20S:execute - tx completed: %O', approveTx) } - - async preAction() { - const checkResBalance = await checkERC20Balance( - this.address, - this.amount, - this.token, - this.sourceToken - ); - if (!checkResBalance.res) { - this.setAmountErrorMessage(checkResBalance.msg); - return - } - this.setAmountErrorMessage(null); + this.updateState('transfer') + const amountWei = toWei(this.amount, this.token.meta.decimals) + const balanceOnDestination = await this.mainnet.getERC20Balance(this.destToken, this.address) + const tx = await sChain.erc20.withdraw(this.originAddress, amountWei, { address: this.address }) + const block = await sChain.provider.getBlock(tx.blockNumber) + this.updateState('transferDone', tx.hash, block.timestamp) + externalEvents.transactionCompleted(tx, block.timestamp, this.chainName1, 'withdraw') + log('TransferERC20S2M:execute - tx completed %O', tx) + this.mainnet.waitERC20BalanceChange(this.destToken, this.address, balanceOnDestination) + this.updateState('received') + log('TransferERC20S2M:execute - tokens received to destination chain') + externalEvents.transferComplete(tx.hash, this.chainName1, this.chainName2, this.token.keyname, false) + } + + async preAction() { + const checkResBalance = await checkERC20Balance(this.address, this.amount, this.token, this.sourceToken) + if (!checkResBalance.res) { + this.setAmountErrorMessage(checkResBalance.msg) + return } + this.setAmountErrorMessage(null) + } } diff --git a/src/core/actions/index.ts b/src/core/actions/index.ts index 875cc23..853fe53 100644 --- a/src/core/actions/index.ts +++ b/src/core/actions/index.ts @@ -21,68 +21,55 @@ * @copyright SKALE Labs 2022-Present */ -import debug from 'debug'; - -import { - TransferERC20S2S, - WrapERC20S, - UnWrapERC20S, - TransferERC20M2S, - TransferERC20S2M -} from './erc20'; - -import { Action } from './action'; - -import { isMainnet } from '../helper'; -import { ActionType, TokenType } from '../dataclasses'; -import { - S2S_POSTFIX, - M2S_POSTFIX, - S2M_POSTFIX, -} from '../constants'; - - -debug.enable('*'); -const log = debug('metaport:actions'); - - -export function getActionName( - chainName1: string, - chainName2: string, - tokenType: TokenType -): string { - if (!chainName1 || !chainName2 || !tokenType) return; - log(`Getting action name: ${chainName1} ${chainName2} ${tokenType}`); - let postfix = S2S_POSTFIX; - if (isMainnet(chainName1)) { postfix = M2S_POSTFIX; }; - if (isMainnet(chainName2)) { postfix = S2M_POSTFIX; }; - const actionName = tokenType + '_' + postfix; - log('Action name: ' + actionName); - return actionName; +import debug from 'debug' + +import { TransferERC20S2S, WrapERC20S, UnWrapERC20S, TransferERC20M2S, TransferERC20S2M } from './erc20' + +import { Action } from './action' + +import { isMainnet } from '../helper' +import { ActionType, TokenType } from '../dataclasses' +import { S2S_POSTFIX, M2S_POSTFIX, S2M_POSTFIX } from '../constants' + +debug.enable('*') +const log = debug('metaport:actions') + +export function getActionName(chainName1: string, chainName2: string, tokenType: TokenType): string { + if (!chainName1 || !chainName2 || !tokenType) return + log(`Getting action name: ${chainName1} ${chainName2} ${tokenType}`) + let postfix = S2S_POSTFIX + if (isMainnet(chainName1)) { + postfix = M2S_POSTFIX + } + if (isMainnet(chainName2)) { + postfix = S2M_POSTFIX + } + const actionName = tokenType + '_' + postfix + log('Action name: ' + actionName) + return actionName } +export const ACTIONS: { [actionType in ActionType]: typeof Action } = { + // eth_m2s: [TransferEthM2S], + // eth_s2m: [TransferEthS2M, UnlockEthM], + // eth_s2s: [], -export const ACTIONS: { [actionType in ActionType]: typeof Action; } = { - // eth_m2s: [TransferEthM2S], - // eth_s2m: [TransferEthS2M, UnlockEthM], - // eth_s2s: [], + wrap: WrapERC20S, + unwrap: UnWrapERC20S, - wrap: WrapERC20S, - unwrap: UnWrapERC20S, + erc20_m2s: TransferERC20M2S, + erc20_s2m: TransferERC20S2M, + erc20_s2s: TransferERC20S2S, - erc20_m2s: TransferERC20M2S, - erc20_s2m: TransferERC20S2M, - erc20_s2s: TransferERC20S2S, + // erc721_m2s: [TransferERC721M2S], + // erc721_s2m: [TransferERC721S2M], + // erc721_s2s: [TransferERC721S2S], - // erc721_m2s: [TransferERC721M2S], - // erc721_s2m: [TransferERC721S2M], - // erc721_s2s: [TransferERC721S2S], + // erc721meta_m2s: [TransferERC721M2S], + // erc721meta_s2m: [TransferERC721S2M], + // erc721meta_s2s: [TransferERC721S2S], - // erc721meta_m2s: [TransferERC721M2S], - // erc721meta_s2m: [TransferERC721S2M], - // erc721meta_s2s: [TransferERC721S2S], - - // erc1155_m2s: [TransferERC1155M2S], - // erc1155_s2m: [TransferERC1155S2M], - // erc1155_s2s: [TransferERC1155S2S] -} \ No newline at end of file + // erc1155_m2s: [TransferERC1155M2S], + // erc1155_s2m: [TransferERC1155S2M], + // erc1155_s2s: [TransferERC1155S2S] +} diff --git a/src/core/chain_id.ts b/src/core/chain_id.ts index 7d3cf08..f86a271 100644 --- a/src/core/chain_id.ts +++ b/src/core/chain_id.ts @@ -21,28 +21,24 @@ * @copyright SKALE Labs 2023-Present */ -import { ethers } from 'ethers'; - +import { ethers } from 'ethers' export function remove0x(s: any) { - if (!s.startsWith('0x')) return s; - return s.slice(2); + if (!s.startsWith('0x')) return s + return s.slice(2) } - function calcChainId(chainName: string): number { - let h = ethers.solidityPackedKeccak256(['string'], [chainName]); - // let h = soliditySha3(sChainName); - h = remove0x(h).toLowerCase(); - while (h.length < 64) - h = "0" + h; - h = h.substr(0, 13); - h = h.replace(/^0+/, ''); - return ethers.getNumber("0x" + h); + let h = ethers.solidityPackedKeccak256(['string'], [chainName]) + // let h = soliditySha3(sChainName); + h = remove0x(h).toLowerCase() + while (h.length < 64) h = '0' + h + h = h.substr(0, 13) + h = h.replace(/^0+/, '') + return ethers.getNumber('0x' + h) } - export function getChainId(chainName: string): number { - // if (chainName === MAINNET_CHAIN_NAME) return CHAIN_IDS[network]; - return calcChainId(chainName); + // if (chainName === MAINNET_CHAIN_NAME) return CHAIN_IDS[network]; + return calcChainId(chainName) } diff --git a/src/core/community_pool.ts b/src/core/community_pool.ts index 958d5b2..eed6df1 100644 --- a/src/core/community_pool.ts +++ b/src/core/community_pool.ts @@ -21,7 +21,6 @@ * @copyright SKALE Labs 2023-Present */ - // import debug from 'debug'; // import { MainnetChain, SChain } from '@skalenetwork/ima-js'; @@ -34,11 +33,9 @@ // MINIMUM_RECHARGE_AMOUNT // } from './constants'; - // debug.enable('*'); // const log = debug('metaport:core:community_pool'); - // export function getEmptyCommunityPoolData(): CommunityPoolData { // return { // exitGasOk: null, @@ -50,7 +47,6 @@ // }; // } - // export async function getCommunityPoolData( // address: string, // chainName1: string, @@ -102,4 +98,4 @@ // } // log('communityPoolData:', communityPoolData); // return communityPoolData; -// } \ No newline at end of file +// } diff --git a/src/core/constants.ts b/src/core/constants.ts index 15aff4f..0c016ce 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -21,87 +21,86 @@ * @copyright SKALE Labs 2022-Present */ -export const MAINNET_CHAIN_NAME = 'mainnet'; +export const MAINNET_CHAIN_NAME = 'mainnet' -export const ETH_ERC20_ADDRESS = '0xD2Aaa00700000000000000000000000000000000'; -export const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; +export const ETH_ERC20_ADDRESS = '0xD2Aaa00700000000000000000000000000000000' +export const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' -export const M2S_POSTFIX = 'm2s'; -export const S2M_POSTFIX = 's2m'; -export const S2S_POSTFIX = 's2s'; -export const WRAP_ACTION = 'wrap'; -export const UNWRAP_ACTION = 'unwrap'; +export const M2S_POSTFIX = 'm2s' +export const S2M_POSTFIX = 's2m' +export const S2S_POSTFIX = 's2s' +export const WRAP_ACTION = 'wrap' +export const UNWRAP_ACTION = 'unwrap' // tslint:disable-next-line -export const MAX_APPROVE_AMOUNT = '115792089237316195423570985008687907853269984665640564039457584007913129639935'; // (2^256 - 1 ) +export const MAX_APPROVE_AMOUNT = '115792089237316195423570985008687907853269984665640564039457584007913129639935' // (2^256 - 1 ) -export const DEFAULT_MIN_SFUEL_WEI = '21000000000000'; +export const DEFAULT_MIN_SFUEL_WEI = '21000000000000' -export const DEFAULT_ERC20_DECIMALS = '18'; -export const DEFAULT_ERROR_MSG = 'Ooops... Something went wrong...'; +export const DEFAULT_ERC20_DECIMALS = '18' +export const DEFAULT_ERROR_MSG = 'Ooops... Something went wrong...' -export const DEFAULT_MP_MARGIN = '20pt'; -export const DEFAULT_MP_Z_INDEX = 99000; +export const DEFAULT_MP_MARGIN = '20pt' +export const DEFAULT_MP_Z_INDEX = 99000 -export const HTTPS_PREFIX = 'https://'; +export const HTTPS_PREFIX = 'https://' export const MAINNET_EXPLORER_URLS: { [skaleNetwork: string]: string } = { - mainnet: 'https://etherscan.io', - staging: 'https://goerli.etherscan.io/', - legacy: 'https://goerli.etherscan.io/', - regression: 'https://goerli.etherscan.io/' -}; + mainnet: 'https://etherscan.io', + staging: 'https://goerli.etherscan.io/', + legacy: 'https://goerli.etherscan.io/', + regression: 'https://goerli.etherscan.io/', +} export const BASE_EXPLORER_URLS = { - mainnet: "explorer.mainnet.skalenodes.com", - staging: "explorer.staging-v3.skalenodes.com", - legacy: "explorer.staging-v3.skalenodes.com", - regression: "regression-explorer.skalenodes.com" -}; + mainnet: 'explorer.mainnet.skalenodes.com', + staging: 'explorer.staging-v3.skalenodes.com', + legacy: 'explorer.staging-v3.skalenodes.com', + regression: 'regression-explorer.skalenodes.com', +} // ETA constants -export const GAS_STATION_API_ENDPOINT = 'https://ethgasstation.info/api/ethgasAPI.json?'; +export const GAS_STATION_API_ENDPOINT = 'https://ethgasstation.info/api/ethgasAPI.json?' -export const IMA_M2S_WAIT = 5; -export const IMA_S2S_WAIT = 2; -export const IMA_HUB_WAIT = 5; +export const IMA_M2S_WAIT = 5 +export const IMA_S2S_WAIT = 2 +export const IMA_HUB_WAIT = 5 // ETF constants -export const COINGECKO_API_ENDPOINT = ''; +export const COINGECKO_API_ENDPOINT = '' -export const DEFAULT_FAUCET_URL = 'https://sfuel.skale.network/'; -export const SFUEL_CHEKCS_INTERVAL = 8; +export const DEFAULT_FAUCET_URL = 'https://sfuel.skale.network/' +export const SFUEL_CHEKCS_INTERVAL = 8 export const SFUEL_TEXT = { - 'sfuel': { - 'action': '', - 'warning': 'You may need sFUEL on the destination chain', - 'error': 'You need sFUEL to perform a transfer' - }, - 'gas': { - 'action': '', - 'warning': 'You may need ETH on the destination chain', - 'error': 'You need ETH to perform a transfer' - } -}; + sfuel: { + action: '', + warning: 'You may need sFUEL on the destination chain', + error: 'You need sFUEL to perform a transfer', + }, + gas: { + action: '', + warning: 'You may need ETH on the destination chain', + error: 'You need ETH to perform a transfer', + }, +} // faucet constants -export const ZERO_FUNCSIG = '0x00000000'; +export const ZERO_FUNCSIG = '0x00000000' -import faucetJson from '../metadata/faucet.json'; -export const FAUCET_DATA = faucetJson; +import faucetJson from '../metadata/faucet.json' +export const FAUCET_DATA = faucetJson // community pool -export const RECHARGE_MULTIPLIER = 1.2; -export const MINIMUM_RECHARGE_AMOUNT = 0.005; -export const COMMUNITY_POOL_WITHDRAW_GAS_LIMIT = '1500000'; -export const BALANCE_UPDATE_INTERVAL_SECONDS = 10; +export const RECHARGE_MULTIPLIER = 1.2 +export const MINIMUM_RECHARGE_AMOUNT = 0.005 +export const COMMUNITY_POOL_WITHDRAW_GAS_LIMIT = '1500000' +export const BALANCE_UPDATE_INTERVAL_SECONDS = 10 +export const SFUEL_RESERVE_AMOUNT = 0.02 -export const SFUEL_RESERVE_AMOUNT = 0.02; - -export const SUCCESS_EMOJIS = ['🎉', '👌', '✅', '🙌', '🎊']; \ No newline at end of file +export const SUCCESS_EMOJIS = ['🎉', '👌', '✅', '🙌', '🎊'] diff --git a/src/core/contracts.ts b/src/core/contracts.ts index f9e7b2c..3137e9e 100644 --- a/src/core/contracts.ts +++ b/src/core/contracts.ts @@ -21,41 +21,41 @@ * @copyright SKALE Labs 2023-Present */ -import { CustomAbiTokenType, TokenType } from './dataclasses'; +import { CustomAbiTokenType, TokenType } from './dataclasses' -import erc20Abi from '../metadata/erc20_abi.json'; -import erc721Abi from '../metadata/erc721_abi.json'; -import erc721MetaAbi from '../metadata/erc721meta_abi.json'; -import erc1155Abi from '../metadata/erc1155_abi.json'; -import erc20WrapperAbi from '../metadata/erc20_wrapper_abi.json'; -import sFuelWrapperAbi from '../metadata/sfuel_wrapper_abi.json'; +import erc20Abi from '../metadata/erc20_abi.json' +import erc721Abi from '../metadata/erc721_abi.json' +import erc721MetaAbi from '../metadata/erc721meta_abi.json' +import erc1155Abi from '../metadata/erc1155_abi.json' +import erc20WrapperAbi from '../metadata/erc20_wrapper_abi.json' +import sFuelWrapperAbi from '../metadata/sfuel_wrapper_abi.json' -import mainnetAddresses from '../metadata/addresses/mainnet.json'; -import stagingAddresses from '../metadata/addresses/staging.json'; -import legacyAddresses from '../metadata/addresses/legacy.json'; -import regressionAddresses from '../metadata/addresses/regression.json'; +import mainnetAddresses from '../metadata/addresses/mainnet.json' +import stagingAddresses from '../metadata/addresses/staging.json' +import legacyAddresses from '../metadata/addresses/legacy.json' +import regressionAddresses from '../metadata/addresses/regression.json' -import sChainAbi from '../metadata/schainAbi.json'; -import mainnetAbi from '../metadata/mainnetAbi.json'; +import sChainAbi from '../metadata/schainAbi.json' +import mainnetAbi from '../metadata/mainnetAbi.json' export const ERC_ABIS: { [tokenType in CustomAbiTokenType | TokenType]: { ['abi']: any } } = { - eth: null, - erc20: erc20Abi, - erc20wrap: erc20WrapperAbi, - sfuelwrap: sFuelWrapperAbi, - erc721: erc721Abi, - erc721meta: erc721MetaAbi, - erc1155: erc1155Abi + eth: null, + erc20: erc20Abi, + erc20wrap: erc20WrapperAbi, + sfuelwrap: sFuelWrapperAbi, + erc721: erc721Abi, + erc721meta: erc721MetaAbi, + erc1155: erc1155Abi, } export const IMA_ADDRESSES = { - mainnet: mainnetAddresses, - staging: stagingAddresses, - legacy: legacyAddresses, - regression: regressionAddresses + mainnet: mainnetAddresses, + staging: stagingAddresses, + legacy: legacyAddresses, + regression: regressionAddresses, } export const IMA_ABIS = { - mainnet: mainnetAbi, - schain: sChainAbi -} \ No newline at end of file + mainnet: mainnetAbi, + schain: sChainAbi, +} diff --git a/src/core/convertation.ts b/src/core/convertation.ts index 81ca100..bf0eea2 100644 --- a/src/core/convertation.ts +++ b/src/core/convertation.ts @@ -21,14 +21,12 @@ * @copyright SKALE Labs 2022-Present */ -import { formatUnits, parseUnits, BigNumberish } from 'ethers'; - +import { formatUnits, parseUnits, BigNumberish } from 'ethers' export function toWei(value: string, decimals: string): bigint { - return parseUnits(value, parseInt(decimals as string)); + return parseUnits(value, parseInt(decimals as string)) } - export function fromWei(value: BigNumberish, decimals: string): string { - return formatUnits(value, parseInt(decimals as string)); -} \ No newline at end of file + return formatUnits(value, parseInt(decimals as string)) +} diff --git a/src/core/dataclasses/ErrorMessage.ts b/src/core/dataclasses/ErrorMessage.ts index 3ecaff5..e916def 100644 --- a/src/core/dataclasses/ErrorMessage.ts +++ b/src/core/dataclasses/ErrorMessage.ts @@ -21,54 +21,47 @@ * @copyright SKALE Labs 2022-Present */ - - export class ErrorMessage { + icon: string + text: string + btnText?: string + fallback?: Function - icon: string - text: string - btnText?: string - fallback?: Function - - constructor(fallback?: Function) { - this.fallback = fallback - } + constructor(fallback?: Function) { + this.fallback = fallback + } } - export class NoTokenPairsMessage extends ErrorMessage { - constructor() { - super() - this.icon = 'link-off' - this.text = 'No token pairs for these chains' - } + constructor() { + super() + this.icon = 'link-off' + this.text = 'No token pairs for these chains' + } } - export class WrongNetworkMessage extends ErrorMessage { - constructor(fallback: Function) { - super(fallback) - this.icon = 'public-off' - this.text = 'Looks like you are connected to the wrong network' - this.btnText = 'Switch network' - } + constructor(fallback: Function) { + super(fallback) + this.icon = 'public-off' + this.text = 'Looks like you are connected to the wrong network' + this.btnText = 'Switch network' + } } - export class TransactionErrorMessage extends ErrorMessage { - constructor(text: string, fallback: Function) { - super(fallback) - this.icon = 'sentiment' - this.text = text - this.btnText = 'Try again' - } + constructor(text: string, fallback: Function) { + super(fallback) + this.icon = 'sentiment' + this.text = text + this.btnText = 'Try again' + } } - export class CustomErrorMessage extends ErrorMessage { - constructor(text: string) { - super(undefined) - this.icon = 'error' - this.text = text - } + constructor(text: string) { + super(undefined) + this.icon = 'error' + this.text = text + } } diff --git a/src/core/dataclasses/EthTokenData.ts b/src/core/dataclasses/EthTokenData.ts index 0b85bde..5047bfa 100644 --- a/src/core/dataclasses/EthTokenData.ts +++ b/src/core/dataclasses/EthTokenData.ts @@ -23,24 +23,23 @@ // import { ETH_ERC20_ADDRESS } from '../constants'; // import { TokenType } from './TokenType'; -import { TokenData } from './TokenData'; - +import { TokenData } from './TokenData' export default class EthTokenData extends TokenData { - // constructor(clone: boolean) { - // super( - // ETH_ERC20_ADDRESS, - // null, - // TokenType.eth, - // TokenType.eth, - // TokenType.eth, - // clone, - // null, - // null, - // TokenType.eth, - // null, - // null, - // null - // ); - // } -} \ No newline at end of file + // constructor(clone: boolean) { + // super( + // ETH_ERC20_ADDRESS, + // null, + // TokenType.eth, + // TokenType.eth, + // TokenType.eth, + // clone, + // null, + // null, + // TokenType.eth, + // null, + // null, + // null + // ); + // } +} diff --git a/src/core/dataclasses/Position.ts b/src/core/dataclasses/Position.ts index bcb5fc7..16abbf0 100644 --- a/src/core/dataclasses/Position.ts +++ b/src/core/dataclasses/Position.ts @@ -21,24 +21,22 @@ * @copyright SKALE Labs 2022-Present */ - -import { DEFAULT_MP_MARGIN } from '../constants'; - +import { DEFAULT_MP_MARGIN } from '../constants' export interface Position { - top: string; - right: string; - bottom: string; - left: string; + top: string + right: string + bottom: string + left: string } - -export interface PositionMap { [positionName: string]: Position; } - +export interface PositionMap { + [positionName: string]: Position +} export const Positions: PositionMap = { - topLeft: { top: DEFAULT_MP_MARGIN, left: DEFAULT_MP_MARGIN, right: 'auto', bottom: 'auto' }, - topRight: { top: DEFAULT_MP_MARGIN, left: 'auto', right: DEFAULT_MP_MARGIN, bottom: 'auto' }, - bottomRight: { top: 'auto', left: 'auto', right: DEFAULT_MP_MARGIN, bottom: DEFAULT_MP_MARGIN }, - bottomLeft: { top: 'auto', left: DEFAULT_MP_MARGIN, right: 'auto', bottom: DEFAULT_MP_MARGIN } + topLeft: { top: DEFAULT_MP_MARGIN, left: DEFAULT_MP_MARGIN, right: 'auto', bottom: 'auto' }, + topRight: { top: DEFAULT_MP_MARGIN, left: 'auto', right: DEFAULT_MP_MARGIN, bottom: 'auto' }, + bottomRight: { top: 'auto', left: 'auto', right: DEFAULT_MP_MARGIN, bottom: DEFAULT_MP_MARGIN }, + bottomLeft: { top: 'auto', left: DEFAULT_MP_MARGIN, right: 'auto', bottom: DEFAULT_MP_MARGIN }, } diff --git a/src/core/dataclasses/StepMetadata.ts b/src/core/dataclasses/StepMetadata.ts index 641cb3a..f88e220 100644 --- a/src/core/dataclasses/StepMetadata.ts +++ b/src/core/dataclasses/StepMetadata.ts @@ -21,87 +21,86 @@ * @copyright SKALE Labs 2022-Present */ -import debug from 'debug'; +import debug from 'debug' -import { TokenType } from './TokenType'; -import { isMainnet } from '../helper'; -import { - S2S_POSTFIX, - M2S_POSTFIX, - S2M_POSTFIX, -} from '../constants'; - - -debug.enable('*'); -const log = debug('metaport:actions'); +import { TokenType } from './TokenType' +import { isMainnet } from '../helper' +import { S2S_POSTFIX, M2S_POSTFIX, S2M_POSTFIX } from '../constants' +debug.enable('*') +const log = debug('metaport:actions') export enum ActionType { - erc20_m2s = 'erc20_m2s', - erc20_s2m = 'erc20_s2m', - erc20_s2s = 'erc20_s2s', - wrap = 'wrap', - unwrap = 'unwrap' + erc20_m2s = 'erc20_m2s', + erc20_s2m = 'erc20_s2m', + erc20_s2s = 'erc20_s2s', + wrap = 'wrap', + unwrap = 'unwrap', } - -export function getActionType( - chainName1: string, - chainName2: string, - tokenType: TokenType -): ActionType { - if (!chainName1 || !chainName2 || !tokenType) return; - let postfix = S2S_POSTFIX; - if (isMainnet(chainName1)) { postfix = M2S_POSTFIX; }; - if (isMainnet(chainName2)) { postfix = S2M_POSTFIX; }; - const actionName = tokenType + '_' + postfix; - log('Action name: ' + actionName); - return actionName as ActionType; +export function getActionType(chainName1: string, chainName2: string, tokenType: TokenType): ActionType { + if (!chainName1 || !chainName2 || !tokenType) return + let postfix = S2S_POSTFIX + if (isMainnet(chainName1)) { + postfix = M2S_POSTFIX + } + if (isMainnet(chainName2)) { + postfix = S2M_POSTFIX + } + const actionName = tokenType + '_' + postfix + log('Action name: ' + actionName) + return actionName as ActionType } - export abstract class StepMetadata { - headline: string = ''; - text: string = ''; - btnText: string = ''; - btnLoadingText: string = ''; - - onSource: boolean = true; - - constructor(public type: ActionType, public from: string, public to: string) { } + headline: string = '' + text: string = '' + btnText: string = '' + btnLoadingText: string = '' + + onSource: boolean = true + + constructor( + public type: ActionType, + public from: string, + public to: string, + ) {} } - export class TransferStepMetadata extends StepMetadata { - headline: string = 'Transfer to'; - text: string = 'You may need to approve first.'; - btnText: string = 'Transfer'; - btnLoadingText: string = 'Transferring'; + headline: string = 'Transfer to' + text: string = 'You may need to approve first.' + btnText: string = 'Transfer' + btnLoadingText: string = 'Transferring' - onSource: boolean = false; + onSource: boolean = false } - export class WrapStepMetadata extends StepMetadata { - headline: string = 'Wrap on'; - text: string = 'Tokens should be wrapped before transferring. Approval may be required.'; - btnText: string = 'Wrap'; - btnLoadingText: string = 'Wrapping'; - - constructor(public from: string, public to: string) { - super(ActionType.wrap, from, to) - } + headline: string = 'Wrap on' + text: string = 'Tokens should be wrapped before transferring. Approval may be required.' + btnText: string = 'Wrap' + btnLoadingText: string = 'Wrapping' + + constructor( + public from: string, + public to: string, + ) { + super(ActionType.wrap, from, to) + } } - export class UnwrapStepMetadata extends StepMetadata { - headline: string = 'Unwrap on'; - text: string = 'Tokens should be unwrapped after transferring.'; - btnText: string = 'Unwrap'; - btnLoadingText: string = 'Unwrapping'; - onSource: boolean = false; - - constructor(public from: string, public to: string) { - super(ActionType.unwrap, from, to) - } -} \ No newline at end of file + headline: string = 'Unwrap on' + text: string = 'Tokens should be unwrapped after transferring.' + btnText: string = 'Unwrap' + btnLoadingText: string = 'Unwrapping' + onSource: boolean = false + + constructor( + public from: string, + public to: string, + ) { + super(ActionType.unwrap, from, to) + } +} diff --git a/src/core/dataclasses/TokenData.ts b/src/core/dataclasses/TokenData.ts index 4408b47..f5694d2 100644 --- a/src/core/dataclasses/TokenData.ts +++ b/src/core/dataclasses/TokenData.ts @@ -21,45 +21,44 @@ * @copyright SKALE Labs 2022-Present */ -import { DEFAULT_ERC20_DECIMALS } from '../constants'; -import { TokenMetadata, ConnectedChainMap } from '../interfaces'; -import { TokenType } from './TokenType'; - +import { DEFAULT_ERC20_DECIMALS } from '../constants' +import { TokenMetadata, ConnectedChainMap } from '../interfaces' +import { TokenType } from './TokenType' export class TokenData { - address: string; - keyname: string; - type: TokenType; - meta: TokenMetadata; - connections: ConnectedChainMap; - chain: string; + address: string + keyname: string + type: TokenType + meta: TokenMetadata + connections: ConnectedChainMap + chain: string - constructor( - address: string, - type: TokenType, - tokenKeyname: string, - metadata: TokenMetadata, - connections: ConnectedChainMap, - chain: string - ) { - this.address = address; - this.meta = metadata; - this.meta.decimals = this.meta.decimals ? this.meta.decimals : DEFAULT_ERC20_DECIMALS; - this.connections = connections; - this.type = type; - this.keyname = tokenKeyname; - this.chain = chain; - } + constructor( + address: string, + type: TokenType, + tokenKeyname: string, + metadata: TokenMetadata, + connections: ConnectedChainMap, + chain: string, + ) { + this.address = address + this.meta = metadata + this.meta.decimals = this.meta.decimals ? this.meta.decimals : DEFAULT_ERC20_DECIMALS + this.connections = connections + this.type = type + this.keyname = tokenKeyname + this.chain = chain + } - wrapper(destChain: string): string | undefined { - return this.connections[destChain].wrapper - } + wrapper(destChain: string): string | undefined { + return this.connections[destChain].wrapper + } - isClone(destChain: string): boolean | undefined { - return this.connections[destChain].clone - } + isClone(destChain: string): boolean | undefined { + return this.connections[destChain].clone + } - wrapsSFuel(destChain: string): boolean | undefined { - return this.connections[destChain].wrapsSFuel - } -} \ No newline at end of file + wrapsSFuel(destChain: string): boolean | undefined { + return this.connections[destChain].wrapsSFuel + } +} diff --git a/src/core/dataclasses/TokenType.ts b/src/core/dataclasses/TokenType.ts index 31acdb5..d41e9c0 100644 --- a/src/core/dataclasses/TokenType.ts +++ b/src/core/dataclasses/TokenType.ts @@ -21,17 +21,15 @@ * @copyright SKALE Labs 2022-Present */ - export enum TokenType { - eth = 'eth', - erc20 = 'erc20', - erc721 = 'erc721', - erc721meta = 'erc721meta', - erc1155 = 'erc1155' + eth = 'eth', + erc20 = 'erc20', + erc721 = 'erc721', + erc721meta = 'erc721meta', + erc1155 = 'erc1155', } - export enum CustomAbiTokenType { - erc20wrap = 'erc20wrap', - sfuelwrap = 'sfuelwrap' -} \ No newline at end of file + erc20wrap = 'erc20wrap', + sfuelwrap = 'sfuelwrap', +} diff --git a/src/core/dataclasses/TransferRequestStatus.ts b/src/core/dataclasses/TransferRequestStatus.ts index 39a4830..42c56a0 100644 --- a/src/core/dataclasses/TransferRequestStatus.ts +++ b/src/core/dataclasses/TransferRequestStatus.ts @@ -21,12 +21,11 @@ * @copyright SKALE Labs 2023-Present */ - export enum TransferRequestStatus { - NO_REQEST = 0, - RECEIVED = 1, - IN_PROGRESS = 2, - IN_PROGRESS_HUB = 3, - DONE = 4, - ERROR = 5 -} \ No newline at end of file + NO_REQEST = 0, + RECEIVED = 1, + IN_PROGRESS = 2, + IN_PROGRESS_HUB = 3, + DONE = 4, + ERROR = 5, +} diff --git a/src/core/dataclasses/View.ts b/src/core/dataclasses/View.ts index 6059ac8..b6e8d89 100644 --- a/src/core/dataclasses/View.ts +++ b/src/core/dataclasses/View.ts @@ -21,11 +21,10 @@ * @copyright SKALE Labs 2022-Present */ - export enum View { - SANDBOX = 'SANDBOX', - UNWRAP = 'UNWRAP', - TRANSFER_REQUEST_SUMMARY = 'TRANSFER_REQUEST_SUMMARY', - TRANSFER_REQUEST_STEPS = 'TRANSFER_REQUEST_STEPS', - ERROR = 'ERROR' -} \ No newline at end of file + SANDBOX = 'SANDBOX', + UNWRAP = 'UNWRAP', + TRANSFER_REQUEST_SUMMARY = 'TRANSFER_REQUEST_SUMMARY', + TRANSFER_REQUEST_STEPS = 'TRANSFER_REQUEST_STEPS', + ERROR = 'ERROR', +} diff --git a/src/core/dataclasses/index.ts b/src/core/dataclasses/index.ts index 16b8139..a077799 100644 --- a/src/core/dataclasses/index.ts +++ b/src/core/dataclasses/index.ts @@ -21,9 +21,9 @@ * @copyright SKALE Labs 2022-Present */ -export * from "./TokenType"; -export * from "./TokenData"; -export * from "./Position"; -export * from "./TransferRequestStatus"; -export * from "./StepMetadata"; -export * from "./ErrorMessage"; +export * from './TokenType' +export * from './TokenData' +export * from './Position' +export * from './TransferRequestStatus' +export * from './StepMetadata' +export * from './ErrorMessage' diff --git a/src/core/ethers.ts b/src/core/ethers.ts index 8460931..cfacbf1 100644 --- a/src/core/ethers.ts +++ b/src/core/ethers.ts @@ -6,42 +6,38 @@ import { type PublicClient, usePublicClient } from 'wagmi' import { FallbackProvider, JsonRpcProvider } from 'ethers' import { type HttpTransport } from 'viem' - export function walletClientToSigner(walletClient: WalletClient) { - const { account, transport } = walletClient - const provider = new BrowserProvider(transport as Eip1193Provider, "any") - const signer = new JsonRpcSigner(provider, account.address) - return signer + const { account, transport } = walletClient + const provider = new BrowserProvider(transport as Eip1193Provider, 'any') + const signer = new JsonRpcSigner(provider, account.address) + return signer } /** Hook to convert a viem Wallet Client to an ethers.js Signer. */ export function useEthersSigner({ chainId }: { chainId?: number } = {}) { - const { data: walletClient } = useWalletClient({ chainId }) - return React.useMemo( - () => (walletClient ? walletClientToSigner(walletClient) : undefined), - [walletClient], - ) + const { data: walletClient } = useWalletClient({ chainId }) + return React.useMemo(() => (walletClient ? walletClientToSigner(walletClient) : undefined), [walletClient]) } export function publicClientToProvider(publicClient: PublicClient) { - const { chain, transport } = publicClient - const network = { - chainId: chain.id, - name: chain.name, - ensAddress: chain.contracts?.ensRegistry?.address, - } - if (transport.type === 'fallback') { - const providers = (transport.transports as ReturnType[]).map( - ({ value }) => new JsonRpcProvider(value?.url, network), - ) - if (providers.length === 1) return providers[0] - return new FallbackProvider(providers) - } - return new JsonRpcProvider(transport.url, network) + const { chain, transport } = publicClient + const network = { + chainId: chain.id, + name: chain.name, + ensAddress: chain.contracts?.ensRegistry?.address, + } + if (transport.type === 'fallback') { + const providers = (transport.transports as ReturnType[]).map( + ({ value }) => new JsonRpcProvider(value?.url, network), + ) + if (providers.length === 1) return providers[0] + return new FallbackProvider(providers) + } + return new JsonRpcProvider(transport.url, network) } /** Hook to convert a viem Public Client to an ethers.js Provider. */ export function useEthersProvider({ chainId }: { chainId?: number } = {}) { - const publicClient = usePublicClient({ chainId }) - return React.useMemo(() => publicClientToProvider(publicClient), [publicClient]) -} \ No newline at end of file + const publicClient = usePublicClient({ chainId }) + return React.useMemo(() => publicClientToProvider(publicClient), [publicClient]) +} diff --git a/src/core/events.ts b/src/core/events.ts index eff409f..3f66ae1 100644 --- a/src/core/events.ts +++ b/src/core/events.ts @@ -21,181 +21,168 @@ * @copyright SKALE Labs 2022-Present */ -import debug from 'debug'; -import * as interfaces from './interfaces/index'; -import { ActionState } from './actions/actionState'; - - -debug.enable('*'); -const log = debug('metaport:core:events'); +import debug from 'debug' +import * as interfaces from './interfaces/index' +import { ActionState } from './actions/actionState' +debug.enable('*') +const log = debug('metaport:core:events') function dispatchEvent(name: string, data = {}) { - log(`dispatchEvent - sending: ${name}`); - window.dispatchEvent(new CustomEvent(name, { detail: data })); - log(`dispatchEvent - sent: ${name}`); + log(`dispatchEvent - sending: ${name}`) + window.dispatchEvent(new CustomEvent(name, { detail: data })) + log(`dispatchEvent - sent: ${name}`) } - export namespace externalEvents { - export function balance(tokenSymbol: string, schainName: string, _balance: string) { - dispatchEvent('metaport_balance', { - "tokenSymbol": tokenSymbol, - "schainName": schainName, - "balance": _balance - }); - } - - export function transferComplete( - tx: string, - chainName1: string, - chainName2: string, - tokenSymbol: string, - unwrap: boolean = false - ) { - dispatchEvent('metaport_transferComplete', { - 'tokenSymbol': tokenSymbol, - 'from': chainName1, - 'to': chainName2, - 'tx': tx, - 'unwrap': unwrap - }); - } - - export function transferRequestCompleted(transferRequest: interfaces.TransferParams) { - dispatchEvent('metaport_transferRequestCompleted', { 'transferRequest': transferRequest }); - } - - export function transactionCompleted( - txData: any, - timestamp: string | number, - chainName: string, - txName: string - ): void { - log('WARNING: Event metaport_transactionCompleted will be removed in the next version') - dispatchEvent( - 'metaport_transactionCompleted', - { - tx: { - gasUsed: txData.gasUsed, - transactionHash: txData.transactionHash - }, - timestamp, - chainName, - txName - } - ); - } - - export function actionStateUpdated( - actionName: string, - actionState: ActionState, - actionData: { - chainName1: string, - chainName2: string, - address: string, - amount: string, - amountWei: bigint, - tokenId: number - }, - transactionHash?: string, - timestamp?: string | number - ): void { - dispatchEvent( - 'metaport_actionStateUpdated', - { - actionState, - actionName, - actionData, - transactionHash, - timestamp - } - ); - } - - export function unwrapComplete( - tx: string, - chainName1: string, - tokenSymbol: string, - ) { - dispatchEvent('metaport_unwrapComplete', { - 'tokenSymbol': tokenSymbol, - 'chain': chainName1, - 'tx': tx - }); - } - - export function ethUnlocked(tx: string) { - dispatchEvent('metaport_ethUnlocked', { - 'tx': tx - }); - } - - export function connected() { - dispatchEvent('metaport_connected'); - } + export function balance(tokenSymbol: string, schainName: string, _balance: string) { + dispatchEvent('metaport_balance', { + tokenSymbol: tokenSymbol, + schainName: schainName, + balance: _balance, + }) + } + + export function transferComplete( + tx: string, + chainName1: string, + chainName2: string, + tokenSymbol: string, + unwrap: boolean = false, + ) { + dispatchEvent('metaport_transferComplete', { + tokenSymbol: tokenSymbol, + from: chainName1, + to: chainName2, + tx: tx, + unwrap: unwrap, + }) + } + + export function transferRequestCompleted(transferRequest: interfaces.TransferParams) { + dispatchEvent('metaport_transferRequestCompleted', { transferRequest: transferRequest }) + } + + export function transactionCompleted( + txData: any, + timestamp: string | number, + chainName: string, + txName: string, + ): void { + log('WARNING: Event metaport_transactionCompleted will be removed in the next version') + dispatchEvent('metaport_transactionCompleted', { + tx: { + gasUsed: txData.gasUsed, + transactionHash: txData.transactionHash, + }, + timestamp, + chainName, + txName, + }) + } + + export function actionStateUpdated( + actionName: string, + actionState: ActionState, + actionData: { + chainName1: string + chainName2: string + address: string + amount: string + amountWei: bigint + tokenId: number + }, + transactionHash?: string, + timestamp?: string | number, + ): void { + dispatchEvent('metaport_actionStateUpdated', { + actionState, + actionName, + actionData, + transactionHash, + timestamp, + }) + } + + export function unwrapComplete(tx: string, chainName1: string, tokenSymbol: string) { + dispatchEvent('metaport_unwrapComplete', { + tokenSymbol: tokenSymbol, + chain: chainName1, + tx: tx, + }) + } + + export function ethUnlocked(tx: string) { + dispatchEvent('metaport_ethUnlocked', { + tx: tx, + }) + } + + export function connected() { + dispatchEvent('metaport_connected') + } } export namespace internalEvents { - export function updateParams(params) { - dispatchEvent('_metaport_updateParams', { - 'tokens': params.tokens, - 'chains': params.chains - }); - } - - export function transfer(params: interfaces.TransferParams): void { - dispatchEvent('_metaport_transfer', { - 'params': params - }); - } - - export function wrap(params) { - dispatchEvent('_metaport_wrap', { - 'amount': params.amount, - 'chain': params.chain, - 'tokens': params.tokens - }); - } - - export function unwrap(params) { - dispatchEvent('_metaport_unwrap', { - 'amount': params.amount, - 'chain': params.chain, - 'tokens': params.tokens - }); - } - - export function swap(params) { - dispatchEvent('_metaport_swap', { - 'amount': params.amount, - 'chain': params.chain, - 'tokens': params.tokens // todo! - }); - } - - export function close() { - dispatchEvent('_metaport_close'); - } - - export function open() { - dispatchEvent('_metaport_open'); - } - - export function reset() { - dispatchEvent('_metaport_reset'); - } - - export function requestBalance(params) { - dispatchEvent('_metaport_requestBalance', { - 'schainName': params.schainName, - 'tokenSymbol': params.tokenSymbol - }); - } - - export function setTheme(theme) { - dispatchEvent('_metaport_setTheme', { - 'theme': theme - }); - } -} \ No newline at end of file + export function updateParams(params) { + dispatchEvent('_metaport_updateParams', { + tokens: params.tokens, + chains: params.chains, + }) + } + + export function transfer(params: interfaces.TransferParams): void { + dispatchEvent('_metaport_transfer', { + params: params, + }) + } + + export function wrap(params) { + dispatchEvent('_metaport_wrap', { + amount: params.amount, + chain: params.chain, + tokens: params.tokens, + }) + } + + export function unwrap(params) { + dispatchEvent('_metaport_unwrap', { + amount: params.amount, + chain: params.chain, + tokens: params.tokens, + }) + } + + export function swap(params) { + dispatchEvent('_metaport_swap', { + amount: params.amount, + chain: params.chain, + tokens: params.tokens, // todo! + }) + } + + export function close() { + dispatchEvent('_metaport_close') + } + + export function open() { + dispatchEvent('_metaport_open') + } + + export function reset() { + dispatchEvent('_metaport_reset') + } + + export function requestBalance(params) { + dispatchEvent('_metaport_requestBalance', { + schainName: params.schainName, + tokenSymbol: params.tokenSymbol, + }) + } + + export function setTheme(theme) { + dispatchEvent('_metaport_setTheme', { + theme: theme, + }) + } +} diff --git a/src/core/explorer.ts b/src/core/explorer.ts index 7e663ce..4b48e8b 100644 --- a/src/core/explorer.ts +++ b/src/core/explorer.ts @@ -21,29 +21,23 @@ * @copyright SKALE Labs 2023-Present */ -import { - HTTPS_PREFIX, - MAINNET_CHAIN_NAME, - MAINNET_EXPLORER_URLS, - BASE_EXPLORER_URLS -} from './constants'; -import { SkaleNetwork } from './interfaces'; - +import { HTTPS_PREFIX, MAINNET_CHAIN_NAME, MAINNET_EXPLORER_URLS, BASE_EXPLORER_URLS } from './constants' +import { SkaleNetwork } from './interfaces' function getMainnetExplorerUrl(skaleNetwork: string) { - return MAINNET_EXPLORER_URLS[skaleNetwork]; + return MAINNET_EXPLORER_URLS[skaleNetwork] } function getSChainExplorerUrl(skaleNetwork: string) { - return BASE_EXPLORER_URLS[skaleNetwork]; + return BASE_EXPLORER_URLS[skaleNetwork] } export function getExplorerUrl(skaleNetwork: SkaleNetwork, chainName: string): string { - if (chainName === MAINNET_CHAIN_NAME) return getMainnetExplorerUrl(skaleNetwork); - return HTTPS_PREFIX + chainName + '.' + getSChainExplorerUrl(skaleNetwork); + if (chainName === MAINNET_CHAIN_NAME) return getMainnetExplorerUrl(skaleNetwork) + return HTTPS_PREFIX + chainName + '.' + getSChainExplorerUrl(skaleNetwork) } export function getTxUrl(chainName: string, skaleNetwork: SkaleNetwork, txHash: string): string { - const explorerUrl = getExplorerUrl(skaleNetwork, chainName); - return `${explorerUrl}/tx/${txHash}`; + const explorerUrl = getExplorerUrl(skaleNetwork, chainName) + return `${explorerUrl}/tx/${txHash}` } diff --git a/src/core/faucet.ts b/src/core/faucet.ts index 738a246..6ad0d9e 100644 --- a/src/core/faucet.ts +++ b/src/core/faucet.ts @@ -21,12 +21,10 @@ * @copyright SKALE Labs 2023-Present */ - // TODO! // import { ZERO_ADDRESS, ZERO_FUNCSIG, FAUCET_DATA } from './constants'; - // function getAddress(chainName: string, skaleNetwork: string) { // if (!isFaucetAvailable(chainName, skaleNetwork)) return ZERO_ADDRESS; // const faucet: { [x: string]: { [x: string]: string } } = FAUCET_DATA[skaleNetwork]; @@ -50,4 +48,4 @@ // const functionSig = getFunc(chainName, skaleNetwork); // const functionParam = web3.eth.abi.encodeParameter('address', address); // return { to: faucetAddress, data: functionSig + functionParam.slice(2) }; -// } \ No newline at end of file +// } diff --git a/src/core/fee_calculator.ts b/src/core/fee_calculator.ts index c60c91d..c14cd63 100644 --- a/src/core/fee_calculator.ts +++ b/src/core/fee_calculator.ts @@ -21,33 +21,31 @@ * @copyright SKALE Labs 2022-Present */ -import { fromWei as _fromWei, toBN } from 'web3-utils'; -import debug from 'debug'; +import { fromWei as _fromWei, toBN } from 'web3-utils' +import debug from 'debug' -import { CoinGeckoClient } from 'coingecko-api-v3'; -import * as interfaces from './interfaces/index'; +import { CoinGeckoClient } from 'coingecko-api-v3' +import * as interfaces from './interfaces/index' -debug.enable('*'); -const log = debug('metaport:components:fee_calculator'); +debug.enable('*') +const log = debug('metaport:components:fee_calculator') -export async function getTransactionFee( - transferRequest: interfaces.TransferParams -): Promise { - // todo: get actual gas limit for transfer - // todo: get actual gas price - log(transferRequest); - const gasLimit = toBN('250000'); - const gasPrice = toBN('10000000000'); +export async function getTransactionFee(transferRequest: interfaces.TransferParams): Promise { + // todo: get actual gas limit for transfer + // todo: get actual gas price + log(transferRequest) + const gasLimit = toBN('250000') + const gasPrice = toBN('10000000000') - const amountWei = gasLimit.mul(gasPrice); - const amountEth = _fromWei(amountWei); + const amountWei = gasLimit.mul(gasPrice) + const amountEth = _fromWei(amountWei) - const client = new CoinGeckoClient({ - timeout: 10000, - autoRetry: true, - }); - const res = await client.simplePrice({ ids: 'ethereum', vs_currencies: 'usd' }); - const ethToUsdRate = res.ethereum.usd; - const amountUSD = Number(amountEth) * ethToUsdRate; - return amountUSD; + const client = new CoinGeckoClient({ + timeout: 10000, + autoRetry: true, + }) + const res = await client.simplePrice({ ids: 'ethereum', vs_currencies: 'usd' }) + const ethToUsdRate = res.ethereum.usd + const amountUSD = Number(amountEth) * ethToUsdRate + return amountUSD } diff --git a/src/core/gas_station.ts b/src/core/gas_station.ts index 3dcf233..d9242cd 100644 --- a/src/core/gas_station.ts +++ b/src/core/gas_station.ts @@ -21,12 +21,11 @@ * @copyright SKALE Labs 2022-Present */ -import { GAS_STATION_API_ENDPOINT } from './constants'; - +import { GAS_STATION_API_ENDPOINT } from './constants' export async function getAvgWaitTime() { - const response = await fetch(GAS_STATION_API_ENDPOINT); - if (!response.ok) return 0; - const data = await response.json(); - return data.avgWait; + const response = await fetch(GAS_STATION_API_ENDPOINT) + if (!response.ok) return 0 + const data = await response.json() + return data.avgWait } diff --git a/src/core/helper.ts b/src/core/helper.ts index 062769b..ca8499d 100644 --- a/src/core/helper.ts +++ b/src/core/helper.ts @@ -21,85 +21,79 @@ * @copyright SKALE Labs 2022-Present */ -import { getAddress } from 'ethers'; +import { getAddress } from 'ethers' -import { MAINNET_CHAIN_NAME } from './constants'; +import { MAINNET_CHAIN_NAME } from './constants' // import utils from 'web3-utils'; -import { TransferRequestStatus } from './dataclasses'; -import { SkaleNetwork } from './interfaces'; - -import mainnetMeta from '../meta/mainnet/chains.json'; -import stagingMeta from '../meta/staging/chains.json'; -import legacyMeta from '../meta/legacy/chains.json'; -import regressionMeta from '../meta/regression/chains.json'; +import { TransferRequestStatus } from './dataclasses' +import { SkaleNetwork } from './interfaces' +import mainnetMeta from '../meta/mainnet/chains.json' +import stagingMeta from '../meta/staging/chains.json' +import legacyMeta from '../meta/legacy/chains.json' +import regressionMeta from '../meta/regression/chains.json' export const CHAINS_META = { - 'mainnet': mainnetMeta, - 'staging': stagingMeta, - 'legacy': legacyMeta, - 'regression': regressionMeta + mainnet: mainnetMeta, + staging: stagingMeta, + legacy: legacyMeta, + regression: regressionMeta, } - export function cls(...args: any): string { - const filteredArgs = args.map((clsName: any) => { - if (typeof clsName === 'string') return clsName; - if (Array.isArray(clsName) && clsName.length === 2 && clsName[1]) return clsName[0]; - }); - return filteredArgs.join(' '); + const filteredArgs = args.map((clsName: any) => { + if (typeof clsName === 'string') return clsName + if (Array.isArray(clsName) && clsName.length === 2 && clsName[1]) return clsName[0] + }) + return filteredArgs.join(' ') } - export function eqArrays(arr1, arr2) { - return JSON.stringify(arr1) === JSON.stringify(arr2); + return JSON.stringify(arr1) === JSON.stringify(arr2) } - export function isMainnet(chainName: string): boolean { - return chainName === MAINNET_CHAIN_NAME; + return chainName === MAINNET_CHAIN_NAME } - export function addressesEqual(address1: string, address2: string): boolean { - return getAddress(address1) === getAddress(address2); + return getAddress(address1) === getAddress(address2) } - export default function isTransferRequestActive(transferRequestStatus: TransferRequestStatus) { - return transferRequestStatus === TransferRequestStatus.IN_PROGRESS || - transferRequestStatus === TransferRequestStatus.IN_PROGRESS_HUB; + return ( + transferRequestStatus === TransferRequestStatus.IN_PROGRESS || + transferRequestStatus === TransferRequestStatus.IN_PROGRESS_HUB + ) } export function delay(ms: number) { - return new Promise(resolve => setTimeout(resolve, ms)); + return new Promise((resolve) => setTimeout(resolve, ms)) } - export function getChainAlias(skaleNetwork: SkaleNetwork, chainName: string, app?: string): string { - if (chainName === MAINNET_CHAIN_NAME) { - if (skaleNetwork != MAINNET_CHAIN_NAME) { - const network = skaleNetwork === 'staging' ? 'Goerli' : skaleNetwork; - return `Ethereum (${network})`; - } - return 'Ethereum'; + if (chainName === MAINNET_CHAIN_NAME) { + if (skaleNetwork != MAINNET_CHAIN_NAME) { + const network = skaleNetwork === 'staging' ? 'Goerli' : skaleNetwork + return `Ethereum (${network})` } - if (CHAINS_META[skaleNetwork] && CHAINS_META[skaleNetwork][chainName]) { - if (app && CHAINS_META[skaleNetwork][chainName].apps && - CHAINS_META[skaleNetwork][chainName].apps[app]) { - return CHAINS_META[skaleNetwork][chainName].apps[app].alias; - } - return CHAINS_META[skaleNetwork][chainName].alias; + return 'Ethereum' + } + if (CHAINS_META[skaleNetwork] && CHAINS_META[skaleNetwork][chainName]) { + if (app && CHAINS_META[skaleNetwork][chainName].apps && CHAINS_META[skaleNetwork][chainName].apps[app]) { + return CHAINS_META[skaleNetwork][chainName].apps[app].alias } - return chainName; + return CHAINS_META[skaleNetwork][chainName].alias + } + return chainName } export function getChainAppsMeta(chainName: string, skaleNetwork: SkaleNetwork) { - if (CHAINS_META[skaleNetwork][chainName] && CHAINS_META[skaleNetwork][chainName].apps) { - return CHAINS_META[skaleNetwork][chainName].apps; - } + if (CHAINS_META[skaleNetwork][chainName] && CHAINS_META[skaleNetwork][chainName].apps) { + return CHAINS_META[skaleNetwork][chainName].apps + } } export function getRandom(list: Array) { - return list[Math.floor((Math.random() * list.length))]; -} \ No newline at end of file + return list[Math.floor(Math.random() * list.length)] +} diff --git a/src/core/interfaces/ChainsMetadata.ts b/src/core/interfaces/ChainsMetadata.ts index d13d14f..f67b6dd 100644 --- a/src/core/interfaces/ChainsMetadata.ts +++ b/src/core/interfaces/ChainsMetadata.ts @@ -21,19 +21,19 @@ * @copyright SKALE Labs 2022-Present */ - export interface ChainMetadata { - alias?: string; - minSfuelWei?: string; - faucetUrl?: string; - apps?: { - [appName: string]: { - alias: string; - background: string; - url: string; - }; + alias?: string + minSfuelWei?: string + faucetUrl?: string + apps?: { + [appName: string]: { + alias: string + background: string + url: string } + } } - -export interface ChainsMetadataMap { [chainName: string]: ChainMetadata; } +export interface ChainsMetadataMap { + [chainName: string]: ChainMetadata +} diff --git a/src/core/interfaces/CheckRes.ts b/src/core/interfaces/CheckRes.ts index 1833b90..63f4304 100644 --- a/src/core/interfaces/CheckRes.ts +++ b/src/core/interfaces/CheckRes.ts @@ -21,9 +21,8 @@ * @copyright SKALE Labs 2022-Present */ - export interface CheckRes { - res: boolean; - approved?: boolean; - msg?: string; -} \ No newline at end of file + res: boolean + approved?: boolean + msg?: string +} diff --git a/src/core/interfaces/CommunityPoolData.ts b/src/core/interfaces/CommunityPoolData.ts index bed8636..cdd7b69 100644 --- a/src/core/interfaces/CommunityPoolData.ts +++ b/src/core/interfaces/CommunityPoolData.ts @@ -21,12 +21,11 @@ * @copyright SKALE Labs 2023-Present */ - export interface CommunityPoolData { - exitGasOk: boolean - isActive: boolean - balance: string - accountBalance: string - recommendedRechargeAmount: string - originalRecommendedRechargeAmount: string -} \ No newline at end of file + exitGasOk: boolean + isActive: boolean + balance: string + accountBalance: string + recommendedRechargeAmount: string + originalRecommendedRechargeAmount: string +} diff --git a/src/core/interfaces/Config.ts b/src/core/interfaces/Config.ts index fc784c4..49202fe 100644 --- a/src/core/interfaces/Config.ts +++ b/src/core/interfaces/Config.ts @@ -21,22 +21,22 @@ * @copyright SKALE Labs 2022-Present */ -import { TokenConnectionsMap, TokenMetadataMap, MetaportTheme } from '.'; +import { TokenConnectionsMap, TokenMetadataMap, MetaportTheme } from '.' -export type SkaleNetwork = 'mainnet' | 'staging' | 'legacy' | 'regression'; +export type SkaleNetwork = 'mainnet' | 'staging' | 'legacy' | 'regression' export interface MetaportConfig { - openOnLoad?: boolean; - openButton?: boolean; - autoLookup?: boolean; - debug?: boolean; + openOnLoad?: boolean + openButton?: boolean + autoLookup?: boolean + debug?: boolean - skaleNetwork: SkaleNetwork; - mainnetEndpoint?: string; - chains?: string[]; + skaleNetwork: SkaleNetwork + mainnetEndpoint?: string + chains?: string[] - tokens: TokenMetadataMap; - connections: TokenConnectionsMap; + tokens: TokenMetadataMap + connections: TokenConnectionsMap - theme?: MetaportTheme; + theme?: MetaportTheme } diff --git a/src/core/interfaces/RouteParams.ts b/src/core/interfaces/RouteParams.ts index 180be63..b7db5cf 100644 --- a/src/core/interfaces/RouteParams.ts +++ b/src/core/interfaces/RouteParams.ts @@ -21,11 +21,10 @@ * @copyright SKALE Labs 2022-Present */ -import { TokenType } from '../dataclasses/TokenType'; - +import { TokenType } from '../dataclasses/TokenType' export interface RouteParams { - hub: string; - tokenKeyname: string; - tokenType: TokenType; -} \ No newline at end of file + hub: string + tokenKeyname: string + tokenType: TokenType +} diff --git a/src/core/interfaces/Theme.ts b/src/core/interfaces/Theme.ts index 161dddd..af1b59c 100644 --- a/src/core/interfaces/Theme.ts +++ b/src/core/interfaces/Theme.ts @@ -21,16 +21,14 @@ * @copyright SKALE Labs 2022-Present */ -import { Position } from '../dataclasses/Position'; - - -export type PaletteMode = 'light' | 'dark'; +import { Position } from '../dataclasses/Position' +export type PaletteMode = 'light' | 'dark' export interface MetaportTheme { - mode: PaletteMode | string; - primary?: string; - background?: string; - position?: Position; - zIndex?: number; -} \ No newline at end of file + mode: PaletteMode | string + primary?: string + background?: string + position?: Position + zIndex?: number +} diff --git a/src/core/interfaces/TokenDataMap.ts b/src/core/interfaces/TokenDataMap.ts index 693b85a..2aba755 100644 --- a/src/core/interfaces/TokenDataMap.ts +++ b/src/core/interfaces/TokenDataMap.ts @@ -21,23 +21,29 @@ * @copyright SKALE Labs 2022-Present */ -import { TokenData } from '../../core/dataclasses/TokenData'; -import EthTokenData from '../../core/dataclasses/EthTokenData'; -import { TokenType } from '../../core/dataclasses/TokenType'; -import { Contract } from "ethers"; - - -export interface TokenDataMap { [tokenSymbol: string]: TokenData; } -export interface EthTokenDataMap { [tokenSymbol: string]: EthTokenData; } +import { TokenData } from '../../core/dataclasses/TokenData' +import EthTokenData from '../../core/dataclasses/EthTokenData' +import { TokenType } from '../../core/dataclasses/TokenType' +import { Contract } from 'ethers' +export interface TokenDataMap { + [tokenSymbol: string]: TokenData +} +export interface EthTokenDataMap { + [tokenSymbol: string]: EthTokenData +} export type TokenDataTypesMap = { - [TokenType.eth]: EthTokenDataMap - [TokenType.erc20]: TokenDataMap - [TokenType.erc721]: TokenDataMap - [TokenType.erc721meta]: TokenDataMap - [TokenType.erc1155]: TokenDataMap + [TokenType.eth]: EthTokenDataMap + [TokenType.erc20]: TokenDataMap + [TokenType.erc721]: TokenDataMap + [TokenType.erc721meta]: TokenDataMap + [TokenType.erc1155]: TokenDataMap } -export interface TokenContractsMap { [tokenKeyname: string]: Contract; }; -export interface TokenBalancesMap { [tokenKeyname: string]: bigint; }; \ No newline at end of file +export interface TokenContractsMap { + [tokenKeyname: string]: Contract +} +export interface TokenBalancesMap { + [tokenKeyname: string]: bigint +} diff --git a/src/core/interfaces/TokenMetadata.ts b/src/core/interfaces/TokenMetadata.ts index f9cdb74..241305f 100644 --- a/src/core/interfaces/TokenMetadata.ts +++ b/src/core/interfaces/TokenMetadata.ts @@ -22,10 +22,12 @@ */ export interface TokenMetadata { - symbol: string, - name?: string, - iconUrl?: string, - decimals?: string + symbol: string + name?: string + iconUrl?: string + decimals?: string } -export interface TokenMetadataMap { [tokenName: string]: TokenMetadata; } \ No newline at end of file +export interface TokenMetadataMap { + [tokenName: string]: TokenMetadata +} diff --git a/src/core/interfaces/Tokens.ts b/src/core/interfaces/Tokens.ts index 3695d2e..262870e 100644 --- a/src/core/interfaces/Tokens.ts +++ b/src/core/interfaces/Tokens.ts @@ -22,23 +22,31 @@ */ export interface EthToken { - chains: ConnectedChainMap + chains: ConnectedChainMap } export interface Token { - address?: string, - chains: ConnectedChainMap + address?: string + chains: ConnectedChainMap } export interface ConnectedChain { - hub?: string - wrapper?: string - wrapsSFuel?: boolean - clone?: boolean + hub?: string + wrapper?: string + wrapsSFuel?: boolean + clone?: boolean } -export interface ConnectedChainMap { [chainName: string]: ConnectedChain; } -export interface ChainTokensMap { [tokenSymbol: string]: Token; } +export interface ConnectedChainMap { + [chainName: string]: ConnectedChain +} +export interface ChainTokensMap { + [tokenSymbol: string]: Token +} // export interface TokenTypeMap { [tokenType: string]: EthToken | ChainTokensMap; } -export interface TokenTypeMap { [tokenType: string]: ChainTokensMap; } -export interface TokenConnectionsMap { [chainName: string]: TokenTypeMap; } \ No newline at end of file +export interface TokenTypeMap { + [tokenType: string]: ChainTokensMap +} +export interface TokenConnectionsMap { + [chainName: string]: TokenTypeMap +} diff --git a/src/core/interfaces/TransactionHistory.ts b/src/core/interfaces/TransactionHistory.ts index 4a30ac4..0b03e6a 100644 --- a/src/core/interfaces/TransactionHistory.ts +++ b/src/core/interfaces/TransactionHistory.ts @@ -1,4 +1,3 @@ - /** * @license * SKALE Metaport @@ -22,16 +21,14 @@ * @copyright SKALE Labs 2023-Present */ - interface TxData { - gasUsed: number; - transactionHash: string; + gasUsed: number + transactionHash: string } - export interface TransactionHistory { - tx: TxData; - timestamp: number; - chainName: string; - txName: string; -} \ No newline at end of file + tx: TxData + timestamp: number + chainName: string + txName: string +} diff --git a/src/core/interfaces/TransferParams.ts b/src/core/interfaces/TransferParams.ts index a2a2b24..5287232 100644 --- a/src/core/interfaces/TransferParams.ts +++ b/src/core/interfaces/TransferParams.ts @@ -21,19 +21,18 @@ * @copyright SKALE Labs 2022-Present */ -import { TokenType } from '../dataclasses/TokenType'; -import { RouteParams } from './RouteParams'; - +import { TokenType } from '../dataclasses/TokenType' +import { RouteParams } from './RouteParams' export interface TransferParams { - tokenKeyname: string; - tokenType: TokenType; - amount?: string; - tokenId?: number; - chains?: string[]; - lockValue?: boolean; - route?: RouteParams; - text?: string; - fromApp?: string; - toApp?: string; -} \ No newline at end of file + tokenKeyname: string + tokenType: TokenType + amount?: string + tokenId?: number + chains?: string[] + lockValue?: boolean + route?: RouteParams + text?: string + fromApp?: string + toApp?: string +} diff --git a/src/core/interfaces/index.ts b/src/core/interfaces/index.ts index 945ebdf..bb0ca49 100644 --- a/src/core/interfaces/index.ts +++ b/src/core/interfaces/index.ts @@ -21,13 +21,13 @@ * @copyright SKALE Labs 2022-Present */ -export * from "./Config"; -export * from "./ChainsMetadata"; -export * from "./Theme"; -export * from "./Tokens"; -export * from "./TokenDataMap"; -export * from "./TransferParams"; -export * from "./CheckRes"; -export * from "./TransactionHistory"; -export * from "./CommunityPoolData"; -export * from "./TokenMetadata"; +export * from './Config' +export * from './ChainsMetadata' +export * from './Theme' +export * from './Tokens' +export * from './TokenDataMap' +export * from './TransferParams' +export * from './CheckRes' +export * from './TransactionHistory' +export * from './CommunityPoolData' +export * from './TokenMetadata' diff --git a/src/core/metadata.ts b/src/core/metadata.ts index e150fda..ae784c6 100644 --- a/src/core/metadata.ts +++ b/src/core/metadata.ts @@ -21,56 +21,51 @@ * @copyright SKALE Labs 2023-Present */ -import { TokenData } from './dataclasses'; -import { SkaleNetwork } from './interfaces'; -import { MAINNET_CHAIN_NAME } from './constants'; +import { TokenData } from './dataclasses' +import { SkaleNetwork } from './interfaces' +import { MAINNET_CHAIN_NAME } from './constants' -import * as MAINNET_CHAIN_ICONS from '../meta/mainnet/icons'; -import * as STAGING_CHAIN_ICONS from '../meta/staging/icons'; -import * as LEGACY_CHAIN_ICONS from '../meta/legacy/icons'; -import * as REGRESSION_CHAIN_ICONS from '../meta/regression/icons'; - -import * as icons from '../icons'; +import * as MAINNET_CHAIN_ICONS from '../meta/mainnet/icons' +import * as STAGING_CHAIN_ICONS from '../meta/staging/icons' +import * as LEGACY_CHAIN_ICONS from '../meta/legacy/icons' +import * as REGRESSION_CHAIN_ICONS from '../meta/regression/icons' +import * as icons from '../icons' const CHAIN_ICONS = { - 'mainnet': MAINNET_CHAIN_ICONS, - 'staging': STAGING_CHAIN_ICONS, - 'legacy': LEGACY_CHAIN_ICONS, - 'regression': REGRESSION_CHAIN_ICONS + mainnet: MAINNET_CHAIN_ICONS, + staging: STAGING_CHAIN_ICONS, + legacy: LEGACY_CHAIN_ICONS, + regression: REGRESSION_CHAIN_ICONS, } - export function chainIconPath(skaleNetwork: SkaleNetwork, name: string, app?: string) { - if (!name) return; - let filename = name.toLowerCase() - if (app) filename += `-${app}`; - if (name === MAINNET_CHAIN_NAME) { - return CHAIN_ICONS[skaleNetwork]['mainnet']; - } - filename = filename.replace(/-([a-z])/g, (_, g) => g.toUpperCase()) - if (CHAIN_ICONS[skaleNetwork][filename]) { - return CHAIN_ICONS[skaleNetwork][filename]; - } + if (!name) return + let filename = name.toLowerCase() + if (app) filename += `-${app}` + if (name === MAINNET_CHAIN_NAME) { + return CHAIN_ICONS[skaleNetwork]['mainnet'] + } + filename = filename.replace(/-([a-z])/g, (_, g) => g.toUpperCase()) + if (CHAIN_ICONS[skaleNetwork][filename]) { + return CHAIN_ICONS[skaleNetwork][filename] + } } - export function tokenIcon(name: string) { - if (!name) return; - const key = name.toLowerCase() - if (icons[key]) { - return icons[key]; - } else { - return icons['eth']; - } + if (!name) return + const key = name.toLowerCase() + if (icons[key]) { + return icons[key] + } else { + return icons['eth'] + } } - export function tokenIconPath(token: TokenData) { - return token.meta.iconUrl ?? tokenIcon(token.meta.symbol); + return token.meta.iconUrl ?? tokenIcon(token.meta.symbol) } - export function getTokenName(token: TokenData): string { - return token.meta.name ?? token.meta.symbol; -} \ No newline at end of file + return token.meta.name ?? token.meta.symbol +} diff --git a/src/core/metaport.ts b/src/core/metaport.ts index 8da24ec..8eba3a8 100644 --- a/src/core/metaport.ts +++ b/src/core/metaport.ts @@ -21,217 +21,170 @@ * @copyright SKALE Labs 2023-Present */ -import { Provider, JsonRpcProvider, Contract } from "ethers"; +import { Provider, JsonRpcProvider, Contract } from 'ethers' -import { MetaportConfig, TokenDataTypesMap, Token, TokenContractsMap, TokenBalancesMap } from './interfaces'; -import { TokenType, TokenData, CustomAbiTokenType } from './dataclasses'; +import { MetaportConfig, TokenDataTypesMap, Token, TokenContractsMap, TokenBalancesMap } from './interfaces' +import { TokenType, TokenData, CustomAbiTokenType } from './dataclasses' -import { getEmptyTokenDataMap } from './tokens/helper'; -import { getChainEndpoint, initIMA, initMainnet, initSChain } from './network'; -import { ERC_ABIS } from './contracts'; +import { getEmptyTokenDataMap } from './tokens/helper' +import { getChainEndpoint, initIMA, initMainnet, initSChain } from './network' +import { ERC_ABIS } from './contracts' +import debug from 'debug' +import { MainnetChain, SChain } from '@skalenetwork/ima-js' -import debug from 'debug'; -import { MainnetChain, SChain } from "@skalenetwork/ima-js"; - - - -const log = debug('ima:test:MainnetChain'); - +const log = debug('ima:test:MainnetChain') export const createTokenData = ( - tokenKeyname: string, - chainName: string, - tokenType: TokenType, - config: MetaportConfig + tokenKeyname: string, + chainName: string, + tokenType: TokenType, + config: MetaportConfig, ): TokenData => { - const configToken: Token = config.connections[chainName][tokenType][tokenKeyname]; - return new TokenData( - configToken.address, - tokenType, - tokenKeyname, - config.tokens[tokenKeyname], - configToken.chains, - chainName - ); + const configToken: Token = config.connections[chainName][tokenType][tokenKeyname] + return new TokenData( + configToken.address, + tokenType, + tokenKeyname, + config.tokens[tokenKeyname], + configToken.chains, + chainName, + ) } - export const addTokenData = ( - tokenKeyname: string, - chainName: string, - tokenType: TokenType, - config: MetaportConfig, - tokens: TokenDataTypesMap + tokenKeyname: string, + chainName: string, + tokenType: TokenType, + config: MetaportConfig, + tokens: TokenDataTypesMap, ) => { - tokens[tokenType][tokenKeyname] = createTokenData( - tokenKeyname, - chainName, - tokenType, - config - ) + tokens[tokenType][tokenKeyname] = createTokenData(tokenKeyname, chainName, tokenType, config) } export const createTokensMap = ( - chainName1: string, - chainName2: string | null | undefined, - config: MetaportConfig + chainName1: string, + chainName2: string | null | undefined, + config: MetaportConfig, ): TokenDataTypesMap => { - const tokens = getEmptyTokenDataMap(); - log(`updating tokens map for ${chainName1} -> ${chainName2}`); - if (chainName1) { - Object.values(TokenType).forEach(tokenType => { - if (config.connections[chainName1][tokenType]) { - Object.keys(config.connections[chainName1][tokenType]).forEach(tokenKeyname => { - const tokenInfo = config.connections[chainName1][tokenType][tokenKeyname]; - if (!chainName2 || (chainName2 && tokenInfo.chains.hasOwnProperty(chainName2))) { - addTokenData(tokenKeyname, chainName1, tokenType as TokenType, config, tokens); - } - }); - } - }); - } - return tokens; + const tokens = getEmptyTokenDataMap() + log(`updating tokens map for ${chainName1} -> ${chainName2}`) + if (chainName1) { + Object.values(TokenType).forEach((tokenType) => { + if (config.connections[chainName1][tokenType]) { + Object.keys(config.connections[chainName1][tokenType]).forEach((tokenKeyname) => { + const tokenInfo = config.connections[chainName1][tokenType][tokenKeyname] + if (!chainName2 || (chainName2 && tokenInfo.chains.hasOwnProperty(chainName2))) { + addTokenData(tokenKeyname, chainName1, tokenType as TokenType, config, tokens) + } + }) + } + }) + } + return tokens } - export default class MetaportCore { - - private _config: MetaportConfig - - constructor(config: MetaportConfig) { - this._config = config; - } - - get config(): MetaportConfig { - return this._config; + private _config: MetaportConfig + + constructor(config: MetaportConfig) { + this._config = config + } + + get config(): MetaportConfig { + return this._config + } + + /** + * Generates available tokens for a given chain or a pair of the chains. + * + * @param {string} from - Source chain name. + * @param {string | null} [to] - Destination chain name. + * + * @returns {TokenDataTypesMap} - Returns a map of token data types for the given chains. + * + * @example + * + * // To get tokens for 'a' -> 'b' + * const tokens = mpc.tokens('a', 'b'); + * + * // To get all tokens from 'a' + * const tokens = mpc.tokens('a'); + */ + tokens(from: string, to?: string | null): TokenDataTypesMap { + if (from === undefined || from === null || from === '') return getEmptyTokenDataMap() + return createTokensMap(from, to, this._config) + } + + async tokenBalance(tokenContract: Contract, address: string): Promise { + return await tokenContract.balanceOf(address) + } + + async tokenBalances(tokenContracts: TokenContractsMap, address: string): Promise { + const balances: TokenBalancesMap = {} + const tokenKeynames = Object.keys(tokenContracts) + for (const tokenKeyname of tokenKeynames) { + balances[tokenKeyname] = await tokenContracts[tokenKeyname].balanceOf(address) } + return balances + } - /** - * Generates available tokens for a given chain or a pair of the chains. - * - * @param {string} from - Source chain name. - * @param {string | null} [to] - Destination chain name. - * - * @returns {TokenDataTypesMap} - Returns a map of token data types for the given chains. - * - * @example - * - * // To get tokens for 'a' -> 'b' - * const tokens = mpc.tokens('a', 'b'); - * - * // To get all tokens from 'a' - * const tokens = mpc.tokens('a'); - */ - tokens( - from: string, - to?: string | null, - ): TokenDataTypesMap { - if (from === undefined || from === null || from === '') return getEmptyTokenDataMap(); - return createTokensMap(from, to, this._config); - } - - async tokenBalance( - tokenContract: Contract, - address: string - ): Promise { - return await tokenContract.balanceOf(address); - } - - async tokenBalances( - tokenContracts: TokenContractsMap, - address: string - ): Promise { - const balances: TokenBalancesMap = {}; - const tokenKeynames = Object.keys(tokenContracts); - for (const tokenKeyname of tokenKeynames) { - balances[tokenKeyname] = await tokenContracts[tokenKeyname].balanceOf(address); - } - return balances; - } - - tokenContracts( - tokens: TokenDataTypesMap, - tokenType: TokenType, - chainName: string, - provider: Provider - ): TokenContractsMap { - const contracts: TokenContractsMap = {}; - if (tokens[tokenType]) { - Object.keys(tokens[tokenType]).forEach(tokenKeyname => { - contracts[tokenKeyname] = this.tokenContract( - chainName, - tokenKeyname, - tokenType, - provider - ) - }); - } - return contracts; - } - - tokenContract( - chainName: string, - tokenKeyname: string, - tokenType: TokenType, - provider: Provider, - customAbiTokenType?: CustomAbiTokenType, - destChainName?: string - ): Contract { - const token = this._config.connections[chainName][tokenType][tokenKeyname]; - const abi = customAbiTokenType ? ERC_ABIS[customAbiTokenType].abi : ERC_ABIS[tokenType].abi; - const address = customAbiTokenType ? token.chains[destChainName].wrapper : token.address; - // TODO: add sFUEL address support! - return new Contract(address, abi, provider); + tokenContracts( + tokens: TokenDataTypesMap, + tokenType: TokenType, + chainName: string, + provider: Provider, + ): TokenContractsMap { + const contracts: TokenContractsMap = {} + if (tokens[tokenType]) { + Object.keys(tokens[tokenType]).forEach((tokenKeyname) => { + contracts[tokenKeyname] = this.tokenContract(chainName, tokenKeyname, tokenType, provider) + }) } + return contracts + } - originAddress( - chainName1: string, - chainName2: string, - tokenKeyname: string, - tokenType: TokenType - ) { - let token = this._config.connections[chainName1][tokenType][tokenKeyname]; - const isClone = token.chains[chainName2].clone; - if (isClone) { - token = this._config.connections[chainName2][tokenType][tokenKeyname]; - } - return token.chains[isClone ? chainName1 : chainName2].wrapper ?? token.address; + tokenContract( + chainName: string, + tokenKeyname: string, + tokenType: TokenType, + provider: Provider, + customAbiTokenType?: CustomAbiTokenType, + destChainName?: string, + ): Contract { + const token = this._config.connections[chainName][tokenType][tokenKeyname] + const abi = customAbiTokenType ? ERC_ABIS[customAbiTokenType].abi : ERC_ABIS[tokenType].abi + const address = customAbiTokenType ? token.chains[destChainName].wrapper : token.address + // TODO: add sFUEL address support! + return new Contract(address, abi, provider) + } + + originAddress(chainName1: string, chainName2: string, tokenKeyname: string, tokenType: TokenType) { + let token = this._config.connections[chainName1][tokenType][tokenKeyname] + const isClone = token.chains[chainName2].clone + if (isClone) { + token = this._config.connections[chainName2][tokenType][tokenKeyname] } + return token.chains[isClone ? chainName1 : chainName2].wrapper ?? token.address + } - endpoint( - chainName: string - ): string { - return getChainEndpoint( - this._config.mainnetEndpoint, - this._config.skaleNetwork, - chainName - ); - } + endpoint(chainName: string): string { + return getChainEndpoint(this._config.mainnetEndpoint, this._config.skaleNetwork, chainName) + } - ima(chainName: string): MainnetChain | SChain { - return initIMA( - this._config.mainnetEndpoint, - this._config.skaleNetwork, - chainName - ); - } + ima(chainName: string): MainnetChain | SChain { + return initIMA(this._config.mainnetEndpoint, this._config.skaleNetwork, chainName) + } - mainnet(): MainnetChain { - return initMainnet( - this._config.mainnetEndpoint, - this._config.skaleNetwork, - ) - } + mainnet(): MainnetChain { + return initMainnet(this._config.mainnetEndpoint, this._config.skaleNetwork) + } - schain(chainName: string): SChain { - return initSChain( - this._config.skaleNetwork, - chainName - ) - } + schain(chainName: string): SChain { + return initSChain(this._config.skaleNetwork, chainName) + } - provider(chainName: string): Provider { - return new JsonRpcProvider(this.endpoint(chainName)); - } + provider(chainName: string): Provider { + return new JsonRpcProvider(this.endpoint(chainName)) + } } diff --git a/src/core/network.ts b/src/core/network.ts index b9a9363..545df6c 100644 --- a/src/core/network.ts +++ b/src/core/network.ts @@ -21,87 +21,68 @@ * @copyright SKALE Labs 2023-Present */ -import { MainnetChain, SChain } from '@skalenetwork/ima-js'; -import { JsonRpcProvider } from "ethers"; - - -import proxyEndpoints from '../metadata/proxy.json'; -import { MAINNET_CHAIN_NAME } from './constants'; -import { IMA_ADDRESSES, IMA_ABIS } from './contracts'; -import { SkaleNetwork } from './interfaces'; +import { MainnetChain, SChain } from '@skalenetwork/ima-js' +import { JsonRpcProvider } from 'ethers' +import proxyEndpoints from '../metadata/proxy.json' +import { MAINNET_CHAIN_NAME } from './constants' +import { IMA_ADDRESSES, IMA_ABIS } from './contracts' +import { SkaleNetwork } from './interfaces' const PROTOCOL: { [protocol in 'http' | 'ws']: string } = { - 'http': 'https://', - 'ws': 'wss://' + http: 'https://', + ws: 'wss://', } export const CHAIN_IDS: { [network in SkaleNetwork]: number } = { - 'staging': 5, - 'legacy': 5, - 'regression': 5, - 'mainnet': 5 + staging: 5, + legacy: 5, + regression: 5, + mainnet: 5, } export function isMainnetChainId(chainId: number | BigInt, skaleNetwork: SkaleNetwork): boolean { - return Number(chainId) === CHAIN_IDS[skaleNetwork]; + return Number(chainId) === CHAIN_IDS[skaleNetwork] } -export function getChainEndpoint( - mainnetEndpoint: string, - network: SkaleNetwork, - chainName: string -): string { - if (chainName === MAINNET_CHAIN_NAME) return mainnetEndpoint; - return getSChainEndpoint(network, chainName); +export function getChainEndpoint(mainnetEndpoint: string, network: SkaleNetwork, chainName: string): string { + if (chainName === MAINNET_CHAIN_NAME) return mainnetEndpoint + return getSChainEndpoint(network, chainName) } -export function getSChainEndpoint( - network: SkaleNetwork, - sChainName: string, - protocol: 'http' | 'ws' = 'http' -): string { - return PROTOCOL[protocol] + getProxyEndpoint(network) + '/v1/' + (protocol === 'ws' ? 'ws/' : '') + sChainName; +export function getSChainEndpoint(network: SkaleNetwork, sChainName: string, protocol: 'http' | 'ws' = 'http'): string { + return PROTOCOL[protocol] + getProxyEndpoint(network) + '/v1/' + (protocol === 'ws' ? 'ws/' : '') + sChainName } function getProxyEndpoint(network: SkaleNetwork) { - return proxyEndpoints[network]; + return proxyEndpoints[network] } export function getMainnetAbi(network: string) { - if (network === 'staging') { - return { ...IMA_ABIS.mainnet, ...IMA_ADDRESSES.staging } - } - if (network === 'legacy') { - return { ...IMA_ABIS.mainnet, ...IMA_ADDRESSES.legacy } - } - if (network === 'regression') { - return { ...IMA_ABIS.mainnet, ...IMA_ADDRESSES.regression } - } - return { ...IMA_ABIS.mainnet, ...IMA_ADDRESSES.mainnet } + if (network === 'staging') { + return { ...IMA_ABIS.mainnet, ...IMA_ADDRESSES.staging } + } + if (network === 'legacy') { + return { ...IMA_ABIS.mainnet, ...IMA_ADDRESSES.legacy } + } + if (network === 'regression') { + return { ...IMA_ABIS.mainnet, ...IMA_ADDRESSES.regression } + } + return { ...IMA_ABIS.mainnet, ...IMA_ADDRESSES.mainnet } } - -export function initIMA( - mainnetEndpoint: string, - network: SkaleNetwork, - chainName: string -): MainnetChain | SChain { - if (chainName === MAINNET_CHAIN_NAME) return initMainnet(mainnetEndpoint, network); - return initSChain(network, chainName); +export function initIMA(mainnetEndpoint: string, network: SkaleNetwork, chainName: string): MainnetChain | SChain { + if (chainName === MAINNET_CHAIN_NAME) return initMainnet(mainnetEndpoint, network) + return initSChain(network, chainName) } export function initMainnet(mainnetEndpoint: string, network: string): MainnetChain { - const provider = new JsonRpcProvider(mainnetEndpoint); - return new MainnetChain(provider, getMainnetAbi(network)); + const provider = new JsonRpcProvider(mainnetEndpoint) + return new MainnetChain(provider, getMainnetAbi(network)) } export function initSChain(network: SkaleNetwork, chainName: string): SChain { - const endpoint = getChainEndpoint( - null, - network, - chainName - ); - const provider = new JsonRpcProvider(endpoint); - return new SChain(provider, IMA_ABIS.schain); + const endpoint = getChainEndpoint(null, network, chainName) + const provider = new JsonRpcProvider(endpoint) + return new SChain(provider, IMA_ABIS.schain) } diff --git a/src/core/sfuel.ts b/src/core/sfuel.ts index c2c6f84..6b93762 100644 --- a/src/core/sfuel.ts +++ b/src/core/sfuel.ts @@ -1,4 +1,3 @@ - /** * @license * SKALE Metaport @@ -29,17 +28,14 @@ // import { getFuncData, isFaucetAvailable } from '../core/faucet'; // import { DEFAULT_MIN_SFUEL_WEI, DEFAULT_FAUCET_URL, MAINNET_CHAIN_NAME } from '../core/constants'; - // debug.enable('*'); // const log = debug('metaport:Widget'); - // function getFaucetUrl(chainsMetadata: object, chainName: string): string { // if (chainsMetadata && chainsMetadata[chainName]) return chainsMetadata[chainName].faucetUrl; // return DEFAULT_FAUCET_URL; // } - // function getMinSfuelWei(chainName: string, chainsMetadata?: object): string { // if (chainsMetadata && chainsMetadata[chainName] && chainsMetadata[chainName].minSfuelWei) { // return chainsMetadata[chainName].minSfuelWei; @@ -48,7 +44,6 @@ // } // } - // async function getSfuelBalance(web3: any, address: string): Promise { // //return await provider.getBalance(address); // // TODO! @@ -56,7 +51,6 @@ // return ''; // } - // export interface StationData { // faucetUrl: string; // minSfuelWei: string; @@ -64,13 +58,11 @@ // ok: boolean; // } - // export interface StationPowRes { // message: string; // ok: boolean; // } - // export class Station { // endpoint: string; diff --git a/src/core/themes.ts b/src/core/themes.ts index 729de92..02c6844 100644 --- a/src/core/themes.ts +++ b/src/core/themes.ts @@ -21,49 +21,44 @@ * @copyright SKALE Labs 2022-Present */ -import { Positions } from './dataclasses/Position'; -import { MetaportTheme } from './interfaces/Theme'; -import { DEFAULT_MP_Z_INDEX } from './constants'; - +import { Positions } from './dataclasses/Position' +import { MetaportTheme } from './interfaces/Theme' +import { DEFAULT_MP_Z_INDEX } from './constants' const defaultThemes = { - 'dark': { - primary: '#29FF94', - background: '#000000', - mode: 'dark', - position: Positions.bottomRight, - zIndex: DEFAULT_MP_Z_INDEX - }, - 'light': { - primary: '#173CFF', - background: '#EFEFEF', - mode: 'light', - position: Positions.bottomRight, - zIndex: DEFAULT_MP_Z_INDEX - } + dark: { + primary: '#29FF94', + background: '#000000', + mode: 'dark', + position: Positions.bottomRight, + zIndex: DEFAULT_MP_Z_INDEX, + }, + light: { + primary: '#173CFF', + background: '#EFEFEF', + mode: 'light', + position: Positions.bottomRight, + zIndex: DEFAULT_MP_Z_INDEX, + }, } // warning: order is important here -const MUI_ELEMENTS = ['mobileStepper', 'fab', 'speedDial', 'appBar', 'drawer', 'modal', - 'snackbar', 'tooltip']; - - -const INDEX_STEP = 50; +const MUI_ELEMENTS = ['mobileStepper', 'fab', 'speedDial', 'appBar', 'drawer', 'modal', 'snackbar', 'tooltip'] +const INDEX_STEP = 50 export function getWidgetTheme(theme: MetaportTheme | null): MetaportTheme { - if (!theme) return defaultThemes.dark as MetaportTheme; - if (theme.mode && Object.keys(theme).length === 1) { - return defaultThemes[theme.mode] as MetaportTheme;; - } - if (theme.position === undefined) theme.position = Positions.bottomRight; - if (theme.zIndex === undefined) theme.zIndex = DEFAULT_MP_Z_INDEX; - if (theme.background === undefined) theme.background = defaultThemes[theme.mode].background; - if (theme.primary === undefined) theme.primary = defaultThemes[theme.mode].primary; - return theme; + if (!theme) return defaultThemes.dark as MetaportTheme + if (theme.mode && Object.keys(theme).length === 1) { + return defaultThemes[theme.mode] as MetaportTheme + } + if (theme.position === undefined) theme.position = Positions.bottomRight + if (theme.zIndex === undefined) theme.zIndex = DEFAULT_MP_Z_INDEX + if (theme.background === undefined) theme.background = defaultThemes[theme.mode].background + if (theme.primary === undefined) theme.primary = defaultThemes[theme.mode].primary + return theme } - export function getMuiZIndex(theme: MetaportTheme): object { - return MUI_ELEMENTS.reduce((x, y, i) => (x[y] = theme.zIndex + ((i + 1) * INDEX_STEP), x), {}); -} \ No newline at end of file + return MUI_ELEMENTS.reduce((x, y, i) => ((x[y] = theme.zIndex + (i + 1) * INDEX_STEP), x), {}) +} diff --git a/src/core/tokens/helper.ts b/src/core/tokens/helper.ts index e10604a..7ee3652 100644 --- a/src/core/tokens/helper.ts +++ b/src/core/tokens/helper.ts @@ -21,41 +21,37 @@ * @copyright SKALE Labs 2022-Present */ -import { TokenData } from '../dataclasses/TokenData'; -import * as interfaces from '../interfaces/index'; - -import { eqArrays } from '../helper'; +import { TokenData } from '../dataclasses/TokenData' +import * as interfaces from '../interfaces/index' +import { eqArrays } from '../helper' export function getEmptyTokenDataMap(): interfaces.TokenDataTypesMap { - return { eth: {}, erc20: {}, erc721: {}, erc721meta: {}, erc1155: {} }; + return { eth: {}, erc20: {}, erc721: {}, erc721meta: {}, erc1155: {} } } - export function getAvailableTokenNumers(availableTokens): number[] { - return Object.entries(availableTokens).map(([_key, value]) => Object.entries(value).length); + return Object.entries(availableTokens).map(([_key, value]) => Object.entries(value).length) } - export function getAvailableTokensTotal(availableTokens): number { - return getAvailableTokenNumers(availableTokens).reduce((a, b) => a + b, 0); + return getAvailableTokenNumers(availableTokens).reduce((a, b) => a + b, 0) } - export function getDefaultToken(availableTokens: interfaces.TokenDataTypesMap): TokenData { - if (availableTokens === undefined) return; - const availableTokenNumers = getAvailableTokenNumers(availableTokens); - // if (eqArrays(availableTokenNumers, [1, 0, 0, 0, 0])) return availableTokens.eth.eth; - if (eqArrays(availableTokenNumers, [0, 1, 0, 0, 0])) { - return Object.values(availableTokens.erc20)[0]; - } - if (eqArrays(availableTokenNumers, [0, 0, 1, 0, 0])) { - return Object.values(availableTokens.erc721)[0]; - } - if (eqArrays(availableTokenNumers, [0, 0, 0, 1, 0])) { - return Object.values(availableTokens.erc721meta)[0]; - } - if (eqArrays(availableTokenNumers, [0, 0, 0, 0, 1])) { - return Object.values(availableTokens.erc1155)[0]; - } + if (availableTokens === undefined) return + const availableTokenNumers = getAvailableTokenNumers(availableTokens) + // if (eqArrays(availableTokenNumers, [1, 0, 0, 0, 0])) return availableTokens.eth.eth; + if (eqArrays(availableTokenNumers, [0, 1, 0, 0, 0])) { + return Object.values(availableTokens.erc20)[0] + } + if (eqArrays(availableTokenNumers, [0, 0, 1, 0, 0])) { + return Object.values(availableTokens.erc721)[0] + } + if (eqArrays(availableTokenNumers, [0, 0, 0, 1, 0])) { + return Object.values(availableTokens.erc721meta)[0] + } + if (eqArrays(availableTokenNumers, [0, 0, 0, 0, 1])) { + return Object.values(availableTokens.erc1155)[0] + } } diff --git a/src/core/transfer_steps.ts b/src/core/transfer_steps.ts index 3e35b60..757888d 100644 --- a/src/core/transfer_steps.ts +++ b/src/core/transfer_steps.ts @@ -21,72 +21,54 @@ * @copyright SKALE Labs 2023-Present */ - -import debug from 'debug'; +import debug from 'debug' import { - TokenData, - WrapStepMetadata, - UnwrapStepMetadata, - TransferStepMetadata, - StepMetadata, - getActionType -} from './dataclasses'; - -import { MetaportConfig } from './interfaces/index'; - -import { MAINNET_CHAIN_NAME } from './constants'; + TokenData, + WrapStepMetadata, + UnwrapStepMetadata, + TransferStepMetadata, + StepMetadata, + getActionType, +} from './dataclasses' +import { MetaportConfig } from './interfaces/index' -debug.enable('*'); -const log = debug('metaport:core:transferSteps'); +import { MAINNET_CHAIN_NAME } from './constants' +debug.enable('*') +const log = debug('metaport:core:transferSteps') -export function getStepsMetadata( - config: MetaportConfig, - token: TokenData, - to: string -): StepMetadata[] { - const steps: StepMetadata[] = []; - if (token === undefined || token === null || to === null || to === '') return steps; +export function getStepsMetadata(config: MetaportConfig, token: TokenData, to: string): StepMetadata[] { + const steps: StepMetadata[] = [] + if (token === undefined || token === null || to === null || to === '') return steps - const toChain = token.connections[to].hub ?? to; - const hubTokenOptions = config.connections[toChain][token.type][token.keyname].chains[token.chain]; - const destTokenOptions = config.connections[to][token.type][token.keyname].chains[token.chain]; - const isCloneToClone = token.isClone(to) && destTokenOptions.clone; + const toChain = token.connections[to].hub ?? to + const hubTokenOptions = config.connections[toChain][token.type][token.keyname].chains[token.chain] + const destTokenOptions = config.connections[to][token.type][token.keyname].chains[token.chain] + const isCloneToClone = token.isClone(to) && destTokenOptions.clone - log(`Setting toChain: ${toChain}`); + log(`Setting toChain: ${toChain}`) - if (token.connections[toChain].wrapper) { - steps.push(new WrapStepMetadata( - token.chain, - to - )) - } - steps.push(new TransferStepMetadata( - getActionType(token.chain, toChain, token.type), - token.chain, - toChain - )); - if (hubTokenOptions.wrapper && !isCloneToClone) { - steps.push(new UnwrapStepMetadata(token.chain, toChain)); - } - if (token.connections[to].hub) { - const tokenOptionsHub = config.connections[toChain][token.type][token.keyname].chains[to]; - if (tokenOptionsHub.wrapper && !isCloneToClone) { - steps.push(new WrapStepMetadata(toChain, to)); - } - steps.push(new TransferStepMetadata( - getActionType(toChain, to, token.type), - toChain, - to - )); - } - if (to === MAINNET_CHAIN_NAME && token.keyname === 'eth') { - // todo: add unlock step! + if (token.connections[toChain].wrapper) { + steps.push(new WrapStepMetadata(token.chain, to)) + } + steps.push(new TransferStepMetadata(getActionType(token.chain, toChain, token.type), token.chain, toChain)) + if (hubTokenOptions.wrapper && !isCloneToClone) { + steps.push(new UnwrapStepMetadata(token.chain, toChain)) + } + if (token.connections[to].hub) { + const tokenOptionsHub = config.connections[toChain][token.type][token.keyname].chains[to] + if (tokenOptionsHub.wrapper && !isCloneToClone) { + steps.push(new WrapStepMetadata(toChain, to)) } + steps.push(new TransferStepMetadata(getActionType(toChain, to, token.type), toChain, to)) + } + if (to === MAINNET_CHAIN_NAME && token.keyname === 'eth') { + // todo: add unlock step! + } - log(`Action steps metadata:`); - log(steps); - return steps; -} \ No newline at end of file + log(`Action steps metadata:`) + log(steps) + return steps +} diff --git a/src/core/views.ts b/src/core/views.ts index aa33581..73363ee 100644 --- a/src/core/views.ts +++ b/src/core/views.ts @@ -21,20 +21,16 @@ * @copyright SKALE Labs 2023-Present */ - -import { View } from './dataclasses/View'; - +import { View } from './dataclasses/View' export function isTransferRequestView(view: View) { - return view === View.TRANSFER_REQUEST_SUMMARY || view === View.TRANSFER_REQUEST_STEPS; + return view === View.TRANSFER_REQUEST_SUMMARY || view === View.TRANSFER_REQUEST_STEPS } - export function isTransferRequestSummary(view: View) { - return view === View.TRANSFER_REQUEST_SUMMARY + return view === View.TRANSFER_REQUEST_SUMMARY } - export function isStepsMetadata(view: View) { - return view === View.TRANSFER_REQUEST_STEPS + return view === View.TRANSFER_REQUEST_STEPS } diff --git a/src/core/wagmi_network.ts b/src/core/wagmi_network.ts index fef4d33..9bf72b9 100644 --- a/src/core/wagmi_network.ts +++ b/src/core/wagmi_network.ts @@ -23,43 +23,41 @@ import { Chain } from 'wagmi' -import { getSChainEndpoint } from './network'; -import { getExplorerUrl } from './explorer'; -import { getChainAlias } from './helper'; -import { getChainId } from './chain_id'; - -import { SkaleNetwork } from './interfaces'; +import { getSChainEndpoint } from './network' +import { getExplorerUrl } from './explorer' +import { getChainAlias } from './helper' +import { getChainId } from './chain_id' +import { SkaleNetwork } from './interfaces' export function constructWagmiChain(network: SkaleNetwork, chainName: string): Chain { - const endpointHttp = getSChainEndpoint(network, chainName); - const endpointWs = getSChainEndpoint(network, chainName, 'ws'); - const explorerUrl = getExplorerUrl(network, chainName); - const name = getChainAlias(network, chainName); - const chainId = getChainId(chainName); - return { - id: chainId, - name: name, - network: `skale-${chainName}`, - nativeCurrency: { - decimals: 18, - name: 'sFUEL', - symbol: 'sFUEL', - }, - rpcUrls: { - public: { http: [endpointHttp], webSocket: [endpointWs] }, - default: { http: [endpointHttp], webSocket: [endpointWs] }, - }, - blockExplorers: { - etherscan: { name: 'SKALE Explorer', url: explorerUrl }, - default: { name: 'SKALE Explorer', url: explorerUrl }, - }, - contracts: {} - } as const satisfies Chain + const endpointHttp = getSChainEndpoint(network, chainName) + const endpointWs = getSChainEndpoint(network, chainName, 'ws') + const explorerUrl = getExplorerUrl(network, chainName) + const name = getChainAlias(network, chainName) + const chainId = getChainId(chainName) + return { + id: chainId, + name: name, + network: `skale-${chainName}`, + nativeCurrency: { + decimals: 18, + name: 'sFUEL', + symbol: 'sFUEL', + }, + rpcUrls: { + public: { http: [endpointHttp], webSocket: [endpointWs] }, + default: { http: [endpointHttp], webSocket: [endpointWs] }, + }, + blockExplorers: { + etherscan: { name: 'SKALE Explorer', url: explorerUrl }, + default: { name: 'SKALE Explorer', url: explorerUrl }, + }, + contracts: {}, + } as const satisfies Chain } - export function getWebSocketUrl(chain: Chain): string { - // return chain.rpcUrls.default.webSocket ? chain.rpcUrls.default.webSocket[0] : ''; - return chain.rpcUrls.default.webSocket ? chain.rpcUrls.default.webSocket[0] : 'wss://goerli-light.eth.linkpool.io/ws'; // TODO - IP! -} \ No newline at end of file + // return chain.rpcUrls.default.webSocket ? chain.rpcUrls.default.webSocket[0] : ''; + return chain.rpcUrls.default.webSocket ? chain.rpcUrls.default.webSocket[0] : 'wss://goerli-light.eth.linkpool.io/ws' // TODO - IP! +} diff --git a/src/index.ts b/src/index.ts index b3a2dee..ef8ee23 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1 +1,3 @@ -export { Metaport, ChainIcon, WidgetUI, interfaces, dataclasses } from "./Metaport"; +export { Metaport, ChainIcon, WidgetUI, interfaces, dataclasses } from './Metaport' +export { useMetaportStore } from './store/MetaportState'; +export { useUIStore, useCollapseStore } from './store/Store'; \ No newline at end of file diff --git a/src/store/MetaportState.ts b/src/store/MetaportState.ts index a2bbc3a..bebb62c 100644 --- a/src/store/MetaportState.ts +++ b/src/store/MetaportState.ts @@ -21,306 +21,286 @@ * @copyright SKALE Labs 2023-Present */ -import debug from 'debug'; +import debug from 'debug' import { MainnetChain, SChain } from '@skalenetwork/ima-js' import { create } from 'zustand' import MetaportCore from '../core/metaport' -import * as interfaces from '../core/interfaces'; -import * as dataclasses from '../core/dataclasses'; -import { getEmptyTokenDataMap } from '../core/tokens/helper'; -import { MAINNET_CHAIN_NAME, DEFAULT_ERROR_MSG } from '../core/constants'; -import { getStepsMetadata } from '../core/transfer_steps'; -import { ACTIONS } from '../core/actions'; -import { WalletClient } from 'viem'; - - -debug.enable('*'); -const log = debug('metaport:state'); +import * as interfaces from '../core/interfaces' +import * as dataclasses from '../core/dataclasses' +import { getEmptyTokenDataMap } from '../core/tokens/helper' +import { MAINNET_CHAIN_NAME, DEFAULT_ERROR_MSG } from '../core/constants' +import { getStepsMetadata } from '../core/transfer_steps' +import { ACTIONS } from '../core/actions' +import { WalletClient } from 'viem' +debug.enable('*') +const log = debug('metaport:state') interface MetaportState { - mainnetChain: MainnetChain - setMainnetChain: (mainnet: MainnetChain) => void - sChain1: SChain - setSChain1: (schain: SChain) => void - sChain2: SChain - setSChain2: (schain: SChain) => void + mainnetChain: MainnetChain + setMainnetChain: (mainnet: MainnetChain) => void + sChain1: SChain + setSChain1: (schain: SChain) => void + sChain2: SChain + setSChain2: (schain: SChain) => void - mpc: MetaportCore, - setMpc: (mpc: MetaportCore) => void + mpc: MetaportCore + setMpc: (mpc: MetaportCore) => void - amount: string - setAmount: (amount: string, address: `0x${string}`) => void + amount: string + setAmount: (amount: string, address: `0x${string}`) => void - tokenId: number - setTokenId: (tokenId: number) => void + tokenId: number + setTokenId: (tokenId: number) => void - execute: ( - address: string, - switchNetwork: (chainId: number) => void, - walletClient: WalletClient - ) => void - check: (amount: string, address: `0x${string}`) => void + execute: (address: string, switchNetwork: (chainId: number) => void, walletClient: WalletClient) => void + check: (amount: string, address: `0x${string}`) => void - currentStep: number - setCurrentStep: (currentStep: number) => void + currentStep: number + setCurrentStep: (currentStep: number) => void - stepsMetadata: dataclasses.StepMetadata[] - setStepsMetadata: (steps: dataclasses.StepMetadata[]) => void + stepsMetadata: dataclasses.StepMetadata[] + setStepsMetadata: (steps: dataclasses.StepMetadata[]) => void - chainName1: string, - chainName2: string, + chainName1: string + chainName2: string - setChainName1: (name: string) => void - setChainName2: (name: string) => void + setChainName1: (name: string) => void + setChainName2: (name: string) => void - tokens: interfaces.TokenDataTypesMap + tokens: interfaces.TokenDataTypesMap - token: dataclasses.TokenData - setToken: (token: dataclasses.TokenData) => void + token: dataclasses.TokenData + setToken: (token: dataclasses.TokenData) => void - tokenContracts: interfaces.TokenContractsMap - tokenBalances: interfaces.TokenBalancesMap - updateTokenBalances: (address: string) => Promise + tokenContracts: interfaces.TokenContractsMap + tokenBalances: interfaces.TokenBalancesMap + updateTokenBalances: (address: string) => Promise - amountErrorMessage: string - setAmountErrorMessage: (amountErrorMessage: string) => void + amountErrorMessage: string + setAmountErrorMessage: (amountErrorMessage: string) => void - errorMessage: dataclasses.ErrorMessage - setErrorMessage: (amountErrorMessage: dataclasses.ErrorMessage) => void + errorMessage: dataclasses.ErrorMessage + setErrorMessage: (amountErrorMessage: dataclasses.ErrorMessage) => void - actionBtnDisabled: boolean - setActionBtnDisabled: (actionBtnDisabled: boolean) => void + actionBtnDisabled: boolean + setActionBtnDisabled: (actionBtnDisabled: boolean) => void - loading: boolean - setLoading: (loading: boolean) => void + loading: boolean + setLoading: (loading: boolean) => void - transferInProgress: boolean - setTransferInProgress: (loading: boolean) => void + transferInProgress: boolean + setTransferInProgress: (loading: boolean) => void - btnText: string - setBtnText: (btnText: string) => void + btnText: string + setBtnText: (btnText: string) => void - errorMessageClosedFallback: () => void - startOver: () => void + errorMessageClosedFallback: () => void + startOver: () => void } - export const useMetaportStore = create()((set, get) => ({ - mainnetChain: null, - setMainnetChain: (mainnet: MainnetChain) => set(() => ({ mainnetChain: mainnet })), + mainnetChain: null, + setMainnetChain: (mainnet: MainnetChain) => set(() => ({ mainnetChain: mainnet })), - sChain1: null, - setSChain1: (schain: SChain) => set(() => ({ sChain1: schain })), + sChain1: null, + setSChain1: (schain: SChain) => set(() => ({ sChain1: schain })), - sChain2: null, - setSChain2: (schain: SChain) => set(() => ({ sChain2: schain })), + sChain2: null, + setSChain2: (schain: SChain) => set(() => ({ sChain2: schain })), - mpc: null, - setMpc: (mpc: MetaportCore) => set(() => ({ mpc: mpc })), + mpc: null, + setMpc: (mpc: MetaportCore) => set(() => ({ mpc: mpc })), - tokenId: null, - setTokenId: (tokenId: number) => set(() => { - return { - tokenId: tokenId - } + tokenId: null, + setTokenId: (tokenId: number) => + set(() => { + return { + tokenId: tokenId, + } }), - amount: '', - setAmount: (amount: string, address: `0x${string}`) => set((state) => { - state.check(amount, address); - return { - amount: amount - } + amount: '', + setAmount: (amount: string, address: `0x${string}`) => + set((state) => { + state.check(amount, address) + return { + amount: amount, + } }), - - execute: async (address: string, switchNetwork: any, walletClient: WalletClient) => { - log('Running execute'); - if (get().stepsMetadata[get().currentStep]) { - set({ - loading: true, - transferInProgress: true - }) - try { - const stepMetadata = get().stepsMetadata[get().currentStep]; - const actionClass = ACTIONS[stepMetadata.type]; - await new actionClass( - get().mpc, - stepMetadata.from, - stepMetadata.to, - address, - get().amount, - get().tokenId, - get().token, - get().setAmountErrorMessage, - get().setBtnText, - switchNetwork, - walletClient - ).execute(); - } catch (err) { - console.error(err); - const msg = err.message ? err.message : DEFAULT_ERROR_MSG; - set({ - errorMessage: new dataclasses.TransactionErrorMessage( - msg, - get().errorMessageClosedFallback - ) - }); - return; - } finally { - set({ loading: false }); - } - set({ - transferInProgress: get().currentStep + 1 !== get().stepsMetadata.length, - currentStep: get().currentStep + 1, - - }); - } - }, - - errorMessageClosedFallback() { - set({ - loading: false, - errorMessage: undefined, - transferInProgress: get().currentStep !== 0 - }); - }, - - startOver() { + execute: async (address: string, switchNetwork: any, walletClient: WalletClient) => { + log('Running execute') + if (get().stepsMetadata[get().currentStep]) { + set({ + loading: true, + transferInProgress: true, + }) + try { + const stepMetadata = get().stepsMetadata[get().currentStep] + const actionClass = ACTIONS[stepMetadata.type] + await new actionClass( + get().mpc, + stepMetadata.from, + stepMetadata.to, + address, + get().amount, + get().tokenId, + get().token, + get().setAmountErrorMessage, + get().setBtnText, + switchNetwork, + walletClient, + ).execute() + } catch (err) { + console.error(err) + const msg = err.message ? err.message : DEFAULT_ERROR_MSG set({ - loading: false, - errorMessage: undefined, - amount: '', - tokenId: null, - currentStep: 0, - transferInProgress: false - }); - }, - - check: async (amount: string, address: string) => { - if (get().stepsMetadata[get().currentStep]) { - set({ - 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(); - // console.log(); - // console.log('going to check amount!!!'); - } - set({ loading: false }); - }, - - currentStep: 0, - setCurrentStep: (currentStep: number) => set(() => ({ currentStep: currentStep })), - - stepsMetadata: [], - setStepsMetadata: (steps: dataclasses.StepMetadata[]) => set(() => ({ stepsMetadata: steps })), - - chainName1: '', - chainName2: '', - - setChainName1: (name: string) => set((state) => { - // updateState( - // name, - // state.chainName2 - // ) - - const updState = {}; - if (name === MAINNET_CHAIN_NAME) { - updState['mainnetChain'] = state.mpc.mainnet(); - } else { - updState['sChain1'] = state.mpc.schain(name); - } - const provider = updState['mainnetChain'] ? updState['mainnetChain'].provider : updState['sChain1'].provider; - const tokens = state.mpc.tokens(name); - const tokenContracts = state.mpc.tokenContracts( - tokens, - dataclasses.TokenType.erc20, - name, - provider - ); - return { - currentStep: 0, - token: null, - chainName1: name, - tokens: tokens, - tokenContracts: tokenContracts, - ...updState - } + errorMessage: new dataclasses.TransactionErrorMessage(msg, get().errorMessageClosedFallback), + }) + return + } finally { + set({ loading: false }) + } + set({ + transferInProgress: get().currentStep + 1 !== get().stepsMetadata.length, + currentStep: get().currentStep + 1, + }) + } + }, + + errorMessageClosedFallback() { + set({ + loading: false, + errorMessage: undefined, + transferInProgress: get().currentStep !== 0, + }) + }, + + startOver() { + set({ + loading: false, + errorMessage: undefined, + amount: '', + tokenId: null, + currentStep: 0, + transferInProgress: false, + }) + }, + + check: async (amount: string, address: string) => { + if (get().stepsMetadata[get().currentStep]) { + set({ + 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() + // console.log(); + // console.log('going to check amount!!!'); + } + set({ loading: false }) + }, + + currentStep: 0, + setCurrentStep: (currentStep: number) => set(() => ({ currentStep: currentStep })), + + stepsMetadata: [], + setStepsMetadata: (steps: dataclasses.StepMetadata[]) => set(() => ({ stepsMetadata: steps })), + + chainName1: '', + chainName2: '', + + setChainName1: (name: string) => + set((state) => { + // updateState( + // name, + // state.chainName2 + // ) + + const updState = {} + if (name === MAINNET_CHAIN_NAME) { + updState['mainnetChain'] = state.mpc.mainnet() + } else { + updState['sChain1'] = state.mpc.schain(name) + } + const provider = updState['mainnetChain'] ? updState['mainnetChain'].provider : updState['sChain1'].provider + const tokens = state.mpc.tokens(name) + const tokenContracts = state.mpc.tokenContracts(tokens, dataclasses.TokenType.erc20, name, provider) + return { + currentStep: 0, + token: null, + chainName1: name, + tokens: tokens, + tokenContracts: tokenContracts, + ...updState, + } }), - setChainName2: (name: string) => set((state) => { - const updState = {}; - if (name === MAINNET_CHAIN_NAME) { - updState['mainnetChain'] = state.mpc.mainnet(); - } else { - updState['sChain2'] = state.mpc.schain(name); - } - return { - currentStep: 0, - token: null, - chainName2: name, - tokens: state.mpc.tokens(state.chainName1, name), - stepsMetadata: getStepsMetadata( - get().mpc.config, - get().token, - name - ), - ...updState - } + setChainName2: (name: string) => + set((state) => { + const updState = {} + if (name === MAINNET_CHAIN_NAME) { + updState['mainnetChain'] = state.mpc.mainnet() + } else { + updState['sChain2'] = state.mpc.schain(name) + } + return { + currentStep: 0, + token: null, + chainName2: name, + tokens: state.mpc.tokens(state.chainName1, name), + stepsMetadata: getStepsMetadata(get().mpc.config, get().token, name), + ...updState, + } }), - tokens: getEmptyTokenDataMap(), + tokens: getEmptyTokenDataMap(), - token: null, - setToken: (token: dataclasses.TokenData) => set(() => ({ - token: token, - stepsMetadata: getStepsMetadata( - get().mpc.config, - token, - get().chainName2 - ) + token: null, + setToken: (token: dataclasses.TokenData) => + set(() => ({ + token: token, + stepsMetadata: getStepsMetadata(get().mpc.config, token, get().chainName2), })), - tokenContracts: {}, - tokenBalances: {}, + tokenContracts: {}, + tokenBalances: {}, - updateTokenBalances: async (address: string) => { - const tokenBalances = await get().mpc.tokenBalances(get().tokenContracts, address); - set({ tokenBalances: tokenBalances }); - }, + updateTokenBalances: async (address: string) => { + const tokenBalances = await get().mpc.tokenBalances(get().tokenContracts, address) + set({ tokenBalances: tokenBalances }) + }, - amountErrorMessage: null, - setAmountErrorMessage: (em: string) => set(() => ({ amountErrorMessage: em })), + amountErrorMessage: null, + setAmountErrorMessage: (em: string) => set(() => ({ amountErrorMessage: em })), - errorMessage: null, - setErrorMessage: (em: dataclasses.ErrorMessage) => set(() => ({ errorMessage: em })), + errorMessage: null, + setErrorMessage: (em: dataclasses.ErrorMessage) => set(() => ({ errorMessage: em })), - actionBtnDisabled: false, - setActionBtnDisabled: (disabled: boolean) => set(() => ({ actionBtnDisabled: disabled })), + actionBtnDisabled: false, + setActionBtnDisabled: (disabled: boolean) => set(() => ({ actionBtnDisabled: disabled })), - loading: false, - setLoading: (loading: boolean) => set(() => ({ loading: loading })), + loading: false, + setLoading: (loading: boolean) => set(() => ({ loading: loading })), - transferInProgress: false, - setTransferInProgress: (inProgress: boolean) => set(() => ({ transferInProgress: inProgress })), + transferInProgress: false, + setTransferInProgress: (inProgress: boolean) => set(() => ({ transferInProgress: inProgress })), - btnText: null, - setBtnText: (btnText: string) => set(() => ({ btnText: btnText })) -})); + btnText: null, + setBtnText: (btnText: string) => set(() => ({ btnText: btnText })), +})) diff --git a/src/store/Store.ts b/src/store/Store.ts index 59e4aa2..43b0952 100644 --- a/src/store/Store.ts +++ b/src/store/Store.ts @@ -23,53 +23,52 @@ import { create } from 'zustand' -import * as interfaces from '../core/interfaces'; +import * as interfaces from '../core/interfaces' interface UIState { - theme: interfaces.MetaportTheme - setTheme: (theme: interfaces.MetaportTheme) => void - open: boolean, - setOpen: (isOpen: boolean) => void + theme: interfaces.MetaportTheme + setTheme: (theme: interfaces.MetaportTheme) => void + open: boolean + setOpen: (isOpen: boolean) => void } - export const useUIStore = create()((set) => ({ - theme: null, - setTheme: (theme: interfaces.MetaportTheme) => set(() => ({ theme: theme })), - open: false, - setOpen: (isOpen: boolean) => set(() => ({ open: isOpen })), -})); - + theme: null, + setTheme: (theme: interfaces.MetaportTheme) => set(() => ({ theme: theme })), + open: false, + setOpen: (isOpen: boolean) => set(() => ({ open: isOpen })), +})) interface CollapseState { - expandedFrom: string | false, - setExpandedFrom: (expanded: string | false) => void, - expandedTo: string | false, - setExpandedTo: (expanded: string | false) => void + expandedFrom: string | false + setExpandedFrom: (expanded: string | false) => void + expandedTo: string | false + setExpandedTo: (expanded: string | false) => void - expandedTokens: string | false, - setExpandedTokens: (expanded: string | false) => void + expandedTokens: string | false + setExpandedTokens: (expanded: string | false) => void } - export const useCollapseStore = create()((set) => ({ - expandedFrom: false, - setExpandedFrom: (expanded: string | false) => set(() => ({ - expandedFrom: expanded, - expandedTo: false, - expandedTokens: false + expandedFrom: false, + setExpandedFrom: (expanded: string | false) => + set(() => ({ + expandedFrom: expanded, + expandedTo: false, + expandedTokens: false, })), - expandedTo: false, - setExpandedTo: (expanded: string | false) => set(() => ({ - expandedTo: expanded, - expandedFrom: false, - expandedTokens: false + expandedTo: false, + setExpandedTo: (expanded: string | false) => + set(() => ({ + expandedTo: expanded, + expandedFrom: false, + expandedTokens: false, })), - expandedTokens: false, - setExpandedTokens: (expanded: string | false) => set(() => ({ - expandedTokens: expanded, - expandedFrom: false, - expandedTo: false - })) -})); - + expandedTokens: false, + setExpandedTokens: (expanded: string | false) => + set(() => ({ + expandedTokens: expanded, + expandedFrom: false, + expandedTo: false, + })), +})) diff --git a/src/types/custom.d.ts b/src/types/custom.d.ts index 9c9c4e8..c1c95ed 100644 --- a/src/types/custom.d.ts +++ b/src/types/custom.d.ts @@ -1,37 +1,32 @@ -declare module "*.json" { - const value: any; - export default value; +declare module '*.json' { + const value: any + export default value } -declare module "*.svg" { - const content: any; - export default content; +declare module '*.svg' { + const content: any + export default content } -declare module "*.png" { - const content: any; - export default content; +declare module '*.png' { + const content: any + export default content } -declare module '*.scss'; +declare module '*.scss' declare module 'node' { - interface NodeRequire { - context: ( - directory: string, - useSubdirectories: boolean, - regExp: RegExp, - mode?: string - ) => any; - } + interface NodeRequire { + context: (directory: string, useSubdirectories: boolean, regExp: RegExp, mode?: string) => any + } } declare namespace NodeJS { - interface Global { - require: NodeRequire; - } + interface Global { + require: NodeRequire + } } interface NodeRequire { - context: (directory: string, useSubdirectories: boolean, regExp: RegExp, mode?: string) => any; + context: (directory: string, useSubdirectories: boolean, regExp: RegExp, mode?: string) => any } diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 8b50155..164e434 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -1,7 +1,7 @@ -export {}; +export {} declare global { interface Window { - ethereum: any; + ethereum: any } -} \ No newline at end of file +} diff --git a/src/types/react-app-env.d.ts b/src/types/react-app-env.d.ts index 0e18010..24feb0b 100644 --- a/src/types/react-app-env.d.ts +++ b/src/types/react-app-env.d.ts @@ -1,4 +1,3 @@ - interface Window { - ethereum: any -} \ No newline at end of file + ethereum: any +} From 1bee1af947f50a6c118443fe7f199173f1e884df Mon Sep 17 00:00:00 2001 From: Dmytro Date: Mon, 14 Aug 2023 22:28:17 +0100 Subject: [PATCH 14/54] Move theming logic to metaport provider --- src/Metaport.tsx | 10 ++- src/components/Metaport/Metaport.tsx | 72 ++--------------- .../MetaportProvider.tsx} | 58 +++++++++---- src/components/MetaportProvider/index.ts | 1 + src/components/Widget/Widget.mdx | 23 ------ src/components/Widget/Widget.stories.tsx | 21 ----- src/components/Widget/index.ts | 1 - src/components/WidgetUI/WidgetUI.tsx | 81 +++++-------------- src/index.ts | 2 +- src/styles/styles.module.scss | 2 + 10 files changed, 80 insertions(+), 191 deletions(-) rename src/components/{Widget/Widget.tsx => MetaportProvider/MetaportProvider.tsx} (74%) create mode 100644 src/components/MetaportProvider/index.ts delete mode 100644 src/components/Widget/Widget.mdx delete mode 100644 src/components/Widget/Widget.stories.tsx delete mode 100644 src/components/Widget/index.ts diff --git a/src/Metaport.tsx b/src/Metaport.tsx index e85d3a5..4c52c2a 100644 --- a/src/Metaport.tsx +++ b/src/Metaport.tsx @@ -25,7 +25,6 @@ import React from 'react' // import { createRoot } from 'react-dom/client'; -import Widget from './components/Widget' import { internalEvents } from './core/events' import * as interfaces from './core/interfaces/index' @@ -41,6 +40,15 @@ export { WidgetUI } import Metaport from './components/Metaport' export { Metaport } +import MetaportProvider from './components/MetaportProvider'; +export { MetaportProvider } + +import SkPaper from './components/SkPaper'; +export { SkPaper } + +import SkConnect from './components/SkConnect'; +export { SkConnect } + // export * as sfuel from './core/sfuel'; export class InjectedMetaport { diff --git a/src/components/Metaport/Metaport.tsx b/src/components/Metaport/Metaport.tsx index 8540da0..fc9863f 100644 --- a/src/components/Metaport/Metaport.tsx +++ b/src/components/Metaport/Metaport.tsx @@ -20,77 +20,15 @@ * @copyright SKALE Labs 2023-Present */ -import { RainbowKitProvider } from '@rainbow-me/rainbowkit' -import { configureChains, createConfig, WagmiConfig } from 'wagmi' -import { mainnet, goerli } from 'wagmi/chains' -import { jsonRpcProvider } from 'wagmi/providers/jsonRpc' -import { connectorsForWallets } from '@rainbow-me/rainbowkit' - -import { injectedWallet, coinbaseWallet, metaMaskWallet } from '@rainbow-me/rainbowkit/wallets' - import { MetaportConfig } from '../../core/interfaces' import WidgetUI from '../WidgetUI' +import MetaportProvider from '../MetaportProvider/MetaportProvider' -import '@rainbow-me/rainbowkit/styles.css' - -import { constructWagmiChain, getWebSocketUrl } from '../../core/wagmi_network' - -const { chains, webSocketPublicClient } = configureChains( - [ - mainnet, - goerli, - constructWagmiChain('staging', 'staging-legal-crazy-castor'), - constructWagmiChain('staging', 'staging-utter-unripe-menkar'), - constructWagmiChain('staging', 'staging-faint-slimy-achird'), - constructWagmiChain('staging', 'staging-perfect-parallel-gacrux'), - constructWagmiChain('staging', 'staging-severe-violet-wezen'), - constructWagmiChain('staging', 'staging-weepy-fitting-caph'), - - constructWagmiChain('mainnet', 'honorable-steel-rasalhague'), - constructWagmiChain('mainnet', 'elated-tan-skat'), - constructWagmiChain('mainnet', 'affectionate-immediate-pollux'), - ], - [ - jsonRpcProvider({ - rpc: (chain) => ({ - http: chain.rpcUrls.default.http[0], - webSocket: getWebSocketUrl(chain), - }), - }), - ], -) - -const connectors = connectorsForWallets([ - { - groupName: 'Supported Wallets', - wallets: [ - metaMaskWallet({ chains, projectId: '' }), - injectedWallet({ chains }), - coinbaseWallet({ chains, appName: 'TEST' }), - ], - }, -]) - -const wagmiConfig = createConfig({ - autoConnect: true, - connectors, - publicClient: webSocketPublicClient, -}) - -export default function Widget(props: { config: MetaportConfig }) { +export default function Metaport(props: { config: MetaportConfig }) { return ( - - - - - + + + ) } diff --git a/src/components/Widget/Widget.tsx b/src/components/MetaportProvider/MetaportProvider.tsx similarity index 74% rename from src/components/Widget/Widget.tsx rename to src/components/MetaportProvider/MetaportProvider.tsx index 12fbec2..c16b054 100644 --- a/src/components/Widget/Widget.tsx +++ b/src/components/MetaportProvider/MetaportProvider.tsx @@ -16,32 +16,37 @@ * along with this program. If not, see . */ /** - * @file Widget.ts + * @file MetaportProvider.ts * @copyright SKALE Labs 2023-Present */ -import React, { useEffect } from 'react' +import { ReactElement, useEffect } from 'react' -import { RainbowKitProvider, darkTheme, lightTheme } from '@rainbow-me/rainbowkit' +import { RainbowKitProvider } from '@rainbow-me/rainbowkit' import { configureChains, createConfig, WagmiConfig } from 'wagmi' import { mainnet, goerli } from 'wagmi/chains' import { jsonRpcProvider } from 'wagmi/providers/jsonRpc' import { connectorsForWallets } from '@rainbow-me/rainbowkit' +import { PaletteMode } from '@mui/material' import { injectedWallet, coinbaseWallet, metaMaskWallet } from '@rainbow-me/rainbowkit/wallets' import { MetaportConfig } from '../../core/interfaces' -import WidgetUI from '../WidgetUI' -import { useUIStore } from '../../store/Store' -import { useMetaportStore } from '../../store/MetaportState' -import { getWidgetTheme } from '../../core/themes' -import MetaportCore from '../../core/metaport' +import { StyledEngineProvider } from '@mui/material/styles' +import { createTheme, ThemeProvider } from '@mui/material/styles' import '@rainbow-me/rainbowkit/styles.css' import { constructWagmiChain, getWebSocketUrl } from '../../core/wagmi_network' +import { getWidgetTheme, getMuiZIndex } from '../../core/themes' + +import { useUIStore } from '../../store/Store' +import { useMetaportStore } from '../../store/MetaportState' +import MetaportCore from '../../core/metaport' + + const { chains, webSocketPublicClient } = configureChains( [ mainnet, @@ -84,16 +89,18 @@ const wagmiConfig = createConfig({ publicClient: webSocketPublicClient, }) -export default function Widget(props: { config: MetaportConfig }) { +export default function MetaportProvider(props: { + config: MetaportConfig, + className?: string + children?: ReactElement | ReactElement[] +}) { + const widgetTheme = getWidgetTheme(props.config.theme) - const theme = widgetTheme.mode === 'dark' ? darkTheme() : lightTheme() const setTheme = useUIStore((state) => state.setTheme) const setMpc = useMetaportStore((state) => state.setMpc) const setOpen = useUIStore((state) => state.setOpen) - - theme.colors.connectButtonInnerBackground = widgetTheme.background - theme.colors.connectButtonBackground = widgetTheme.background + const metaportTheme = useUIStore((state) => state.theme) useEffect(() => { setOpen(props.config.openOnLoad) @@ -107,6 +114,24 @@ export default function Widget(props: { config: MetaportConfig }) { setMpc(new MetaportCore(props.config)) }, [setMpc]) + let theme = createTheme({ + zIndex: getMuiZIndex(widgetTheme), + palette: { + mode: widgetTheme.mode as PaletteMode, + background: { + paper: widgetTheme.background, + }, + primary: { + main: widgetTheme.primary, + }, + secondary: { + main: widgetTheme.background, + }, + }, + }) + + if (!metaportTheme) return
+ return ( - + + + {props.children} + + ) diff --git a/src/components/MetaportProvider/index.ts b/src/components/MetaportProvider/index.ts new file mode 100644 index 0000000..c947cbc --- /dev/null +++ b/src/components/MetaportProvider/index.ts @@ -0,0 +1 @@ +export { default } from './MetaportProvider' diff --git a/src/components/Widget/Widget.mdx b/src/components/Widget/Widget.mdx deleted file mode 100644 index 425c0a4..0000000 --- a/src/components/Widget/Widget.mdx +++ /dev/null @@ -1,23 +0,0 @@ -import { useState } from 'react' - -import { Canvas, Story, ArgsTable } from '@storybook/blocks' - -import Grid from '@mui/material/Grid' -import TextField from '@mui/material/TextField' -import Button from '@mui/material/Button' - -import { internalEvents } from '../../core/events' -import * as WidgetStories from './Widget.stories' - -# Functional Metaport Demo - - - - ## Sandbox mode - You can try functional Metaport demo in a Sandbox mode here. - - - - - - diff --git a/src/components/Widget/Widget.stories.tsx b/src/components/Widget/Widget.stories.tsx deleted file mode 100644 index 1d9405d..0000000 --- a/src/components/Widget/Widget.stories.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/react' -import Widget from './Widget' -// import { storyDecorator } from "../WidgetUI/StorybookHelper"; - -const METAPORT_CONFIG = require('../../metadata/metaportConfigStaging.json') -METAPORT_CONFIG.mainnetEndpoint = process.env.STORYBOOK_MAINNET_ENDPOINT - -const meta: Meta = { - title: 'Functional/Widget', - component: Widget, - // decorators: [storyDecorator], -} - -export default meta -type Story = StoryObj - -export const WidgetDemo: Story = { - args: { - config: METAPORT_CONFIG, - }, -} diff --git a/src/components/Widget/index.ts b/src/components/Widget/index.ts deleted file mode 100644 index 81db243..0000000 --- a/src/components/Widget/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Widget' diff --git a/src/components/WidgetUI/WidgetUI.tsx b/src/components/WidgetUI/WidgetUI.tsx index ea7402a..443533c 100644 --- a/src/components/WidgetUI/WidgetUI.tsx +++ b/src/components/WidgetUI/WidgetUI.tsx @@ -29,9 +29,6 @@ import Collapse from '@mui/material/Collapse' import Fab from '@mui/material/Fab' import CloseIcon from '@mui/icons-material/Close' -import { createTheme, ThemeProvider } from '@mui/material/styles' -import { getMuiZIndex } from '../../core/themes' - import skaleLogo from './skale_logo_short.svg' import { useUIStore } from '../../store/Store' @@ -44,58 +41,22 @@ import { cls } from '../../core/helper' import styles from '../../styles/styles.module.scss' import common from '../../styles/common.module.scss' -import { PaletteMode } from '@mui/material' - -import { getWidgetTheme } from '../../core/themes' import SkConnect from '../SkConnect' import ErrorMessage from '../ErrorMessage' import { MetaportConfig } from '../../core/interfaces' -import MetaportCore from '../../core/metaport' + export function WidgetUI(props: { config: MetaportConfig }) { - const widgetTheme = getWidgetTheme(props.config.theme) - const setTheme = useUIStore((state) => state.setTheme) - const setMpc = useMetaportStore((state) => state.setMpc) + const metaportTheme = useUIStore((state) => state.theme) + const isOpen = useUIStore((state) => state.open) const setOpen = useUIStore((state) => state.setOpen) - useEffect(() => { - setOpen(props.config.openOnLoad) - }, []) - - useEffect(() => { - setTheme(widgetTheme) - }, [setTheme]) - - useEffect(() => { - setMpc(new MetaportCore(props.config)) - }, [setMpc]) - const { address } = useAccount() - const metaportTheme = useUIStore((state) => state.theme) - const isOpen = useUIStore((state) => state.open) - const errorMessage = useMetaportStore((state) => state.errorMessage) - if (!metaportTheme) return
- - let theme = createTheme({ - zIndex: getMuiZIndex(metaportTheme), - palette: { - mode: metaportTheme.mode as PaletteMode, - background: { - paper: metaportTheme.background, - }, - primary: { - main: metaportTheme.primary, - }, - secondary: { - main: metaportTheme.background, - }, - }, - }) const handleClick = (_: React.MouseEvent) => { setOpen(isOpen ? false : true) @@ -137,27 +98,23 @@ export function WidgetUI(props: { config: MetaportConfig }) { ) return ( - - -
-
{fabTop ? fabButton : null}
- - - - - - - - {address ? :
}
-
+
+
{fabTop ? fabButton : null}
+ + + + + + -
{fabTop ? null : fabButton}
-
- - + {address ? :
}
+ +
+
{fabTop ? null : fabButton}
+
) } diff --git a/src/index.ts b/src/index.ts index ef8ee23..0499aae 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,3 @@ -export { Metaport, ChainIcon, WidgetUI, interfaces, dataclasses } from './Metaport' +export { SkConnect, SkPaper, MetaportProvider, Metaport, ChainIcon, WidgetUI, interfaces, dataclasses } from './Metaport' export { useMetaportStore } from './store/MetaportState'; export { useUIStore, useCollapseStore } from './store/Store'; \ No newline at end of file diff --git a/src/styles/styles.module.scss b/src/styles/styles.module.scss index b55885c..b61a340 100644 --- a/src/styles/styles.module.scss +++ b/src/styles/styles.module.scss @@ -214,6 +214,8 @@ button { padding-top: 0.8em !important; padding-bottom: 0.8em !important; min-height: $sk-btn-height !important; + border-radius: $sk-border-radius !important; + box-shadow: none !important; } .btnChain { From 4c3f9d1c8529bc05e3c1989d8ca4d6d29b2fa1c5 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Tue, 15 Aug 2023 16:26:05 +0100 Subject: [PATCH 15/54] Make tokenIcon exportable, add external interfaces --- .../MetaportProvider/MetaportProvider.tsx | 12 +++++- src/components/SkConnect/SkConnect.tsx | 4 +- src/components/TokenIcon/TokenIcon.tsx | 15 ++++--- src/components/TokenList/TokenList.tsx | 2 +- .../TokenListSection/TokenListSection.tsx | 5 ++- src/components/WidgetUI/WidgetUI.tsx | 5 +-- src/core/metadata.ts | 10 ++--- src/index.ts | 39 +++++++++++++++++-- 8 files changed, 67 insertions(+), 25 deletions(-) diff --git a/src/components/MetaportProvider/MetaportProvider.tsx b/src/components/MetaportProvider/MetaportProvider.tsx index c16b054..c30ff69 100644 --- a/src/components/MetaportProvider/MetaportProvider.tsx +++ b/src/components/MetaportProvider/MetaportProvider.tsx @@ -42,10 +42,15 @@ import { constructWagmiChain, getWebSocketUrl } from '../../core/wagmi_network' import { getWidgetTheme, getMuiZIndex } from '../../core/themes' +import { cls } from '../../core/helper' + import { useUIStore } from '../../store/Store' import { useMetaportStore } from '../../store/MetaportState' import MetaportCore from '../../core/metaport' +import styles from '../../styles/styles.module.scss' +import common from '../../styles/common.module.scss' + const { chains, webSocketPublicClient } = configureChains( [ @@ -102,6 +107,9 @@ export default function MetaportProvider(props: { const setOpen = useUIStore((state) => state.setOpen) const metaportTheme = useUIStore((state) => state.theme) + const themeCls = widgetTheme.mode === 'dark' ? styles.darkTheme : styles.lightTheme + const commonThemeCls = widgetTheme.mode === 'dark' ? common.darkTheme : common.lightTheme + useEffect(() => { setOpen(props.config.openOnLoad) }, []) @@ -144,7 +152,9 @@ export default function MetaportProvider(props: { > - {props.children} +
+ {props.children} +
diff --git a/src/components/SkConnect/SkConnect.tsx b/src/components/SkConnect/SkConnect.tsx index a286ead..27c097b 100644 --- a/src/components/SkConnect/SkConnect.tsx +++ b/src/components/SkConnect/SkConnect.tsx @@ -32,7 +32,7 @@ import { cls } from '../../core/helper' import styles from '../../styles/styles.module.scss' import common from '../../styles/common.module.scss' -// import skaleLogoFull from '../WidgetUI/skale_logo.svg'; +import skaleLogoFull from '../WidgetUI/skale_logo.svg'; import { useMetaportStore } from '../../store/MetaportState' import ChainIcon from '../ChainIcon' @@ -63,7 +63,7 @@ export default function SkConnect() { return (
- {/* */} +
} - - const iconPath = tokenIconPath(props.token) + const iconPath = props.iconUrl ?? tokenIcon(props.tokenSymbol) if (iconPath.default) { return } diff --git a/src/components/TokenList/TokenList.tsx b/src/components/TokenList/TokenList.tsx index 3f0d7ee..c938cc7 100644 --- a/src/components/TokenList/TokenList.tsx +++ b/src/components/TokenList/TokenList.tsx @@ -89,7 +89,7 @@ export default function TokenList() { >
- +

- +

{fabTop ? fabButton : null}
- diff --git a/src/core/metadata.ts b/src/core/metadata.ts index ae784c6..4086aa1 100644 --- a/src/core/metadata.ts +++ b/src/core/metadata.ts @@ -52,9 +52,9 @@ export function chainIconPath(skaleNetwork: SkaleNetwork, name: string, app?: st } } -export function tokenIcon(name: string) { - if (!name) return - const key = name.toLowerCase() +export function tokenIcon(tokenSymbol: string) { + if (!tokenSymbol) return + const key = tokenSymbol.toLowerCase() if (icons[key]) { return icons[key] } else { @@ -62,10 +62,6 @@ export function tokenIcon(name: string) { } } -export function tokenIconPath(token: TokenData) { - return token.meta.iconUrl ?? tokenIcon(token.meta.symbol) -} - export function getTokenName(token: TokenData): string { return token.meta.name ?? token.meta.symbol } diff --git a/src/index.ts b/src/index.ts index 0499aae..9fad3a7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,36 @@ -export { SkConnect, SkPaper, MetaportProvider, Metaport, ChainIcon, WidgetUI, interfaces, dataclasses } from './Metaport' -export { useMetaportStore } from './store/MetaportState'; -export { useUIStore, useCollapseStore } from './store/Store'; \ No newline at end of file +export { interfaces, dataclasses } from './Metaport' + +export { useMetaportStore } from './store/MetaportState' +export { useUIStore, useCollapseStore } from './store/Store' + +import Metaport from './components/Metaport' +import MetaportProvider from './components/MetaportProvider' + +import SkConnect from './components/SkConnect' +import SkPaper from './components/SkPaper' + +import ChainIcon from './components/ChainIcon' +import TokenIcon from './components/TokenIcon' + +import ChainsList from './components/ChainsList' +import TokenList from './components/TokenList' +import AmountInput from './components/AmountInput' + +import { cls } from './core/helper' +import styles from './styles/styles.module.scss' +import common from './styles/common.module.scss' + +export { + Metaport, + MetaportProvider, + SkPaper, + SkConnect, + ChainIcon, + TokenIcon, + ChainsList, + TokenList, + AmountInput, + cls, + styles, + common +} \ No newline at end of file From 035c1334205efbb4b7e0190518a29eb79e605d9c Mon Sep 17 00:00:00 2001 From: Dmytro Date: Tue, 15 Aug 2023 16:44:57 +0100 Subject: [PATCH 16/54] Fix storybook build - add react-dom --- .storybook/preview.ts | 1 - package.json | 2 ++ src/Metaport.tsx | 6 ++--- .../MetaportProvider/MetaportProvider.tsx | 8 ++---- src/components/SkConnect/SkConnect.tsx | 2 +- src/components/TokenIcon/TokenIcon.tsx | 5 ++-- src/components/TokenList/TokenList.tsx | 2 +- .../TokenListSection/TokenListSection.tsx | 5 +--- src/components/WidgetUI/WidgetUI.tsx | 4 --- src/index.ts | 26 +++++++++---------- 10 files changed, 25 insertions(+), 36 deletions(-) diff --git a/.storybook/preview.ts b/.storybook/preview.ts index 76fc315..f3f8a70 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.ts @@ -1,5 +1,4 @@ import type { Preview } from '@storybook/react' -import '../src/lib/tailwind/theme.css' const preview: Preview = { parameters: { diff --git a/package.json b/package.json index 05d80c2..a3477ad 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,8 @@ "postcss": "8.4.27", "prettier": "3.0.1", "prop-types": "15.8.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", "sass": "^1.65.1", "storybook": "7.2.2", "typescript": "5.1.6", diff --git a/src/Metaport.tsx b/src/Metaport.tsx index 4c52c2a..97751fd 100644 --- a/src/Metaport.tsx +++ b/src/Metaport.tsx @@ -40,13 +40,13 @@ export { WidgetUI } import Metaport from './components/Metaport' export { Metaport } -import MetaportProvider from './components/MetaportProvider'; +import MetaportProvider from './components/MetaportProvider' export { MetaportProvider } -import SkPaper from './components/SkPaper'; +import SkPaper from './components/SkPaper' export { SkPaper } -import SkConnect from './components/SkConnect'; +import SkConnect from './components/SkConnect' export { SkConnect } // export * as sfuel from './core/sfuel'; diff --git a/src/components/MetaportProvider/MetaportProvider.tsx b/src/components/MetaportProvider/MetaportProvider.tsx index c30ff69..f28e7be 100644 --- a/src/components/MetaportProvider/MetaportProvider.tsx +++ b/src/components/MetaportProvider/MetaportProvider.tsx @@ -51,7 +51,6 @@ import MetaportCore from '../../core/metaport' import styles from '../../styles/styles.module.scss' import common from '../../styles/common.module.scss' - const { chains, webSocketPublicClient } = configureChains( [ mainnet, @@ -95,11 +94,10 @@ const wagmiConfig = createConfig({ }) export default function MetaportProvider(props: { - config: MetaportConfig, + config: MetaportConfig className?: string children?: ReactElement | ReactElement[] }) { - const widgetTheme = getWidgetTheme(props.config.theme) const setTheme = useUIStore((state) => state.setTheme) @@ -152,9 +150,7 @@ export default function MetaportProvider(props: { > -
- {props.children} -
+
{props.children}
diff --git a/src/components/SkConnect/SkConnect.tsx b/src/components/SkConnect/SkConnect.tsx index 27c097b..50df7f7 100644 --- a/src/components/SkConnect/SkConnect.tsx +++ b/src/components/SkConnect/SkConnect.tsx @@ -32,7 +32,7 @@ import { cls } from '../../core/helper' import styles from '../../styles/styles.module.scss' import common from '../../styles/common.module.scss' -import skaleLogoFull from '../WidgetUI/skale_logo.svg'; +import skaleLogoFull from '../WidgetUI/skale_logo.svg' import { useMetaportStore } from '../../store/MetaportState' import ChainIcon from '../ChainIcon' diff --git a/src/components/TokenIcon/TokenIcon.tsx b/src/components/TokenIcon/TokenIcon.tsx index 1c22a05..6f980a3 100644 --- a/src/components/TokenIcon/TokenIcon.tsx +++ b/src/components/TokenIcon/TokenIcon.tsx @@ -27,10 +27,9 @@ import { tokenIcon } from '../../core/metadata' import styles from '../../styles/styles.module.scss' - export default function TokenIcon(props: { - tokenSymbol: string | undefined | null; - iconUrl?: string | undefined | null, + tokenSymbol: string | undefined | null + iconUrl?: string | undefined | null size?: 'xs' | 'sm' | 'md' | 'lg' }) { const size = props.size ?? 'sm' diff --git a/src/components/TokenList/TokenList.tsx b/src/components/TokenList/TokenList.tsx index c938cc7..ac83c71 100644 --- a/src/components/TokenList/TokenList.tsx +++ b/src/components/TokenList/TokenList.tsx @@ -89,7 +89,7 @@ export default function TokenList() { >
- +

- +

state.theme) const isOpen = useUIStore((state) => state.open) const setOpen = useUIStore((state) => state.setOpen) @@ -57,12 +55,10 @@ export function WidgetUI(props: { config: MetaportConfig }) { const errorMessage = useMetaportStore((state) => state.errorMessage) - const handleClick = (_: React.MouseEvent) => { setOpen(isOpen ? false : true) } - let fabTop: boolean = false let fabLeft: boolean = false if (metaportTheme) { diff --git a/src/index.ts b/src/index.ts index 9fad3a7..ee53b61 100644 --- a/src/index.ts +++ b/src/index.ts @@ -21,16 +21,16 @@ import styles from './styles/styles.module.scss' import common from './styles/common.module.scss' export { - Metaport, - MetaportProvider, - SkPaper, - SkConnect, - ChainIcon, - TokenIcon, - ChainsList, - TokenList, - AmountInput, - cls, - styles, - common -} \ No newline at end of file + Metaport, + MetaportProvider, + SkPaper, + SkConnect, + ChainIcon, + TokenIcon, + ChainsList, + TokenList, + AmountInput, + cls, + styles, + common, +} From b8d45b4b93e850db6d9a0ec7d65f89424187cfd4 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Tue, 15 Aug 2023 16:46:10 +0100 Subject: [PATCH 17/54] Update vercel build command --- vercel.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vercel.json b/vercel.json index 9bd088d..202e3db 100644 --- a/vercel.json +++ b/vercel.json @@ -2,7 +2,7 @@ "$schema": "https://openapi.vercel.sh/vercel.json", "buildCommand": "yarn build-storybook", "devCommand": "yarn storybook", - "installCommand": "bash prepare_meta.sh && yarn install", + "installCommand": "bash prepare_meta.sh && yarn install && yarn build", "framework": null, "outputDirectory": "./storybook-static" } \ No newline at end of file From 2c4c4fe35880b0ec01c1da8dbfc9dfddc3c27b22 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Wed, 16 Aug 2023 13:00:42 +0100 Subject: [PATCH 18/54] Remove reduntant scss ts modules, add transfer ETA and ETF modules --- .../AmountErrorMessage/AmountErrorMessage.tsx | 2 +- .../AmountInput/AmountInput.module.scss | 2 +- .../AmountInput/AmountInput.module.scss.d.ts | 9 --- src/components/AmountInput/AmountInput.tsx | 4 +- src/components/Metaport/Metaport.stories.tsx | 26 +++++++++ .../MetaportProvider/MetaportProvider.tsx | 2 +- src/components/Stepper/SkStepper.module.scss | 4 +- .../Stepper/SkStepper.module.scss.d.ts | 16 ------ src/components/Stepper/SkStepper.tsx | 8 +-- src/components/TokenList/TokenList.scss | 4 +- .../TokenListSection/TokenListSection.scss | 4 +- src/components/TransferETA/TransferETA.tsx | 53 ++++++++++++++++++ src/components/TransferETA/index.ts | 1 + src/components/TransferETF/TransferETF.tsx | 56 +++++++++++++++++++ src/components/TransferETF/index.ts | 1 + src/components/WidgetBody/WidgetBody.tsx | 11 +--- src/core/constants.ts | 2 +- src/core/fee_calculator.ts | 3 +- src/core/gas_station.ts | 31 ---------- src/core/metadata.ts | 2 + src/core/themes.ts | 2 +- src/index.ts | 14 +++++ src/styles/styles.module.scss | 37 ++++++------ 23 files changed, 193 insertions(+), 101 deletions(-) delete mode 100644 src/components/AmountInput/AmountInput.module.scss.d.ts create mode 100644 src/components/Metaport/Metaport.stories.tsx delete mode 100644 src/components/Stepper/SkStepper.module.scss.d.ts create mode 100644 src/components/TransferETA/TransferETA.tsx create mode 100644 src/components/TransferETA/index.ts create mode 100644 src/components/TransferETF/TransferETF.tsx create mode 100644 src/components/TransferETF/index.ts delete mode 100644 src/core/gas_station.ts diff --git a/src/components/AmountErrorMessage/AmountErrorMessage.tsx b/src/components/AmountErrorMessage/AmountErrorMessage.tsx index 40b2c67..e6315f3 100644 --- a/src/components/AmountErrorMessage/AmountErrorMessage.tsx +++ b/src/components/AmountErrorMessage/AmountErrorMessage.tsx @@ -9,7 +9,7 @@ import { useMetaportStore } from '../../store/MetaportState' export default function AmountErrorMessage() { const amountErrorMessage = useMetaportStore((state) => state.amountErrorMessage) return ( - +

+

diff --git a/src/components/Metaport/Metaport.stories.tsx b/src/components/Metaport/Metaport.stories.tsx new file mode 100644 index 0000000..2b8f557 --- /dev/null +++ b/src/components/Metaport/Metaport.stories.tsx @@ -0,0 +1,26 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import Metaport from "./Metaport"; + +import * as interfaces from '../../core/interfaces' +// import { storyDecorator } from "../WidgetUI/StorybookHelper"; + +import METAPORT_CONFIG from '../../metadata/metaportConfigStaging.json'; +const config = METAPORT_CONFIG as interfaces.MetaportConfig; + +// METAPORT_CONFIG.mainnetEndpoint = process.env.STORYBOOK_MAINNET_ENDPOINT; + +const meta: Meta = { + title: "Functional/Metaport", + component: Metaport, + // decorators: [storyDecorator], +}; + +export default meta; +type Story = StoryObj; + + +export const WidgetDemo: Story = { + args: { + config: config + } +}; \ No newline at end of file diff --git a/src/components/MetaportProvider/MetaportProvider.tsx b/src/components/MetaportProvider/MetaportProvider.tsx index f28e7be..54af185 100644 --- a/src/components/MetaportProvider/MetaportProvider.tsx +++ b/src/components/MetaportProvider/MetaportProvider.tsx @@ -150,7 +150,7 @@ export default function MetaportProvider(props: { > -
{props.children}
+
{props.children}
diff --git a/src/components/Stepper/SkStepper.module.scss b/src/components/Stepper/SkStepper.module.scss index 0196a89..14213ba 100644 --- a/src/components/Stepper/SkStepper.module.scss +++ b/src/components/Stepper/SkStepper.module.scss @@ -1,4 +1,4 @@ -.mp__labelStep { +.labelStep { // font-weight: 600 !important; text-transform: uppercase !important; font-size: 0.6525rem !important; @@ -6,7 +6,7 @@ letter-spacing: 0.02857em !important; } -.mp__stepper { +.stepper { :global span { font-weight: 600 !important; diff --git a/src/components/Stepper/SkStepper.module.scss.d.ts b/src/components/Stepper/SkStepper.module.scss.d.ts deleted file mode 100644 index 06fc8b2..0000000 --- a/src/components/Stepper/SkStepper.module.scss.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -import globalClassNames from '../../style.d' -declare const classNames: typeof globalClassNames & { - readonly mp__labelStep: 'mp__labelStep' - readonly mp__stepper: 'mp__stepper' - readonly 'MuiStepConnector-line': 'MuiStepConnector-line' - readonly 'MuiBox-root': 'MuiBox-root' - readonly 'MuiSvgIcon-root': 'MuiSvgIcon-root' - readonly 'MuiStepContent-root': 'MuiStepContent-root' - readonly 'MuiChip-icon': 'MuiChip-icon' - readonly 'MuiStepLabel-root': 'MuiStepLabel-root' - readonly 'MuiStepLabel-iconContainer': 'MuiStepLabel-iconContainer' - readonly 'MuiStepLabel-labelContainer': 'MuiStepLabel-labelContainer' - readonly 'MuiStepLabel-label': 'MuiStepLabel-label' - readonly 'Mui-active': 'Mui-active' -} -export = classNames diff --git a/src/components/Stepper/SkStepper.tsx b/src/components/Stepper/SkStepper.tsx index 2047ed1..50beacd 100644 --- a/src/components/Stepper/SkStepper.tsx +++ b/src/components/Stepper/SkStepper.tsx @@ -13,7 +13,6 @@ import common from '../../styles/common.module.scss' import styles from '../../styles/styles.module.scss' import localStyles from './SkStepper.module.scss' import ChainIcon from '../ChainIcon' -import SkPaper from '../SkPaper' import { useMetaportStore } from '../../store/MetaportState' import { Collapse } from '@mui/material' @@ -50,13 +49,13 @@ export default function SkStepper(props: { skaleNetwork: SkaleNetwork }) { if (stepsMetadata.length === 0) return
return ( - + - + {stepsMetadata.map((step, i) => ( - +

{step.headline}

@@ -145,7 +144,6 @@ export default function SkStepper(props: { skaleNetwork: SkaleNetwork }) {
)} - ) } diff --git a/src/components/TokenList/TokenList.scss b/src/components/TokenList/TokenList.scss index 53c672c..a93d6e6 100644 --- a/src/components/TokenList/TokenList.scss +++ b/src/components/TokenList/TokenList.scss @@ -1,11 +1,11 @@ -.mp__iconToken { +.iconToken { width: 22px; height: 22px; } -.default-mp__iconToken { +.default-iconToken { color: black; background-color: #dbe106; padding: 4px; diff --git a/src/components/TokenListSection/TokenListSection.scss b/src/components/TokenListSection/TokenListSection.scss index 0822c74..0377d29 100644 --- a/src/components/TokenListSection/TokenListSection.scss +++ b/src/components/TokenListSection/TokenListSection.scss @@ -1,13 +1,13 @@ -.mp__iconToken { +.iconToken { width: 21px; height: 21px; margin-left: 2px; margin-right: 2px; } -.default-mp__iconToken { +.default-iconToken { color: black; background-color: #dbe106; padding: 4px; diff --git a/src/components/TransferETA/TransferETA.tsx b/src/components/TransferETA/TransferETA.tsx new file mode 100644 index 0000000..c2ea774 --- /dev/null +++ b/src/components/TransferETA/TransferETA.tsx @@ -0,0 +1,53 @@ +import React, { useEffect } from 'react'; +import Tooltip from '@mui/material/Tooltip'; +import InfoIcon from '@mui/icons-material/Info'; +import Skeleton from '@mui/material/Skeleton'; + +import { isMainnet, cls } from '../../core/helper'; +import { IMA_M2S_WAIT, IMA_S2S_WAIT, IMA_HUB_WAIT } from '../../core/constants'; +// import { getAvgWaitTime } from '../../core/gas_station'; +import common from '../../styles/common.module.scss'; +import { TokenData } from '../../core/dataclasses'; + +export default function TransferETA(props: { token: TokenData, toChain: string }) { + const [eta, setEta] = React.useState(); + const [isLoaded, setIsLoaded] = React.useState(false); + + async function calcETA() { + setIsLoaded(false); + let baseETA = 0; + const fromMainnet = isMainnet(props.token.chain); + const toMainnet = isMainnet(props.toChain); + baseETA += fromMainnet || toMainnet ? IMA_M2S_WAIT : IMA_S2S_WAIT; + if (props.token.connections[props.toChain] && props.token.connections[props.toChain].hub) { + baseETA += IMA_HUB_WAIT; + } + setEta(baseETA) + setIsLoaded(true); + } + + useEffect(() => { + if (props.token && props.toChain) calcETA(); + }, [props.token, props.toChain]); + + const tooltipText = 'Estimated transfer time (may vary depending on the network load)'; + + return ( + +
+
+

+ ETA +

+ +
+ {isLoaded ? ( +

+ ~{eta}-{eta + 1} min +

) : ( + + )} +
+
+ ) +} \ No newline at end of file diff --git a/src/components/TransferETA/index.ts b/src/components/TransferETA/index.ts new file mode 100644 index 0000000..0e4694c --- /dev/null +++ b/src/components/TransferETA/index.ts @@ -0,0 +1 @@ +export { default } from './TransferETA' diff --git a/src/components/TransferETF/TransferETF.tsx b/src/components/TransferETF/TransferETF.tsx new file mode 100644 index 0000000..7f2fdb7 --- /dev/null +++ b/src/components/TransferETF/TransferETF.tsx @@ -0,0 +1,56 @@ +import React, { useEffect } from 'react'; +import Tooltip from '@mui/material/Tooltip'; +import InfoIcon from '@mui/icons-material/Info'; +import Skeleton from '@mui/material/Skeleton'; + +import { isMainnet, cls } from '../../core/helper'; +// import { getTransactionFee } from '../../core/fee_calculator'; + +import common from '../../styles/common.module.scss'; + + +function roundDown(number, decimals) { + decimals = decimals || 0; + return (Math.floor(number * Math.pow(10, decimals)) / Math.pow(10, decimals)); +} + + +export default function TransferETF(props: { fromChain: string }) { + const [etf, setEtf] = React.useState(); + const [isLoaded, setIsLoaded] = React.useState(false); + + async function calcETF() { + setIsLoaded(false); + const fromMainnet = isMainnet(props.fromChain); + let baseETF = 0; + // if (fromMainnet) baseETF = await getTransactionFee(); + if (fromMainnet) baseETF = 2.5 + setEtf(baseETF) + setIsLoaded(true); + } + + useEffect(() => { + if (props.fromChain) calcETF(); + }, [props.fromChain]); + + const tooltipText = 'Estimated transaction fee (You pay only for Mainnet transactions, all transfers within SKALE are free)'; + const etfText = (etf === 0) ? 'Free' : `~${roundDown(etf, 3)} USD` + + return ( + +
+
+

+ Estimated Transaction Fee +

+ +
+ {isLoaded ? ( +

+ {etfText}

) : ( + + )} +
+
+ ) +} \ No newline at end of file diff --git a/src/components/TransferETF/index.ts b/src/components/TransferETF/index.ts new file mode 100644 index 0000000..4879f38 --- /dev/null +++ b/src/components/TransferETF/index.ts @@ -0,0 +1 @@ +export { default } from './TransferETF' diff --git a/src/components/WidgetBody/WidgetBody.tsx b/src/components/WidgetBody/WidgetBody.tsx index fa7f668..88d8ec2 100644 --- a/src/components/WidgetBody/WidgetBody.tsx +++ b/src/components/WidgetBody/WidgetBody.tsx @@ -9,6 +9,8 @@ import SkStepper from '../Stepper' import SkPaper from '../SkPaper' import AmountErrorMessage from '../AmountErrorMessage' import SwitchDirection from '../SwitchDirection' +import TransferETF from '../TransferETF' +import TransferETA from '../TransferETA' import common from '../../styles/common.module.scss' import { cls } from '../../core/helper' @@ -68,15 +70,6 @@ export function WidgetBody(props) { disabledChain={chainName1} disabled={transferInProgress} /> - - {/*
-
- -
-
- {token ? : null} -
-
*/} diff --git a/src/core/constants.ts b/src/core/constants.ts index 0c016ce..39746ed 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -61,7 +61,7 @@ export const BASE_EXPLORER_URLS = { // ETA constants -export const GAS_STATION_API_ENDPOINT = 'https://ethgasstation.info/api/ethgasAPI.json?' +// export const GAS_STATION_API_ENDPOINT = 'https://ethgasstation.info/api/ethgasAPI.json?' export const IMA_M2S_WAIT = 5 export const IMA_S2S_WAIT = 2 diff --git a/src/core/fee_calculator.ts b/src/core/fee_calculator.ts index c14cd63..f8e2f90 100644 --- a/src/core/fee_calculator.ts +++ b/src/core/fee_calculator.ts @@ -30,10 +30,9 @@ import * as interfaces from './interfaces/index' debug.enable('*') const log = debug('metaport:components:fee_calculator') -export async function getTransactionFee(transferRequest: interfaces.TransferParams): Promise { +export async function getTransactionFee(): Promise { // todo: get actual gas limit for transfer // todo: get actual gas price - log(transferRequest) const gasLimit = toBN('250000') const gasPrice = toBN('10000000000') diff --git a/src/core/gas_station.ts b/src/core/gas_station.ts deleted file mode 100644 index d9242cd..0000000 --- a/src/core/gas_station.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @license - * SKALE Metaport - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -/** - * @file gas_station.ts - * @copyright SKALE Labs 2022-Present - */ - -import { GAS_STATION_API_ENDPOINT } from './constants' - -export async function getAvgWaitTime() { - const response = await fetch(GAS_STATION_API_ENDPOINT) - if (!response.ok) return 0 - const data = await response.json() - return data.avgWait -} diff --git a/src/core/metadata.ts b/src/core/metadata.ts index 4086aa1..4deb5a1 100644 --- a/src/core/metadata.ts +++ b/src/core/metadata.ts @@ -32,6 +32,8 @@ import * as REGRESSION_CHAIN_ICONS from '../meta/regression/icons' import * as icons from '../icons' +// const icons = { eth: { default: '' } }; // TODO: fix for storybook + const CHAIN_ICONS = { mainnet: MAINNET_CHAIN_ICONS, staging: STAGING_CHAIN_ICONS, diff --git a/src/core/themes.ts b/src/core/themes.ts index 02c6844..da8fdf8 100644 --- a/src/core/themes.ts +++ b/src/core/themes.ts @@ -47,7 +47,7 @@ const MUI_ELEMENTS = ['mobileStepper', 'fab', 'speedDial', 'appBar', 'drawer', ' const INDEX_STEP = 50 -export function getWidgetTheme(theme: MetaportTheme | null): MetaportTheme { +export function getWidgetTheme(theme: MetaportTheme | null | undefined): MetaportTheme { if (!theme) return defaultThemes.dark as MetaportTheme if (theme.mode && Object.keys(theme).length === 1) { return defaultThemes[theme.mode] as MetaportTheme diff --git a/src/index.ts b/src/index.ts index ee53b61..1b7c83d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,11 +15,19 @@ import TokenIcon from './components/TokenIcon' import ChainsList from './components/ChainsList' import TokenList from './components/TokenList' import AmountInput from './components/AmountInput' +import SwitchDirection from './components/SwitchDirection' +import SkStepper from './components/Stepper' +import TransferETF from './components/TransferETF' +import TransferETA from './components/TransferETA' import { cls } from './core/helper' import styles from './styles/styles.module.scss' import common from './styles/common.module.scss' +import { getWidgetTheme as getMetaportTheme } from './core/themes'; + +import { useAccount as useWagmiAccount } from 'wagmi' + export { Metaport, MetaportProvider, @@ -30,7 +38,13 @@ export { ChainsList, TokenList, AmountInput, + SwitchDirection, + SkStepper, + TransferETF, + TransferETA, cls, styles, common, + getMetaportTheme, + useWagmiAccount } diff --git a/src/styles/styles.module.scss b/src/styles/styles.module.scss index b61a340..d76e4f0 100644 --- a/src/styles/styles.module.scss +++ b/src/styles/styles.module.scss @@ -20,13 +20,6 @@ padding: 10pt; border-radius: $sk-border-radius-outter; border: 1px rgba(127, 127, 127, .2705882353) solid; - - :global(.Mui-disabled) { - :global(.MuiAccordionSummary-expandIconWrapper) { - display: none !important; - } - opacity: 1 !important; - } } .darkTheme { @@ -115,9 +108,7 @@ button { } -.imaWidgetBody { - border-radius: $sk-border-radius-outter !important; - position: fixed; +.metaport { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif !important; -webkit-font-smoothing: antialiased; @@ -126,15 +117,29 @@ button { background-color: transparent !important; } - :global(.MuiAccordionDetails-root) { - padding: 0 !important; - } - :global(.MuiButton-root) { font-weight: 600 !important; box-shadow: none !important; border-radius: $sk-border-radius !important; } + + :global(.Mui-disabled) { + :global(.MuiAccordionSummary-expandIconWrapper) { + display: none !important; + } + + opacity: 1 !important; + } + + :global(.MuiAccordionDetails-root) { + padding: 0 !important; + } +} + + +.imaWidgetBody { + border-radius: $sk-border-radius-outter !important; + position: fixed; } .chainIconxs { @@ -187,8 +192,8 @@ button { .sk__btnSwitch { width: 100%; text-align: center; - margin-top: -13pt; - margin-bottom: -13pt; + margin-top: -13pt !important; + margin-bottom: -13pt !important; button { border: 13px #1a1a1a solid; From de8a4c129c842f426c3f680000415c162f59e69a Mon Sep 17 00:00:00 2001 From: Dmytro Date: Wed, 16 Aug 2023 19:25:35 +0100 Subject: [PATCH 19/54] New amount input, export amount error module --- src/components/AmountInput/AmountInput.tsx | 24 +++++++++---- src/components/Stepper/SkStepper.tsx | 7 ++-- src/components/TokenList/TokenList.tsx | 38 +++++++++++++-------- src/components/WidgetBody/WidgetBody.tsx | 39 +++++++++++++++------- src/core/metadata.ts | 2 +- src/index.ts | 2 ++ src/styles/common.module.scss | 5 +++ src/styles/styles.module.scss | 4 +++ 8 files changed, 85 insertions(+), 36 deletions(-) diff --git a/src/components/AmountInput/AmountInput.tsx b/src/components/AmountInput/AmountInput.tsx index e7523fa..ad30f9d 100644 --- a/src/components/AmountInput/AmountInput.tsx +++ b/src/components/AmountInput/AmountInput.tsx @@ -7,7 +7,10 @@ import { cls } from '../../core/helper' import common from '../../styles/common.module.scss' import localStyles from './AmountInput.module.scss' +import TokenList from '../TokenList' import { useMetaportStore } from '../../store/MetaportState' +import { useCollapseStore } from '../../store/Store' + export default function AmountInput() { const { address } = useAccount() @@ -16,6 +19,7 @@ export default function AmountInput() { const transferInProgress = useMetaportStore((state) => state.transferInProgress) const setAmount = useMetaportStore((state) => state.setAmount) const amount = useMetaportStore((state) => state.amount) + const expandedTokens = useCollapseStore((state) => state.expandedTokens) const handleChange = (event: React.ChangeEvent) => { if (parseFloat(event.target.value) < 0) { @@ -41,10 +45,15 @@ export default function AmountInput() { // } // } - if (!token) return + // if (!token) return return (
-
+ + {expandedTokens ? null :
-
+ + {/*
- {token.meta.symbol} -
+ {token ? token.meta.symbol : 'ETH'} +
*/} {/* {props.maxBtn ?
) diff --git a/src/components/TokenList/index.ts b/src/components/TokenList/index.ts index ba9b61b..a555ff1 100644 --- a/src/components/TokenList/index.ts +++ b/src/components/TokenList/index.ts @@ -1 +1,4 @@ export { default } from './TokenList' + +import TokenBalance from './TokenBalance' +export { TokenBalance } diff --git a/src/components/TokenListSection/TokenListSection.tsx b/src/components/TokenListSection/TokenListSection.tsx index e07d68e..3001eb2 100644 --- a/src/components/TokenListSection/TokenListSection.tsx +++ b/src/components/TokenListSection/TokenListSection.tsx @@ -71,7 +71,11 @@ export default function TokenListSection(props: { {getTokenName(props.tokens[key])}

- +
diff --git a/src/components/WidgetBody/WidgetBody.tsx b/src/components/WidgetBody/WidgetBody.tsx index cf266cf..d94d5e8 100644 --- a/src/components/WidgetBody/WidgetBody.tsx +++ b/src/components/WidgetBody/WidgetBody.tsx @@ -2,15 +2,14 @@ import React, { useEffect } from 'react' import { useCollapseStore } from '../../store/Store' import { useMetaportStore } from '../../store/MetaportState' -import TokenList from '../TokenList' import ChainsList from '../ChainsList' import AmountInput from '../AmountInput' import SkStepper from '../Stepper' import SkPaper from '../SkPaper' import AmountErrorMessage from '../AmountErrorMessage' import SwitchDirection from '../SwitchDirection' -import TransferETF from '../TransferETF' -import TransferETA from '../TransferETA' +import { TokenBalance } from '../TokenList' +import DestTokenBalance from '../DestTokenBalance' import common from '../../styles/common.module.scss' import { cls } from '../../core/helper' @@ -33,6 +32,7 @@ export function WidgetBody(props) { const mpc = useMetaportStore((state) => state.mpc) const tokens = useMetaportStore((state) => state.tokens) const setToken = useMetaportStore((state) => state.setToken) + const tokenBalances = useMetaportStore((state) => state.tokenBalances) const transferInProgress = useMetaportStore((state) => state.transferInProgress) @@ -51,6 +51,16 @@ export function WidgetBody(props) {
+
+

From

+
+ {token ? : null} +
+
+
+

To

+ +
Promise + destTokenContract: Contract + destTokenBalance: bigint + updateDestTokenBalance: (address: string) => Promise + amountErrorMessage: string setAmountErrorMessage: (amountErrorMessage: string) => void @@ -272,15 +278,32 @@ export const useMetaportStore = create()((set, get) => ({ tokens: getEmptyTokenDataMap(), token: null, - setToken: (token: dataclasses.TokenData) => - set(() => ({ + + setToken: async (token: dataclasses.TokenData) => { + const provider = get().chainName2 === MAINNET_CHAIN_NAME ? get().mainnetChain.provider : get().sChain2.provider + const destTokenContract = get().mpc.tokenContract( + get().chainName2, + token.keyname, + token.type, + provider + ) + set({ token: token, stepsMetadata: getStepsMetadata(get().mpc.config, token, get().chainName2), - })), + destTokenContract: destTokenContract + }) + }, tokenContracts: {}, tokenBalances: {}, + destTokenContract: null, + destTokenBalance: null, + updateDestTokenBalance: async (address: string) => { + const balance = await get().mpc.tokenBalance(get().destTokenContract, address) + set({ destTokenBalance: balance }) + }, + updateTokenBalances: async (address: string) => { const tokenBalances = await get().mpc.tokenBalances(get().tokenContracts, address) set({ tokenBalances: tokenBalances }) diff --git a/src/styles/common.module.scss b/src/styles/common.module.scss index 0cf9d38..15dba77 100644 --- a/src/styles/common.module.scss +++ b/src/styles/common.module.scss @@ -137,6 +137,10 @@ padding-top: 10px !important; } +.paddTop20 { + padding-top: 20px !important; +} + .paddBott10 { padding-bottom: 10px !important; } From b3333d6bf8c51dd9d64625603334f851f0a574c0 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Thu, 17 Aug 2023 18:34:14 +0100 Subject: [PATCH 21/54] Fix dest token balance, export proxy endpoints --- src/components/Metaport/Metaport.stories.tsx | 10 +- src/components/WidgetBody/WidgetBody.tsx | 115 +++++++++++------- src/core/network.ts | 2 + src/index.ts | 7 +- ...gStaging.json => metaportConfigStaging.ts} | 47 ++++--- src/store/MetaportState.ts | 40 +++--- tsconfig.json | 2 +- 7 files changed, 139 insertions(+), 84 deletions(-) rename src/metadata/{metaportConfigStaging.json => metaportConfigStaging.ts} (84%) diff --git a/src/components/Metaport/Metaport.stories.tsx b/src/components/Metaport/Metaport.stories.tsx index 2b8f557..34fbb2e 100644 --- a/src/components/Metaport/Metaport.stories.tsx +++ b/src/components/Metaport/Metaport.stories.tsx @@ -1,13 +1,9 @@ import type { Meta, StoryObj } from '@storybook/react'; import Metaport from "./Metaport"; -import * as interfaces from '../../core/interfaces' -// import { storyDecorator } from "../WidgetUI/StorybookHelper"; -import METAPORT_CONFIG from '../../metadata/metaportConfigStaging.json'; -const config = METAPORT_CONFIG as interfaces.MetaportConfig; - -// METAPORT_CONFIG.mainnetEndpoint = process.env.STORYBOOK_MAINNET_ENDPOINT; +import { METAPORT_CONFIG } from '../../metadata/metaportConfigStaging'; +METAPORT_CONFIG.mainnetEndpoint = import.meta.env.VITE_MAINNET_ENDPOINT; const meta: Meta = { title: "Functional/Metaport", @@ -21,6 +17,6 @@ type Story = StoryObj; export const WidgetDemo: Story = { args: { - config: config + config: METAPORT_CONFIG } }; \ No newline at end of file diff --git a/src/components/WidgetBody/WidgetBody.tsx b/src/components/WidgetBody/WidgetBody.tsx index d94d5e8..bdf4005 100644 --- a/src/components/WidgetBody/WidgetBody.tsx +++ b/src/components/WidgetBody/WidgetBody.tsx @@ -10,6 +10,7 @@ import AmountErrorMessage from '../AmountErrorMessage' import SwitchDirection from '../SwitchDirection' import { TokenBalance } from '../TokenList' import DestTokenBalance from '../DestTokenBalance' +import ErrorMessage from '../ErrorMessage' import common from '../../styles/common.module.scss' import { cls } from '../../core/helper' @@ -22,6 +23,8 @@ export function WidgetBody(props) { const expandedTo = useCollapseStore((state) => state.expandedTo) const setExpandedTo = useCollapseStore((state) => state.setExpandedTo) + const expandedTokens = useCollapseStore((state) => state.expandedTokens) + const token = useMetaportStore((state) => state.token) const chainName1 = useMetaportStore((state) => state.chainName1) const chainName2 = useMetaportStore((state) => state.chainName2) @@ -34,6 +37,8 @@ export function WidgetBody(props) { const setToken = useMetaportStore((state) => state.setToken) const tokenBalances = useMetaportStore((state) => state.tokenBalances) + const errorMessage = useMetaportStore((state) => state.errorMessage) + const transferInProgress = useMetaportStore((state) => state.transferInProgress) useEffect(() => { @@ -47,61 +52,87 @@ export function WidgetBody(props) { } }, [tokens]); + const showFrom = !expandedTo && !expandedTokens && !errorMessage + const showTo = !expandedFrom && !expandedTokens && !errorMessage + const showInput = !expandedFrom && !expandedTo && !errorMessage + const showSwitch = !expandedFrom && !expandedTo && !expandedTokens && !errorMessage + const showStepper = !expandedFrom && !expandedTo && !expandedTokens && !errorMessage + const showError = !!errorMessage; + return (
+ + + -
-

From

-
- {token ? : null} + +
+

From

+
+ {token ? : null} +
+ +
+ + + + + + + + + + + + + + +
+

To

+
- {/* - - */}
+
- {/* */} - - - - {/* */} - - - -
-

To

- -
- -
- - - + + + + + + +
) } diff --git a/src/core/network.ts b/src/core/network.ts index 545df6c..3f07564 100644 --- a/src/core/network.ts +++ b/src/core/network.ts @@ -29,6 +29,8 @@ import { MAINNET_CHAIN_NAME } from './constants' import { IMA_ADDRESSES, IMA_ABIS } from './contracts' import { SkaleNetwork } from './interfaces' +export { proxyEndpoints as PROXY_ENDPOINTS } + const PROTOCOL: { [protocol in 'http' | 'ws']: string } = { http: 'https://', ws: 'wss://', diff --git a/src/index.ts b/src/index.ts index 36dbe1f..400926d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -21,6 +21,7 @@ import TransferETF from './components/TransferETF' import TransferETA from './components/TransferETA' import AmountErrorMessage from './components/AmountErrorMessage' import DestTokenBalance from './components/DestTokenBalance' +import ErrorMessage from './components/ErrorMessage' import { cls } from './core/helper' import styles from './styles/styles.module.scss' @@ -30,6 +31,8 @@ import { getWidgetTheme as getMetaportTheme } from './core/themes'; import { useAccount as useWagmiAccount } from 'wagmi' +import { PROXY_ENDPOINTS } from './core/network' + export { Metaport, MetaportProvider, @@ -47,9 +50,11 @@ export { AmountErrorMessage, TokenBalance, DestTokenBalance, + ErrorMessage, cls, styles, common, getMetaportTheme, - useWagmiAccount + useWagmiAccount, + PROXY_ENDPOINTS } diff --git a/src/metadata/metaportConfigStaging.json b/src/metadata/metaportConfigStaging.ts similarity index 84% rename from src/metadata/metaportConfigStaging.json rename to src/metadata/metaportConfigStaging.ts index eaa3f7a..f0e57a8 100644 --- a/src/metadata/metaportConfigStaging.json +++ b/src/metadata/metaportConfigStaging.ts @@ -1,16 +1,18 @@ -{ +import * as interfaces from '../core/interfaces' + +export const METAPORT_CONFIG: interfaces.MetaportConfig = { "skaleNetwork": "staging", "openOnLoad": true, "openButton": true, "debug": false, "chains": [ "mainnet", - "staging-legal-crazy-castor", - "staging-utter-unripe-menkar", - "staging-faint-slimy-achird", - "staging-perfect-parallel-gacrux", - "staging-severe-violet-wezen", - "staging-weepy-fitting-caph" + "staging-legal-crazy-castor", // Europa + "staging-utter-unripe-menkar", // Calypso + "staging-faint-slimy-achird", // Nebula + "staging-perfect-parallel-gacrux", // Test Chain 1 + "staging-severe-violet-wezen", // Test Chain 2 + "staging-weepy-fitting-caph" // Tank War Zone ], "tokens": { "eth": { @@ -108,7 +110,10 @@ "usdc": { "address": "0x85dedAA65D33210E15911Da5E9dc29F5C93a50A9", "chains": { - "staging-legal-crazy-castor": {} + "staging-legal-crazy-castor": {}, + "staging-utter-unripe-menkar": { + "hub": "staging-legal-crazy-castor" + } } }, "wbtc": { @@ -135,7 +140,7 @@ } } }, - "staging-utter-unripe-menkar": { + "staging-utter-unripe-menkar": { // Calypso connections "erc20": { "skl": { "address": "0x7E1B8750C21AebC3bb2a0bDf40be104C609a9852", @@ -152,6 +157,18 @@ "clone": true } } + }, + "usdc": { + "address": "0x49c37d0Bb6238933eEe2157e9Df417fd62723fF6", + "chains": { + "staging-legal-crazy-castor": { + "clone": true + }, + "mainnet": { + "hub": "staging-legal-crazy-castor", + "clone": true + } + } } } }, @@ -175,7 +192,7 @@ } } }, - "staging-legal-crazy-castor": { + "staging-legal-crazy-castor": { // Europa connections "erc20": { "skl": { "address": "0xbA1E9BA7CDd4815Da6a51586bE56e8643d1bEAb6", @@ -228,6 +245,9 @@ "chains": { "mainnet": { "clone": true + }, + "staging-utter-unripe-menkar": { + "wrapper": "0x4f250cCE5b8B39caA96D1144b9A32E1c6a9f97b0" } } }, @@ -242,11 +262,8 @@ } }, "staging-perfect-parallel-gacrux": { - "erc20": { - }, - "erc721": { - - }, + "erc20": {}, + "erc721": {}, "erc1155": { "skaliens": { "address": "0xBA9fF38A2b22edDfa8e05805bD22C8f20c40546e", diff --git a/src/store/MetaportState.ts b/src/store/MetaportState.ts index e2c3ea9..37f75ae 100644 --- a/src/store/MetaportState.ts +++ b/src/store/MetaportState.ts @@ -193,6 +193,7 @@ export const useMetaportStore = create()((set, get) => ({ tokenId: null, currentStep: 0, transferInProgress: false, + destTokenBalance: null }) }, @@ -254,26 +255,28 @@ export const useMetaportStore = create()((set, get) => ({ chainName1: name, tokens: tokens, tokenContracts: tokenContracts, + tokenBalances: {}, ...updState, } }), - setChainName2: (name: string) => - set((state) => { - const updState = {} - if (name === MAINNET_CHAIN_NAME) { - updState['mainnetChain'] = state.mpc.mainnet() - } else { - updState['sChain2'] = state.mpc.schain(name) - } - return { - currentStep: 0, - token: null, - chainName2: name, - tokens: state.mpc.tokens(state.chainName1, name), - stepsMetadata: getStepsMetadata(get().mpc.config, get().token, name), - ...updState, - } - }), + setChainName2: (name: string) => { + const updState = {} + if (name === MAINNET_CHAIN_NAME) { + updState['mainnetChain'] = get().mpc.mainnet() + } else { + updState['sChain2'] = get().mpc.schain(name) + } + set({ + currentStep: 0, + token: null, + destTokenBalance: null, + destTokenContract: null, + chainName2: name, + tokens: get().mpc.tokens(get().chainName1, name), + stepsMetadata: getStepsMetadata(get().mpc.config, get().token, name), + ...updState, + }) + }, tokens: getEmptyTokenDataMap(), @@ -290,7 +293,8 @@ export const useMetaportStore = create()((set, get) => ({ set({ token: token, stepsMetadata: getStepsMetadata(get().mpc.config, token, get().chainName2), - destTokenContract: destTokenContract + destTokenContract: destTokenContract, + destTokenBalance: null }) }, diff --git a/tsconfig.json b/tsconfig.json index 99dcac8..ad5b433 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,7 +15,7 @@ "isolatedModules": true, "noEmit": true, "jsx": "react-jsx", - "typeRoots": ["./src/types", "./node_modules/@types"], + "typeRoots": ["./src/vite-env.d.ts", "./src/types", "./node_modules/@types"], }, "include": ["./src/**/*.ts", "./src/**/*.tsx"], "exclude": ["./src/**/*.stories.*"] From 90078c7632bae275297048d846f3d7e1a9f6b8b2 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Fri, 18 Aug 2023 17:06:14 +0100 Subject: [PATCH 22/54] Update dest chains filtering logic, update config --- src/components/AmountInput/AmountInput.tsx | 49 +------ src/components/ChainsList/ChainsList.tsx | 3 +- src/components/TokenList/TokenList.tsx | 143 ++++++++++----------- src/components/WidgetBody/WidgetBody.tsx | 10 +- src/core/metadata.ts | 2 +- src/metadata/metaportConfigStaging.ts | 27 ++-- src/store/MetaportState.ts | 19 +-- src/styles/styles.module.scss | 2 +- 8 files changed, 108 insertions(+), 147 deletions(-) diff --git a/src/components/AmountInput/AmountInput.tsx b/src/components/AmountInput/AmountInput.tsx index ad30f9d..fb58d67 100644 --- a/src/components/AmountInput/AmountInput.tsx +++ b/src/components/AmountInput/AmountInput.tsx @@ -29,23 +29,6 @@ export default function AmountInput() { setAmount(event.target.value, address) } - // const setMaxAmount = () => { - // if (token && !token.clone && - // (token.wrapsSFuel || token.type === TokenType.eth)) { - // const adjustedAmount = Number(token.balance) - SFUEL_RESERVE_AMOUNT; - // if (adjustedAmount > 0) { - // props.setAmount(adjustedAmount.toString()); - // } - // } else { - // if (token && !token.clone && token.unwrappedBalance) { - // props.setAmount(token.unwrappedBalance); - // } else { - // props.setAmount(token.balance); - // } - // } - // } - - // if (!token) return return (
@@ -63,36 +46,10 @@ export default function AmountInput() { disabled={transferInProgress} />
- } - - - {/*
- {token ? token.meta.symbol : 'ETH'} -
*/} - - {/* {props.maxBtn ?
- -
: null} */} +
+ +
) } diff --git a/src/components/ChainsList/ChainsList.tsx b/src/components/ChainsList/ChainsList.tsx index 04cf519..7964326 100644 --- a/src/components/ChainsList/ChainsList.tsx +++ b/src/components/ChainsList/ChainsList.tsx @@ -22,6 +22,7 @@ export default function ChainsList(props: { setExpanded: (expanded: string | false) => void setChain: (chain: string) => void chain: string + chains: string[] disabledChain: string from?: boolean disabled?: boolean @@ -32,7 +33,7 @@ export default function ChainsList(props: { const schainNames = [] - for (let chain of props.config.chains) { + for (let chain of props.chains) { if (chain != props.disabledChain && chain != props.chain) { schainNames.push(chain) } diff --git a/src/components/TokenList/TokenList.tsx b/src/components/TokenList/TokenList.tsx index a5da607..c82f659 100644 --- a/src/components/TokenList/TokenList.tsx +++ b/src/components/TokenList/TokenList.tsx @@ -68,93 +68,88 @@ export default function TokenList() { setExpandedTokens(isExpanded ? panel : false) } - // if (noTokens) { - // return - // } - let tokensText = token ? token.meta.symbol : 'TOKEN'; if (noTokens) { - tokensText = 'ETH' + tokensText = 'N/A' } return ( -
- + } + aria-controls="panel1bh-content" + id="panel1bh-header" + className={styles.accordionSummaryTokens} + > - } - aria-controls="panel1bh-content" - id="panel1bh-header" - className={styles.accordionSummaryTokens} - - > -
-
- -
-

- {tokensText} -

- - {/*
+
+
+ +
+

+ {tokensText} +

+ + {/*
{token ? : null}
*/} -
- +
+ - {expandedTokens ? - {/* + {/* */} - - - - - : null} - - -
+ + + + + : null} + +
) } diff --git a/src/components/WidgetBody/WidgetBody.tsx b/src/components/WidgetBody/WidgetBody.tsx index bdf4005..30db64b 100644 --- a/src/components/WidgetBody/WidgetBody.tsx +++ b/src/components/WidgetBody/WidgetBody.tsx @@ -25,6 +25,8 @@ export function WidgetBody(props) { const expandedTokens = useCollapseStore((state) => state.expandedTokens) + const destChains = useMetaportStore((state) => state.destChains) + const token = useMetaportStore((state) => state.token) const chainName1 = useMetaportStore((state) => state.chainName1) const chainName2 = useMetaportStore((state) => state.chainName2) @@ -47,7 +49,7 @@ export function WidgetBody(props) { }, []); useEffect(() => { - if (tokens && tokens.erc20) { + if (tokens && tokens.erc20 && Object.values(tokens.erc20)[0]) { setToken(Object.values(tokens.erc20)[0]) } }, [tokens]); @@ -89,6 +91,7 @@ export function WidgetBody(props) { expanded={expandedFrom} setExpanded={setExpandedFrom} chain={chainName1} + chains={props.config.chains} setChain={setChainName1} disabledChain={chainName2} disabled={transferInProgress} @@ -118,16 +121,15 @@ export function WidgetBody(props) { expanded={expandedTo} setExpanded={setExpandedTo} chain={chainName2} + chains={destChains} setChain={setChainName2} disabledChain={chainName1} disabled={transferInProgress} /> - - - + diff --git a/src/core/metadata.ts b/src/core/metadata.ts index 428da54..2684b85 100644 --- a/src/core/metadata.ts +++ b/src/core/metadata.ts @@ -32,7 +32,7 @@ import * as REGRESSION_CHAIN_ICONS from '../meta/regression/icons' import * as icons from '../icons' -// const icons = { eth: { default: '' } }; // TODO: storybook fix +// const icons = { eth: { default: '' }, skl: { default: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHZpZXdCb3g9IjAgMCAzMiAzMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSJub25lIj48Y2lyY2xlIGZpbGw9IiMwMDAiIGN4PSIxNiIgY3k9IjE2IiByPSIxNiIvPjxnIGZpbGw9IiNGRkYiPjxwYXRoIGQ9Ik0yMi41MTQgOC40OTJ2Ljk5MUg5LjgxdjEzLjAzNGgxMi43MDRWMjQuNWwtNy40Mi0uMDU3LTcuNDUtLjA4NS0uMDg2LTguNDQzTDcuNSA3LjVoMTUuMDE0eiIvPjxwYXRoIGQ9Ik0yMy42OTggMTAuOWMxLjEyNi4zMTIgMi4xMDggMS4xOSAyLjQyNSAyLjE4Mi4xNzMuNTk1LjA4Ny42NTEtLjkyNC42NTEtLjc4IDAtMS4yMTItLjE3LTEuNDcyLS41NjYtLjQzMy0uNzA5LTIuMzk3LS43OTQtMi45NzQtLjExNC0uNjM1Ljc2NS4wNTggMS4zMzIgMi4zMSAxLjg0MiAxLjEyNi4yNTUgMi4zMS42OCAyLjYyNy45NjMgMS40NDQgMS4yNzUuODY2IDQuMDgtMS4wMSA0Ljg0NS0xLjI3LjUxLTMuMzUuNTEtNC42MiAwLS44NjYtLjM2OC0xLjg3Ny0xLjY0My0xLjg3Ny0yLjQzNiAwLS41MSAxLjg3Ny0uMzEyIDIuMzY4LjI4MyAxLjA0IDEuMTYyIDMuNDY0Ljk5MiAzLjYzOC0uMjU1LjE0NC0uOTYzLS40MDUtMS4zODgtMi4wNS0xLjU4Ny0yLjY4NS0uMzY4LTMuNjY3LTEuMTktMy42NjctMy4wNiAwLTIuMjEgMi40MjUtMy41MTMgNS4yMjYtMi43NDh6Ii8+PC9nPjwvZz48L3N2Zz4=' } }; // TODO: storybook fix const CHAIN_ICONS = { mainnet: MAINNET_CHAIN_ICONS, diff --git a/src/metadata/metaportConfigStaging.ts b/src/metadata/metaportConfigStaging.ts index f0e57a8..a65c6fd 100644 --- a/src/metadata/metaportConfigStaging.ts +++ b/src/metadata/metaportConfigStaging.ts @@ -261,22 +261,25 @@ export const METAPORT_CONFIG: interfaces.MetaportConfig = { } } }, + "staging-severe-violet-wezen": { + "erc20": {} + }, "staging-perfect-parallel-gacrux": { "erc20": {}, "erc721": {}, "erc1155": { - "skaliens": { - "address": "0xBA9fF38A2b22edDfa8e05805bD22C8f20c40546e", - "chains": {} - }, - "medals": { - "address": "0x5D8bD602dC5468B3998e8514A1851bd5888E9639", - "chains": {} - }, - "_ANIMALS_0xDf87EEF0977148129969b01b329379b17756cdDE": { - "address": "0xDf87EEF0977148129969b01b329379b17756cdDE", - "chains": {} - } + // "skaliens": { + // "address": "0xBA9fF38A2b22edDfa8e05805bD22C8f20c40546e", + // "chains": {} + // }, + // "medals": { + // "address": "0x5D8bD602dC5468B3998e8514A1851bd5888E9639", + // "chains": {} + // }, + // "_ANIMALS_0xDf87EEF0977148129969b01b329379b17756cdDE": { + // "address": "0xDf87EEF0977148129969b01b329379b17756cdDE", + // "chains": {} + // } } } }, diff --git a/src/store/MetaportState.ts b/src/store/MetaportState.ts index 37f75ae..02aa95d 100644 --- a/src/store/MetaportState.ts +++ b/src/store/MetaportState.ts @@ -69,6 +69,8 @@ interface MetaportState { chainName1: string chainName2: string + destChains: string[] + setChainName1: (name: string) => void setChainName2: (name: string) => void @@ -233,13 +235,10 @@ export const useMetaportStore = create()((set, get) => ({ chainName1: '', chainName2: '', + destChains: [], + setChainName1: (name: string) => set((state) => { - // updateState( - // name, - // state.chainName2 - // ) - const updState = {} if (name === MAINNET_CHAIN_NAME) { updState['mainnetChain'] = state.mpc.mainnet() @@ -256,6 +255,7 @@ export const useMetaportStore = create()((set, get) => ({ tokens: tokens, tokenContracts: tokenContracts, tokenBalances: {}, + destChains: get().mpc.config.chains, ...updState, } }), @@ -294,7 +294,8 @@ export const useMetaportStore = create()((set, get) => ({ token: token, stepsMetadata: getStepsMetadata(get().mpc.config, token, get().chainName2), destTokenContract: destTokenContract, - destTokenBalance: null + destTokenBalance: null, + destChains: Object.keys(token.connections) }) }, @@ -304,8 +305,10 @@ export const useMetaportStore = create()((set, get) => ({ destTokenContract: null, destTokenBalance: null, updateDestTokenBalance: async (address: string) => { - const balance = await get().mpc.tokenBalance(get().destTokenContract, address) - set({ destTokenBalance: balance }) + if (get().destTokenContract) { + const balance = await get().mpc.tokenBalance(get().destTokenContract, address) + set({ destTokenBalance: balance }) + } }, updateTokenBalances: async (address: string) => { diff --git a/src/styles/styles.module.scss b/src/styles/styles.module.scss index 9cc7238..d47c11b 100644 --- a/src/styles/styles.module.scss +++ b/src/styles/styles.module.scss @@ -15,7 +15,7 @@ } .popper { - width: 390px; + max-width: 390px; max-height: calc(100vh - 110pt); padding: 10pt; border-radius: $sk-border-radius-outter; From c2546e48da3c8629541d7aa736cd41b1126bb7d8 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Tue, 22 Aug 2023 13:28:35 +0100 Subject: [PATCH 23/54] Update styling system, add community pool management --- package.json | 2 +- .../AmountErrorMessage/AmountErrorMessage.tsx | 20 +- src/components/AmountInput/AmountInput.tsx | 35 +- src/components/ChainApps/ChainApps.tsx | 21 +- src/components/ChainsList/ChainsList.tsx | 62 +-- .../CommunityPool/CommunityPool.tsx | 238 +++++++++ src/components/CommunityPool/index.ts | 1 + .../DestTokenBalance/DestTokenBalance.tsx | 10 +- src/components/ErrorMessage/ErrorMessage.tsx | 42 +- src/components/Metaport/Metaport.stories.tsx | 24 +- .../MetaportProvider/MetaportProvider.tsx | 4 +- src/components/SkConnect/SkConnect.tsx | 48 +- src/components/SkPaper/SkPaper.tsx | 4 +- src/components/Stepper/SkStepper.tsx | 163 +++--- .../SwitchDirection/SwitchDirection.tsx | 12 +- src/components/TokenList/TokenBalance.tsx | 52 +- src/components/TokenList/TokenList.tsx | 93 ++-- .../TokenListSection/TokenListSection.tsx | 37 +- src/components/TransferETA/TransferETA.tsx | 57 ++- src/components/TransferETF/TransferETF.tsx | 53 +- src/components/WidgetBody/WidgetBody.tsx | 67 +-- src/components/WidgetUI/WidgetUI.tsx | 16 +- src/core/actions/action.ts | 6 - src/core/community_pool.ts | 229 ++++++--- src/core/constants.ts | 2 +- src/core/interfaces/CommunityPoolData.ts | 8 +- src/core/metadata.ts | 10 +- src/index.ts | 10 +- src/metadata/metaportConfigStaging.ts | 464 +++++++++--------- src/store/CommunityPoolStore.ts | 72 +++ src/store/MetaportState.ts | 15 +- src/store/Store.ts | 14 + .../{common.module.scss => cmn.module.scss} | 96 +--- src/styles/common.module.scss.d.ts | 55 --- src/styles/styles.module.scss | 18 + 35 files changed, 1150 insertions(+), 910 deletions(-) create mode 100644 src/components/CommunityPool/CommunityPool.tsx create mode 100644 src/components/CommunityPool/index.ts create mode 100644 src/store/CommunityPoolStore.ts rename src/styles/{common.module.scss => cmn.module.scss} (70%) delete mode 100644 src/styles/common.module.scss.d.ts diff --git a/package.json b/package.json index a3477ad..579c0f6 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "@mui/lab": "^5.0.0-alpha.88", "@mui/material": "^5.8.1", "@rainbow-me/rainbowkit": "^1.0.8", - "@skalenetwork/ima-js": "2.0.0-experimental.1", + "@skalenetwork/ima-js": "2.0.0-develop.3", "@skaleproject/pow-ethers": "0.3.2", "coingecko-api-v3": "^0.0.28", "react-jazzicon": "^1.0.4", diff --git a/src/components/AmountErrorMessage/AmountErrorMessage.tsx b/src/components/AmountErrorMessage/AmountErrorMessage.tsx index e6315f3..b0ed862 100644 --- a/src/components/AmountErrorMessage/AmountErrorMessage.tsx +++ b/src/components/AmountErrorMessage/AmountErrorMessage.tsx @@ -2,7 +2,7 @@ import React from 'react' import Collapse from '@mui/material/Collapse' import { cls } from '../../core/helper' -import common from '../../styles/common.module.scss' +import cmn from '../../styles/cmn.module.scss' import { useMetaportStore } from '../../store/MetaportState' @@ -12,15 +12,15 @@ export default function AmountErrorMessage() {

🔴 {amountErrorMessage} diff --git a/src/components/AmountInput/AmountInput.tsx b/src/components/AmountInput/AmountInput.tsx index fb58d67..1318898 100644 --- a/src/components/AmountInput/AmountInput.tsx +++ b/src/components/AmountInput/AmountInput.tsx @@ -4,14 +4,13 @@ import { useAccount } from 'wagmi' import TextField from '@mui/material/TextField' import { cls } from '../../core/helper' -import common from '../../styles/common.module.scss' +import cmn from '../../styles/cmn.module.scss' import localStyles from './AmountInput.module.scss' import TokenList from '../TokenList' import { useMetaportStore } from '../../store/MetaportState' import { useCollapseStore } from '../../store/Store' - export default function AmountInput() { const { address } = useAccount() @@ -30,24 +29,20 @@ export default function AmountInput() { } return ( -

- - {expandedTokens ? null :
- -
- } -
+
+ {expandedTokens ? null : ( +
+ +
+ )} +
diff --git a/src/components/ChainApps/ChainApps.tsx b/src/components/ChainApps/ChainApps.tsx index ba9356a..ea454c9 100644 --- a/src/components/ChainApps/ChainApps.tsx +++ b/src/components/ChainApps/ChainApps.tsx @@ -2,7 +2,7 @@ import React from 'react' import { cls, getChainAppsMeta, getChainAlias } from '../../core/helper' import styles from '../../styles/styles.module.scss' -import common from '../../styles/common.module.scss' +import cmn from '../../styles/cmn.module.scss' import { SkaleNetwork } from '../../core/interfaces' import ChainIcon from '../ChainIcon' @@ -12,27 +12,18 @@ export default function ChainApps(props: { skaleNetwork: SkaleNetwork; chain: st if (!apps || !Object.keys(apps) || Object.keys(apps).length === 0) return
return ( -
-
+
+
{Object.keys(apps).map((key, _) => ( -
+
-

+

{getChainAlias(props.skaleNetwork, props.chain, key)}

diff --git a/src/components/ChainsList/ChainsList.tsx b/src/components/ChainsList/ChainsList.tsx index 7964326..7218df9 100644 --- a/src/components/ChainsList/ChainsList.tsx +++ b/src/components/ChainsList/ChainsList.tsx @@ -13,7 +13,7 @@ import ChainIcon from '../ChainIcon' import { MetaportConfig } from '../../core/interfaces' import { cls, getChainAlias } from '../../core/helper' -import common from '../../styles/common.module.scss' +import cmn from '../../styles/cmn.module.scss' import styles from '../../styles/styles.module.scss' export default function ChainsList(props: { @@ -59,17 +59,17 @@ export default function ChainsList(props: { className={styles.accordionSummary} > {props.chain ? ( -
-
+
+
-

+

{getChainAlias(props.config.skaleNetwork, props.chain)}

-
- {/*
+
+ {/*
*/}
) : ( -
-
+
+
-

+

Transfer {props.from ? 'from' : 'to'}...

)} -
+
{schainNames.map((name) => ( - -
+
diff --git a/src/components/CommunityPool/CommunityPool.tsx b/src/components/CommunityPool/CommunityPool.tsx new file mode 100644 index 0000000..ad43b12 --- /dev/null +++ b/src/components/CommunityPool/CommunityPool.tsx @@ -0,0 +1,238 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/** + * @file CommunityPool.ts + * @copyright SKALE Labs 2023-Present + */ + +import React, { useEffect } from 'react' + +import { useAccount, useWalletClient, useSwitchNetwork } from 'wagmi' + +import Accordion from '@mui/material/Accordion' +import AccordionSummary from '@mui/material/AccordionSummary' +import AccordionDetails from '@mui/material/AccordionDetails' +import Grid from '@mui/material/Grid' +import TextField from '@mui/material/TextField' + +import localStyles from '../AmountInput/AmountInput.module.scss' + +import SkPaper from '../SkPaper/SkPaper' +import { TokenBalance } from '../TokenList' + +import Button from '@mui/material/Button' + +import ExpandMoreIcon from '@mui/icons-material/ExpandMore' + +import CheckCircleIcon from '@mui/icons-material/CheckCircle' +import ErrorIcon from '@mui/icons-material/Error' + +import { fromWei } from '../../core/convertation' +import { withdraw } from '../../core/community_pool' +import { DEFAULT_ERC20_DECIMALS } from '../../core/constants' + +import { cls } from '../../core/helper' +import cmn from '../../styles/cmn.module.scss' +import styles from '../../styles/styles.module.scss' + +import { useCPStore } from '../../store/CommunityPoolStore' +import { useCollapseStore } from '../../store/Store' +import { useMetaportStore } from '../../store/MetaportState' + +// import { getChainIcon } from '../ChainsList/helper'; + +export default function CommunityPool(props: { + // communityPoolData: CommunityPoolData + // loading: string | false + // rechargeAmount: string + // setRechargeAmount: (amount: string) => {} + // expanded: string | false + // setExpanded: (expanded: string | false) => {} + // recharge: () => {} + // withdraw: () => {} + // marg: boolean +}) { + const { data: walletClient } = useWalletClient() + const { switchNetworkAsync } = useSwitchNetwork() + + const cpData = useCPStore((state) => state.cpData) + const loading = useCPStore((state) => state.loading) + const setLoading = useCPStore((state) => state.setLoading) + const amount = useCPStore((state) => state.amount) + const setAmount = useCPStore((state) => state.setAmount) + const updateCPData = useCPStore((state) => state.updateCPData) + + const chainName1 = useMetaportStore((state) => state.chainName1) + const chainName2 = useMetaportStore((state) => state.chainName2) + const mpc = useMetaportStore((state) => state.mpc) + const setErrorMessage = useMetaportStore((state) => state.setErrorMessage) + + const expandedCP = useCollapseStore((state) => state.expandedCP) + const setExpandedCP = useCollapseStore((state) => state.setExpandedCP) + + const { address } = useAccount() + + const handleChange = (panel: string) => (_: React.SyntheticEvent, isExpanded: boolean) => { + setExpandedCP(isExpanded ? panel : false) + } + + const handleAmountChange = (event: React.ChangeEvent) => { + if (parseFloat(event.target.value) < 0) { + setAmount('') + return + } + setAmount(event.target.value) + } + + useEffect(() => { + updateCPData(address, chainName1, chainName2, mpc) + const intervalId = setInterval(() => { + updateCPData(address, chainName1, chainName2, mpc) + }, 10000) // Fetch users every 10 seconds + + return () => { + clearInterval(intervalId) // Clear interval on component unmount + } + }, [chainName1, chainName2, address]) + + const text = cpData.exitGasOk ? 'Exit gas wallet OK' : 'Recharge exit gas wallet' + const icon = cpData.exitGasOk ? : + const accountBalanceEther = cpData.accountBalance ? fromWei(cpData.accountBalance, DEFAULT_ERC20_DECIMALS) : null + + function getRechargeBtnText() { + if (loading === 'recharge') return 'Recharging...' + if (loading === 'activate') return 'Activating account...' + if (Number(amount) > Number(accountBalanceEther)) return 'Insufficient ETH balance' + if (amount === '' || amount === '0' || !amount) return 'Enter an amount' + return 'Recharge exit gas wallet' + } + + function getWithdrawBtnText() { + if (loading === 'withdraw') return 'Withdrawing...' + return 'Withdraw all' + } + + function withdrawCP() { + withdraw( + mpc, + walletClient, + chainName1, + cpData.balance, + address, + switchNetworkAsync, + setLoading, + setErrorMessage, + async () => { + setLoading(false) + setErrorMessage(null) + }, + ) + } + + return ( +
+ + } + aria-controls="panel1a-content" + id="panel1a-header" + > +
+
{icon}
+

{text}

+
+
+ + +

+ This wallet is used to pay for Ethereum gas fees from your transactions to the Ethereum Mainnet. You may + withdraw funds from your SKALE Gas Wallet at anytime. +

+
+

ETH Balance

+
+ +
+
+
+

Exit wallet Balance

+
+ +
+
+ + + +
+
+ +
+

+ ETH +

+
+
+
+ +
+
+ +
+
+
+
+
+
+
+ ) +} diff --git a/src/components/CommunityPool/index.ts b/src/components/CommunityPool/index.ts new file mode 100644 index 0000000..759a246 --- /dev/null +++ b/src/components/CommunityPool/index.ts @@ -0,0 +1 @@ +export { default } from './CommunityPool' diff --git a/src/components/DestTokenBalance/DestTokenBalance.tsx b/src/components/DestTokenBalance/DestTokenBalance.tsx index 56906be..6d46d52 100644 --- a/src/components/DestTokenBalance/DestTokenBalance.tsx +++ b/src/components/DestTokenBalance/DestTokenBalance.tsx @@ -4,9 +4,7 @@ import { useAccount } from 'wagmi' import { TokenBalance } from '../TokenList' import { useMetaportStore } from '../../store/MetaportState' - export default function DestTokenBalance() { - const { address } = useAccount() const token = useMetaportStore((state) => state.token) @@ -23,11 +21,7 @@ export default function DestTokenBalance() { } }, [updateDestTokenBalance, token, address]) - if (!token) return; + if (!token) return - return + return } diff --git a/src/components/ErrorMessage/ErrorMessage.tsx b/src/components/ErrorMessage/ErrorMessage.tsx index 3305422..8806ea2 100644 --- a/src/components/ErrorMessage/ErrorMessage.tsx +++ b/src/components/ErrorMessage/ErrorMessage.tsx @@ -2,7 +2,7 @@ import React from 'react' import Button from '@mui/material/Button' import { cls } from '../../core/helper' -import common from '../../styles/common.module.scss' +import cmn from '../../styles/cmn.module.scss' import styles from '../../styles/styles.module.scss' import { ErrorMessage } from '../../core/dataclasses' @@ -23,48 +23,20 @@ export default function Error(props: { errorMessage: ErrorMessage }) { if (!props.errorMessage) return return (
-
- {ERROR_ICONS[props.errorMessage.icon]} -
+
{ERROR_ICONS[props.errorMessage.icon]}

Error occured

-

+

Please check logs in developer console

-
+

{props.errorMessage.text}

@@ -75,7 +47,7 @@ export default function Error(props: { errorMessage: ErrorMessage }) { variant="contained" color="primary" size="medium" - className={cls(styles.btnAction, common.margTop5)} + className={cls(styles.btnAction, cmn.mtop5)} onClick={() => { props.errorMessage.fallback() }} diff --git a/src/components/Metaport/Metaport.stories.tsx b/src/components/Metaport/Metaport.stories.tsx index 34fbb2e..04c5abd 100644 --- a/src/components/Metaport/Metaport.stories.tsx +++ b/src/components/Metaport/Metaport.stories.tsx @@ -1,22 +1,20 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import Metaport from "./Metaport"; +import type { Meta, StoryObj } from '@storybook/react' +import Metaport from './Metaport' - -import { METAPORT_CONFIG } from '../../metadata/metaportConfigStaging'; -METAPORT_CONFIG.mainnetEndpoint = import.meta.env.VITE_MAINNET_ENDPOINT; +import { METAPORT_CONFIG } from '../../metadata/metaportConfigStaging' +METAPORT_CONFIG.mainnetEndpoint = import.meta.env.VITE_MAINNET_ENDPOINT const meta: Meta = { - title: "Functional/Metaport", + title: 'Functional/Metaport', component: Metaport, // decorators: [storyDecorator], -}; - -export default meta; -type Story = StoryObj; +} +export default meta +type Story = StoryObj export const WidgetDemo: Story = { args: { - config: METAPORT_CONFIG - } -}; \ No newline at end of file + config: METAPORT_CONFIG, + }, +} diff --git a/src/components/MetaportProvider/MetaportProvider.tsx b/src/components/MetaportProvider/MetaportProvider.tsx index 54af185..108458c 100644 --- a/src/components/MetaportProvider/MetaportProvider.tsx +++ b/src/components/MetaportProvider/MetaportProvider.tsx @@ -49,7 +49,7 @@ import { useMetaportStore } from '../../store/MetaportState' import MetaportCore from '../../core/metaport' import styles from '../../styles/styles.module.scss' -import common from '../../styles/common.module.scss' +import cmn from '../../styles/cmn.module.scss' const { chains, webSocketPublicClient } = configureChains( [ @@ -106,7 +106,7 @@ export default function MetaportProvider(props: { const metaportTheme = useUIStore((state) => state.theme) const themeCls = widgetTheme.mode === 'dark' ? styles.darkTheme : styles.lightTheme - const commonThemeCls = widgetTheme.mode === 'dark' ? common.darkTheme : common.lightTheme + const commonThemeCls = widgetTheme.mode === 'dark' ? cmn.darkTheme : cmn.lightTheme useEffect(() => { setOpen(props.config.openOnLoad) diff --git a/src/components/SkConnect/SkConnect.tsx b/src/components/SkConnect/SkConnect.tsx index 50df7f7..f7151e8 100644 --- a/src/components/SkConnect/SkConnect.tsx +++ b/src/components/SkConnect/SkConnect.tsx @@ -30,7 +30,7 @@ import ExpandMoreIcon from '@mui/icons-material/ExpandMore' import { cls } from '../../core/helper' import styles from '../../styles/styles.module.scss' -import common from '../../styles/common.module.scss' +import cmn from '../../styles/cmn.module.scss' import skaleLogoFull from '../WidgetUI/skale_logo.svg' import { useMetaportStore } from '../../store/MetaportState' @@ -62,79 +62,69 @@ export default function SkConnect() { if (!connected) { return (
-
+
-
+
-

+

Connect a wallet to use SKALE Metaport

- )} -
- - - - ))} - - +
+ + + +

{step.text}

+
+ {loading ? ( + + {btnText} + {/* {props.loadingTokens ? 'Loading...' : step.btnLoadingText} */} + + ) : ( + + )} +
+
+
+ + ))} + + - {currentStep === stepsMetadata.length && ( -
-
-

- {emoji} Transfer completed -

-
- + {currentStep === stepsMetadata.length && ( +
+
+

+ {emoji} Transfer completed +

- )} - + +
+ )} + ) } diff --git a/src/components/SwitchDirection/SwitchDirection.tsx b/src/components/SwitchDirection/SwitchDirection.tsx index 6d74d50..93be651 100644 --- a/src/components/SwitchDirection/SwitchDirection.tsx +++ b/src/components/SwitchDirection/SwitchDirection.tsx @@ -3,7 +3,7 @@ import React, { useRef } from 'react' import IconButton from '@mui/material/IconButton' import ArrowDownwardRoundedIcon from '@mui/icons-material/ArrowDownwardRounded' import styles from '../../styles/styles.module.scss' -import common from '../../styles/common.module.scss' +import cmn from '../../styles/cmn.module.scss' import { cls } from '../../core/helper' import { useUIStore } from '../../store/Store' @@ -24,15 +24,15 @@ export default function SwitchDirection() { const transferInProgress = useMetaportStore((state) => state.transferInProgress) return ( -
-
+
+
-
+
) } diff --git a/src/components/TokenList/TokenBalance.tsx b/src/components/TokenList/TokenBalance.tsx index 9d95780..be28657 100644 --- a/src/components/TokenList/TokenBalance.tsx +++ b/src/components/TokenList/TokenBalance.tsx @@ -1,25 +1,49 @@ import React from 'react' import { formatUnits } from 'ethers' import { cls } from '../../core/helper' -import common from '../../styles/common.module.scss' +import cmn from '../../styles/cmn.module.scss' +import { DEFAULT_ERC20_DECIMALS } from '../../core/constants' -function formatBalance(balance: bigint, decimals: string): string { - return formatUnits(balance, parseInt(decimals)) +function formatBalance(balance: bigint, decimals?: string): string { + const tokenDecimals = decimals ?? DEFAULT_ERC20_DECIMALS + return formatUnits(balance, parseInt(tokenDecimals)) } -export default function TokenBalance(props: { balance: bigint, decimals: string, symbol: string }) { +function truncateDecimals(input: string, numDecimals: number): string { + const delimiter = input.includes(',') ? ',' : '.' + const [integerPart, decimalPart = ''] = input.split(delimiter) + return `${integerPart}${delimiter}${decimalPart.slice(0, numDecimals)}` +} + +export default function TokenBalance(props: { + balance: bigint + symbol: string + decimals?: string + truncate?: number + primary?: boolean + size?: 'xs' | 'sm' +}) { if (props.balance === undefined || props.balance === null) return + let balance = formatBalance(props.balance, props.decimals) + if (props.truncate) { + balance = truncateDecimals(balance, props.truncate) + } + let size = props.size ?? 'xs' return ( -
-

- {formatBalance(props.balance, props.decimals)} {props.symbol} +

+

+ {balance} {props.symbol}

) diff --git a/src/components/TokenList/TokenList.tsx b/src/components/TokenList/TokenList.tsx index c82f659..2350f8c 100644 --- a/src/components/TokenList/TokenList.tsx +++ b/src/components/TokenList/TokenList.tsx @@ -20,7 +20,7 @@ import TokenBalance from './TokenBalance' import TokenIcon from '../TokenIcon' import styles from '../../styles/styles.module.scss' -import common from '../../styles/common.module.scss' +import cmn from '../../styles/cmn.module.scss' import { getTokenName } from '../../core/metadata' import { useCollapseStore } from '../../store/Store' @@ -68,7 +68,7 @@ export default function TokenList() { setExpandedTokens(isExpanded ? panel : false) } - let tokensText = token ? token.meta.symbol : 'TOKEN'; + let tokensText = token ? token.meta.symbol : 'TOKEN' if (noTokens) { tokensText = 'N/A' } @@ -79,77 +79,74 @@ export default function TokenList() { onChange={handleChange('panel1')} disabled={disabled || transferInProgress || noTokens} elevation={0} - className={common.fullWidth} + className={cmn.fullWidth} > } aria-controls="panel1bh-content" id="panel1bh-header" className={styles.accordionSummaryTokens} - > -
-
- +
+
+

{tokensText}

- {/*
+ {/*
{token ? : null}
*/}
- {expandedTokens ? - {/* + {/* */} - - - - - : null} - + + + + + + ) : null} ) } diff --git a/src/components/TokenListSection/TokenListSection.tsx b/src/components/TokenListSection/TokenListSection.tsx index 3001eb2..5698796 100644 --- a/src/components/TokenListSection/TokenListSection.tsx +++ b/src/components/TokenListSection/TokenListSection.tsx @@ -8,7 +8,7 @@ import { cls } from '../../core/helper' import TokenBalance from '../TokenList/TokenBalance' import TokenIcon from '../TokenIcon' -import common from '../../styles/common.module.scss' +import cmn from '../../styles/cmn.module.scss' import { getTokenName } from '../../core/metadata' @@ -27,17 +27,9 @@ export default function TokenListSection(props: { if (Object.keys(props.tokens).length === 0) return return ( -
+

{props.type} @@ -47,30 +39,17 @@ export default function TokenListSection(props: { key={key} color="secondary" size="small" - className={common.fullWidth} + className={cmn.fullWidth} onClick={() => handle(props.tokens[key])} > -

-
+
+
-

+

{getTokenName(props.tokens[key])}

-
+
(); - const [isLoaded, setIsLoaded] = React.useState(false); +export default function TransferETA(props: { token: TokenData; toChain: string }) { + const [eta, setEta] = React.useState() + const [isLoaded, setIsLoaded] = React.useState(false) async function calcETA() { - setIsLoaded(false); - let baseETA = 0; - const fromMainnet = isMainnet(props.token.chain); - const toMainnet = isMainnet(props.toChain); - baseETA += fromMainnet || toMainnet ? IMA_M2S_WAIT : IMA_S2S_WAIT; + setIsLoaded(false) + let baseETA = 0 + const fromMainnet = isMainnet(props.token.chain) + const toMainnet = isMainnet(props.toChain) + baseETA += fromMainnet || toMainnet ? IMA_M2S_WAIT : IMA_S2S_WAIT if (props.token.connections[props.toChain] && props.token.connections[props.toChain].hub) { - baseETA += IMA_HUB_WAIT; + baseETA += IMA_HUB_WAIT } setEta(baseETA) - setIsLoaded(true); + setIsLoaded(true) } useEffect(() => { - if (props.token && props.toChain) calcETA(); - }, [props.token, props.toChain]); + if (props.token && props.toChain) calcETA() + }, [props.token, props.toChain]) - const tooltipText = 'Estimated transfer time (may vary depending on the network load)'; + const tooltipText = 'Estimated transfer time (may vary depending on the network load)' return (
-
-

- ETA -

- +
+

ETA

+
{isLoaded ? ( -

+

~{eta}-{eta + 1} min -

) : ( +

+ ) : ( )}
) -} \ No newline at end of file +} diff --git a/src/components/TransferETF/TransferETF.tsx b/src/components/TransferETF/TransferETF.tsx index 7f2fdb7..bcc7345 100644 --- a/src/components/TransferETF/TransferETF.tsx +++ b/src/components/TransferETF/TransferETF.tsx @@ -1,56 +1,53 @@ -import React, { useEffect } from 'react'; -import Tooltip from '@mui/material/Tooltip'; -import InfoIcon from '@mui/icons-material/Info'; -import Skeleton from '@mui/material/Skeleton'; +import React, { useEffect } from 'react' +import Tooltip from '@mui/material/Tooltip' +import InfoIcon from '@mui/icons-material/Info' +import Skeleton from '@mui/material/Skeleton' -import { isMainnet, cls } from '../../core/helper'; +import { isMainnet, cls } from '../../core/helper' // import { getTransactionFee } from '../../core/fee_calculator'; -import common from '../../styles/common.module.scss'; - +import cmn from '../../styles/cmn.module.scss' function roundDown(number, decimals) { - decimals = decimals || 0; - return (Math.floor(number * Math.pow(10, decimals)) / Math.pow(10, decimals)); + decimals = decimals || 0 + return Math.floor(number * Math.pow(10, decimals)) / Math.pow(10, decimals) } - export default function TransferETF(props: { fromChain: string }) { - const [etf, setEtf] = React.useState(); - const [isLoaded, setIsLoaded] = React.useState(false); + const [etf, setEtf] = React.useState() + const [isLoaded, setIsLoaded] = React.useState(false) async function calcETF() { - setIsLoaded(false); - const fromMainnet = isMainnet(props.fromChain); - let baseETF = 0; + setIsLoaded(false) + const fromMainnet = isMainnet(props.fromChain) + let baseETF = 0 // if (fromMainnet) baseETF = await getTransactionFee(); if (fromMainnet) baseETF = 2.5 setEtf(baseETF) - setIsLoaded(true); + setIsLoaded(true) } useEffect(() => { - if (props.fromChain) calcETF(); - }, [props.fromChain]); + if (props.fromChain) calcETF() + }, [props.fromChain]) - const tooltipText = 'Estimated transaction fee (You pay only for Mainnet transactions, all transfers within SKALE are free)'; - const etfText = (etf === 0) ? 'Free' : `~${roundDown(etf, 3)} USD` + const tooltipText = + 'Estimated transaction fee (You pay only for Mainnet transactions, all transfers within SKALE are free)' + const etfText = etf === 0 ? 'Free' : `~${roundDown(etf, 3)} USD` return (
-
-

- Estimated Transaction Fee -

- +
+

Estimated Transaction Fee

+
{isLoaded ? ( -

- {etfText}

) : ( +

{etfText}

+ ) : ( )}
) -} \ No newline at end of file +} diff --git a/src/components/WidgetBody/WidgetBody.tsx b/src/components/WidgetBody/WidgetBody.tsx index 30db64b..87d7829 100644 --- a/src/components/WidgetBody/WidgetBody.tsx +++ b/src/components/WidgetBody/WidgetBody.tsx @@ -11,10 +11,12 @@ import SwitchDirection from '../SwitchDirection' import { TokenBalance } from '../TokenList' import DestTokenBalance from '../DestTokenBalance' import ErrorMessage from '../ErrorMessage' +import CommunityPool from '../CommunityPool' -import common from '../../styles/common.module.scss' +import cmn from '../../styles/cmn.module.scss' import { cls } from '../../core/helper' import { Collapse } from '@mui/material' +import { MAINNET_CHAIN_NAME } from '../../core/constants' export function WidgetBody(props) { const expandedFrom = useCollapseStore((state) => state.expandedFrom) @@ -23,6 +25,7 @@ export function WidgetBody(props) { const expandedTo = useCollapseStore((state) => state.expandedTo) const setExpandedTo = useCollapseStore((state) => state.setExpandedTo) + const expandedCP = useCollapseStore((state) => state.expandedCP) const expandedTokens = useCollapseStore((state) => state.expandedTokens) const destChains = useMetaportStore((state) => state.destChains) @@ -46,44 +49,40 @@ export function WidgetBody(props) { useEffect(() => { setChainName1(mpc.config.chains ? mpc.config.chains[0] : '') setChainName2(mpc.config.chains ? mpc.config.chains[1] : '') - }, []); + }, []) useEffect(() => { if (tokens && tokens.erc20 && Object.values(tokens.erc20)[0]) { setToken(Object.values(tokens.erc20)[0]) } - }, [tokens]); + }, [tokens]) - const showFrom = !expandedTo && !expandedTokens && !errorMessage - const showTo = !expandedFrom && !expandedTokens && !errorMessage - const showInput = !expandedFrom && !expandedTo && !errorMessage - const showSwitch = !expandedFrom && !expandedTo && !expandedTokens && !errorMessage - const showStepper = !expandedFrom && !expandedTo && !expandedTokens && !errorMessage - const showError = !!errorMessage; + const showFrom = !expandedTo && !expandedTokens && !errorMessage && !expandedCP + const showTo = !expandedFrom && !expandedTokens && !errorMessage && !expandedCP + const showInput = !expandedFrom && !expandedTo && !errorMessage && !expandedCP + const showSwitch = !expandedFrom && !expandedTo && !expandedTokens && !errorMessage && !expandedCP + const showStepper = !expandedFrom && !expandedTo && !expandedTokens && !errorMessage && !expandedCP + const showCP = !expandedFrom && !expandedTo && !expandedTokens && chainName2 === MAINNET_CHAIN_NAME + const showError = !!errorMessage return (
- - + + -
-

From

+
+

From

- {token ? : null} + {token ? ( + + ) : null}
- + - -
-

To

+ +
+

To

- + + + + + + + + -
) } diff --git a/src/components/WidgetUI/WidgetUI.tsx b/src/components/WidgetUI/WidgetUI.tsx index 745cf35..f96813d 100644 --- a/src/components/WidgetUI/WidgetUI.tsx +++ b/src/components/WidgetUI/WidgetUI.tsx @@ -40,7 +40,7 @@ import WidgetBody from '../WidgetBody' import { cls } from '../../core/helper' import styles from '../../styles/styles.module.scss' -import common from '../../styles/common.module.scss' +import cmn from '../../styles/cmn.module.scss' import SkConnect from '../SkConnect' import ErrorMessage from '../ErrorMessage' @@ -67,9 +67,9 @@ export function WidgetUI(props: { config: MetaportConfig }) { } const fabButton = ( -
-
-
+
+
+
-
{fabTop ? fabButton : null}
+
{fabTop ? fabButton : null}
- {address ? :
}
+ + {address ? :
} +
-
{fabTop ? null : fabButton}
+
{fabTop ? null : fabButton}
) } diff --git a/src/core/actions/action.ts b/src/core/actions/action.ts index 353f1bc..20a43a0 100644 --- a/src/core/actions/action.ts +++ b/src/core/actions/action.ts @@ -140,12 +140,6 @@ export class Action { this.originAddress = this.mpc.originAddress(chainName1, chainName2, token.keyname, token.type) - console.log('----') - console.log(this.chainName2) - console.log(token) - console.log(token.wrapper(this.chainName2)) - console.log('----') - if (this.token.wrapper(this.chainName2)) { this.unwrappedToken = mpc.tokenContract(chainName1, token.keyname, token.type, provider1) } diff --git a/src/core/community_pool.ts b/src/core/community_pool.ts index eed6df1..809014c 100644 --- a/src/core/community_pool.ts +++ b/src/core/community_pool.ts @@ -21,81 +21,176 @@ * @copyright SKALE Labs 2023-Present */ -// import debug from 'debug'; -// import { MainnetChain, SChain } from '@skalenetwork/ima-js'; +import debug from 'debug' +import { ethers } from 'ethers' +import { MainnetChain, SChain } from '@skalenetwork/ima-js' -// import { CommunityPoolData } from './interfaces'; -// import { fromWei } from './convertation'; -// import { -// MAINNET_CHAIN_NAME, -// DEFAULT_ERC20_DECIMALS, -// RECHARGE_MULTIPLIER, -// MINIMUM_RECHARGE_AMOUNT -// } from './constants'; +import { WalletClient } from 'viem' +import { Chain } from '@wagmi/core' -// debug.enable('*'); -// const log = debug('metaport:core:community_pool'); +import { CommunityPoolData } from './interfaces' +import { fromWei } from './convertation' +import { walletClientToSigner } from './ethers' +import { + MAINNET_CHAIN_NAME, + DEFAULT_ERC20_DECIMALS, + RECHARGE_MULTIPLIER, + MINIMUM_RECHARGE_AMOUNT, + COMMUNITY_POOL_WITHDRAW_GAS_LIMIT, + DEFAULT_ERROR_MSG, +} from './constants' +import { CHAIN_IDS, isMainnetChainId, getMainnetAbi } from './network' +import MetaportCore from './metaport' -// export function getEmptyCommunityPoolData(): CommunityPoolData { -// return { -// exitGasOk: null, -// isActive: null, -// balance: null, -// accountBalance: null, -// recommendedRechargeAmount: null, -// originalRecommendedRechargeAmount: null -// }; -// } +import * as dataclasses from '../core/dataclasses' -// export async function getCommunityPoolData( -// address: string, -// chainName1: string, -// chainName2: string, -// mainnet: MainnetChain, -// sChain: SChain -// ): Promise { +debug.enable('*') +const log = debug('metaport:core:community_pool') -// if (chainName2 !== MAINNET_CHAIN_NAME) { -// log('not a S2M transfer, skipping community pool check'); -// return { -// exitGasOk: true, -// isActive: null, -// balance: null, -// accountBalance: null, -// recommendedRechargeAmount: null, -// originalRecommendedRechargeAmount: null -// } -// } +export function getEmptyCommunityPoolData(): CommunityPoolData { + return { + exitGasOk: null, + isActive: null, + balance: null, + accountBalance: null, + recommendedRechargeAmount: null, + originalRecommendedRechargeAmount: null, + } +} + +export async function getCommunityPoolData( + address: string, + chainName1: string, + chainName2: string, + mainnet: MainnetChain, + sChain: SChain, +): Promise { + if (chainName2 !== MAINNET_CHAIN_NAME) { + log('not a S2M transfer, skipping community pool check') + return { + exitGasOk: true, + isActive: null, + balance: null, + accountBalance: null, + recommendedRechargeAmount: null, + originalRecommendedRechargeAmount: null, + } + } -// log('Getting community pool data', address, chainName1); -// const balanceWei = await mainnet.communityPool.balance(address, chainName1); -// const accountBalanceWei = await mainnet.ethBalance(address); -// const activeS = await sChain.communityLocker.contract.activeUsers( -// address -// ) -// const chainHash = mainnet.web3.utils.soliditySha3(chainName1); -// const activeM = await mainnet.communityPool.contract.activeUsers( -// address, -// chainHash -// ) + log('Getting community pool data', address, chainName1) + const balanceWei = await mainnet.communityPool.balance(address, chainName1) + const accountBalanceWei = await mainnet.ethBalance(address) + const activeS = await sChain.communityLocker.contract.activeUsers(address) + const chainHash = ethers.id(chainName1) + const activeM = await mainnet.communityPool.contract.activeUsers(address, chainHash) -// const rraWei = await mainnet.communityPool.contract.getRecommendedRechargeAmount( -// mainnet.web3.utils.soliditySha3(chainName1), -// address -// ) -// const rraEther = fromWei(rraWei as string, DEFAULT_ERC20_DECIMALS); + const rraWei = await mainnet.communityPool.contract.getRecommendedRechargeAmount(chainHash, address) + const rraEther = fromWei(rraWei as string, DEFAULT_ERC20_DECIMALS) -// let recommendedAmount = parseFloat(rraEther as string) * RECHARGE_MULTIPLIER; -// if (recommendedAmount < MINIMUM_RECHARGE_AMOUNT) recommendedAmount = MINIMUM_RECHARGE_AMOUNT; + let recommendedAmount = parseFloat(rraEther as string) * RECHARGE_MULTIPLIER + if (recommendedAmount < MINIMUM_RECHARGE_AMOUNT) recommendedAmount = MINIMUM_RECHARGE_AMOUNT -// const communityPoolData = { -// exitGasOk: activeM && activeS && rraWei === '0', -// isActive: activeM && activeS, -// balance: balanceWei, -// accountBalance: accountBalanceWei, -// recommendedRechargeAmount: recommendedAmount.toString(), -// originalRecommendedRechargeAmount: rraWei + const communityPoolData = { + exitGasOk: activeM && activeS && rraWei === 0n, + isActive: activeM && activeS, + balance: balanceWei, + accountBalance: accountBalanceWei, + recommendedRechargeAmount: recommendedAmount, + originalRecommendedRechargeAmount: rraWei, + } + log('communityPoolData:', communityPoolData) + return communityPoolData +} + +export async function connectedMainnetChain( + mpc: MetaportCore, + walletClient: WalletClient, + switchNetwork: (chainId: number | bigint) => Promise, +): Promise { + const currentChainId = walletClient.chain.id + const chainId = CHAIN_IDS[mpc.config.skaleNetwork] + log(`Current chainId: ${currentChainId}, required chainId: ${chainId} `) + if (currentChainId !== Number(chainId)) { + log(`Switching network to ${chainId}...`) + const chain = await switchNetwork(Number(chainId)) + if (!chain) { + throw new Error(`Failed to switch from ${currentChainId} to ${chainId} `) + } + log(`Network switched to ${chainId}...`) + } + const signer = walletClientToSigner(walletClient) + return new MainnetChain(signer.provider, getMainnetAbi(mpc.config.skaleNetwork)) +} + +export async function withdraw( + mpc: MetaportCore, + walletClient: WalletClient, + chainName: string, + amount: bigint, + address: `0x${string}`, + switchNetwork: (chainId: number | bigint) => Promise, + setLoading: (loading: string | false) => void, + setErrorMessage: (errorMessage: dataclasses.ErrorMessage) => void, + errorMessageClosedFallback: () => void, +) { + setLoading('withdraw') + try { + log(`Withdrawing from community pool: ${chainName}, amount: ${amount}`) + const mainnetMetamask = await connectedMainnetChain(mpc, walletClient, switchNetwork) + await mainnetMetamask.communityPool.withdraw(chainName, amount, { + address: address, + customGasLimit: COMMUNITY_POOL_WITHDRAW_GAS_LIMIT, + }) + setLoading(false) + } catch (err) { + console.error(err) + const msg = err.message ? err.message : DEFAULT_ERROR_MSG + setErrorMessage(new dataclasses.TransactionErrorMessage(msg, errorMessageClosedFallback)) + } +} + +// async function rechargeCommunityPool() { +// // todo: optimize +// setLoadingCommunityPool('recharge'); +// try { +// log('Recharging community pool...') +// const sChain = initSChain( +// props.config.skaleNetwork, +// chainName1 +// ); +// const mainnetMetamask = await initMainnet1(); +// setChainId(getChainId(props.config.skaleNetwork, MAINNET_CHAIN_NAME)); +// await mainnetMetamask.communityPool.recharge(chainName1, address, { +// address: address, +// value: toWei(rechargeAmount, DEFAULT_ERC20_DECIMALS) +// }); +// setLoadingCommunityPool('activate'); +// let active = false; +// const chainHash = mainnet.web3.utils.soliditySha3(chainName1); +// let counter = 0; +// while (!active) { +// log('Waiting for account activation...'); +// let activeM = await mainnet.communityPool.contract.methods.activeUsers( +// address, +// chainHash +// ).call(); +// let activeS = await sChain.communityLocker.contract.methods.activeUsers( +// address +// ).call(); +// active = activeS && activeM; +// await delay(BALANCE_UPDATE_INTERVAL_SECONDS * 1000); +// counter++; +// if (counter >= 10) break; +// } +// } catch (err) { +// console.error(err); +// const msg = err.message ? err.message : DEFAULT_ERROR_MSG; +// setErrorMessage(new TransactionErrorMessage(msg, errorMessageClosedFallback)); +// } finally { +// await initSchain1(); +// setChainId(getChainId(props.config.skaleNetwork, chainName1)); +// setMainnet(initMainnet(props.config.skaleNetwork, props.config.mainnetEndpoint)); +// await updateCommunityPoolData(); +// setLoadingCommunityPool(false); // } -// log('communityPoolData:', communityPoolData); -// return communityPoolData; // } diff --git a/src/core/constants.ts b/src/core/constants.ts index 39746ed..029739d 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -98,7 +98,7 @@ export const FAUCET_DATA = faucetJson export const RECHARGE_MULTIPLIER = 1.2 export const MINIMUM_RECHARGE_AMOUNT = 0.005 -export const COMMUNITY_POOL_WITHDRAW_GAS_LIMIT = '1500000' +export const COMMUNITY_POOL_WITHDRAW_GAS_LIMIT = 1500000n export const BALANCE_UPDATE_INTERVAL_SECONDS = 10 export const SFUEL_RESERVE_AMOUNT = 0.02 diff --git a/src/core/interfaces/CommunityPoolData.ts b/src/core/interfaces/CommunityPoolData.ts index cdd7b69..087f867 100644 --- a/src/core/interfaces/CommunityPoolData.ts +++ b/src/core/interfaces/CommunityPoolData.ts @@ -24,8 +24,8 @@ export interface CommunityPoolData { exitGasOk: boolean isActive: boolean - balance: string - accountBalance: string - recommendedRechargeAmount: string - originalRecommendedRechargeAmount: string + balance: bigint + accountBalance: bigint + recommendedRechargeAmount: number + originalRecommendedRechargeAmount: bigint } diff --git a/src/core/metadata.ts b/src/core/metadata.ts index 2684b85..6148c94 100644 --- a/src/core/metadata.ts +++ b/src/core/metadata.ts @@ -30,9 +30,15 @@ import * as STAGING_CHAIN_ICONS from '../meta/staging/icons' import * as LEGACY_CHAIN_ICONS from '../meta/legacy/icons' import * as REGRESSION_CHAIN_ICONS from '../meta/regression/icons' -import * as icons from '../icons' +// import * as icons from '../icons' -// const icons = { eth: { default: '' }, skl: { default: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHZpZXdCb3g9IjAgMCAzMiAzMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSJub25lIj48Y2lyY2xlIGZpbGw9IiMwMDAiIGN4PSIxNiIgY3k9IjE2IiByPSIxNiIvPjxnIGZpbGw9IiNGRkYiPjxwYXRoIGQ9Ik0yMi41MTQgOC40OTJ2Ljk5MUg5LjgxdjEzLjAzNGgxMi43MDRWMjQuNWwtNy40Mi0uMDU3LTcuNDUtLjA4NS0uMDg2LTguNDQzTDcuNSA3LjVoMTUuMDE0eiIvPjxwYXRoIGQ9Ik0yMy42OTggMTAuOWMxLjEyNi4zMTIgMi4xMDggMS4xOSAyLjQyNSAyLjE4Mi4xNzMuNTk1LjA4Ny42NTEtLjkyNC42NTEtLjc4IDAtMS4yMTItLjE3LTEuNDcyLS41NjYtLjQzMy0uNzA5LTIuMzk3LS43OTQtMi45NzQtLjExNC0uNjM1Ljc2NS4wNTggMS4zMzIgMi4zMSAxLjg0MiAxLjEyNi4yNTUgMi4zMS42OCAyLjYyNy45NjMgMS40NDQgMS4yNzUuODY2IDQuMDgtMS4wMSA0Ljg0NS0xLjI3LjUxLTMuMzUuNTEtNC42MiAwLS44NjYtLjM2OC0xLjg3Ny0xLjY0My0xLjg3Ny0yLjQzNiAwLS41MSAxLjg3Ny0uMzEyIDIuMzY4LjI4MyAxLjA0IDEuMTYyIDMuNDY0Ljk5MiAzLjYzOC0uMjU1LjE0NC0uOTYzLS40MDUtMS4zODgtMi4wNS0xLjU4Ny0yLjY4NS0uMzY4LTMuNjY3LTEuMTktMy42NjctMy4wNiAwLTIuMjEgMi40MjUtMy41MTMgNS4yMjYtMi43NDh6Ii8+PC9nPjwvZz48L3N2Zz4=' } }; // TODO: storybook fix +const icons = { + eth: { default: '' }, + skl: { + default: + 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHZpZXdCb3g9IjAgMCAzMiAzMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSJub25lIj48Y2lyY2xlIGZpbGw9IiMwMDAiIGN4PSIxNiIgY3k9IjE2IiByPSIxNiIvPjxnIGZpbGw9IiNGRkYiPjxwYXRoIGQ9Ik0yMi41MTQgOC40OTJ2Ljk5MUg5LjgxdjEzLjAzNGgxMi43MDRWMjQuNWwtNy40Mi0uMDU3LTcuNDUtLjA4NS0uMDg2LTguNDQzTDcuNSA3LjVoMTUuMDE0eiIvPjxwYXRoIGQ9Ik0yMy42OTggMTAuOWMxLjEyNi4zMTIgMi4xMDggMS4xOSAyLjQyNSAyLjE4Mi4xNzMuNTk1LjA4Ny42NTEtLjkyNC42NTEtLjc4IDAtMS4yMTItLjE3LTEuNDcyLS41NjYtLjQzMy0uNzA5LTIuMzk3LS43OTQtMi45NzQtLjExNC0uNjM1Ljc2NS4wNTggMS4zMzIgMi4zMSAxLjg0MiAxLjEyNi4yNTUgMi4zMS42OCAyLjYyNy45NjMgMS40NDQgMS4yNzUuODY2IDQuMDgtMS4wMSA0Ljg0NS0xLjI3LjUxLTMuMzUuNTEtNC42MiAwLS44NjYtLjM2OC0xLjg3Ny0xLjY0My0xLjg3Ny0yLjQzNiAwLS41MSAxLjg3Ny0uMzEyIDIuMzY4LjI4MyAxLjA0IDEuMTYyIDMuNDY0Ljk5MiAzLjYzOC0uMjU1LjE0NC0uOTYzLS40MDUtMS4zODgtMi4wNS0xLjU4Ny0yLjY4NS0uMzY4LTMuNjY3LTEuMTktMy42NjctMy4wNiAwLTIuMjEgMi40MjUtMy41MTMgNS4yMjYtMi43NDh6Ii8+PC9nPjwvZz48L3N2Zz4=', + }, +} // TODO: storybook fix const CHAIN_ICONS = { mainnet: MAINNET_CHAIN_ICONS, diff --git a/src/index.ts b/src/index.ts index 400926d..0660704 100644 --- a/src/index.ts +++ b/src/index.ts @@ -22,12 +22,13 @@ import TransferETA from './components/TransferETA' import AmountErrorMessage from './components/AmountErrorMessage' import DestTokenBalance from './components/DestTokenBalance' import ErrorMessage from './components/ErrorMessage' +import CommunityPool from './components/CommunityPool' import { cls } from './core/helper' import styles from './styles/styles.module.scss' -import common from './styles/common.module.scss' +import cmn from './styles/cmn.module.scss' -import { getWidgetTheme as getMetaportTheme } from './core/themes'; +import { getWidgetTheme as getMetaportTheme } from './core/themes' import { useAccount as useWagmiAccount } from 'wagmi' @@ -51,10 +52,11 @@ export { TokenBalance, DestTokenBalance, ErrorMessage, + CommunityPool, cls, styles, - common, + cmn, getMetaportTheme, useWagmiAccount, - PROXY_ENDPOINTS + PROXY_ENDPOINTS, } diff --git a/src/metadata/metaportConfigStaging.ts b/src/metadata/metaportConfigStaging.ts index a65c6fd..3c42430 100644 --- a/src/metadata/metaportConfigStaging.ts +++ b/src/metadata/metaportConfigStaging.ts @@ -1,273 +1,275 @@ import * as interfaces from '../core/interfaces' export const METAPORT_CONFIG: interfaces.MetaportConfig = { - "skaleNetwork": "staging", - "openOnLoad": true, - "openButton": true, - "debug": false, - "chains": [ - "mainnet", - "staging-legal-crazy-castor", // Europa - "staging-utter-unripe-menkar", // Calypso - "staging-faint-slimy-achird", // Nebula - "staging-perfect-parallel-gacrux", // Test Chain 1 - "staging-severe-violet-wezen", // Test Chain 2 - "staging-weepy-fitting-caph" // Tank War Zone + skaleNetwork: 'staging', + openOnLoad: true, + openButton: true, + debug: false, + chains: [ + 'mainnet', + 'staging-legal-crazy-castor', // Europa + 'staging-utter-unripe-menkar', // Calypso + 'staging-faint-slimy-achird', // Nebula + 'staging-perfect-parallel-gacrux', // Test Chain 1 + 'staging-severe-violet-wezen', // Test Chain 2 + 'staging-weepy-fitting-caph', // Tank War Zone ], - "tokens": { - "eth": { - "symbol": "eth" + tokens: { + eth: { + symbol: 'eth', }, - "skl": { - "decimals": "18", - "name": "SKALE", - "symbol": "SKL" + skl: { + decimals: '18', + name: 'SKALE', + symbol: 'SKL', }, - "usdc": { - "decimals": "6", - "symbol": "USDC", - "name": "USD Coin" + usdc: { + decimals: '6', + symbol: 'USDC', + name: 'USD Coin', }, - "usdt": { - "decimals": "6", - "symbol": "USDT", - "name": "Tether USD" + usdt: { + decimals: '6', + symbol: 'USDT', + name: 'Tether USD', }, - "wbtc": { - "decimals": "18", - "symbol": "WBTC", - "name": "WBTC" + wbtc: { + decimals: '18', + symbol: 'WBTC', + name: 'WBTC', }, - "_SPACE_1": { - "name": "SKALE Space", - "symbol": "SPACE", - "iconUrl": "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Rocket/3D/rocket_3d.png" + _SPACE_1: { + name: 'SKALE Space', + symbol: 'SPACE', + iconUrl: 'https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Rocket/3D/rocket_3d.png', }, - "_SKALIENS_1": { - "name": "SKALIENS Collection", - "symbol": "SKALIENS", - "iconUrl": "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Alien/3D/alien_3d.png" + _SKALIENS_1: { + name: 'SKALIENS Collection', + symbol: 'SKALIENS', + iconUrl: 'https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Alien/3D/alien_3d.png', }, - "ruby": { - "name": "Ruby Token", - "iconUrl": "https://ruby.exchange/images/tokens/ruby-square.png", - "symbol": "RUBY" + ruby: { + name: 'Ruby Token', + iconUrl: 'https://ruby.exchange/images/tokens/ruby-square.png', + symbol: 'RUBY', }, - "dai": { - "name": "DAI Stablecoin", - "symbol": "DAI" + dai: { + name: 'DAI Stablecoin', + symbol: 'DAI', }, - "usdp": { - "name": "Pax Dollar", - "symbol": "USDP", - "iconUrl": "https://ruby.exchange/images/tokens/usdp-square.png" + usdp: { + name: 'Pax Dollar', + symbol: 'USDP', + iconUrl: 'https://ruby.exchange/images/tokens/usdp-square.png', + }, + hmt: { + name: 'Human Token', + symbol: 'HMT', + iconUrl: 'https://s2.coinmarketcap.com/static/img/coins/64x64/10347.png', }, - "hmt": { - "name": "Human Token", - "symbol": "HMT", - "iconUrl": "https://s2.coinmarketcap.com/static/img/coins/64x64/10347.png" - } }, - "connections": { - "mainnet": { - "erc20": { - "skl": { - "address": "0x493D4442013717189C9963a2e275Ad33bfAFcE11", - "chains": { - "staging-legal-crazy-castor": {}, - "staging-utter-unripe-menkar": { - "hub": "staging-legal-crazy-castor" + connections: { + mainnet: { + erc20: { + skl: { + address: '0x493D4442013717189C9963a2e275Ad33bfAFcE11', + chains: { + 'staging-legal-crazy-castor': {}, + 'staging-utter-unripe-menkar': { + hub: 'staging-legal-crazy-castor', + }, + 'staging-faint-slimy-achird': { + hub: 'staging-legal-crazy-castor', }, - "staging-faint-slimy-achird": { - "hub": "staging-legal-crazy-castor" - } - } + }, }, - "ruby": { - "address": "0xd66641E25E9D36A995682572eaD74E24C11Bb422", - "chains": { - "staging-legal-crazy-castor": {} - } + ruby: { + address: '0xd66641E25E9D36A995682572eaD74E24C11Bb422', + chains: { + 'staging-legal-crazy-castor': {}, + }, }, - "dai": { - "address": "0x83B38f79cFFB47CF74f7eC8a5F8D7DD69349fBf7", - "chains": { - "staging-legal-crazy-castor": {} - } + dai: { + address: '0x83B38f79cFFB47CF74f7eC8a5F8D7DD69349fBf7', + chains: { + 'staging-legal-crazy-castor': {}, + }, }, - "usdp": { - "address": "0x66259E472f8d09083ecB51D42F9F872A61001426", - "chains": { - "staging-legal-crazy-castor": {} - } + usdp: { + address: '0x66259E472f8d09083ecB51D42F9F872A61001426', + chains: { + 'staging-legal-crazy-castor': {}, + }, }, - "usdt": { - "address": "0xD1E44e3afd6d3F155e7704c67705E3bAC2e491b6", - "chains": { - "staging-legal-crazy-castor": {} - } + usdt: { + address: '0xD1E44e3afd6d3F155e7704c67705E3bAC2e491b6', + chains: { + 'staging-legal-crazy-castor': {}, + }, + }, + usdc: { + address: '0x85dedAA65D33210E15911Da5E9dc29F5C93a50A9', + chains: { + 'staging-legal-crazy-castor': {}, + 'staging-utter-unripe-menkar': { + hub: 'staging-legal-crazy-castor', + }, + }, }, - "usdc": { - "address": "0x85dedAA65D33210E15911Da5E9dc29F5C93a50A9", - "chains": { - "staging-legal-crazy-castor": {}, - "staging-utter-unripe-menkar": { - "hub": "staging-legal-crazy-castor" - } - } + wbtc: { + address: '0xd80BC0126A38c9F7b915e1B2B9f78280639cadb3', + chains: { + 'staging-legal-crazy-castor': {}, + }, }, - "wbtc": { - "address": "0xd80BC0126A38c9F7b915e1B2B9f78280639cadb3", - "chains": { - "staging-legal-crazy-castor": {} - } + hmt: { + address: '0x4058d058ff62ED347dB8a69c43Ae9C67268B50b0', + chains: {}, }, - "hmt": { - "address": "0x4058d058ff62ED347dB8a69c43Ae9C67268B50b0", - "chains": {} - } }, - "erc721meta": { - "_SPACE_1": { - "address": "0x1b7729d7E1025A031aF9D6E68598b57f4C2adfF6", - "chains": {} - } + erc721meta: { + _SPACE_1: { + address: '0x1b7729d7E1025A031aF9D6E68598b57f4C2adfF6', + chains: {}, + }, + }, + erc1155: { + _SKALIENS_1: { + address: '0x6cb73D413970ae9379560aA45c769b417Fbf33D6', + chains: {}, + }, }, - "erc1155": { - "_SKALIENS_1": { - "address": "0x6cb73D413970ae9379560aA45c769b417Fbf33D6", - "chains": {} - } - } }, - "staging-utter-unripe-menkar": { // Calypso connections - "erc20": { - "skl": { - "address": "0x7E1B8750C21AebC3bb2a0bDf40be104C609a9852", - "chains": { - "staging-legal-crazy-castor": { - "clone": true + 'staging-utter-unripe-menkar': { + // Calypso connections + erc20: { + skl: { + address: '0x7E1B8750C21AebC3bb2a0bDf40be104C609a9852', + chains: { + 'staging-legal-crazy-castor': { + clone: true, }, - "staging-faint-slimy-achird": { - "hub": "staging-legal-crazy-castor", - "clone": true + 'staging-faint-slimy-achird': { + hub: 'staging-legal-crazy-castor', + clone: true, }, - "mainnet": { - "hub": "staging-legal-crazy-castor", - "clone": true - } - } + mainnet: { + hub: 'staging-legal-crazy-castor', + clone: true, + }, + }, }, - "usdc": { - "address": "0x49c37d0Bb6238933eEe2157e9Df417fd62723fF6", - "chains": { - "staging-legal-crazy-castor": { - "clone": true + usdc: { + address: '0x49c37d0Bb6238933eEe2157e9Df417fd62723fF6', + chains: { + 'staging-legal-crazy-castor': { + clone: true, + }, + mainnet: { + hub: 'staging-legal-crazy-castor', + clone: true, }, - "mainnet": { - "hub": "staging-legal-crazy-castor", - "clone": true - } - } - } - } + }, + }, + }, }, - "staging-faint-slimy-achird": { - "erc20": { - "skl": { - "address": "0x7F73B66d4e6e67bCdeaF277b9962addcDabBFC4d", - "chains": { - "staging-legal-crazy-castor": { - "clone": true + 'staging-faint-slimy-achird': { + erc20: { + skl: { + address: '0x7F73B66d4e6e67bCdeaF277b9962addcDabBFC4d', + chains: { + 'staging-legal-crazy-castor': { + clone: true, + }, + mainnet: { + hub: 'staging-legal-crazy-castor', + clone: true, }, - "mainnet": { - "hub": "staging-legal-crazy-castor", - "clone": true + 'staging-utter-unripe-menkar': { + hub: 'staging-legal-crazy-castor', + clone: true, }, - "staging-utter-unripe-menkar": { - "hub": "staging-legal-crazy-castor", - "clone": true - } - } - } - } + }, + }, + }, }, - "staging-legal-crazy-castor": { // Europa connections - "erc20": { - "skl": { - "address": "0xbA1E9BA7CDd4815Da6a51586bE56e8643d1bEAb6", - "chains": { - "mainnet": { - "clone": true + 'staging-legal-crazy-castor': { + // Europa connections + erc20: { + skl: { + address: '0xbA1E9BA7CDd4815Da6a51586bE56e8643d1bEAb6', + chains: { + mainnet: { + clone: true, + }, + 'staging-utter-unripe-menkar': { + wrapper: '0x6a679eF80aF3fE01A646F858Ca1e26D58b5430B6', }, - "staging-utter-unripe-menkar": { - "wrapper": "0x6a679eF80aF3fE01A646F858Ca1e26D58b5430B6" + 'staging-faint-slimy-achird': { + wrapper: '0x6a679eF80aF3fE01A646F858Ca1e26D58b5430B6', }, - "staging-faint-slimy-achird": { - "wrapper": "0x6a679eF80aF3fE01A646F858Ca1e26D58b5430B6" - } - } + }, }, - "ruby": { - "address": "0xf06De9214B1Db39fFE9db2AebFA74E52f1e46e39", - "chains": { - "mainnet": { - "clone": true - } - } + ruby: { + address: '0xf06De9214B1Db39fFE9db2AebFA74E52f1e46e39', + chains: { + mainnet: { + clone: true, + }, + }, }, - "dai": { - "address": "0x3595E2f313780cb2f23e197B8e297066fd410d30", - "chains": { - "mainnet": { - "clone": true - } - } + dai: { + address: '0x3595E2f313780cb2f23e197B8e297066fd410d30', + chains: { + mainnet: { + clone: true, + }, + }, }, - "usdp": { - "address": "0xe0E2cb3A5d6f94a5bc2D00FAa3e64460A9D241E1", - "chains": { - "mainnet": { - "clone": true - } - } + usdp: { + address: '0xe0E2cb3A5d6f94a5bc2D00FAa3e64460A9D241E1', + chains: { + mainnet: { + clone: true, + }, + }, }, - "usdt": { - "address": "0xa388F9783d8E5B0502548061c3b06bf4300Fc0E1", - "chains": { - "mainnet": { - "clone": true - } - } + usdt: { + address: '0xa388F9783d8E5B0502548061c3b06bf4300Fc0E1', + chains: { + mainnet: { + clone: true, + }, + }, }, - "usdc": { - "address": "0x5d42495D417fcd9ECf42F3EA8a55FcEf44eD9B33", - "chains": { - "mainnet": { - "clone": true + usdc: { + address: '0x5d42495D417fcd9ECf42F3EA8a55FcEf44eD9B33', + chains: { + mainnet: { + clone: true, + }, + 'staging-utter-unripe-menkar': { + wrapper: '0x4f250cCE5b8B39caA96D1144b9A32E1c6a9f97b0', }, - "staging-utter-unripe-menkar": { - "wrapper": "0x4f250cCE5b8B39caA96D1144b9A32E1c6a9f97b0" - } - } + }, }, - "wbtc": { - "address": "0xf5E880E1066DDc90471B9BAE6f183D5344fd289F", - "chains": { - "mainnet": { - "clone": true - } - } - } - } + wbtc: { + address: '0xf5E880E1066DDc90471B9BAE6f183D5344fd289F', + chains: { + mainnet: { + clone: true, + }, + }, + }, + }, }, - "staging-severe-violet-wezen": { - "erc20": {} + 'staging-severe-violet-wezen': { + erc20: {}, }, - "staging-perfect-parallel-gacrux": { - "erc20": {}, - "erc721": {}, - "erc1155": { + 'staging-perfect-parallel-gacrux': { + erc20: {}, + erc721: {}, + erc1155: { // "skaliens": { // "address": "0xBA9fF38A2b22edDfa8e05805bD22C8f20c40546e", // "chains": {} @@ -280,10 +282,10 @@ export const METAPORT_CONFIG: interfaces.MetaportConfig = { // "address": "0xDf87EEF0977148129969b01b329379b17756cdDE", // "chains": {} // } - } - } + }, + }, + }, + theme: { + mode: 'dark', }, - "theme": { - "mode": "dark" - } -} \ No newline at end of file +} diff --git a/src/store/CommunityPoolStore.ts b/src/store/CommunityPoolStore.ts new file mode 100644 index 0000000..3f12bf7 --- /dev/null +++ b/src/store/CommunityPoolStore.ts @@ -0,0 +1,72 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/** + * @file CommunityPoolStore.ts + * @copyright SKALE Labs 2023-Present + */ + +import { create } from 'zustand' +import { MainnetChain, SChain } from '@skalenetwork/ima-js' + +import * as interfaces from '../core/interfaces' +import { getEmptyCommunityPoolData, getCommunityPoolData } from '../core/community_pool' +import MetaportCore from '../core/metaport' +import { MAINNET_CHAIN_NAME } from '../core/constants' + + +interface CommunityPoolState { + cpData: interfaces.CommunityPoolData + setCpData: (cpData: interfaces.CommunityPoolData) => void + loading: string | false + setLoading: (loading: string | false) => void + amount: string + setAmount: (amount: string) => void + updateCPData: (address: string, chainName1: string, chainName2: string, mpc: MetaportCore) => void + chainName: string + mainnet: MainnetChain + sChain: SChain +} + +export const useCPStore = create()((set, get) => ({ + cpData: getEmptyCommunityPoolData(), + setCpData: (cpData: interfaces.CommunityPoolData) => set(() => ({ cpData: cpData })), + loading: false, + setLoading: (loading: string | false) => set(() => ({ loading: loading })), + amount: '', + setAmount: (amount: string) => + set(() => { + return { amount: amount } + }), + + mainnet: null, + sChain: null, + chainName: null, + + updateCPData: async (address: string, chainName1: string, chainName2: string, mpc: MetaportCore) => { + if (chainName2 !== MAINNET_CHAIN_NAME) return + if (!get().mainnet) { + set({ mainnet: mpc.mainnet() }) + } + if (!get().sChain || get().chainName !== chainName1) { + set({ sChain: mpc.schain(chainName1) }) + } + const cpData = await getCommunityPoolData(address, chainName1, chainName2, get().mainnet, get().sChain) + set({ cpData: cpData }) + }, +})) diff --git a/src/store/MetaportState.ts b/src/store/MetaportState.ts index 02aa95d..780458f 100644 --- a/src/store/MetaportState.ts +++ b/src/store/MetaportState.ts @@ -23,7 +23,7 @@ import debug from 'debug' -import { Contract } from 'ethers'; +import { Contract } from 'ethers' import { MainnetChain, SChain } from '@skalenetwork/ima-js' import { create } from 'zustand' @@ -91,7 +91,7 @@ interface MetaportState { setAmountErrorMessage: (amountErrorMessage: string) => void errorMessage: dataclasses.ErrorMessage - setErrorMessage: (amountErrorMessage: dataclasses.ErrorMessage) => void + setErrorMessage: (errorMessage: dataclasses.ErrorMessage) => void actionBtnDisabled: boolean setActionBtnDisabled: (actionBtnDisabled: boolean) => void @@ -195,7 +195,7 @@ export const useMetaportStore = create()((set, get) => ({ tokenId: null, currentStep: 0, transferInProgress: false, - destTokenBalance: null + destTokenBalance: null, }) }, @@ -284,18 +284,13 @@ export const useMetaportStore = create()((set, get) => ({ setToken: async (token: dataclasses.TokenData) => { const provider = get().chainName2 === MAINNET_CHAIN_NAME ? get().mainnetChain.provider : get().sChain2.provider - const destTokenContract = get().mpc.tokenContract( - get().chainName2, - token.keyname, - token.type, - provider - ) + const destTokenContract = get().mpc.tokenContract(get().chainName2, token.keyname, token.type, provider) set({ token: token, stepsMetadata: getStepsMetadata(get().mpc.config, token, get().chainName2), destTokenContract: destTokenContract, destTokenBalance: null, - destChains: Object.keys(token.connections) + destChains: Object.keys(token.connections), }) }, diff --git a/src/store/Store.ts b/src/store/Store.ts index 43b0952..cb63089 100644 --- a/src/store/Store.ts +++ b/src/store/Store.ts @@ -47,6 +47,9 @@ interface CollapseState { expandedTokens: string | false setExpandedTokens: (expanded: string | false) => void + + expandedCP: string | false + setExpandedCP: (expanded: string | false) => void } export const useCollapseStore = create()((set) => ({ @@ -56,6 +59,7 @@ export const useCollapseStore = create()((set) => ({ expandedFrom: expanded, expandedTo: false, expandedTokens: false, + expandedCP: false, })), expandedTo: false, setExpandedTo: (expanded: string | false) => @@ -63,6 +67,7 @@ export const useCollapseStore = create()((set) => ({ expandedTo: expanded, expandedFrom: false, expandedTokens: false, + expandedCP: false, })), expandedTokens: false, setExpandedTokens: (expanded: string | false) => @@ -70,5 +75,14 @@ export const useCollapseStore = create()((set) => ({ expandedTokens: expanded, expandedFrom: false, expandedTo: false, + expandedCP: false, + })), + expandedCP: false, + setExpandedCP: (expanded: string | false) => + set(() => ({ + expandedCP: expanded, + expandedFrom: false, + expandedTo: false, + expandedTokens: false, })), })) diff --git a/src/styles/common.module.scss b/src/styles/cmn.module.scss similarity index 70% rename from src/styles/common.module.scss rename to src/styles/cmn.module.scss index 15dba77..8efd048 100644 --- a/src/styles/common.module.scss +++ b/src/styles/cmn.module.scss @@ -9,16 +9,16 @@ justify-content: end; } -.flexCentered { +.flexc { align-items: center; justify-content: center; } -.flexCenteredVert { +.flexcv { align-items: center; } -.flexGrow { +.flexg { flex-grow: 1; } @@ -27,49 +27,41 @@ flex-wrap: wrap; } -.marg10 { - margin: 10px !important; -} .padd10 { padding: 10px !important; } -.margTop10 { +.mtop10 { margin-top: 10px !important; } -.margTop20 { +.mtop20 { margin-top: 20px !important; } -.margTop40 { - margin-top: 40px !important; -} - - -.margLeft5 { +.mleft5 { margin-left: 5px !important; } -.margLeft10 { +.mleft10 { margin-left: 10px !important; } -.margLeft20 { +.mleft20 { margin-left: 20px !important; } -.margRi20 { +.mri20 { margin-right: 20px !important; } -.margRi10 { +.mri10 { margin-right: 10px !important; } -.margRi5 { +.mri5 { margin-right: 5px !important; } @@ -81,75 +73,39 @@ margin-bottom: -15px !important; } -.marg-top-20 { - margin-top: 20px !important; -} - -.margTop20Pt { +.mtop20Pt { margin-top: 20pt !important; } -.marg-top-30 { - margin-top: 30px !important; -} - -.margBott20 { +.mbott20 { margin-bottom: 20px !important; } -.margBott40 { - margin-bottom: 40px !important; -} - -.margBott15 { - margin-bottom: 15px !important; -} - -.margBott10 { +.mbott10 { margin-bottom: 10px !important; } -.marg-bott-40 { - margin-bottom: 40px !important; -} - -.margBott5 { +.mbott5 { margin-bottom: 5px !important; } -.margTop5 { +.mtop5 { margin-top: 5px !important; } -.noMargTop { - margin-top: 0 !important; -} - -.noMargBott { - margin-bottom: 0 !important; -} - -.noMarg { +.nom { margin: 0 !important; } -.paddTop10 { - padding-top: 10px !important; -} - -.paddTop20 { +.ptop20 { padding-top: 20px !important; } -.paddBott10 { - padding-bottom: 10px !important; -} - -.noPadd { +.nop { padding: 0 !important; } -.capitalize { +.cap { text-transform: capitalize !important; } @@ -176,7 +132,7 @@ } -.uppercase { +.upp { text-transform: uppercase !important; } @@ -201,11 +157,11 @@ } .darkTheme { - .pMain { + .pPrim { color: white !important; } - .pSecondary { + .pSec { color: $sk-secondary-dark !important; } @@ -215,11 +171,11 @@ } .lightTheme { - .pMain { + .pPrim { color: black !important; } - .pSecondary { + .pSec { color: $sk-secondary-light !important; } @@ -232,7 +188,7 @@ width: 100% !important; } -.textCentered { +.pCent { text-align: center; } diff --git a/src/styles/common.module.scss.d.ts b/src/styles/common.module.scss.d.ts deleted file mode 100644 index b3bc836..0000000 --- a/src/styles/common.module.scss.d.ts +++ /dev/null @@ -1,55 +0,0 @@ -import globalClassNames from '../style.d' -declare const classNames: typeof globalClassNames & { - readonly flex: 'flex' - readonly flexRight: 'flexRight' - readonly flexCentered: 'flexCentered' - readonly flexCenteredVert: 'flexCenteredVert' - readonly flexGrow: 'flexGrow' - readonly flexRow: 'flexRow' - readonly marg10: 'marg10' - readonly padd10: 'padd10' - readonly margTop10: 'margTop10' - readonly margTop20: 'margTop20' - readonly margTop40: 'margTop40' - readonly margLeft5: 'margLeft5' - readonly margLeft10: 'margLeft10' - readonly margLeft20: 'margLeft20' - readonly margRi20: 'margRi20' - readonly margRi10: 'margRi10' - readonly margRi5: 'margRi5' - readonly margBottMin10: 'margBottMin10' - readonly margBottMin15: 'margBottMin15' - readonly 'marg-top-20': 'marg-top-20' - readonly margTop20Pt: 'margTop20Pt' - readonly 'marg-top-30': 'marg-top-30' - readonly margBott20: 'margBott20' - readonly margBott40: 'margBott40' - readonly margBott15: 'margBott15' - readonly margBott10: 'margBott10' - readonly 'marg-bott-40': 'marg-bott-40' - readonly margBott5: 'margBott5' - readonly margTop5: 'margTop5' - readonly noMargTop: 'noMargTop' - readonly noMargBott: 'noMargBott' - readonly noMarg: 'noMarg' - readonly paddTop10: 'paddTop10' - readonly paddBott10: 'paddBott10' - readonly noPadd: 'noPadd' - readonly capitalize: 'capitalize' - readonly p: 'p' - readonly p500: 'p500' - readonly p600: 'p600' - readonly uppercase: 'uppercase' - readonly p1: 'p1' - readonly p2: 'p2' - readonly p3: 'p3' - readonly p4: 'p4' - readonly darkTheme: 'darkTheme' - readonly pMain: 'pMain' - readonly pSecondary: 'pSecondary' - readonly pDisabled: 'pDisabled' - readonly lightTheme: 'lightTheme' - readonly fullWidth: 'fullWidth' - readonly textCentered: 'textCentered' -} -export = classNames diff --git a/src/styles/styles.module.scss b/src/styles/styles.module.scss index d47c11b..3c1a742 100644 --- a/src/styles/styles.module.scss +++ b/src/styles/styles.module.scss @@ -15,6 +15,7 @@ } .popper { + margin-left: 20px; max-width: 390px; max-height: calc(100vh - 110pt); padding: 10pt; @@ -115,8 +116,16 @@ button { :global(.MuiAccordion-root) { background-color: transparent !important; + background-image: none !important; } + + // .accordionSm { + // :global(.MuiAccordionSummary-content) { + // margin: 0 !important; + // } + // } + :global(.MuiButton-root) { font-weight: 600 !important; box-shadow: none !important; @@ -136,6 +145,11 @@ button { } } +.widgetContent { + max-height: calc(100vh - 180px); + overflow-y: auto; +} + .imaWidgetBody { border-radius: $sk-border-radius-outter !important; @@ -268,6 +282,10 @@ button { padding: 10px 26px !important; } +.accordionContent { + padding: 0 26px !important; +} + .accordionSummaryTokens { padding-right: 11pt !important; } \ No newline at end of file From a390b5fcfd5fdcf07d11b4217be6a9592ffd8880 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Tue, 22 Aug 2023 17:32:15 +0100 Subject: [PATCH 24/54] Add recharge community pool function --- .../CommunityPool/CommunityPool.tsx | 75 ++++++++++----- src/components/Stepper/SkStepper.tsx | 6 +- src/core/community_pool.ts | 91 +++++++++---------- src/store/CommunityPoolStore.ts | 5 +- 4 files changed, 104 insertions(+), 73 deletions(-) diff --git a/src/components/CommunityPool/CommunityPool.tsx b/src/components/CommunityPool/CommunityPool.tsx index ad43b12..b225e57 100644 --- a/src/components/CommunityPool/CommunityPool.tsx +++ b/src/components/CommunityPool/CommunityPool.tsx @@ -44,7 +44,7 @@ import CheckCircleIcon from '@mui/icons-material/CheckCircle' import ErrorIcon from '@mui/icons-material/Error' import { fromWei } from '../../core/convertation' -import { withdraw } from '../../core/community_pool' +import { withdraw, recharge } from '../../core/community_pool' import { DEFAULT_ERC20_DECIMALS } from '../../core/constants' import { cls } from '../../core/helper' @@ -55,19 +55,8 @@ import { useCPStore } from '../../store/CommunityPoolStore' import { useCollapseStore } from '../../store/Store' import { useMetaportStore } from '../../store/MetaportState' -// import { getChainIcon } from '../ChainsList/helper'; - -export default function CommunityPool(props: { - // communityPoolData: CommunityPoolData - // loading: string | false - // rechargeAmount: string - // setRechargeAmount: (amount: string) => {} - // expanded: string | false - // setExpanded: (expanded: string | false) => {} - // recharge: () => {} - // withdraw: () => {} - // marg: boolean -}) { + +export default function CommunityPool() { const { data: walletClient } = useWalletClient() const { switchNetworkAsync } = useSwitchNetwork() @@ -145,9 +134,31 @@ export default function CommunityPool(props: { ) } + async function rechargeCP() { + await recharge( + mpc, + walletClient, + chainName1, + amount, + address, + switchNetworkAsync, + setLoading, + setErrorMessage, + async () => { + setLoading(false) + setErrorMessage(null) + } + ) + setExpandedCP(false) + } + return (
- + } @@ -161,20 +172,26 @@ export default function CommunityPool(props: { -

- This wallet is used to pay for Ethereum gas fees from your transactions to the Ethereum Mainnet. You may - withdraw funds from your SKALE Gas Wallet at anytime. +

+ This wallet is used to pay for Ethereum gas fees from your transactions to the + Ethereum Mainnet. You may withdraw funds from your SKALE Gas Wallet at anytime.

-

ETH Balance

+

+ ETH Balance +

- +
-

Exit wallet Balance

+

+ Exit wallet Balance +

- +
@@ -189,10 +206,18 @@ export default function CommunityPool(props: { placeholder="0.00" value={amount} onChange={handleAmountChange} - // disabled={transferInProgress} + disabled={!!loading} />
-

+

ETH

@@ -203,7 +228,7 @@ export default function CommunityPool(props: { color="primary" size="medium" className={cls(styles.btnAction, cmn.mtop5)} - //onClick={props.recharge} + onClick={rechargeCP} disabled={ !!loading || !cpData.accountBalance || diff --git a/src/components/Stepper/SkStepper.tsx b/src/components/Stepper/SkStepper.tsx index 77f5cdf..1fa37e8 100644 --- a/src/components/Stepper/SkStepper.tsx +++ b/src/components/Stepper/SkStepper.tsx @@ -15,6 +15,7 @@ import localStyles from './SkStepper.module.scss' import ChainIcon from '../ChainIcon' import { useMetaportStore } from '../../store/MetaportState' +import { useCPStore } from '../../store/CommunityPoolStore' import { Collapse } from '@mui/material' import { SkaleNetwork } from '../../core/interfaces' @@ -43,6 +44,8 @@ export default function SkStepper(props: { skaleNetwork: SkaleNetwork }) { const amount = useMetaportStore((state) => state.amount) + const cpData = useCPStore((state) => state.cpData) + const [emoji, setEmoji] = useState() useEffect(() => { setEmoji(getRandom(SUCCESS_EMOJIS)) @@ -96,7 +99,8 @@ export default function SkStepper(props: { skaleNetwork: SkaleNetwork }) { size="medium" className={cls(styles.btnAction, cmn.mtop5)} onClick={() => execute(address, switchNetworkAsync, walletClient)} - disabled={!!(amountErrorMessage || actionBtnDisabled || loading || amount == '')} + disabled={!!( + amountErrorMessage || actionBtnDisabled || loading || amount == '' || !cpData.exitGasOk)} > {step.btnText} diff --git a/src/core/community_pool.ts b/src/core/community_pool.ts index 809014c..d704855 100644 --- a/src/core/community_pool.ts +++ b/src/core/community_pool.ts @@ -29,7 +29,7 @@ import { WalletClient } from 'viem' import { Chain } from '@wagmi/core' import { CommunityPoolData } from './interfaces' -import { fromWei } from './convertation' +import { fromWei, toWei } from './convertation' import { walletClientToSigner } from './ethers' import { MAINNET_CHAIN_NAME, @@ -38,7 +38,9 @@ import { MINIMUM_RECHARGE_AMOUNT, COMMUNITY_POOL_WITHDRAW_GAS_LIMIT, DEFAULT_ERROR_MSG, + BALANCE_UPDATE_INTERVAL_SECONDS } from './constants' +import { delay } from './helper' import { CHAIN_IDS, isMainnetChainId, getMainnetAbi } from './network' import MetaportCore from './metaport' @@ -149,48 +151,45 @@ export async function withdraw( } } -// async function rechargeCommunityPool() { -// // todo: optimize -// setLoadingCommunityPool('recharge'); -// try { -// log('Recharging community pool...') -// const sChain = initSChain( -// props.config.skaleNetwork, -// chainName1 -// ); -// const mainnetMetamask = await initMainnet1(); -// setChainId(getChainId(props.config.skaleNetwork, MAINNET_CHAIN_NAME)); -// await mainnetMetamask.communityPool.recharge(chainName1, address, { -// address: address, -// value: toWei(rechargeAmount, DEFAULT_ERC20_DECIMALS) -// }); -// setLoadingCommunityPool('activate'); -// let active = false; -// const chainHash = mainnet.web3.utils.soliditySha3(chainName1); -// let counter = 0; -// while (!active) { -// log('Waiting for account activation...'); -// let activeM = await mainnet.communityPool.contract.methods.activeUsers( -// address, -// chainHash -// ).call(); -// let activeS = await sChain.communityLocker.contract.methods.activeUsers( -// address -// ).call(); -// active = activeS && activeM; -// await delay(BALANCE_UPDATE_INTERVAL_SECONDS * 1000); -// counter++; -// if (counter >= 10) break; -// } -// } catch (err) { -// console.error(err); -// const msg = err.message ? err.message : DEFAULT_ERROR_MSG; -// setErrorMessage(new TransactionErrorMessage(msg, errorMessageClosedFallback)); -// } finally { -// await initSchain1(); -// setChainId(getChainId(props.config.skaleNetwork, chainName1)); -// setMainnet(initMainnet(props.config.skaleNetwork, props.config.mainnetEndpoint)); -// await updateCommunityPoolData(); -// setLoadingCommunityPool(false); -// } -// } +export async function recharge( + mpc: MetaportCore, + walletClient: WalletClient, + chainName: string, + amount: string, + address: `0x${string}`, + switchNetwork: (chainId: number | bigint) => Promise, + setLoading: (loading: string | false) => void, + setErrorMessage: (errorMessage: dataclasses.ErrorMessage) => void, + errorMessageClosedFallback: () => void, +) { + setLoading('recharge'); + try { + log(`Recharging community pool: ${chainName}, amount: ${amount}`) + + const sChain = mpc.schain(chainName) + const mainnetMetamask = await connectedMainnetChain(mpc, walletClient, switchNetwork) + await mainnetMetamask.communityPool.recharge(chainName, address, { + address: address, + value: toWei(amount, DEFAULT_ERC20_DECIMALS) + }); + setLoading('activate'); + let active = false; + const chainHash = ethers.id(chainName) + let counter = 0; + while (!active) { + log('Waiting for account activation...'); + let activeM = await mainnetMetamask.communityPool.contract.activeUsers(address, chainHash); + let activeS = await sChain.communityLocker.contract.activeUsers(address); + active = activeS && activeM; + await delay(BALANCE_UPDATE_INTERVAL_SECONDS * 1000); + counter++; + if (counter >= 10) break; + } + } catch (err) { + console.error(err); + const msg = err.message ? err.message : DEFAULT_ERROR_MSG; + setErrorMessage(new dataclasses.TransactionErrorMessage(msg, errorMessageClosedFallback)); + } finally { + setLoading(false); + } +} diff --git a/src/store/CommunityPoolStore.ts b/src/store/CommunityPoolStore.ts index 3f12bf7..1a994ca 100644 --- a/src/store/CommunityPoolStore.ts +++ b/src/store/CommunityPoolStore.ts @@ -67,6 +67,9 @@ export const useCPStore = create()((set, get) => ({ set({ sChain: mpc.schain(chainName1) }) } const cpData = await getCommunityPoolData(address, chainName1, chainName2, get().mainnet, get().sChain) - set({ cpData: cpData }) + set({ + cpData: cpData, + amount: cpData.recommendedRechargeAmount.toString() + }) }, })) From d55550f284d0d805e88181c9d1c1755d2c5433bd Mon Sep 17 00:00:00 2001 From: Dmytro Date: Tue, 22 Aug 2023 20:02:14 +0100 Subject: [PATCH 25/54] Update storybook, update vercel script --- package.json | 14 +++++++------- vercel.json | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 579c0f6..df162fe 100644 --- a/package.json +++ b/package.json @@ -35,13 +35,13 @@ }, "devDependencies": { "@babel/core": "7.22.10", - "@storybook/addon-essentials": "7.2.2", - "@storybook/addon-interactions": "7.2.2", - "@storybook/addon-links": "7.2.2", + "@storybook/addon-essentials": "7.3.2", + "@storybook/addon-interactions": "7.3.2", + "@storybook/addon-links": "7.3.2", "@storybook/addon-styling": "1.3.6", - "@storybook/blocks": "7.2.2", - "@storybook/react": "7.2.2", - "@storybook/react-vite": "7.2.2", + "@storybook/blocks": "7.3.2", + "@storybook/react": "7.3.2", + "@storybook/react-vite": "7.3.2", "@storybook/testing-library": "0.2.0", "@testing-library/react": "14.0.0", "@types/node": "20.4.9", @@ -69,7 +69,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "sass": "^1.65.1", - "storybook": "7.2.2", + "storybook": "7.3.2", "typescript": "5.1.6", "vite": "4.4.9", "vite-plugin-dts": "3.5.1", diff --git a/vercel.json b/vercel.json index 202e3db..cab7b14 100644 --- a/vercel.json +++ b/vercel.json @@ -1,8 +1,8 @@ { "$schema": "https://openapi.vercel.sh/vercel.json", - "buildCommand": "yarn build-storybook", - "devCommand": "yarn storybook", - "installCommand": "bash prepare_meta.sh && yarn install && yarn build", + "buildCommand": "yarn build", + "devCommand": "yarn dev", + "installCommand": "bash prepare_meta.sh && yarn install && yarn build:lib", "framework": null, "outputDirectory": "./storybook-static" } \ No newline at end of file From d7bd049b749e3ff78311459b955ec15bce413f3b Mon Sep 17 00:00:00 2001 From: Dmytro Date: Tue, 22 Aug 2023 20:06:06 +0100 Subject: [PATCH 26/54] Use default token icons --- src/core/metadata.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/core/metadata.ts b/src/core/metadata.ts index 6148c94..af58bf0 100644 --- a/src/core/metadata.ts +++ b/src/core/metadata.ts @@ -30,15 +30,15 @@ import * as STAGING_CHAIN_ICONS from '../meta/staging/icons' import * as LEGACY_CHAIN_ICONS from '../meta/legacy/icons' import * as REGRESSION_CHAIN_ICONS from '../meta/regression/icons' -// import * as icons from '../icons' +import * as icons from '../icons' -const icons = { - eth: { default: '' }, - skl: { - default: - 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHZpZXdCb3g9IjAgMCAzMiAzMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSJub25lIj48Y2lyY2xlIGZpbGw9IiMwMDAiIGN4PSIxNiIgY3k9IjE2IiByPSIxNiIvPjxnIGZpbGw9IiNGRkYiPjxwYXRoIGQ9Ik0yMi41MTQgOC40OTJ2Ljk5MUg5LjgxdjEzLjAzNGgxMi43MDRWMjQuNWwtNy40Mi0uMDU3LTcuNDUtLjA4NS0uMDg2LTguNDQzTDcuNSA3LjVoMTUuMDE0eiIvPjxwYXRoIGQ9Ik0yMy42OTggMTAuOWMxLjEyNi4zMTIgMi4xMDggMS4xOSAyLjQyNSAyLjE4Mi4xNzMuNTk1LjA4Ny42NTEtLjkyNC42NTEtLjc4IDAtMS4yMTItLjE3LTEuNDcyLS41NjYtLjQzMy0uNzA5LTIuMzk3LS43OTQtMi45NzQtLjExNC0uNjM1Ljc2NS4wNTggMS4zMzIgMi4zMSAxLjg0MiAxLjEyNi4yNTUgMi4zMS42OCAyLjYyNy45NjMgMS40NDQgMS4yNzUuODY2IDQuMDgtMS4wMSA0Ljg0NS0xLjI3LjUxLTMuMzUuNTEtNC42MiAwLS44NjYtLjM2OC0xLjg3Ny0xLjY0My0xLjg3Ny0yLjQzNiAwLS41MSAxLjg3Ny0uMzEyIDIuMzY4LjI4MyAxLjA0IDEuMTYyIDMuNDY0Ljk5MiAzLjYzOC0uMjU1LjE0NC0uOTYzLS40MDUtMS4zODgtMi4wNS0xLjU4Ny0yLjY4NS0uMzY4LTMuNjY3LTEuMTktMy42NjctMy4wNiAwLTIuMjEgMi40MjUtMy41MTMgNS4yMjYtMi43NDh6Ii8+PC9nPjwvZz48L3N2Zz4=', - }, -} // TODO: storybook fix +// const icons = { +// eth: { default: '' }, +// skl: { +// default: +// 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHZpZXdCb3g9IjAgMCAzMiAzMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSJub25lIj48Y2lyY2xlIGZpbGw9IiMwMDAiIGN4PSIxNiIgY3k9IjE2IiByPSIxNiIvPjxnIGZpbGw9IiNGRkYiPjxwYXRoIGQ9Ik0yMi41MTQgOC40OTJ2Ljk5MUg5LjgxdjEzLjAzNGgxMi43MDRWMjQuNWwtNy40Mi0uMDU3LTcuNDUtLjA4NS0uMDg2LTguNDQzTDcuNSA3LjVoMTUuMDE0eiIvPjxwYXRoIGQ9Ik0yMy42OTggMTAuOWMxLjEyNi4zMTIgMi4xMDggMS4xOSAyLjQyNSAyLjE4Mi4xNzMuNTk1LjA4Ny42NTEtLjkyNC42NTEtLjc4IDAtMS4yMTItLjE3LTEuNDcyLS41NjYtLjQzMy0uNzA5LTIuMzk3LS43OTQtMi45NzQtLjExNC0uNjM1Ljc2NS4wNTggMS4zMzIgMi4zMSAxLjg0MiAxLjEyNi4yNTUgMi4zMS42OCAyLjYyNy45NjMgMS40NDQgMS4yNzUuODY2IDQuMDgtMS4wMSA0Ljg0NS0xLjI3LjUxLTMuMzUuNTEtNC42MiAwLS44NjYtLjM2OC0xLjg3Ny0xLjY0My0xLjg3Ny0yLjQzNiAwLS41MSAxLjg3Ny0uMzEyIDIuMzY4LjI4MyAxLjA0IDEuMTYyIDMuNDY0Ljk5MiAzLjYzOC0uMjU1LjE0NC0uOTYzLS40MDUtMS4zODgtMi4wNS0xLjU4Ny0yLjY4NS0uMzY4LTMuNjY3LTEuMTktMy42NjctMy4wNiAwLTIuMjEgMi40MjUtMy41MTMgNS4yMjYtMi43NDh6Ii8+PC9nPjwvZz48L3N2Zz4=', +// }, +// } // TODO: storybook fix const CHAIN_ICONS = { mainnet: MAINNET_CHAIN_ICONS, From 78234c8cb782c5063c32f234c302b26767cc4921 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Tue, 22 Aug 2023 20:43:22 +0100 Subject: [PATCH 27/54] Fix community pool logic for hub chains --- .../CommunityPool/CommunityPool.tsx | 27 ++++++++++++++----- src/store/CommunityPoolStore.ts | 7 ++--- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/components/CommunityPool/CommunityPool.tsx b/src/components/CommunityPool/CommunityPool.tsx index b225e57..50d9c72 100644 --- a/src/components/CommunityPool/CommunityPool.tsx +++ b/src/components/CommunityPool/CommunityPool.tsx @@ -69,6 +69,8 @@ export default function CommunityPool() { const chainName1 = useMetaportStore((state) => state.chainName1) const chainName2 = useMetaportStore((state) => state.chainName2) + const token = useMetaportStore((state) => state.token) + const mpc = useMetaportStore((state) => state.mpc) const setErrorMessage = useMetaportStore((state) => state.setErrorMessage) @@ -77,6 +79,12 @@ export default function CommunityPool() { const { address } = useAccount() + let chainName + if (token) { + chainName = chainName1 + if (token.connections[chainName2].hub) chainName = token.connections[chainName2].hub + } + const handleChange = (panel: string) => (_: React.SyntheticEvent, isExpanded: boolean) => { setExpandedCP(isExpanded ? panel : false) } @@ -90,15 +98,19 @@ export default function CommunityPool() { } useEffect(() => { - updateCPData(address, chainName1, chainName2, mpc) + updateCPData(address, chainName, chainName2, mpc) + }, []) + + useEffect(() => { + updateCPData(address, chainName, chainName2, mpc) const intervalId = setInterval(() => { - updateCPData(address, chainName1, chainName2, mpc) + updateCPData(address, chainName, chainName2, mpc) }, 10000) // Fetch users every 10 seconds return () => { clearInterval(intervalId) // Clear interval on component unmount } - }, [chainName1, chainName2, address]) + }, [chainName, chainName2, address]) const text = cpData.exitGasOk ? 'Exit gas wallet OK' : 'Recharge exit gas wallet' const icon = cpData.exitGasOk ? : @@ -121,7 +133,7 @@ export default function CommunityPool() { withdraw( mpc, walletClient, - chainName1, + chainName, cpData.balance, address, switchNetworkAsync, @@ -138,7 +150,7 @@ export default function CommunityPool() { await recharge( mpc, walletClient, - chainName1, + chainName, amount, address, switchNetworkAsync, @@ -235,7 +247,8 @@ export default function CommunityPool() { Number(amount) > Number(accountBalanceEther) || amount === '' || amount === '0' || - !amount + !amount || + !chainName } > {getRechargeBtnText()} @@ -248,7 +261,7 @@ export default function CommunityPool() { size="small" className={cls(styles.btnAction, cmn.mtop5)} onClick={withdrawCP} - disabled={!!loading} + disabled={!!loading || !chainName} > {getWithdrawBtnText()} diff --git a/src/store/CommunityPoolStore.ts b/src/store/CommunityPoolStore.ts index 1a994ca..f36bdf0 100644 --- a/src/store/CommunityPoolStore.ts +++ b/src/store/CommunityPoolStore.ts @@ -59,7 +59,7 @@ export const useCPStore = create()((set, get) => ({ chainName: null, updateCPData: async (address: string, chainName1: string, chainName2: string, mpc: MetaportCore) => { - if (chainName2 !== MAINNET_CHAIN_NAME) return + if (!chainName1 || !chainName2) return if (!get().mainnet) { set({ mainnet: mpc.mainnet() }) } @@ -68,8 +68,9 @@ export const useCPStore = create()((set, get) => ({ } const cpData = await getCommunityPoolData(address, chainName1, chainName2, get().mainnet, get().sChain) set({ + chainName: chainName1, cpData: cpData, - amount: cpData.recommendedRechargeAmount.toString() + amount: cpData.recommendedRechargeAmount ? cpData.recommendedRechargeAmount.toString() : null }) - }, + } })) From f4d687c92acc7172042314764dfcc3bd73abfa31 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Wed, 23 Aug 2023 19:38:37 +0100 Subject: [PATCH 28/54] Add sFUEL station, fix community pool errors --- package.json | 2 +- .../CommunityPool/CommunityPool.tsx | 2 +- .../DestTokenBalance/DestTokenBalance.tsx | 2 +- src/components/SFuelWarning/SFuelWarning.tsx | 230 ++++++++++++++++++ src/components/SFuelWarning/index.ts | 1 + src/components/TokenList/TokenList.tsx | 2 +- src/components/WidgetBody/WidgetBody.tsx | 9 +- src/core/constants.ts | 4 +- src/core/faucet.ts | 64 ++--- src/core/sfuel.ts | 183 ++++++-------- src/store/CommunityPoolStore.ts | 3 +- src/store/SFuelStore.ts | 92 +++++++ 12 files changed, 448 insertions(+), 146 deletions(-) create mode 100644 src/components/SFuelWarning/SFuelWarning.tsx create mode 100644 src/components/SFuelWarning/index.ts create mode 100644 src/store/SFuelStore.ts diff --git a/package.json b/package.json index df162fe..2ad2617 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "@mui/material": "^5.8.1", "@rainbow-me/rainbowkit": "^1.0.8", "@skalenetwork/ima-js": "2.0.0-develop.3", - "@skaleproject/pow-ethers": "0.3.2", + "@skaleproject/pow-ethers": "0.3.3", "coingecko-api-v3": "^0.0.28", "react-jazzicon": "^1.0.4", "viem": "^1.5.3", diff --git a/src/components/CommunityPool/CommunityPool.tsx b/src/components/CommunityPool/CommunityPool.tsx index 50d9c72..c3170ac 100644 --- a/src/components/CommunityPool/CommunityPool.tsx +++ b/src/components/CommunityPool/CommunityPool.tsx @@ -105,7 +105,7 @@ export default function CommunityPool() { updateCPData(address, chainName, chainName2, mpc) const intervalId = setInterval(() => { updateCPData(address, chainName, chainName2, mpc) - }, 10000) // Fetch users every 10 seconds + }, 10000) return () => { clearInterval(intervalId) // Clear interval on component unmount diff --git a/src/components/DestTokenBalance/DestTokenBalance.tsx b/src/components/DestTokenBalance/DestTokenBalance.tsx index 6d46d52..eb7b7e4 100644 --- a/src/components/DestTokenBalance/DestTokenBalance.tsx +++ b/src/components/DestTokenBalance/DestTokenBalance.tsx @@ -15,7 +15,7 @@ export default function DestTokenBalance() { updateDestTokenBalance(address) // Fetch users immediately on component mount const intervalId = setInterval(() => { updateDestTokenBalance(address) - }, 10000) // Fetch users every 10 seconds + }, 10000) return () => { clearInterval(intervalId) // Clear interval on component unmount } diff --git a/src/components/SFuelWarning/SFuelWarning.tsx b/src/components/SFuelWarning/SFuelWarning.tsx new file mode 100644 index 0000000..9652891 --- /dev/null +++ b/src/components/SFuelWarning/SFuelWarning.tsx @@ -0,0 +1,230 @@ + +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/** + * @file SFuelWarning.ts + * @copyright SKALE Labs 2023-Present + */ + +import React, { useEffect } from 'react'; +import debug from 'debug'; + +import { useAccount } from 'wagmi' + +import Button from '@mui/material/Button'; +import LoadingButton from '@mui/lab/LoadingButton'; +import { Collapse } from '@mui/material'; + +import { + MAINNET_CHAIN_NAME, + SFUEL_CHEKCS_INTERVAL, + SFUEL_TEXT, + DEFAULT_FAUCET_URL +} from '../../core/constants'; + + +import { Station, StationData } from '../../core/sfuel'; +import { View } from '../../core/dataclasses/View'; + + +import { useMetaportStore } from '../../store/MetaportState' +import { useSFuelStore } from '../../store/SFuelStore' + +import { cls } from '../../core/helper'; +import cmn from '../../styles/cmn.module.scss' +import styles from '../../styles/styles.module.scss' + +// import CustomStationUrl from '../CustomStationUrl'; + + +debug.enable('*'); +const log = debug('metaport:components:SFuel'); + + +export default function SFuelWarning(props: {}) { + + const mpc = useMetaportStore((state) => state.mpc) + const chainName1 = useMetaportStore((state) => state.chainName1) + const chainName2 = useMetaportStore((state) => state.chainName2) + const token = useMetaportStore((state) => state.token) + + const loading = useSFuelStore((state) => state.loading) + const setLoading = useSFuelStore((state) => state.setLoading) + const mining = useSFuelStore((state) => state.mining) + const setMining = useSFuelStore((state) => state.setMining) + + const fromChainStation = useSFuelStore((state) => state.fromChainStation); + const setFromChainStation = useSFuelStore((state) => state.setFromChainStation); + + const toChainStation = useSFuelStore((state) => state.toChainStation); + const setToChainStation = useSFuelStore((state) => state.setToChainStation); + + const hubChainStation = useSFuelStore((state) => state.hubChainStation); + const setHubChainStation = useSFuelStore((state) => state.setHubChainStation); + + const sFuelStatus = useSFuelStore((state) => state.sFuelStatus); + const setSFuelStatus = useSFuelStore((state) => state.setSFuelStatus); + + const sFuelOk = useSFuelStore((state) => state.sFuelOk); + const setSFuelOk = useSFuelStore((state) => state.setSFuelOk); + + const fromStationData = useSFuelStore((state) => state.fromStationData); + const setFromStationData = useSFuelStore((state) => state.setFromStationData); + + const toStationData = useSFuelStore((state) => state.toStationData); + const setToStationData = useSFuelStore((state) => state.setToStationData); + + const hubStationData = useSFuelStore((state) => state.hubStationData); + const setHubStationData = useSFuelStore((state) => state.setHubStationData); + + const { address } = useAccount() + + let hubChain; + + if (token && token.connections[chainName2].hub) { + hubChain = token.connections[chainName2].hub + } + + useEffect(() => { + if (!chainName1 || !chainName2 || !address) return; + log('Initializing SFuelWarning', chainName1, chainName2, hubChain, address); + createStations() + + }, [chainName1, chainName2, hubChain, address]) + + + useEffect(() => { + if (!fromStationData.ok || (hubChainStation && !hubStationData.ok)) { + setSFuelStatus('error'); + setSFuelOk(false); + } else { + if (!toStationData.ok) { + setSFuelStatus('warning'); + setSFuelOk(false); + } else { + setSFuelStatus('action'); + setSFuelOk(true); + } + } + }, [fromStationData, toStationData, hubStationData]) + + + useEffect(() => { + updateStationsData() + const intervalId = setInterval(() => { + updateStationsData() + }, 10000) + return () => { + clearInterval(intervalId) // Clear interval on component unmount + } + }, [fromChainStation, toChainStation, hubChainStation]) + + function createStations() { + setFromChainStation(new Station(chainName1, mpc)) + setToChainStation(new Station(chainName2, mpc)) + if (hubChain) setHubChainStation(new Station(hubChain, mpc)) + } + + async function updateStationsData() { + if (fromChainStation) setFromStationData(await fromChainStation.getData(address)); + if (toChainStation) setToStationData(await toChainStation.getData(address)); + if (hubChainStation) setHubStationData(await hubChainStation.getData(address)); + setLoading(false) + } + + async function doPoW() { + let fromPowRes; + let toPowRes; + let hubPowRes; + + setMining(true); + + if (fromChainStation && !fromStationData.ok) { + log(`Doing PoW on ${fromChainStation.chainName}`); + fromPowRes = await fromChainStation.doPoW(address); + } + if (toChainStation && !toStationData.ok) { + log(`Doing PoW on ${toChainStation.chainName}`); + toPowRes = await toChainStation.doPoW(address); + } + if (hubChainStation && !hubStationData.ok) { + log(`Doing PoW on ${hubChainStation.chainName}`); + hubPowRes = await hubChainStation.doPoW(address); + } + + if ( + (fromPowRes && !fromPowRes.ok) || + (toPowRes && !toPowRes.ok) || + (hubPowRes && !hubPowRes.ok) + ) { + log('PoW failed!'); + if (fromPowRes) log(chainName1, fromPowRes.message); + if (toPowRes) log(chainName2, toPowRes.message); + if (hubPowRes) log(hubChain, hubPowRes.message); + // window.open(DEFAULT_FAUCET_URL, '_blank'); + } + await updateStationsData(); + setMining(false); + } + + const noEth = (fromStationData && !fromStationData.ok && chainName1 === MAINNET_CHAIN_NAME); + const noEthDest = (toStationData && !toStationData.ok && chainName2 === MAINNET_CHAIN_NAME); + + function getSFuelText() { + if (noEth || (fromStationData && fromStationData.ok && noEthDest)) { + return SFUEL_TEXT['gas'][sFuelStatus]; + } + return SFUEL_TEXT['sfuel'][sFuelStatus]; + } + + return ( +
+

+ ⛽ {getSFuelText()} +

+ { + !noEth && ((fromStationData && !fromStationData.ok) || !noEthDest) ? (
+ {mining ? + Getting sFUEL... + : } +
+ ) : null + } +
+
) +} \ No newline at end of file diff --git a/src/components/SFuelWarning/index.ts b/src/components/SFuelWarning/index.ts new file mode 100644 index 0000000..d96f36f --- /dev/null +++ b/src/components/SFuelWarning/index.ts @@ -0,0 +1 @@ +export { default } from "./SFuelWarning"; \ No newline at end of file diff --git a/src/components/TokenList/TokenList.tsx b/src/components/TokenList/TokenList.tsx index 2350f8c..98db15d 100644 --- a/src/components/TokenList/TokenList.tsx +++ b/src/components/TokenList/TokenList.tsx @@ -46,7 +46,7 @@ export default function TokenList() { updateTokenBalances(address) // Fetch users immediately on component mount const intervalId = setInterval(() => { updateTokenBalances(address) - }, 10000) // Fetch users every 10 seconds + }, 10000) return () => { clearInterval(intervalId) // Clear interval on component unmount diff --git a/src/components/WidgetBody/WidgetBody.tsx b/src/components/WidgetBody/WidgetBody.tsx index 87d7829..1f0d705 100644 --- a/src/components/WidgetBody/WidgetBody.tsx +++ b/src/components/WidgetBody/WidgetBody.tsx @@ -1,6 +1,8 @@ import React, { useEffect } from 'react' import { useCollapseStore } from '../../store/Store' import { useMetaportStore } from '../../store/MetaportState' +import { useSFuelStore } from '../../store/SFuelStore' + import ChainsList from '../ChainsList' import AmountInput from '../AmountInput' @@ -12,6 +14,7 @@ import { TokenBalance } from '../TokenList' import DestTokenBalance from '../DestTokenBalance' import ErrorMessage from '../ErrorMessage' import CommunityPool from '../CommunityPool' +import SFuelWarning from '../SFuelWarning' import cmn from '../../styles/cmn.module.scss' import { cls } from '../../core/helper' @@ -46,6 +49,8 @@ export function WidgetBody(props) { const transferInProgress = useMetaportStore((state) => state.transferInProgress) + const sFuelOk = useSFuelStore((state) => state.sFuelOk); + useEffect(() => { setChainName1(mpc.config.chains ? mpc.config.chains[0] : '') setChainName2(mpc.config.chains ? mpc.config.chains[1] : '') @@ -61,7 +66,7 @@ export function WidgetBody(props) { const showTo = !expandedFrom && !expandedTokens && !errorMessage && !expandedCP const showInput = !expandedFrom && !expandedTo && !errorMessage && !expandedCP const showSwitch = !expandedFrom && !expandedTo && !expandedTokens && !errorMessage && !expandedCP - const showStepper = !expandedFrom && !expandedTo && !expandedTokens && !errorMessage && !expandedCP + const showStepper = !expandedFrom && !expandedTo && !expandedTokens && !errorMessage && !expandedCP && sFuelOk const showCP = !expandedFrom && !expandedTo && !expandedTokens && chainName2 === MAINNET_CHAIN_NAME const showError = !!errorMessage @@ -135,6 +140,8 @@ export function WidgetBody(props) { + + diff --git a/src/core/constants.ts b/src/core/constants.ts index 029739d..9efab24 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -35,7 +35,7 @@ export const UNWRAP_ACTION = 'unwrap' // tslint:disable-next-line export const MAX_APPROVE_AMOUNT = '115792089237316195423570985008687907853269984665640564039457584007913129639935' // (2^256 - 1 ) -export const DEFAULT_MIN_SFUEL_WEI = '21000000000000' +export const DEFAULT_MIN_SFUEL_WEI = 21000000000000n export const DEFAULT_ERC20_DECIMALS = '18' export const DEFAULT_ERROR_MSG = 'Ooops... Something went wrong...' @@ -76,12 +76,10 @@ export const SFUEL_CHEKCS_INTERVAL = 8 export const SFUEL_TEXT = { sfuel: { - action: '', warning: 'You may need sFUEL on the destination chain', error: 'You need sFUEL to perform a transfer', }, gas: { - action: '', warning: 'You may need ETH on the destination chain', error: 'You need ETH to perform a transfer', }, diff --git a/src/core/faucet.ts b/src/core/faucet.ts index 6ad0d9e..d4e681f 100644 --- a/src/core/faucet.ts +++ b/src/core/faucet.ts @@ -21,31 +21,39 @@ * @copyright SKALE Labs 2023-Present */ -// TODO! - -// import { ZERO_ADDRESS, ZERO_FUNCSIG, FAUCET_DATA } from './constants'; - -// function getAddress(chainName: string, skaleNetwork: string) { -// if (!isFaucetAvailable(chainName, skaleNetwork)) return ZERO_ADDRESS; -// const faucet: { [x: string]: { [x: string]: string } } = FAUCET_DATA[skaleNetwork]; -// return faucet[chainName].address; -// } - -// function getFunc(chainName: string, skaleNetwork: string) { -// if (!isFaucetAvailable(chainName, skaleNetwork)) return ZERO_FUNCSIG; -// const faucet: { [x: string]: { [x: string]: string } } = FAUCET_DATA[skaleNetwork]; -// return faucet[chainName].func; -// } - -// export function isFaucetAvailable(chainName: string, skaleNetwork: string) { -// if (!FAUCET_DATA[skaleNetwork]) return false; -// const keys = Object.keys(FAUCET_DATA[skaleNetwork]); -// return keys.includes(chainName); -// } - -// export function getFuncData(web3: Web3, chainName: string, address: string, skaleNetwork: string) { -// const faucetAddress = getAddress(chainName, skaleNetwork); -// const functionSig = getFunc(chainName, skaleNetwork); -// const functionParam = web3.eth.abi.encodeParameter('address', address); -// return { to: faucetAddress, data: functionSig + functionParam.slice(2) }; -// } +import { Provider, AbiCoder } from 'ethers' +import { ZERO_ADDRESS, ZERO_FUNCSIG, FAUCET_DATA } from './constants' + +function getAddress(chainName: string, skaleNetwork: string) { + if (!isFaucetAvailable(chainName, skaleNetwork)) return ZERO_ADDRESS; + const faucet: { [x: string]: { [x: string]: string } } = FAUCET_DATA[skaleNetwork]; + return faucet[chainName].address; +} + +function getFunc(chainName: string, skaleNetwork: string) { + if (!isFaucetAvailable(chainName, skaleNetwork)) return ZERO_FUNCSIG; + const faucet: { [x: string]: { [x: string]: string } } = FAUCET_DATA[skaleNetwork]; + return faucet[chainName].func; +} + +export function isFaucetAvailable(chainName: string, skaleNetwork: string) { + if (!FAUCET_DATA[skaleNetwork]) return false; + const keys = Object.keys(FAUCET_DATA[skaleNetwork]); + return keys.includes(chainName); +} + +export function getFuncData( + provider: Provider, + chainName: string, + address: string, + skaleNetwork: string +) { + const faucetAddress = getAddress(chainName, skaleNetwork); + const functionSig = getFunc(chainName, skaleNetwork); + + const encoder = new AbiCoder() + const functionParam = encoder.encode(['address'], [address]) + + // const functionParam = web3.eth.abi.encodeParameter('address', address); + return { to: faucetAddress, data: functionSig + functionParam.slice(2) }; +} diff --git a/src/core/sfuel.ts b/src/core/sfuel.ts index 6b93762..4ed6e5a 100644 --- a/src/core/sfuel.ts +++ b/src/core/sfuel.ts @@ -21,111 +21,78 @@ * @copyright SKALE Labs 2022-Present */ -// import debug from 'debug'; -// import { AnonymousPoW } from "@skaleproject/pow-ethers"; - -// import { getChainEndpoint, initWeb3 } from '../core/core'; -// import { getFuncData, isFaucetAvailable } from '../core/faucet'; -// import { DEFAULT_MIN_SFUEL_WEI, DEFAULT_FAUCET_URL, MAINNET_CHAIN_NAME } from '../core/constants'; - -// debug.enable('*'); -// const log = debug('metaport:Widget'); - -// function getFaucetUrl(chainsMetadata: object, chainName: string): string { -// if (chainsMetadata && chainsMetadata[chainName]) return chainsMetadata[chainName].faucetUrl; -// return DEFAULT_FAUCET_URL; -// } - -// function getMinSfuelWei(chainName: string, chainsMetadata?: object): string { -// if (chainsMetadata && chainsMetadata[chainName] && chainsMetadata[chainName].minSfuelWei) { -// return chainsMetadata[chainName].minSfuelWei; -// } else { -// return DEFAULT_MIN_SFUEL_WEI; -// } -// } - -// async function getSfuelBalance(web3: any, address: string): Promise { -// //return await provider.getBalance(address); -// // TODO! -// console.log(web3, address); -// return ''; -// } - -// export interface StationData { -// faucetUrl: string; -// minSfuelWei: string; -// balance: string; -// ok: boolean; -// } - -// export interface StationPowRes { -// message: string; -// ok: boolean; -// } - -// export class Station { - -// endpoint: string; -// web3: any; // todo! - -// constructor( -// public chainName: string, -// public skaleNetwork: string, -// public mainnetEndpoint?: string, -// public chainsMetadata?: object -// ) { -// this.chainName = chainName; -// this.skaleNetwork = skaleNetwork; - -// this.endpoint = getChainEndpoint(chainName, mainnetEndpoint, skaleNetwork); - -// this.web3 = initWeb3(this.endpoint); -// this.chainsMetadata = chainsMetadata; -// } - -// async getData(address: string): Promise { -// try { -// const minSfuelWei = getMinSfuelWei(this.chainName, this.chainsMetadata); -// const balance = await getSfuelBalance(this.web3, address); -// return { -// faucetUrl: getFaucetUrl(this.chainsMetadata, this.chainName), -// minSfuelWei, -// balance, -// ok: Number(balance) >= Number(minSfuelWei) -// } -// } catch (e) { -// log(`ERROR: getSFuelData for ${this.chainName} failed!`); -// log(e); -// return { -// faucetUrl: undefined, minSfuelWei: undefined, balance: undefined, ok: undefined -// }; -// } -// } - -// async doPoW(address: string): Promise { -// if (!this.chainName || !isFaucetAvailable(this.chainName, this.skaleNetwork)) { -// log('WARNING: PoW is not available for this chain'); -// if (this.chainName === MAINNET_CHAIN_NAME) { -// return { ok: true, message: 'PoW is not available for Ethereum Mainnet' }; -// } -// return { ok: false, message: 'PoW is not available for this chain' }; -// } -// log('Mining sFUEL for ' + address + ' on ' + this.chainName + '...'); -// try { -// const endpoint = getChainEndpoint(this.chainName, undefined, this.skaleNetwork); -// const web3 = initWeb3(endpoint); -// const anon = new AnonymousPoW({ rpcUrl: endpoint }); -// await (await anon.send(getFuncData( -// web3, -// this.chainName, -// address, -// this.skaleNetwork -// ))).wait(); -// return { ok: true, message: 'PoW finished successfully' } -// } catch (e) { -// log('ERROR: PoW failed!'); -// log(e); -// return { ok: false, message: e.message }; -// } -// } -// } +import debug from 'debug'; +import { Provider } from 'ethers'; +import { AnonymousPoW } from "@skaleproject/pow-ethers"; + +import MetaportCore from './metaport' +import { getFuncData, isFaucetAvailable } from '../core/faucet' +import { MAINNET_CHAIN_NAME, DEFAULT_MIN_SFUEL_WEI } from '../core/constants' + + +debug.enable('*'); +const log = debug('metaport:sfuel'); + + +export interface StationData { + balance: bigint + ok: boolean +} + +export interface StationPowRes { + message: string + ok: boolean +} + +export class Station { + + endpoint: string; + provider: Provider; + + constructor( + public chainName: string, + public mpc: MetaportCore + ) { + this.chainName = chainName + this.mpc = mpc + this.provider = mpc.provider(chainName); + } + + async getData(address: string): Promise { + try { + const balance = await this.provider.getBalance(address); + return { balance, ok: balance >= DEFAULT_MIN_SFUEL_WEI } + } catch (e) { + log(`ERROR: getSFuelData for ${this.chainName} failed!`); + log(e); + return { balance: undefined, ok: undefined }; + } + } + + async doPoW(address: string): Promise { + // return { ok: true, message: 'PoW is not available for Ethereum Mainnet' }; + if (!this.chainName || !isFaucetAvailable(this.chainName, this.mpc.config.skaleNetwork)) { + log('WARNING: PoW is not available for this chain'); + if (this.chainName === MAINNET_CHAIN_NAME) { + return { ok: true, message: 'PoW is not available for Ethereum Mainnet' }; + } + return { ok: false, message: 'PoW is not available for this chain' }; + } + log('Mining sFUEL for ' + address + ' on ' + this.chainName + '...'); + try { + const endpoint = this.mpc.endpoint(this.chainName) + const anon = new AnonymousPoW({ rpcUrl: endpoint }); + await (await anon.send(getFuncData( + this.provider, + this.chainName, + address, + this.mpc.config.skaleNetwork + ))).wait(); + return { ok: true, message: 'PoW finished successfully' } + } catch (e) { + log('ERROR: PoW failed!'); + log(e); + return { ok: false, message: e.message }; + } + } +} diff --git a/src/store/CommunityPoolStore.ts b/src/store/CommunityPoolStore.ts index f36bdf0..bc0754a 100644 --- a/src/store/CommunityPoolStore.ts +++ b/src/store/CommunityPoolStore.ts @@ -27,7 +27,6 @@ import { MainnetChain, SChain } from '@skalenetwork/ima-js' import * as interfaces from '../core/interfaces' import { getEmptyCommunityPoolData, getCommunityPoolData } from '../core/community_pool' import MetaportCore from '../core/metaport' -import { MAINNET_CHAIN_NAME } from '../core/constants' interface CommunityPoolState { @@ -70,7 +69,7 @@ export const useCPStore = create()((set, get) => ({ set({ chainName: chainName1, cpData: cpData, - amount: cpData.recommendedRechargeAmount ? cpData.recommendedRechargeAmount.toString() : null + amount: cpData.recommendedRechargeAmount ? cpData.recommendedRechargeAmount.toString() : '' }) } })) diff --git a/src/store/SFuelStore.ts b/src/store/SFuelStore.ts new file mode 100644 index 0000000..d9a2ce4 --- /dev/null +++ b/src/store/SFuelStore.ts @@ -0,0 +1,92 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/** + * @file SFuelStore.ts + * @copyright SKALE Labs 2023-Present + */ + +import { create } from 'zustand' +import { MainnetChain, SChain } from '@skalenetwork/ima-js' + +import * as interfaces from '../core/interfaces' +import { Station, StationData } from '../core/sfuel' +import MetaportCore from '../core/metaport' + + +interface SFuelState { + loading: boolean + setLoading: (loading: boolean) => void + mining: boolean + setMining: (loading: boolean) => void + + fromChainStation: Station + setFromChainStation: (station: Station) => void + + toChainStation: Station + setToChainStation: (station: Station) => void + + hubChainStation: Station + setHubChainStation: (station: Station) => void + + sFuelStatus: 'action' | 'warning' | 'error'; + setSFuelStatus: (status: 'action' | 'warning' | 'error') => void + + sFuelOk: boolean + setSFuelOk: (loading: boolean) => void + + fromStationData: StationData; + setFromStationData: (data: StationData) => void; + + toStationData: StationData; + setToStationData: (data: StationData) => void; + + hubStationData: StationData; + setHubStationData: (data: StationData) => void; +} + +export const useSFuelStore = create()((set, get) => ({ + loading: true, + setLoading: (loading: boolean) => set(() => ({ loading: loading })), + mining: false, + setMining: (mining: boolean) => set(() => ({ mining: mining })), + + fromChainStation: undefined, + setFromChainStation: (station: Station) => set({ fromChainStation: station }), + + toChainStation: undefined, + setToChainStation: (station: Station) => set({ toChainStation: station }), + + hubChainStation: undefined, + setHubChainStation: (station: Station) => set({ hubChainStation: station }), + + sFuelStatus: 'action', + setSFuelStatus: (status: 'action' | 'warning' | 'error') => set({ sFuelStatus: status }), + + sFuelOk: false, + setSFuelOk: (sFuelOk: boolean) => set(() => ({ sFuelOk: sFuelOk })), + + fromStationData: { ok: false, balance: null }, + setFromStationData: (data: StationData) => set({ fromStationData: data }), + + toStationData: { ok: false, balance: null }, + setToStationData: (data: StationData) => set({ toStationData: data }), + + hubStationData: { ok: false, balance: null }, + setHubStationData: (data: StationData) => set({ hubStationData: data }), +})) From a463b13c289413c65e8ea55976fcec777c5e4d76 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Mon, 28 Aug 2023 17:40:56 +0100 Subject: [PATCH 29/54] PoW sFUEL faucet --- package.json | 1 - src/core/faucet.ts | 38 +++++++++++++++--- src/core/interfaces/index.ts | 2 + src/core/miner.ts | 75 ++++++++++++++++++++++++++++++++++++ src/core/sfuel.ts | 17 +++----- src/metadata/faucet.json | 12 ++++++ 6 files changed, 126 insertions(+), 19 deletions(-) create mode 100644 src/core/miner.ts diff --git a/package.json b/package.json index 2ad2617..c1f9603 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,6 @@ "@mui/material": "^5.8.1", "@rainbow-me/rainbowkit": "^1.0.8", "@skalenetwork/ima-js": "2.0.0-develop.3", - "@skaleproject/pow-ethers": "0.3.3", "coingecko-api-v3": "^0.0.28", "react-jazzicon": "^1.0.4", "viem": "^1.5.3", diff --git a/src/core/faucet.ts b/src/core/faucet.ts index d4e681f..1d7be5b 100644 --- a/src/core/faucet.ts +++ b/src/core/faucet.ts @@ -21,8 +21,13 @@ * @copyright SKALE Labs 2023-Present */ -import { Provider, AbiCoder } from 'ethers' +import { Provider, Wallet, JsonRpcProvider, AbiCoder, TransactionResponse } from 'ethers'; + +import SkalePowMiner from './miner' import { ZERO_ADDRESS, ZERO_FUNCSIG, FAUCET_DATA } from './constants' +import { AddressType, SkaleNetwork } from './interfaces'; +import MetaportCore from './metaport'; + function getAddress(chainName: string, skaleNetwork: string) { if (!isFaucetAvailable(chainName, skaleNetwork)) return ZERO_ADDRESS; @@ -30,30 +35,51 @@ function getAddress(chainName: string, skaleNetwork: string) { return faucet[chainName].address; } + function getFunc(chainName: string, skaleNetwork: string) { if (!isFaucetAvailable(chainName, skaleNetwork)) return ZERO_FUNCSIG; const faucet: { [x: string]: { [x: string]: string } } = FAUCET_DATA[skaleNetwork]; return faucet[chainName].func; } + export function isFaucetAvailable(chainName: string, skaleNetwork: string) { if (!FAUCET_DATA[skaleNetwork]) return false; const keys = Object.keys(FAUCET_DATA[skaleNetwork]); return keys.includes(chainName); } -export function getFuncData( - provider: Provider, + +function getFuncData( chainName: string, address: string, skaleNetwork: string ) { const faucetAddress = getAddress(chainName, skaleNetwork); const functionSig = getFunc(chainName, skaleNetwork); - const encoder = new AbiCoder() const functionParam = encoder.encode(['address'], [address]) - - // const functionParam = web3.eth.abi.encodeParameter('address', address); return { to: faucetAddress, data: functionSig + functionParam.slice(2) }; } + + +export async function getSFuel( + chainName: string, + address: AddressType, + mpc: MetaportCore +): Promise { + const endpoint = mpc.endpoint(chainName) + const miner = new SkalePowMiner() + const provider = new JsonRpcProvider(endpoint); + const wallet = Wallet.createRandom().connect(provider) + let nonce: number = await wallet.getNonce(); + const mineFreeGasResult = await miner.mineGasForTransaction(nonce, 100000, wallet.address); + const { to, data } = getFuncData(chainName, address, mpc.config.skaleNetwork) + return await wallet.sendTransaction({ + from: wallet.address, + to, + data, + nonce, + gasPrice: mineFreeGasResult + }) +} \ No newline at end of file diff --git a/src/core/interfaces/index.ts b/src/core/interfaces/index.ts index bb0ca49..e76f9bb 100644 --- a/src/core/interfaces/index.ts +++ b/src/core/interfaces/index.ts @@ -31,3 +31,5 @@ export * from './CheckRes' export * from './TransactionHistory' export * from './CommunityPoolData' export * from './TokenMetadata' + +export type AddressType = `0x${string}` \ No newline at end of file diff --git a/src/core/miner.ts b/src/core/miner.ts new file mode 100644 index 0000000..e12debd --- /dev/null +++ b/src/core/miner.ts @@ -0,0 +1,75 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/** + * @file miner.ts + * @copyright SKALE Labs 2023-Present + */ + +import BN from "bn.js"; +import { isHexString, getNumber, randomBytes, keccak256, hexlify, toBeHex } from 'ethers' + + +interface Params { + difficulty?: BN; +} + + +export default class SkalePowMiner { + + public difficulty: BN = new BN(1); + + constructor(params?: Params) { + if (params && params.difficulty) this.difficulty = params.difficulty; + } + + public async mineGasForTransaction(nonce: string | number, gas: string | number, from: string, bytes?: string): Promise { + let address = from; + nonce = isHexString(nonce) ? getNumber(nonce) : nonce as number; + gas = isHexString(gas) ? getNumber(gas) : gas as number; + return await this.mineFreeGas(gas as number, address, nonce as number, bytes); + } + + public async mineFreeGas(gasAmount: number, address: string, nonce: number, bytes?: string) { + let nonceHash = new BN((keccak256(toBeHex(nonce, 32))).slice(2), 16); + let addressHash = new BN((keccak256(address) as string).slice(2), 16); + let nonceAddressXOR = nonceHash.xor(addressHash) + let maxNumber = new BN(2).pow(new BN(256)).sub(new BN(1)); + let divConstant = maxNumber.div(this.difficulty); + let candidate: BN; + let _bytes: string; + let iterations = 0 + + while (true) { + const _bt = hexlify(randomBytes(32)) + _bytes = _bt.slice(2); + candidate = new BN(bytes ?? _bytes, 16); + let candidateHash = new BN((keccak256(_bt)).slice(2), 16); + let resultHash = nonceAddressXOR.xor(candidateHash); + let externalGas = divConstant.div(resultHash).toNumber(); + if (externalGas >= gasAmount) { + break; + } + // every 2k iterations, yield to the event loop + if (iterations++ % 2_000 === 0) { + await new Promise((resolve) => setTimeout(resolve, 0)); + } + } + return BigInt(candidate) + } +} \ No newline at end of file diff --git a/src/core/sfuel.ts b/src/core/sfuel.ts index 4ed6e5a..acdee35 100644 --- a/src/core/sfuel.ts +++ b/src/core/sfuel.ts @@ -23,10 +23,10 @@ import debug from 'debug'; import { Provider } from 'ethers'; -import { AnonymousPoW } from "@skaleproject/pow-ethers"; import MetaportCore from './metaport' -import { getFuncData, isFaucetAvailable } from '../core/faucet' +import { AddressType } from './interfaces' +import { isFaucetAvailable, getSFuel } from './faucet' import { MAINNET_CHAIN_NAME, DEFAULT_MIN_SFUEL_WEI } from '../core/constants' @@ -58,7 +58,7 @@ export class Station { this.provider = mpc.provider(chainName); } - async getData(address: string): Promise { + async getData(address: AddressType): Promise { try { const balance = await this.provider.getBalance(address); return { balance, ok: balance >= DEFAULT_MIN_SFUEL_WEI } @@ -69,7 +69,7 @@ export class Station { } } - async doPoW(address: string): Promise { + async doPoW(address: AddressType): Promise { // return { ok: true, message: 'PoW is not available for Ethereum Mainnet' }; if (!this.chainName || !isFaucetAvailable(this.chainName, this.mpc.config.skaleNetwork)) { log('WARNING: PoW is not available for this chain'); @@ -80,14 +80,7 @@ export class Station { } log('Mining sFUEL for ' + address + ' on ' + this.chainName + '...'); try { - const endpoint = this.mpc.endpoint(this.chainName) - const anon = new AnonymousPoW({ rpcUrl: endpoint }); - await (await anon.send(getFuncData( - this.provider, - this.chainName, - address, - this.mpc.config.skaleNetwork - ))).wait(); + await getSFuel(this.chainName, address, this.mpc) return { ok: true, message: 'PoW finished successfully' } } catch (e) { log('ERROR: PoW failed!'); diff --git a/src/metadata/faucet.json b/src/metadata/faucet.json index d40e6e5..8b1163f 100644 --- a/src/metadata/faucet.json +++ b/src/metadata/faucet.json @@ -33,6 +33,18 @@ "staging-severe-violet-wezen": { "address": "0x37412E23bBF1058A7e325A16C01FF654E1D53562", "func": "0x0c11dedd" + }, + "staging-legal-crazy-castor": { + "address": "0x436389289aEAFefD1d7471b7FbEc67539Bde3E34", + "func": "0x6a627842" + }, + "staging-utter-unripe-menkar": { + "address": "0x84b7265Bc964BB69b4275d4Dac4df0FD87556960", + "func": "0x0c11dedd" + }, + "staging-faint-slimy-achird": { + "address": "0xfd56A3456fbAB0fc013213edCc830B9d32403C8B", + "func": "0x0c11dedd" } }, "legacy": null, From 4eb413f874b07bfbbcba982bec85e5dfb10acf12 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Mon, 28 Aug 2023 18:14:29 +0100 Subject: [PATCH 30/54] Remove web3-utils --- src/core/constants.ts | 4 ++-- src/core/fee_calculator.ts | 13 ++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/core/constants.ts b/src/core/constants.ts index 9efab24..bf88ec4 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -76,11 +76,11 @@ export const SFUEL_CHEKCS_INTERVAL = 8 export const SFUEL_TEXT = { sfuel: { - warning: 'You may need sFUEL on the destination chain', + warning: 'You need sFUEL on the destination chain', error: 'You need sFUEL to perform a transfer', }, gas: { - warning: 'You may need ETH on the destination chain', + warning: 'You need ETH on the destination chain', error: 'You need ETH to perform a transfer', }, } diff --git a/src/core/fee_calculator.ts b/src/core/fee_calculator.ts index f8e2f90..a9e5e2a 100644 --- a/src/core/fee_calculator.ts +++ b/src/core/fee_calculator.ts @@ -21,11 +21,10 @@ * @copyright SKALE Labs 2022-Present */ -import { fromWei as _fromWei, toBN } from 'web3-utils' import debug from 'debug' - +import { fromWei } from './convertation' import { CoinGeckoClient } from 'coingecko-api-v3' -import * as interfaces from './interfaces/index' +import { DEFAULT_ERC20_DECIMALS } from './constants' debug.enable('*') const log = debug('metaport:components:fee_calculator') @@ -33,11 +32,11 @@ const log = debug('metaport:components:fee_calculator') export async function getTransactionFee(): Promise { // todo: get actual gas limit for transfer // todo: get actual gas price - const gasLimit = toBN('250000') - const gasPrice = toBN('10000000000') + const gasLimit = 250000n + const gasPrice = 10000000000n - const amountWei = gasLimit.mul(gasPrice) - const amountEth = _fromWei(amountWei) + const amountWei = gasLimit * gasPrice + const amountEth = fromWei(amountWei, DEFAULT_ERC20_DECIMALS) const client = new CoinGeckoClient({ timeout: 10000, From 480fa553758ae5daf9946a23d708e3f62610f96b Mon Sep 17 00:00:00 2001 From: Dmytro Date: Mon, 28 Aug 2023 19:00:57 +0100 Subject: [PATCH 31/54] Optimize miner script, update prettier rules --- .prettierrc | 2 +- package.json | 3 +- src/components/ChainsList/ChainsList.tsx | 24 +- .../CommunityPool/CommunityPool.tsx | 47 ++- .../DestTokenBalance/DestTokenBalance.tsx | 10 +- src/components/ErrorMessage/ErrorMessage.tsx | 4 +- src/components/SFuelWarning/SFuelWarning.tsx | 355 +++++++++--------- src/components/SFuelWarning/index.ts | 2 +- src/components/SkConnect/SkConnect.tsx | 27 +- src/components/Stepper/SkStepper.tsx | 23 +- src/components/TokenList/TokenList.tsx | 2 +- .../TokenListSection/TokenListSection.tsx | 18 +- src/components/WidgetBody/WidgetBody.tsx | 9 +- src/components/WidgetUI/WidgetUI.tsx | 4 +- src/core/actions/action.ts | 4 +- src/core/actions/checks.ts | 6 +- src/core/actions/erc20.ts | 92 ++++- src/core/actions/index.ts | 14 +- src/core/community_pool.ts | 41 +- src/core/constants.ts | 3 +- src/core/dataclasses/StepMetadata.ts | 6 +- src/core/ethers.ts | 5 +- src/core/explorer.ts | 7 +- src/core/faucet.ts | 81 ++-- src/core/helper.ts | 6 +- src/core/interfaces/index.ts | 2 +- src/core/metaport.ts | 20 +- src/core/miner.ts | 83 ++-- src/core/network.ts | 26 +- src/core/sfuel.ts | 91 +++-- src/core/themes.ts | 11 +- src/core/transfer_steps.ts | 10 +- src/core/wagmi_network.ts | 4 +- src/metadata/metaportConfigStaging.ts | 6 +- src/store/CommunityPoolStore.ts | 20 +- src/store/MetaportState.ts | 32 +- src/store/SFuelStore.ts | 15 +- 37 files changed, 680 insertions(+), 435 deletions(-) diff --git a/.prettierrc b/.prettierrc index b13587a..37bf3d9 100644 --- a/.prettierrc +++ b/.prettierrc @@ -2,6 +2,6 @@ "semi": false, "trailingComma": "all", "singleQuote": true, - "printWidth": 120, + "printWidth": 100, "endOfLine": "auto" } \ No newline at end of file diff --git a/package.json b/package.json index c1f9603..8038e38 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,6 @@ "prepack": "json -f package.json -I -e \"delete this.devDependencies; delete this.dependencies\"" }, "devDependencies": { - "@babel/core": "7.22.10", "@storybook/addon-essentials": "7.3.2", "@storybook/addon-interactions": "7.3.2", "@storybook/addon-links": "7.3.2", @@ -51,7 +50,6 @@ "@vitejs/plugin-react": "4.0.4", "@vitest/coverage-v8": "0.34.1", "autoprefixer": "10.4.14", - "babel-loader": "9.1.3", "eslint": "8.46.0", "eslint-config-prettier": "9.0.0", "eslint-config-standard-with-typescript": "37.0.0", @@ -85,6 +83,7 @@ "@mui/material": "^5.8.1", "@rainbow-me/rainbowkit": "^1.0.8", "@skalenetwork/ima-js": "2.0.0-develop.3", + "bn.js": "^5.2.1", "coingecko-api-v3": "^0.0.28", "react-jazzicon": "^1.0.4", "viem": "^1.5.3", diff --git a/src/components/ChainsList/ChainsList.tsx b/src/components/ChainsList/ChainsList.tsx index 7218df9..b284f38 100644 --- a/src/components/ChainsList/ChainsList.tsx +++ b/src/components/ChainsList/ChainsList.tsx @@ -88,13 +88,21 @@ export default function ChainsList(props: { )} -
+
{schainNames.map((name) => ( -
@@ -203,7 +213,12 @@ export default function CommunityPool() {

+ balance={cpData.balance} + symbol="ETH" + truncate={4} + size="sm" + primary + />
@@ -221,15 +236,17 @@ export default function CommunityPool() { disabled={!!loading} />
-

+

ETH

diff --git a/src/components/DestTokenBalance/DestTokenBalance.tsx b/src/components/DestTokenBalance/DestTokenBalance.tsx index eb7b7e4..7fb4684 100644 --- a/src/components/DestTokenBalance/DestTokenBalance.tsx +++ b/src/components/DestTokenBalance/DestTokenBalance.tsx @@ -15,7 +15,7 @@ export default function DestTokenBalance() { updateDestTokenBalance(address) // Fetch users immediately on component mount const intervalId = setInterval(() => { updateDestTokenBalance(address) - }, 10000) + }, 10000) return () => { clearInterval(intervalId) // Clear interval on component unmount } @@ -23,5 +23,11 @@ export default function DestTokenBalance() { if (!token) return - return + return ( + + ) } diff --git a/src/components/ErrorMessage/ErrorMessage.tsx b/src/components/ErrorMessage/ErrorMessage.tsx index 8806ea2..52d34a5 100644 --- a/src/components/ErrorMessage/ErrorMessage.tsx +++ b/src/components/ErrorMessage/ErrorMessage.tsx @@ -23,7 +23,9 @@ export default function Error(props: { errorMessage: ErrorMessage }) { if (!props.errorMessage) return return (
-
{ERROR_ICONS[props.errorMessage.icon]}
+
+ {ERROR_ICONS[props.errorMessage.icon]} +

state.mpc) - const chainName1 = useMetaportStore((state) => state.chainName1) - const chainName2 = useMetaportStore((state) => state.chainName2) - const token = useMetaportStore((state) => state.token) - - const loading = useSFuelStore((state) => state.loading) - const setLoading = useSFuelStore((state) => state.setLoading) - const mining = useSFuelStore((state) => state.mining) - const setMining = useSFuelStore((state) => state.setMining) - - const fromChainStation = useSFuelStore((state) => state.fromChainStation); - const setFromChainStation = useSFuelStore((state) => state.setFromChainStation); - - const toChainStation = useSFuelStore((state) => state.toChainStation); - const setToChainStation = useSFuelStore((state) => state.setToChainStation); - - const hubChainStation = useSFuelStore((state) => state.hubChainStation); - const setHubChainStation = useSFuelStore((state) => state.setHubChainStation); - - const sFuelStatus = useSFuelStore((state) => state.sFuelStatus); - const setSFuelStatus = useSFuelStore((state) => state.setSFuelStatus); - - const sFuelOk = useSFuelStore((state) => state.sFuelOk); - const setSFuelOk = useSFuelStore((state) => state.setSFuelOk); - - const fromStationData = useSFuelStore((state) => state.fromStationData); - const setFromStationData = useSFuelStore((state) => state.setFromStationData); - - const toStationData = useSFuelStore((state) => state.toStationData); - const setToStationData = useSFuelStore((state) => state.setToStationData); - - const hubStationData = useSFuelStore((state) => state.hubStationData); - const setHubStationData = useSFuelStore((state) => state.setHubStationData); - - const { address } = useAccount() - - let hubChain; - - if (token && token.connections[chainName2].hub) { - hubChain = token.connections[chainName2].hub + const mpc = useMetaportStore((state) => state.mpc) + const chainName1 = useMetaportStore((state) => state.chainName1) + const chainName2 = useMetaportStore((state) => state.chainName2) + const token = useMetaportStore((state) => state.token) + + const loading = useSFuelStore((state) => state.loading) + const setLoading = useSFuelStore((state) => state.setLoading) + const mining = useSFuelStore((state) => state.mining) + const setMining = useSFuelStore((state) => state.setMining) + + const fromChainStation = useSFuelStore((state) => state.fromChainStation) + const setFromChainStation = useSFuelStore((state) => state.setFromChainStation) + + const toChainStation = useSFuelStore((state) => state.toChainStation) + const setToChainStation = useSFuelStore((state) => state.setToChainStation) + + const hubChainStation = useSFuelStore((state) => state.hubChainStation) + const setHubChainStation = useSFuelStore((state) => state.setHubChainStation) + + const sFuelStatus = useSFuelStore((state) => state.sFuelStatus) + const setSFuelStatus = useSFuelStore((state) => state.setSFuelStatus) + + const sFuelOk = useSFuelStore((state) => state.sFuelOk) + const setSFuelOk = useSFuelStore((state) => state.setSFuelOk) + + const fromStationData = useSFuelStore((state) => state.fromStationData) + const setFromStationData = useSFuelStore((state) => state.setFromStationData) + + const toStationData = useSFuelStore((state) => state.toStationData) + const setToStationData = useSFuelStore((state) => state.setToStationData) + + const hubStationData = useSFuelStore((state) => state.hubStationData) + const setHubStationData = useSFuelStore((state) => state.setHubStationData) + + const { address } = useAccount() + + let hubChain + + if (token && token.connections[chainName2].hub) { + hubChain = token.connections[chainName2].hub + } + + useEffect(() => { + if (!chainName1 || !chainName2 || !address) return + log('Initializing SFuelWarning', chainName1, chainName2, hubChain, address) + createStations() + }, [chainName1, chainName2, hubChain, address]) + + useEffect(() => { + if (!fromStationData.ok || (hubChainStation && !hubStationData.ok)) { + setSFuelStatus('error') + setSFuelOk(false) + } else { + if (!toStationData.ok) { + setSFuelStatus('warning') + setSFuelOk(false) + } else { + setSFuelStatus('action') + setSFuelOk(true) + } } - - useEffect(() => { - if (!chainName1 || !chainName2 || !address) return; - log('Initializing SFuelWarning', chainName1, chainName2, hubChain, address); - createStations() - - }, [chainName1, chainName2, hubChain, address]) - - - useEffect(() => { - if (!fromStationData.ok || (hubChainStation && !hubStationData.ok)) { - setSFuelStatus('error'); - setSFuelOk(false); - } else { - if (!toStationData.ok) { - setSFuelStatus('warning'); - setSFuelOk(false); - } else { - setSFuelStatus('action'); - setSFuelOk(true); - } - } - }, [fromStationData, toStationData, hubStationData]) - - - useEffect(() => { - updateStationsData() - const intervalId = setInterval(() => { - updateStationsData() - }, 10000) - return () => { - clearInterval(intervalId) // Clear interval on component unmount - } - }, [fromChainStation, toChainStation, hubChainStation]) - - function createStations() { - setFromChainStation(new Station(chainName1, mpc)) - setToChainStation(new Station(chainName2, mpc)) - if (hubChain) setHubChainStation(new Station(hubChain, mpc)) + }, [fromStationData, toStationData, hubStationData]) + + useEffect(() => { + updateStationsData() + const intervalId = setInterval(() => { + updateStationsData() + }, 10000) + return () => { + clearInterval(intervalId) // Clear interval on component unmount } - - async function updateStationsData() { - if (fromChainStation) setFromStationData(await fromChainStation.getData(address)); - if (toChainStation) setToStationData(await toChainStation.getData(address)); - if (hubChainStation) setHubStationData(await hubChainStation.getData(address)); - setLoading(false) + }, [fromChainStation, toChainStation, hubChainStation]) + + function createStations() { + setFromChainStation(new Station(chainName1, mpc)) + setToChainStation(new Station(chainName2, mpc)) + if (hubChain) setHubChainStation(new Station(hubChain, mpc)) + } + + async function updateStationsData() { + if (fromChainStation) setFromStationData(await fromChainStation.getData(address)) + if (toChainStation) setToStationData(await toChainStation.getData(address)) + if (hubChainStation) setHubStationData(await hubChainStation.getData(address)) + setLoading(false) + } + + async function doPoW() { + let fromPowRes + let toPowRes + let hubPowRes + + setMining(true) + + if (fromChainStation && !fromStationData.ok) { + log(`Doing PoW on ${fromChainStation.chainName}`) + fromPowRes = await fromChainStation.doPoW(address) + } + if (toChainStation && !toStationData.ok) { + log(`Doing PoW on ${toChainStation.chainName}`) + toPowRes = await toChainStation.doPoW(address) + } + if (hubChainStation && !hubStationData.ok) { + log(`Doing PoW on ${hubChainStation.chainName}`) + hubPowRes = await hubChainStation.doPoW(address) } - async function doPoW() { - let fromPowRes; - let toPowRes; - let hubPowRes; - - setMining(true); - - if (fromChainStation && !fromStationData.ok) { - log(`Doing PoW on ${fromChainStation.chainName}`); - fromPowRes = await fromChainStation.doPoW(address); - } - if (toChainStation && !toStationData.ok) { - log(`Doing PoW on ${toChainStation.chainName}`); - toPowRes = await toChainStation.doPoW(address); - } - if (hubChainStation && !hubStationData.ok) { - log(`Doing PoW on ${hubChainStation.chainName}`); - hubPowRes = await hubChainStation.doPoW(address); - } - - if ( - (fromPowRes && !fromPowRes.ok) || - (toPowRes && !toPowRes.ok) || - (hubPowRes && !hubPowRes.ok) - ) { - log('PoW failed!'); - if (fromPowRes) log(chainName1, fromPowRes.message); - if (toPowRes) log(chainName2, toPowRes.message); - if (hubPowRes) log(hubChain, hubPowRes.message); - // window.open(DEFAULT_FAUCET_URL, '_blank'); - } - await updateStationsData(); - setMining(false); + if ( + (fromPowRes && !fromPowRes.ok) || + (toPowRes && !toPowRes.ok) || + (hubPowRes && !hubPowRes.ok) + ) { + log('PoW failed!') + if (fromPowRes) log(chainName1, fromPowRes.message) + if (toPowRes) log(chainName2, toPowRes.message) + if (hubPowRes) log(hubChain, hubPowRes.message) + // window.open(DEFAULT_FAUCET_URL, '_blank'); } + await updateStationsData() + setMining(false) + } - const noEth = (fromStationData && !fromStationData.ok && chainName1 === MAINNET_CHAIN_NAME); - const noEthDest = (toStationData && !toStationData.ok && chainName2 === MAINNET_CHAIN_NAME); + const noEth = fromStationData && !fromStationData.ok && chainName1 === MAINNET_CHAIN_NAME + const noEthDest = toStationData && !toStationData.ok && chainName2 === MAINNET_CHAIN_NAME - function getSFuelText() { - if (noEth || (fromStationData && fromStationData.ok && noEthDest)) { - return SFUEL_TEXT['gas'][sFuelStatus]; - } - return SFUEL_TEXT['sfuel'][sFuelStatus]; + function getSFuelText() { + if (noEth || (fromStationData && fromStationData.ok && noEthDest)) { + return SFUEL_TEXT['gas'][sFuelStatus] } - - return ( -

-

- ⛽ {getSFuelText()} -

- { - !noEth && ((fromStationData && !fromStationData.ok) || !noEthDest) ? (
- {mining ? - Getting sFUEL... - : } -
- ) : null - } -
- ) -} \ No newline at end of file + return SFUEL_TEXT['sfuel'][sFuelStatus] + } + + return ( + +
+

+ ⛽ {getSFuelText()} +

+ {!noEth && ((fromStationData && !fromStationData.ok) || !noEthDest) ? ( +
+ {mining ? ( + + Getting sFUEL... + + ) : ( + + )} +
+ ) : null} +
+
+ ) +} diff --git a/src/components/SFuelWarning/index.ts b/src/components/SFuelWarning/index.ts index d96f36f..3512fcb 100644 --- a/src/components/SFuelWarning/index.ts +++ b/src/components/SFuelWarning/index.ts @@ -1 +1 @@ -export { default } from "./SFuelWarning"; \ No newline at end of file +export { default } from './SFuelWarning' diff --git a/src/components/SkConnect/SkConnect.tsx b/src/components/SkConnect/SkConnect.tsx index f7151e8..322cd11 100644 --- a/src/components/SkConnect/SkConnect.tsx +++ b/src/components/SkConnect/SkConnect.tsx @@ -41,12 +41,23 @@ export default function SkConnect() { const transferInProgress = useMetaportStore((state) => state.transferInProgress) return ( - {({ account, chain, openAccountModal, openChainModal, openConnectModal, authenticationStatus, mounted }) => { + {({ + account, + chain, + openAccountModal, + openChainModal, + openConnectModal, + authenticationStatus, + mounted, + }) => { // Note: If your app doesn't use authentication, you // can remove all 'authenticationStatus' checks const ready = mounted && authenticationStatus !== 'loading' const connected = - ready && account && chain && (!authenticationStatus || authenticationStatus === 'authenticated') + ready && + account && + chain && + (!authenticationStatus || authenticationStatus === 'authenticated') return (
-

+

Connect a wallet to use SKALE Metaport

@@ -116,7 +123,17 @@ export default function SkStepper(props: { skaleNetwork: SkaleNetwork }) { {currentStep === stepsMetadata.length && (
-

+

{emoji} Transfer completed

diff --git a/src/components/TokenList/TokenList.tsx b/src/components/TokenList/TokenList.tsx index 98db15d..ff81587 100644 --- a/src/components/TokenList/TokenList.tsx +++ b/src/components/TokenList/TokenList.tsx @@ -46,7 +46,7 @@ export default function TokenList() { updateTokenBalances(address) // Fetch users immediately on component mount const intervalId = setInterval(() => { updateTokenBalances(address) - }, 10000) + }, 10000) return () => { clearInterval(intervalId) // Clear interval on component unmount diff --git a/src/components/TokenListSection/TokenListSection.tsx b/src/components/TokenListSection/TokenListSection.tsx index 5698796..ea2fce3 100644 --- a/src/components/TokenListSection/TokenListSection.tsx +++ b/src/components/TokenListSection/TokenListSection.tsx @@ -44,9 +44,23 @@ export default function TokenListSection(props: { >
- +
-

+

{getTokenName(props.tokens[key])}

diff --git a/src/components/WidgetBody/WidgetBody.tsx b/src/components/WidgetBody/WidgetBody.tsx index 1f0d705..d7e5351 100644 --- a/src/components/WidgetBody/WidgetBody.tsx +++ b/src/components/WidgetBody/WidgetBody.tsx @@ -3,7 +3,6 @@ import { useCollapseStore } from '../../store/Store' import { useMetaportStore } from '../../store/MetaportState' import { useSFuelStore } from '../../store/SFuelStore' - import ChainsList from '../ChainsList' import AmountInput from '../AmountInput' import SkStepper from '../Stepper' @@ -49,7 +48,7 @@ export function WidgetBody(props) { const transferInProgress = useMetaportStore((state) => state.transferInProgress) - const sFuelOk = useSFuelStore((state) => state.sFuelOk); + const sFuelOk = useSFuelStore((state) => state.sFuelOk) useEffect(() => { setChainName1(mpc.config.chains ? mpc.config.chains[0] : '') @@ -66,8 +65,10 @@ export function WidgetBody(props) { const showTo = !expandedFrom && !expandedTokens && !errorMessage && !expandedCP const showInput = !expandedFrom && !expandedTo && !errorMessage && !expandedCP const showSwitch = !expandedFrom && !expandedTo && !expandedTokens && !errorMessage && !expandedCP - const showStepper = !expandedFrom && !expandedTo && !expandedTokens && !errorMessage && !expandedCP && sFuelOk - const showCP = !expandedFrom && !expandedTo && !expandedTokens && chainName2 === MAINNET_CHAIN_NAME + const showStepper = + !expandedFrom && !expandedTo && !expandedTokens && !errorMessage && !expandedCP && sFuelOk + const showCP = + !expandedFrom && !expandedTo && !expandedTokens && chainName2 === MAINNET_CHAIN_NAME const showError = !!errorMessage return ( diff --git a/src/components/WidgetUI/WidgetUI.tsx b/src/components/WidgetUI/WidgetUI.tsx index f96813d..507587e 100644 --- a/src/components/WidgetUI/WidgetUI.tsx +++ b/src/components/WidgetUI/WidgetUI.tsx @@ -96,7 +96,9 @@ export function WidgetUI(props: { config: MetaportConfig }) { className={cls(styles.imaWidgetBody)} style={metaportTheme ? { ...metaportTheme.position, zIndex: metaportTheme.zIndex } : null} > -
{fabTop ? fabButton : null}
+
+ {fabTop ? fabButton : null} +
diff --git a/src/core/actions/action.ts b/src/core/actions/action.ts index 20a43a0..8cfa2f0 100644 --- a/src/core/actions/action.ts +++ b/src/core/actions/action.ts @@ -146,7 +146,9 @@ export class Action { // todo: use wrapper address! const destWrapperAddress = - this.mpc.config.connections[this.chainName2][this.token.type][this.token.keyname].chains[this.chainName1].wrapper + this.mpc.config.connections[this.chainName2][this.token.type][this.token.keyname].chains[ + this.chainName1 + ].wrapper if (this.token.isClone(this.chainName2) && destWrapperAddress) { this.destToken = mpc.tokenContract( chainName2, diff --git a/src/core/actions/checks.ts b/src/core/actions/checks.ts index 0e6a83c..af93a66 100644 --- a/src/core/actions/checks.ts +++ b/src/core/actions/checks.ts @@ -85,7 +85,11 @@ export async function checkERC20Balance( } } -export async function checkSFuelBalance(address: string, amount: string, sChain: SChain): Promise { +export async function checkSFuelBalance( + address: string, + amount: string, + sChain: SChain, +): Promise { const checkRes: interfaces.CheckRes = { res: false } if (!amount || Number(amount) === 0) return checkRes try { diff --git a/src/core/actions/erc20.ts b/src/core/actions/erc20.ts index fc19744..6ee8587 100644 --- a/src/core/actions/erc20.ts +++ b/src/core/actions/erc20.ts @@ -53,9 +53,14 @@ export class TransferERC20S2S extends TransferAction { )) as SChain if (!checkResAllowance.res) { this.updateState('approve') - const approveTx = await sChain.erc20.approve(this.token.keyname, MAX_APPROVE_AMOUNT, sChain.erc20.address, { - address: this.address, - }) + const approveTx = await sChain.erc20.approve( + this.token.keyname, + MAX_APPROVE_AMOUNT, + sChain.erc20.address, + { + address: this.address, + }, + ) const txBlock = await sChain.provider.getBlock(approveTx.blockNumber) this.updateState('approveDone', approveTx.hash, txBlock.timestamp) externalEvents.transactionCompleted(approveTx, txBlock.timestamp, this.chainName1, 'approve') @@ -93,7 +98,12 @@ export class TransferERC20S2S extends TransferAction { } async preAction() { - const checkResBalance = await checkERC20Balance(this.address, this.amount, this.token, this.sourceToken) + const checkResBalance = await checkERC20Balance( + this.address, + this.amount, + this.token, + this.sourceToken, + ) if (!checkResBalance.res) { this.setAmountErrorMessage(checkResBalance.msg) return @@ -149,21 +159,33 @@ export class WrapERC20S extends Action { sChain.erc20.addToken(`wrap_${this.token.keyname}`, wrapperToken) if (!checkResAllowance.res) { this.updateState('approveWrap') - const approveTx = await sChain.erc20.approve(this.token.keyname, MAX_APPROVE_AMOUNT, this.token.address, { - address: this.address, - }) + const approveTx = await sChain.erc20.approve( + this.token.keyname, + MAX_APPROVE_AMOUNT, + this.token.address, + { + address: this.address, + }, + ) const txBlock = await this.sChain1.provider.getBlock(approveTx.blockNumber) this.updateState('approveWrapDone', approveTx.hash, txBlock.timestamp) } this.updateState('wrap') const amountWei = toWei(this.amount, this.token.meta.decimals) - const tx = await sChain.erc20.wrap(`wrap_${this.token.keyname}`, amountWei, { address: this.address }) + const tx = await sChain.erc20.wrap(`wrap_${this.token.keyname}`, amountWei, { + address: this.address, + }) const block = await this.sChain1.provider.getBlock(tx.blockNumber) this.updateState('wrapDone', tx.hash, block.timestamp) } async preAction() { - const checkResBalance = await checkERC20Balance(this.address, this.amount, this.token, this.unwrappedToken) + const checkResBalance = await checkERC20Balance( + this.address, + this.amount, + this.token, + this.unwrappedToken, + ) if (!checkResBalance.res) { this.setAmountErrorMessage(checkResBalance.msg) return @@ -249,7 +271,12 @@ export class UnWrapERC20S extends Action { async preAction() { log('preAction: UnWrapERC20S') const tokenContract = this.sChain1.erc20.tokens[this.token.keyname] - const checkResBalance = await checkERC20Balance(this.address, this.amount, this.token, tokenContract) + const checkResBalance = await checkERC20Balance( + this.address, + this.amount, + this.token, + tokenContract, + ) if (!checkResBalance.res) { this.setAmountErrorMessage(checkResBalance.msg) return @@ -272,7 +299,9 @@ export class TransferERC20M2S extends TransferAction { const mainnet = (await this.getConnectedChain(this.mainnet.provider)) as MainnetChain if (!checkResAllowance.res) { this.updateState('approve') - const approveTx = await mainnet.erc20.approve(this.token.keyname, MAX_APPROVE_AMOUNT, { address: this.address }) + const approveTx = await mainnet.erc20.approve(this.token.keyname, MAX_APPROVE_AMOUNT, { + address: this.address, + }) const txBlock = await mainnet.provider.getBlock(approveTx.blockNumber) this.updateState('approveDone', approveTx.hash, txBlock.timestamp) } @@ -290,11 +319,22 @@ export class TransferERC20M2S extends TransferAction { await this.sChain2.waitERC20BalanceChange(this.destToken, this.address, balanceOnDestination) this.updateState('received') log('TransferERC20M2S:execute - tokens received to destination chain') - externalEvents.transferComplete(tx.hash, this.chainName1, this.chainName2, this.token.keyname, false) + externalEvents.transferComplete( + tx.hash, + this.chainName1, + this.chainName2, + this.token.keyname, + false, + ) } async preAction() { - const checkResBalance = await checkERC20Balance(this.address, this.amount, this.token, this.sourceToken) + const checkResBalance = await checkERC20Balance( + this.address, + this.amount, + this.token, + this.sourceToken, + ) if (!checkResBalance.res) { this.setAmountErrorMessage(checkResBalance.msg) return @@ -318,9 +358,14 @@ export class TransferERC20S2M extends TransferAction { const sChain = (await this.getConnectedChain(this.sChain1.provider)) as SChain if (!checkResAllowance.res) { this.updateState('approve') - const approveTx = await sChain.erc20.approve(this.token.keyname, MAX_APPROVE_AMOUNT, sChain.erc20.address, { - address: this.address, - }) + const approveTx = await sChain.erc20.approve( + this.token.keyname, + MAX_APPROVE_AMOUNT, + sChain.erc20.address, + { + address: this.address, + }, + ) const txBlock = await sChain.provider.getBlock(approveTx.blockNumber) this.updateState('approveDone', approveTx.hash, txBlock.timestamp) externalEvents.transactionCompleted(approveTx, txBlock.timestamp, this.chainName1, 'approve') @@ -337,11 +382,22 @@ export class TransferERC20S2M extends TransferAction { this.mainnet.waitERC20BalanceChange(this.destToken, this.address, balanceOnDestination) this.updateState('received') log('TransferERC20S2M:execute - tokens received to destination chain') - externalEvents.transferComplete(tx.hash, this.chainName1, this.chainName2, this.token.keyname, false) + externalEvents.transferComplete( + tx.hash, + this.chainName1, + this.chainName2, + this.token.keyname, + false, + ) } async preAction() { - const checkResBalance = await checkERC20Balance(this.address, this.amount, this.token, this.sourceToken) + const checkResBalance = await checkERC20Balance( + this.address, + this.amount, + this.token, + this.sourceToken, + ) if (!checkResBalance.res) { this.setAmountErrorMessage(checkResBalance.msg) return diff --git a/src/core/actions/index.ts b/src/core/actions/index.ts index 853fe53..8af3f83 100644 --- a/src/core/actions/index.ts +++ b/src/core/actions/index.ts @@ -23,7 +23,13 @@ import debug from 'debug' -import { TransferERC20S2S, WrapERC20S, UnWrapERC20S, TransferERC20M2S, TransferERC20S2M } from './erc20' +import { + TransferERC20S2S, + WrapERC20S, + UnWrapERC20S, + TransferERC20M2S, + TransferERC20S2M, +} from './erc20' import { Action } from './action' @@ -34,7 +40,11 @@ import { S2S_POSTFIX, M2S_POSTFIX, S2M_POSTFIX } from '../constants' debug.enable('*') const log = debug('metaport:actions') -export function getActionName(chainName1: string, chainName2: string, tokenType: TokenType): string { +export function getActionName( + chainName1: string, + chainName2: string, + tokenType: TokenType, +): string { if (!chainName1 || !chainName2 || !tokenType) return log(`Getting action name: ${chainName1} ${chainName2} ${tokenType}`) let postfix = S2S_POSTFIX diff --git a/src/core/community_pool.ts b/src/core/community_pool.ts index d704855..f3a817d 100644 --- a/src/core/community_pool.ts +++ b/src/core/community_pool.ts @@ -38,7 +38,7 @@ import { MINIMUM_RECHARGE_AMOUNT, COMMUNITY_POOL_WITHDRAW_GAS_LIMIT, DEFAULT_ERROR_MSG, - BALANCE_UPDATE_INTERVAL_SECONDS + BALANCE_UPDATE_INTERVAL_SECONDS, } from './constants' import { delay } from './helper' import { CHAIN_IDS, isMainnetChainId, getMainnetAbi } from './network' @@ -86,7 +86,10 @@ export async function getCommunityPoolData( const chainHash = ethers.id(chainName1) const activeM = await mainnet.communityPool.contract.activeUsers(address, chainHash) - const rraWei = await mainnet.communityPool.contract.getRecommendedRechargeAmount(chainHash, address) + const rraWei = await mainnet.communityPool.contract.getRecommendedRechargeAmount( + chainHash, + address, + ) const rraEther = fromWei(rraWei as string, DEFAULT_ERC20_DECIMALS) let recommendedAmount = parseFloat(rraEther as string) * RECHARGE_MULTIPLIER @@ -162,7 +165,7 @@ export async function recharge( setErrorMessage: (errorMessage: dataclasses.ErrorMessage) => void, errorMessageClosedFallback: () => void, ) { - setLoading('recharge'); + setLoading('recharge') try { log(`Recharging community pool: ${chainName}, amount: ${amount}`) @@ -170,26 +173,26 @@ export async function recharge( const mainnetMetamask = await connectedMainnetChain(mpc, walletClient, switchNetwork) await mainnetMetamask.communityPool.recharge(chainName, address, { address: address, - value: toWei(amount, DEFAULT_ERC20_DECIMALS) - }); - setLoading('activate'); - let active = false; + value: toWei(amount, DEFAULT_ERC20_DECIMALS), + }) + setLoading('activate') + let active = false const chainHash = ethers.id(chainName) - let counter = 0; + let counter = 0 while (!active) { - log('Waiting for account activation...'); - let activeM = await mainnetMetamask.communityPool.contract.activeUsers(address, chainHash); - let activeS = await sChain.communityLocker.contract.activeUsers(address); - active = activeS && activeM; - await delay(BALANCE_UPDATE_INTERVAL_SECONDS * 1000); - counter++; - if (counter >= 10) break; + log('Waiting for account activation...') + let activeM = await mainnetMetamask.communityPool.contract.activeUsers(address, chainHash) + let activeS = await sChain.communityLocker.contract.activeUsers(address) + active = activeS && activeM + await delay(BALANCE_UPDATE_INTERVAL_SECONDS * 1000) + counter++ + if (counter >= 10) break } } catch (err) { - console.error(err); - const msg = err.message ? err.message : DEFAULT_ERROR_MSG; - setErrorMessage(new dataclasses.TransactionErrorMessage(msg, errorMessageClosedFallback)); + console.error(err) + const msg = err.message ? err.message : DEFAULT_ERROR_MSG + setErrorMessage(new dataclasses.TransactionErrorMessage(msg, errorMessageClosedFallback)) } finally { - setLoading(false); + setLoading(false) } } diff --git a/src/core/constants.ts b/src/core/constants.ts index bf88ec4..d77ab4e 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -33,7 +33,8 @@ export const WRAP_ACTION = 'wrap' export const UNWRAP_ACTION = 'unwrap' // tslint:disable-next-line -export const MAX_APPROVE_AMOUNT = '115792089237316195423570985008687907853269984665640564039457584007913129639935' // (2^256 - 1 ) +export const MAX_APPROVE_AMOUNT = + '115792089237316195423570985008687907853269984665640564039457584007913129639935' // (2^256 - 1 ) export const DEFAULT_MIN_SFUEL_WEI = 21000000000000n diff --git a/src/core/dataclasses/StepMetadata.ts b/src/core/dataclasses/StepMetadata.ts index f88e220..380162c 100644 --- a/src/core/dataclasses/StepMetadata.ts +++ b/src/core/dataclasses/StepMetadata.ts @@ -38,7 +38,11 @@ export enum ActionType { unwrap = 'unwrap', } -export function getActionType(chainName1: string, chainName2: string, tokenType: TokenType): ActionType { +export function getActionType( + chainName1: string, + chainName2: string, + tokenType: TokenType, +): ActionType { if (!chainName1 || !chainName2 || !tokenType) return let postfix = S2S_POSTFIX if (isMainnet(chainName1)) { diff --git a/src/core/ethers.ts b/src/core/ethers.ts index cfacbf1..8c2fa91 100644 --- a/src/core/ethers.ts +++ b/src/core/ethers.ts @@ -16,7 +16,10 @@ export function walletClientToSigner(walletClient: WalletClient) { /** Hook to convert a viem Wallet Client to an ethers.js Signer. */ export function useEthersSigner({ chainId }: { chainId?: number } = {}) { const { data: walletClient } = useWalletClient({ chainId }) - return React.useMemo(() => (walletClient ? walletClientToSigner(walletClient) : undefined), [walletClient]) + return React.useMemo( + () => (walletClient ? walletClientToSigner(walletClient) : undefined), + [walletClient], + ) } export function publicClientToProvider(publicClient: PublicClient) { diff --git a/src/core/explorer.ts b/src/core/explorer.ts index 4b48e8b..f51fcb6 100644 --- a/src/core/explorer.ts +++ b/src/core/explorer.ts @@ -21,7 +21,12 @@ * @copyright SKALE Labs 2023-Present */ -import { HTTPS_PREFIX, MAINNET_CHAIN_NAME, MAINNET_EXPLORER_URLS, BASE_EXPLORER_URLS } from './constants' +import { + HTTPS_PREFIX, + MAINNET_CHAIN_NAME, + MAINNET_EXPLORER_URLS, + BASE_EXPLORER_URLS, +} from './constants' import { SkaleNetwork } from './interfaces' function getMainnetExplorerUrl(skaleNetwork: string) { diff --git a/src/core/faucet.ts b/src/core/faucet.ts index 1d7be5b..20468a5 100644 --- a/src/core/faucet.ts +++ b/src/core/faucet.ts @@ -21,65 +21,56 @@ * @copyright SKALE Labs 2023-Present */ -import { Provider, Wallet, JsonRpcProvider, AbiCoder, TransactionResponse } from 'ethers'; +import { Provider, Wallet, JsonRpcProvider, AbiCoder, TransactionResponse } from 'ethers' import SkalePowMiner from './miner' import { ZERO_ADDRESS, ZERO_FUNCSIG, FAUCET_DATA } from './constants' -import { AddressType, SkaleNetwork } from './interfaces'; -import MetaportCore from './metaport'; - +import { AddressType, SkaleNetwork } from './interfaces' +import MetaportCore from './metaport' function getAddress(chainName: string, skaleNetwork: string) { - if (!isFaucetAvailable(chainName, skaleNetwork)) return ZERO_ADDRESS; - const faucet: { [x: string]: { [x: string]: string } } = FAUCET_DATA[skaleNetwork]; - return faucet[chainName].address; + if (!isFaucetAvailable(chainName, skaleNetwork)) return ZERO_ADDRESS + const faucet: { [x: string]: { [x: string]: string } } = FAUCET_DATA[skaleNetwork] + return faucet[chainName].address } - function getFunc(chainName: string, skaleNetwork: string) { - if (!isFaucetAvailable(chainName, skaleNetwork)) return ZERO_FUNCSIG; - const faucet: { [x: string]: { [x: string]: string } } = FAUCET_DATA[skaleNetwork]; - return faucet[chainName].func; + if (!isFaucetAvailable(chainName, skaleNetwork)) return ZERO_FUNCSIG + const faucet: { [x: string]: { [x: string]: string } } = FAUCET_DATA[skaleNetwork] + return faucet[chainName].func } - export function isFaucetAvailable(chainName: string, skaleNetwork: string) { - if (!FAUCET_DATA[skaleNetwork]) return false; - const keys = Object.keys(FAUCET_DATA[skaleNetwork]); - return keys.includes(chainName); + if (!FAUCET_DATA[skaleNetwork]) return false + const keys = Object.keys(FAUCET_DATA[skaleNetwork]) + return keys.includes(chainName) } - -function getFuncData( - chainName: string, - address: string, - skaleNetwork: string -) { - const faucetAddress = getAddress(chainName, skaleNetwork); - const functionSig = getFunc(chainName, skaleNetwork); - const encoder = new AbiCoder() - const functionParam = encoder.encode(['address'], [address]) - return { to: faucetAddress, data: functionSig + functionParam.slice(2) }; +function getFuncData(chainName: string, address: string, skaleNetwork: string) { + const faucetAddress = getAddress(chainName, skaleNetwork) + const functionSig = getFunc(chainName, skaleNetwork) + const encoder = new AbiCoder() + const functionParam = encoder.encode(['address'], [address]) + return { to: faucetAddress, data: functionSig + functionParam.slice(2) } } - export async function getSFuel( - chainName: string, - address: AddressType, - mpc: MetaportCore + chainName: string, + address: AddressType, + mpc: MetaportCore, ): Promise { - const endpoint = mpc.endpoint(chainName) - const miner = new SkalePowMiner() - const provider = new JsonRpcProvider(endpoint); - const wallet = Wallet.createRandom().connect(provider) - let nonce: number = await wallet.getNonce(); - const mineFreeGasResult = await miner.mineGasForTransaction(nonce, 100000, wallet.address); - const { to, data } = getFuncData(chainName, address, mpc.config.skaleNetwork) - return await wallet.sendTransaction({ - from: wallet.address, - to, - data, - nonce, - gasPrice: mineFreeGasResult - }) -} \ No newline at end of file + const endpoint = mpc.endpoint(chainName) + const miner = new SkalePowMiner() + const provider = new JsonRpcProvider(endpoint) + const wallet = Wallet.createRandom().connect(provider) + let nonce: number = await wallet.getNonce() + const mineFreeGasResult = await miner.mineGasForTransaction(nonce, 100000, wallet.address) + const { to, data } = getFuncData(chainName, address, mpc.config.skaleNetwork) + return await wallet.sendTransaction({ + from: wallet.address, + to, + data, + nonce, + gasPrice: mineFreeGasResult, + }) +} diff --git a/src/core/helper.ts b/src/core/helper.ts index ca8499d..0f89f6a 100644 --- a/src/core/helper.ts +++ b/src/core/helper.ts @@ -80,7 +80,11 @@ export function getChainAlias(skaleNetwork: SkaleNetwork, chainName: string, app return 'Ethereum' } if (CHAINS_META[skaleNetwork] && CHAINS_META[skaleNetwork][chainName]) { - if (app && CHAINS_META[skaleNetwork][chainName].apps && CHAINS_META[skaleNetwork][chainName].apps[app]) { + if ( + app && + CHAINS_META[skaleNetwork][chainName].apps && + CHAINS_META[skaleNetwork][chainName].apps[app] + ) { return CHAINS_META[skaleNetwork][chainName].apps[app].alias } return CHAINS_META[skaleNetwork][chainName].alias diff --git a/src/core/interfaces/index.ts b/src/core/interfaces/index.ts index e76f9bb..b8a8543 100644 --- a/src/core/interfaces/index.ts +++ b/src/core/interfaces/index.ts @@ -32,4 +32,4 @@ export * from './TransactionHistory' export * from './CommunityPoolData' export * from './TokenMetadata' -export type AddressType = `0x${string}` \ No newline at end of file +export type AddressType = `0x${string}` diff --git a/src/core/metaport.ts b/src/core/metaport.ts index 8eba3a8..9d1d45d 100644 --- a/src/core/metaport.ts +++ b/src/core/metaport.ts @@ -23,7 +23,13 @@ import { Provider, JsonRpcProvider, Contract } from 'ethers' -import { MetaportConfig, TokenDataTypesMap, Token, TokenContractsMap, TokenBalancesMap } from './interfaces' +import { + MetaportConfig, + TokenDataTypesMap, + Token, + TokenContractsMap, + TokenBalancesMap, +} from './interfaces' import { TokenType, TokenData, CustomAbiTokenType } from './dataclasses' import { getEmptyTokenDataMap } from './tokens/helper' @@ -120,7 +126,10 @@ export default class MetaportCore { return await tokenContract.balanceOf(address) } - async tokenBalances(tokenContracts: TokenContractsMap, address: string): Promise { + async tokenBalances( + tokenContracts: TokenContractsMap, + address: string, + ): Promise { const balances: TokenBalancesMap = {} const tokenKeynames = Object.keys(tokenContracts) for (const tokenKeyname of tokenKeynames) { @@ -159,7 +168,12 @@ export default class MetaportCore { return new Contract(address, abi, provider) } - originAddress(chainName1: string, chainName2: string, tokenKeyname: string, tokenType: TokenType) { + originAddress( + chainName1: string, + chainName2: string, + tokenKeyname: string, + tokenType: TokenType, + ) { let token = this._config.connections[chainName1][tokenType][tokenKeyname] const isClone = token.chains[chainName2].clone if (isClone) { diff --git a/src/core/miner.ts b/src/core/miner.ts index e12debd..52913f5 100644 --- a/src/core/miner.ts +++ b/src/core/miner.ts @@ -21,55 +21,52 @@ * @copyright SKALE Labs 2023-Present */ -import BN from "bn.js"; -import { isHexString, getNumber, randomBytes, keccak256, hexlify, toBeHex } from 'ethers' - +import BN from 'bn.js' +import { isHexString, getNumber, randomBytes, keccak256, hexlify, toBeHex, toBigInt } from 'ethers' interface Params { - difficulty?: BN; + difficulty?: BN } - export default class SkalePowMiner { + public difficulty: BN = new BN(1) - public difficulty: BN = new BN(1); + constructor(params?: Params) { + if (params && params.difficulty) this.difficulty = params.difficulty + } - constructor(params?: Params) { - if (params && params.difficulty) this.difficulty = params.difficulty; - } + public async mineGasForTransaction( + nonce: string | number, + gas: string | number, + from: string, + ): Promise { + let address = from + nonce = isHexString(nonce) ? getNumber(nonce) : (nonce as number) + gas = isHexString(gas) ? getNumber(gas) : (gas as number) + return await this.mineFreeGas(gas as number, address, nonce as number) + } - public async mineGasForTransaction(nonce: string | number, gas: string | number, from: string, bytes?: string): Promise { - let address = from; - nonce = isHexString(nonce) ? getNumber(nonce) : nonce as number; - gas = isHexString(gas) ? getNumber(gas) : gas as number; - return await this.mineFreeGas(gas as number, address, nonce as number, bytes); + public async mineFreeGas(gasAmount: number, address: string, nonce: number): Promise { + let nonceHash = new BN(keccak256(toBeHex(nonce, 32)).slice(2), 16) + let addressHash = new BN((keccak256(address) as string).slice(2), 16) + let nonceAddressXOR = nonceHash.xor(addressHash) + let maxNumber = new BN(2).pow(new BN(256)).sub(new BN(1)) + let divConstant = maxNumber.div(this.difficulty) + let candidate: string + let iterations = 0 + while (true) { + candidate = hexlify(randomBytes(32)) + let candidateHash = new BN(keccak256(candidate).slice(2), 16) + let resultHash = nonceAddressXOR.xor(candidateHash) + let externalGas = divConstant.div(resultHash).toNumber() + if (externalGas >= gasAmount) { + break + } + // every 2k iterations, yield to the event loop + if (iterations++ % 2_000 === 0) { + await new Promise((resolve) => setTimeout(resolve, 0)) + } } - - public async mineFreeGas(gasAmount: number, address: string, nonce: number, bytes?: string) { - let nonceHash = new BN((keccak256(toBeHex(nonce, 32))).slice(2), 16); - let addressHash = new BN((keccak256(address) as string).slice(2), 16); - let nonceAddressXOR = nonceHash.xor(addressHash) - let maxNumber = new BN(2).pow(new BN(256)).sub(new BN(1)); - let divConstant = maxNumber.div(this.difficulty); - let candidate: BN; - let _bytes: string; - let iterations = 0 - - while (true) { - const _bt = hexlify(randomBytes(32)) - _bytes = _bt.slice(2); - candidate = new BN(bytes ?? _bytes, 16); - let candidateHash = new BN((keccak256(_bt)).slice(2), 16); - let resultHash = nonceAddressXOR.xor(candidateHash); - let externalGas = divConstant.div(resultHash).toNumber(); - if (externalGas >= gasAmount) { - break; - } - // every 2k iterations, yield to the event loop - if (iterations++ % 2_000 === 0) { - await new Promise((resolve) => setTimeout(resolve, 0)); - } - } - return BigInt(candidate) - } -} \ No newline at end of file + return toBigInt(candidate) + } +} diff --git a/src/core/network.ts b/src/core/network.ts index 3f07564..40aaba5 100644 --- a/src/core/network.ts +++ b/src/core/network.ts @@ -47,13 +47,27 @@ export function isMainnetChainId(chainId: number | BigInt, skaleNetwork: SkaleNe return Number(chainId) === CHAIN_IDS[skaleNetwork] } -export function getChainEndpoint(mainnetEndpoint: string, network: SkaleNetwork, chainName: string): string { +export function getChainEndpoint( + mainnetEndpoint: string, + network: SkaleNetwork, + chainName: string, +): string { if (chainName === MAINNET_CHAIN_NAME) return mainnetEndpoint return getSChainEndpoint(network, chainName) } -export function getSChainEndpoint(network: SkaleNetwork, sChainName: string, protocol: 'http' | 'ws' = 'http'): string { - return PROTOCOL[protocol] + getProxyEndpoint(network) + '/v1/' + (protocol === 'ws' ? 'ws/' : '') + sChainName +export function getSChainEndpoint( + network: SkaleNetwork, + sChainName: string, + protocol: 'http' | 'ws' = 'http', +): string { + return ( + PROTOCOL[protocol] + + getProxyEndpoint(network) + + '/v1/' + + (protocol === 'ws' ? 'ws/' : '') + + sChainName + ) } function getProxyEndpoint(network: SkaleNetwork) { @@ -73,7 +87,11 @@ export function getMainnetAbi(network: string) { return { ...IMA_ABIS.mainnet, ...IMA_ADDRESSES.mainnet } } -export function initIMA(mainnetEndpoint: string, network: SkaleNetwork, chainName: string): MainnetChain | SChain { +export function initIMA( + mainnetEndpoint: string, + network: SkaleNetwork, + chainName: string, +): MainnetChain | SChain { if (chainName === MAINNET_CHAIN_NAME) return initMainnet(mainnetEndpoint, network) return initSChain(network, chainName) } diff --git a/src/core/sfuel.ts b/src/core/sfuel.ts index acdee35..965fb23 100644 --- a/src/core/sfuel.ts +++ b/src/core/sfuel.ts @@ -21,71 +21,68 @@ * @copyright SKALE Labs 2022-Present */ -import debug from 'debug'; -import { Provider } from 'ethers'; +import debug from 'debug' +import { Provider } from 'ethers' import MetaportCore from './metaport' import { AddressType } from './interfaces' import { isFaucetAvailable, getSFuel } from './faucet' import { MAINNET_CHAIN_NAME, DEFAULT_MIN_SFUEL_WEI } from '../core/constants' - -debug.enable('*'); -const log = debug('metaport:sfuel'); - +debug.enable('*') +const log = debug('metaport:sfuel') export interface StationData { - balance: bigint - ok: boolean + balance: bigint + ok: boolean } export interface StationPowRes { - message: string - ok: boolean + message: string + ok: boolean } export class Station { + endpoint: string + provider: Provider - endpoint: string; - provider: Provider; + constructor( + public chainName: string, + public mpc: MetaportCore, + ) { + this.chainName = chainName + this.mpc = mpc + this.provider = mpc.provider(chainName) + } - constructor( - public chainName: string, - public mpc: MetaportCore - ) { - this.chainName = chainName - this.mpc = mpc - this.provider = mpc.provider(chainName); + async getData(address: AddressType): Promise { + try { + const balance = await this.provider.getBalance(address) + return { balance, ok: balance >= DEFAULT_MIN_SFUEL_WEI } + } catch (e) { + log(`ERROR: getSFuelData for ${this.chainName} failed!`) + log(e) + return { balance: undefined, ok: undefined } } + } - async getData(address: AddressType): Promise { - try { - const balance = await this.provider.getBalance(address); - return { balance, ok: balance >= DEFAULT_MIN_SFUEL_WEI } - } catch (e) { - log(`ERROR: getSFuelData for ${this.chainName} failed!`); - log(e); - return { balance: undefined, ok: undefined }; - } + async doPoW(address: AddressType): Promise { + // return { ok: true, message: 'PoW is not available for Ethereum Mainnet' }; + if (!this.chainName || !isFaucetAvailable(this.chainName, this.mpc.config.skaleNetwork)) { + log('WARNING: PoW is not available for this chain') + if (this.chainName === MAINNET_CHAIN_NAME) { + return { ok: true, message: 'PoW is not available for Ethereum Mainnet' } + } + return { ok: false, message: 'PoW is not available for this chain' } } - - async doPoW(address: AddressType): Promise { - // return { ok: true, message: 'PoW is not available for Ethereum Mainnet' }; - if (!this.chainName || !isFaucetAvailable(this.chainName, this.mpc.config.skaleNetwork)) { - log('WARNING: PoW is not available for this chain'); - if (this.chainName === MAINNET_CHAIN_NAME) { - return { ok: true, message: 'PoW is not available for Ethereum Mainnet' }; - } - return { ok: false, message: 'PoW is not available for this chain' }; - } - log('Mining sFUEL for ' + address + ' on ' + this.chainName + '...'); - try { - await getSFuel(this.chainName, address, this.mpc) - return { ok: true, message: 'PoW finished successfully' } - } catch (e) { - log('ERROR: PoW failed!'); - log(e); - return { ok: false, message: e.message }; - } + log('Mining sFUEL for ' + address + ' on ' + this.chainName + '...') + try { + await getSFuel(this.chainName, address, this.mpc) + return { ok: true, message: 'PoW finished successfully' } + } catch (e) { + log('ERROR: PoW failed!') + log(e) + return { ok: false, message: e.message } } + } } diff --git a/src/core/themes.ts b/src/core/themes.ts index da8fdf8..3f2603a 100644 --- a/src/core/themes.ts +++ b/src/core/themes.ts @@ -43,7 +43,16 @@ const defaultThemes = { } // warning: order is important here -const MUI_ELEMENTS = ['mobileStepper', 'fab', 'speedDial', 'appBar', 'drawer', 'modal', 'snackbar', 'tooltip'] +const MUI_ELEMENTS = [ + 'mobileStepper', + 'fab', + 'speedDial', + 'appBar', + 'drawer', + 'modal', + 'snackbar', + 'tooltip', +] const INDEX_STEP = 50 diff --git a/src/core/transfer_steps.ts b/src/core/transfer_steps.ts index 757888d..2ec2049 100644 --- a/src/core/transfer_steps.ts +++ b/src/core/transfer_steps.ts @@ -39,7 +39,11 @@ import { MAINNET_CHAIN_NAME } from './constants' debug.enable('*') const log = debug('metaport:core:transferSteps') -export function getStepsMetadata(config: MetaportConfig, token: TokenData, to: string): StepMetadata[] { +export function getStepsMetadata( + config: MetaportConfig, + token: TokenData, + to: string, +): StepMetadata[] { const steps: StepMetadata[] = [] if (token === undefined || token === null || to === null || to === '') return steps @@ -53,7 +57,9 @@ export function getStepsMetadata(config: MetaportConfig, token: TokenData, to: s if (token.connections[toChain].wrapper) { steps.push(new WrapStepMetadata(token.chain, to)) } - steps.push(new TransferStepMetadata(getActionType(token.chain, toChain, token.type), token.chain, toChain)) + steps.push( + new TransferStepMetadata(getActionType(token.chain, toChain, token.type), token.chain, toChain), + ) if (hubTokenOptions.wrapper && !isCloneToClone) { steps.push(new UnwrapStepMetadata(token.chain, toChain)) } diff --git a/src/core/wagmi_network.ts b/src/core/wagmi_network.ts index 9bf72b9..2491124 100644 --- a/src/core/wagmi_network.ts +++ b/src/core/wagmi_network.ts @@ -59,5 +59,7 @@ export function constructWagmiChain(network: SkaleNetwork, chainName: string): C export function getWebSocketUrl(chain: Chain): string { // return chain.rpcUrls.default.webSocket ? chain.rpcUrls.default.webSocket[0] : ''; - return chain.rpcUrls.default.webSocket ? chain.rpcUrls.default.webSocket[0] : 'wss://goerli-light.eth.linkpool.io/ws' // TODO - IP! + return chain.rpcUrls.default.webSocket + ? chain.rpcUrls.default.webSocket[0] + : 'wss://goerli-light.eth.linkpool.io/ws' // TODO - IP! } diff --git a/src/metadata/metaportConfigStaging.ts b/src/metadata/metaportConfigStaging.ts index 3c42430..7e43ae6 100644 --- a/src/metadata/metaportConfigStaging.ts +++ b/src/metadata/metaportConfigStaging.ts @@ -41,12 +41,14 @@ export const METAPORT_CONFIG: interfaces.MetaportConfig = { _SPACE_1: { name: 'SKALE Space', symbol: 'SPACE', - iconUrl: 'https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Rocket/3D/rocket_3d.png', + iconUrl: + 'https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Rocket/3D/rocket_3d.png', }, _SKALIENS_1: { name: 'SKALIENS Collection', symbol: 'SKALIENS', - iconUrl: 'https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Alien/3D/alien_3d.png', + iconUrl: + 'https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Alien/3D/alien_3d.png', }, ruby: { name: 'Ruby Token', diff --git a/src/store/CommunityPoolStore.ts b/src/store/CommunityPoolStore.ts index bc0754a..18d219d 100644 --- a/src/store/CommunityPoolStore.ts +++ b/src/store/CommunityPoolStore.ts @@ -28,7 +28,6 @@ import * as interfaces from '../core/interfaces' import { getEmptyCommunityPoolData, getCommunityPoolData } from '../core/community_pool' import MetaportCore from '../core/metaport' - interface CommunityPoolState { cpData: interfaces.CommunityPoolData setCpData: (cpData: interfaces.CommunityPoolData) => void @@ -57,7 +56,12 @@ export const useCPStore = create()((set, get) => ({ sChain: null, chainName: null, - updateCPData: async (address: string, chainName1: string, chainName2: string, mpc: MetaportCore) => { + updateCPData: async ( + address: string, + chainName1: string, + chainName2: string, + mpc: MetaportCore, + ) => { if (!chainName1 || !chainName2) return if (!get().mainnet) { set({ mainnet: mpc.mainnet() }) @@ -65,11 +69,17 @@ export const useCPStore = create()((set, get) => ({ if (!get().sChain || get().chainName !== chainName1) { set({ sChain: mpc.schain(chainName1) }) } - const cpData = await getCommunityPoolData(address, chainName1, chainName2, get().mainnet, get().sChain) + const cpData = await getCommunityPoolData( + address, + chainName1, + chainName2, + get().mainnet, + get().sChain, + ) set({ chainName: chainName1, cpData: cpData, - amount: cpData.recommendedRechargeAmount ? cpData.recommendedRechargeAmount.toString() : '' + amount: cpData.recommendedRechargeAmount ? cpData.recommendedRechargeAmount.toString() : '', }) - } + }, })) diff --git a/src/store/MetaportState.ts b/src/store/MetaportState.ts index 780458f..afba2f8 100644 --- a/src/store/MetaportState.ts +++ b/src/store/MetaportState.ts @@ -57,7 +57,11 @@ interface MetaportState { tokenId: number setTokenId: (tokenId: number) => void - execute: (address: string, switchNetwork: (chainId: number) => void, walletClient: WalletClient) => void + execute: ( + address: string, + switchNetwork: (chainId: number) => void, + walletClient: WalletClient, + ) => void check: (amount: string, address: `0x${string}`) => void currentStep: number @@ -166,7 +170,10 @@ export const useMetaportStore = create()((set, get) => ({ console.error(err) const msg = err.message ? err.message : DEFAULT_ERROR_MSG set({ - errorMessage: new dataclasses.TransactionErrorMessage(msg, get().errorMessageClosedFallback), + errorMessage: new dataclasses.TransactionErrorMessage( + msg, + get().errorMessageClosedFallback, + ), }) return } finally { @@ -245,9 +252,16 @@ export const useMetaportStore = create()((set, get) => ({ } else { updState['sChain1'] = state.mpc.schain(name) } - const provider = updState['mainnetChain'] ? updState['mainnetChain'].provider : updState['sChain1'].provider + const provider = updState['mainnetChain'] + ? updState['mainnetChain'].provider + : updState['sChain1'].provider const tokens = state.mpc.tokens(name) - const tokenContracts = state.mpc.tokenContracts(tokens, dataclasses.TokenType.erc20, name, provider) + const tokenContracts = state.mpc.tokenContracts( + tokens, + dataclasses.TokenType.erc20, + name, + provider, + ) return { currentStep: 0, token: null, @@ -283,8 +297,14 @@ export const useMetaportStore = create()((set, get) => ({ token: null, setToken: async (token: dataclasses.TokenData) => { - const provider = get().chainName2 === MAINNET_CHAIN_NAME ? get().mainnetChain.provider : get().sChain2.provider - const destTokenContract = get().mpc.tokenContract(get().chainName2, token.keyname, token.type, provider) + const provider = + get().chainName2 === MAINNET_CHAIN_NAME ? get().mainnetChain.provider : get().sChain2.provider + const destTokenContract = get().mpc.tokenContract( + get().chainName2, + token.keyname, + token.type, + provider, + ) set({ token: token, stepsMetadata: getStepsMetadata(get().mpc.config, token, get().chainName2), diff --git a/src/store/SFuelStore.ts b/src/store/SFuelStore.ts index d9a2ce4..9938ca5 100644 --- a/src/store/SFuelStore.ts +++ b/src/store/SFuelStore.ts @@ -28,7 +28,6 @@ import * as interfaces from '../core/interfaces' import { Station, StationData } from '../core/sfuel' import MetaportCore from '../core/metaport' - interface SFuelState { loading: boolean setLoading: (loading: boolean) => void @@ -44,20 +43,20 @@ interface SFuelState { hubChainStation: Station setHubChainStation: (station: Station) => void - sFuelStatus: 'action' | 'warning' | 'error'; + sFuelStatus: 'action' | 'warning' | 'error' setSFuelStatus: (status: 'action' | 'warning' | 'error') => void sFuelOk: boolean setSFuelOk: (loading: boolean) => void - fromStationData: StationData; - setFromStationData: (data: StationData) => void; + fromStationData: StationData + setFromStationData: (data: StationData) => void - toStationData: StationData; - setToStationData: (data: StationData) => void; + toStationData: StationData + setToStationData: (data: StationData) => void - hubStationData: StationData; - setHubStationData: (data: StationData) => void; + hubStationData: StationData + setHubStationData: (data: StationData) => void } export const useSFuelStore = create()((set, get) => ({ From 6a9889fea416d19a24c7d0add51d65e354a5d3a4 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Mon, 28 Aug 2023 19:55:33 +0100 Subject: [PATCH 32/54] Drop bn.js requirement --- package.json | 1 - src/core/community_pool.ts | 2 +- src/core/constants.ts | 2 ++ src/core/miner.ts | 21 ++++++++++----------- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 8038e38..01296b6 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,6 @@ "@mui/material": "^5.8.1", "@rainbow-me/rainbowkit": "^1.0.8", "@skalenetwork/ima-js": "2.0.0-develop.3", - "bn.js": "^5.2.1", "coingecko-api-v3": "^0.0.28", "react-jazzicon": "^1.0.4", "viem": "^1.5.3", diff --git a/src/core/community_pool.ts b/src/core/community_pool.ts index f3a817d..4345cef 100644 --- a/src/core/community_pool.ts +++ b/src/core/community_pool.ts @@ -68,7 +68,7 @@ export async function getCommunityPoolData( sChain: SChain, ): Promise { if (chainName2 !== MAINNET_CHAIN_NAME) { - log('not a S2M transfer, skipping community pool check') + // log('not a S2M transfer, skipping community pool check') return { exitGasOk: true, isActive: null, diff --git a/src/core/constants.ts b/src/core/constants.ts index d77ab4e..635a367 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -32,6 +32,8 @@ export const S2S_POSTFIX = 's2s' export const WRAP_ACTION = 'wrap' export const UNWRAP_ACTION = 'unwrap' +export const MAX_NUMBER = 2n ** 256n - 1n + // tslint:disable-next-line export const MAX_APPROVE_AMOUNT = '115792089237316195423570985008687907853269984665640564039457584007913129639935' // (2^256 - 1 ) diff --git a/src/core/miner.ts b/src/core/miner.ts index 52913f5..e426ddf 100644 --- a/src/core/miner.ts +++ b/src/core/miner.ts @@ -21,15 +21,15 @@ * @copyright SKALE Labs 2023-Present */ -import BN from 'bn.js' import { isHexString, getNumber, randomBytes, keccak256, hexlify, toBeHex, toBigInt } from 'ethers' +import { MAX_NUMBER } from './constants' interface Params { - difficulty?: BN + difficulty?: bigint } export default class SkalePowMiner { - public difficulty: BN = new BN(1) + public difficulty: bigint = 1n constructor(params?: Params) { if (params && params.difficulty) this.difficulty = params.difficulty @@ -47,18 +47,17 @@ export default class SkalePowMiner { } public async mineFreeGas(gasAmount: number, address: string, nonce: number): Promise { - let nonceHash = new BN(keccak256(toBeHex(nonce, 32)).slice(2), 16) - let addressHash = new BN((keccak256(address) as string).slice(2), 16) - let nonceAddressXOR = nonceHash.xor(addressHash) - let maxNumber = new BN(2).pow(new BN(256)).sub(new BN(1)) - let divConstant = maxNumber.div(this.difficulty) + let nonceHash = toBigInt(keccak256(toBeHex(nonce, 32))) + let addressHash = toBigInt(keccak256(address)) + let nonceAddressXOR = nonceHash ^ addressHash + let divConstant = MAX_NUMBER / this.difficulty let candidate: string let iterations = 0 while (true) { candidate = hexlify(randomBytes(32)) - let candidateHash = new BN(keccak256(candidate).slice(2), 16) - let resultHash = nonceAddressXOR.xor(candidateHash) - let externalGas = divConstant.div(resultHash).toNumber() + let candidateHash = toBigInt(keccak256(candidate)) + let resultHash = nonceAddressXOR ^ candidateHash + let externalGas = divConstant / resultHash if (externalGas >= gasAmount) { break } From 5219de7387192a764802be0c48e4422e94160439 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Mon, 28 Aug 2023 20:09:56 +0100 Subject: [PATCH 33/54] Update miner scirpt --- src/core/miner.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/core/miner.ts b/src/core/miner.ts index e426ddf..0ab235e 100644 --- a/src/core/miner.ts +++ b/src/core/miner.ts @@ -51,10 +51,11 @@ export default class SkalePowMiner { let addressHash = toBigInt(keccak256(address)) let nonceAddressXOR = nonceHash ^ addressHash let divConstant = MAX_NUMBER / this.difficulty - let candidate: string + let candidate: Uint8Array let iterations = 0 + const start = performance.now() while (true) { - candidate = hexlify(randomBytes(32)) + candidate = randomBytes(32) let candidateHash = toBigInt(keccak256(candidate)) let resultHash = nonceAddressXOR ^ candidateHash let externalGas = divConstant / resultHash @@ -66,6 +67,8 @@ export default class SkalePowMiner { await new Promise((resolve) => setTimeout(resolve, 0)) } } + const end = performance.now() + console.log(`PoW xecution time: ${end - start} ms`) return toBigInt(candidate) } } From 69d6ac614738739a21c70c9de48aa4714eaa33be Mon Sep 17 00:00:00 2001 From: Dmytro Date: Tue, 29 Aug 2023 20:09:21 +0100 Subject: [PATCH 34/54] Update sFUEL logic, add vibrant mode --- src/components/ChainApps/ChainApps.tsx | 36 +++++- src/components/ChainsList/ChainsList.tsx | 88 +++++++++---- src/components/SFuelWarning/SFuelWarning.tsx | 125 ++++++++++--------- src/components/WidgetBody/WidgetBody.tsx | 13 +- src/core/constants.ts | 2 +- src/core/faucet.ts | 2 +- src/core/interfaces/Theme.ts | 1 + src/core/metadata.ts | 17 +++ src/core/miner.ts | 2 +- src/index.ts | 5 + src/metadata/metaportConfigStaging.ts | 3 +- src/store/SFuelStore.ts | 20 +-- src/styles/cmn.module.scss | 4 + src/styles/styles.module.scss | 4 + 14 files changed, 214 insertions(+), 108 deletions(-) diff --git a/src/components/ChainApps/ChainApps.tsx b/src/components/ChainApps/ChainApps.tsx index ea454c9..245edd4 100644 --- a/src/components/ChainApps/ChainApps.tsx +++ b/src/components/ChainApps/ChainApps.tsx @@ -7,23 +7,51 @@ import { SkaleNetwork } from '../../core/interfaces' import ChainIcon from '../ChainIcon' -export default function ChainApps(props: { skaleNetwork: SkaleNetwork; chain: string }) { +export default function ChainApps(props: { + skaleNetwork: SkaleNetwork + chain: string + size?: 'sm' | 'md' +}) { const apps = getChainAppsMeta(props.chain, props.skaleNetwork) if (!apps || !Object.keys(apps) || Object.keys(apps).length === 0) return
+ const size = props.size ?? 'sm' + const iconSize = props.size === 'sm' ? 'xs' : 'sm' + return (
{Object.keys(apps).map((key, _) => ( -
+
-

+

{getChainAlias(props.skaleNetwork, props.chain, key)}

diff --git a/src/components/ChainsList/ChainsList.tsx b/src/components/ChainsList/ChainsList.tsx index b284f38..3acfed5 100644 --- a/src/components/ChainsList/ChainsList.tsx +++ b/src/components/ChainsList/ChainsList.tsx @@ -6,6 +6,7 @@ import Typography from '@mui/material/Typography' import ExpandMoreIcon from '@mui/icons-material/ExpandMore' import Tooltip from '@mui/material/Tooltip' import Button from '@mui/material/Button' +import KeyboardArrowRightRoundedIcon from '@mui/icons-material/KeyboardArrowRightRounded' import ChainApps from '../ChainApps' import ChainIcon from '../ChainIcon' @@ -26,6 +27,7 @@ export default function ChainsList(props: { disabledChain: string from?: boolean disabled?: boolean + size?: 'sm' | 'md' }) { const handleChange = (panel: string) => (_: React.SyntheticEvent, isExpanded: boolean) => { props.setExpanded(isExpanded ? panel : false) @@ -44,6 +46,8 @@ export default function ChainsList(props: { props.setChain(schainName) } + const size = props.size ?? 'sm' + return (
{props.chain ? (
-
- +
+
- -

- {getChainAlias(props.config.skaleNetwork, props.chain)} -

-
+

+ {getChainAlias(props.config.skaleNetwork, props.chain)} +

{/*
-
- +
+
{schainNames.map((name) => ( @@ -106,16 +130,41 @@ export default function ChainsList(props: { {/*
*/} -
-
- +
+
+

- {/*
- -
*/} +
-
- +
+
))} diff --git a/src/components/SFuelWarning/SFuelWarning.tsx b/src/components/SFuelWarning/SFuelWarning.tsx index e093926..72887af 100644 --- a/src/components/SFuelWarning/SFuelWarning.tsx +++ b/src/components/SFuelWarning/SFuelWarning.tsx @@ -29,16 +29,10 @@ import { useAccount } from 'wagmi' import Button from '@mui/material/Button' import LoadingButton from '@mui/lab/LoadingButton' import { Collapse } from '@mui/material' +import LinearProgress from '@mui/material/LinearProgress'; -import { - MAINNET_CHAIN_NAME, - SFUEL_CHEKCS_INTERVAL, - SFUEL_TEXT, - DEFAULT_FAUCET_URL, -} from '../../core/constants' - -import { Station, StationData } from '../../core/sfuel' -import { View } from '../../core/dataclasses/View' +import { MAINNET_CHAIN_NAME, SFUEL_TEXT } from '../../core/constants' +import { Station } from '../../core/sfuel' import { useMetaportStore } from '../../store/MetaportState' import { useSFuelStore } from '../../store/SFuelStore' @@ -47,8 +41,6 @@ import { cls } from '../../core/helper' import cmn from '../../styles/cmn.module.scss' import styles from '../../styles/styles.module.scss' -// import CustomStationUrl from '../CustomStationUrl'; - debug.enable('*') const log = debug('metaport:components:SFuel') @@ -78,15 +70,6 @@ export default function SFuelWarning(props: {}) { const sFuelOk = useSFuelStore((state) => state.sFuelOk) const setSFuelOk = useSFuelStore((state) => state.setSFuelOk) - const fromStationData = useSFuelStore((state) => state.fromStationData) - const setFromStationData = useSFuelStore((state) => state.setFromStationData) - - const toStationData = useSFuelStore((state) => state.toStationData) - const setToStationData = useSFuelStore((state) => state.setToStationData) - - const hubStationData = useSFuelStore((state) => state.hubStationData) - const setHubStationData = useSFuelStore((state) => state.setHubStationData) - const { address } = useAccount() let hubChain @@ -97,25 +80,15 @@ export default function SFuelWarning(props: {}) { useEffect(() => { if (!chainName1 || !chainName2 || !address) return + setLoading(true) + setFromChainStation(null) + setToChainStation(null) + setHubChainStation(null) + setSFuelOk(false) log('Initializing SFuelWarning', chainName1, chainName2, hubChain, address) createStations() }, [chainName1, chainName2, hubChain, address]) - useEffect(() => { - if (!fromStationData.ok || (hubChainStation && !hubStationData.ok)) { - setSFuelStatus('error') - setSFuelOk(false) - } else { - if (!toStationData.ok) { - setSFuelStatus('warning') - setSFuelOk(false) - } else { - setSFuelStatus('action') - setSFuelOk(true) - } - } - }, [fromStationData, toStationData, hubStationData]) - useEffect(() => { updateStationsData() const intervalId = setInterval(() => { @@ -133,10 +106,35 @@ export default function SFuelWarning(props: {}) { } async function updateStationsData() { - if (fromChainStation) setFromStationData(await fromChainStation.getData(address)) - if (toChainStation) setToStationData(await toChainStation.getData(address)) - if (hubChainStation) setHubStationData(await hubChainStation.getData(address)) - setLoading(false) + let fromData + let toData + let hubData + if (fromChainStation) { + fromData = await fromChainStation.getData(address) + } + if (toChainStation) { + toData = await toChainStation.getData(address) + } + if (hubChainStation) { + hubData = await hubChainStation.getData(address) + } + if ((fromData && !fromData.ok) || (hubData && !hubData.ok)) { + setSFuelStatus('error') + setSFuelOk(false) + } else { + if (toData && !toData.ok) { + setSFuelStatus('warning') + setSFuelOk(false) + } else { + if (fromData && fromData.ok && toData && toData.ok) { + setSFuelStatus('action') + setSFuelOk(true) + } + } + } + if (fromData && toData) { + setLoading(false) + } } async function doPoW() { @@ -145,20 +143,27 @@ export default function SFuelWarning(props: {}) { let hubPowRes setMining(true) - - if (fromChainStation && !fromStationData.ok) { - log(`Doing PoW on ${fromChainStation.chainName}`) - fromPowRes = await fromChainStation.doPoW(address) + if (fromChainStation) { + const fromData = await fromChainStation.getData(address) + if (!fromData.ok) { + log(`Doing PoW on ${fromChainStation.chainName}`) + fromPowRes = await fromChainStation.doPoW(address) + } } - if (toChainStation && !toStationData.ok) { - log(`Doing PoW on ${toChainStation.chainName}`) - toPowRes = await toChainStation.doPoW(address) + if (toChainStation) { + const toData = await toChainStation.getData(address) + if (!toData.ok) { + log(`Doing PoW on ${toChainStation.chainName}`) + toPowRes = await toChainStation.doPoW(address) + } } - if (hubChainStation && !hubStationData.ok) { - log(`Doing PoW on ${hubChainStation.chainName}`) - hubPowRes = await hubChainStation.doPoW(address) + if (hubChainStation) { + const hubData = await hubChainStation.getData(address) + if (!hubData.ok) { + log(`Doing PoW on ${hubChainStation.chainName}`) + hubPowRes = await hubChainStation.doPoW(address) + } } - if ( (fromPowRes && !fromPowRes.ok) || (toPowRes && !toPowRes.ok) || @@ -169,28 +174,34 @@ export default function SFuelWarning(props: {}) { if (toPowRes) log(chainName2, toPowRes.message) if (hubPowRes) log(hubChain, hubPowRes.message) // window.open(DEFAULT_FAUCET_URL, '_blank'); + } else { + setSFuelStatus('action') + setSFuelOk(true) } - await updateStationsData() + // await updateStationsData() setMining(false) } - const noEth = fromStationData && !fromStationData.ok && chainName1 === MAINNET_CHAIN_NAME - const noEthDest = toStationData && !toStationData.ok && chainName2 === MAINNET_CHAIN_NAME + const mainnetTransfer = chainName1 === MAINNET_CHAIN_NAME || chainName2 === MAINNET_CHAIN_NAME function getSFuelText() { - if (noEth || (fromStationData && fromStationData.ok && noEthDest)) { + if (mainnetTransfer) { return SFUEL_TEXT['gas'][sFuelStatus] } return SFUEL_TEXT['sfuel'][sFuelStatus] } + if (loading) return
+ +
+ return ( - +
-

+

⛽ {getSFuelText()}

- {!noEth && ((fromStationData && !fromStationData.ok) || !noEthDest) ? ( + {!mainnetTransfer ? (
{mining ? ( state.expandedFrom) @@ -50,6 +53,8 @@ export function WidgetBody(props) { const sFuelOk = useSFuelStore((state) => state.sFuelOk) + const theme = useUIStore((state) => state.theme) + useEffect(() => { setChainName1(mpc.config.chains ? mpc.config.chains[0] : '') setChainName2(mpc.config.chains ? mpc.config.chains[1] : '') @@ -71,12 +76,16 @@ export function WidgetBody(props) { !expandedFrom && !expandedTo && !expandedTokens && chainName2 === MAINNET_CHAIN_NAME const showError = !!errorMessage + const grayBg = 'rgb(136 135 135 / 15%)' + const sourceBg = theme.vibrant ? chainBg(mpc.config.skaleNetwork, chainName1) : grayBg + const destBg = theme.vibrant ? chainBg(mpc.config.skaleNetwork, chainName2) : grayBg + return (
- +
@@ -116,7 +125,7 @@ export function WidgetBody(props) { - +

To

diff --git a/src/core/constants.ts b/src/core/constants.ts index 635a367..dff456a 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -75,7 +75,7 @@ export const IMA_HUB_WAIT = 5 export const COINGECKO_API_ENDPOINT = '' export const DEFAULT_FAUCET_URL = 'https://sfuel.skale.network/' -export const SFUEL_CHEKCS_INTERVAL = 8 +export const SFUEL_CHECKS_INTERVAL = 8 export const SFUEL_TEXT = { sfuel: { diff --git a/src/core/faucet.ts b/src/core/faucet.ts index 20468a5..8bcbefd 100644 --- a/src/core/faucet.ts +++ b/src/core/faucet.ts @@ -64,7 +64,7 @@ export async function getSFuel( const provider = new JsonRpcProvider(endpoint) const wallet = Wallet.createRandom().connect(provider) let nonce: number = await wallet.getNonce() - const mineFreeGasResult = await miner.mineGasForTransaction(nonce, 100000, wallet.address) + const mineFreeGasResult = await miner.mineGasForTransaction(nonce, 1000000, wallet.address) const { to, data } = getFuncData(chainName, address, mpc.config.skaleNetwork) return await wallet.sendTransaction({ from: wallet.address, diff --git a/src/core/interfaces/Theme.ts b/src/core/interfaces/Theme.ts index af1b59c..abedad6 100644 --- a/src/core/interfaces/Theme.ts +++ b/src/core/interfaces/Theme.ts @@ -31,4 +31,5 @@ export interface MetaportTheme { background?: string position?: Position zIndex?: number + vibrant?: boolean } diff --git a/src/core/metadata.ts b/src/core/metadata.ts index af58bf0..1e5dd74 100644 --- a/src/core/metadata.ts +++ b/src/core/metadata.ts @@ -24,6 +24,7 @@ import { TokenData } from './dataclasses' import { SkaleNetwork } from './interfaces' import { MAINNET_CHAIN_NAME } from './constants' +import { CHAINS_META } from './helper' import * as MAINNET_CHAIN_ICONS from '../meta/mainnet/icons' import * as STAGING_CHAIN_ICONS from '../meta/staging/icons' @@ -60,6 +61,22 @@ export function chainIconPath(skaleNetwork: SkaleNetwork, name: string, app?: st } } +export function chainBg(skaleNetwork: SkaleNetwork, chainName: string, app?: string): string { + if (CHAINS_META[skaleNetwork][chainName]) { + if (app) { + if (CHAINS_META[skaleNetwork][chainName]['apps'][app]['gradientBackground']) { + return CHAINS_META[skaleNetwork][chainName]['apps'][app]['gradientBackground'] + } + return CHAINS_META[skaleNetwork][chainName]['apps'][app]['background'] + } + if (CHAINS_META[skaleNetwork][chainName]['gradientBackground']) { + return CHAINS_META[skaleNetwork][chainName]['gradientBackground'] + } + return CHAINS_META[skaleNetwork][chainName]['background'] + } + return 'linear-gradient(273.67deg, rgb(47 50 80), rgb(39 43 68))' +} + export function tokenIcon(tokenSymbol: string) { if (!tokenSymbol) return const key = tokenSymbol.toLowerCase() diff --git a/src/core/miner.ts b/src/core/miner.ts index 0ab235e..d889df9 100644 --- a/src/core/miner.ts +++ b/src/core/miner.ts @@ -68,7 +68,7 @@ export default class SkalePowMiner { } } const end = performance.now() - console.log(`PoW xecution time: ${end - start} ms`) + console.log(`PoW execution time: ${end - start} ms`) return toBigInt(candidate) } } diff --git a/src/index.ts b/src/index.ts index 0660704..42f89c2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,6 +2,7 @@ export { interfaces, dataclasses } from './Metaport' export { useMetaportStore } from './store/MetaportState' export { useUIStore, useCollapseStore } from './store/Store' +export { useSFuelStore } from './store/SFuelStore' import Metaport from './components/Metaport' import MetaportProvider from './components/MetaportProvider' @@ -23,8 +24,10 @@ import AmountErrorMessage from './components/AmountErrorMessage' import DestTokenBalance from './components/DestTokenBalance' import ErrorMessage from './components/ErrorMessage' import CommunityPool from './components/CommunityPool' +import SFuelWarning from './components/SFuelWarning' import { cls } from './core/helper' +import { chainBg } from './core/metadata' import styles from './styles/styles.module.scss' import cmn from './styles/cmn.module.scss' @@ -53,10 +56,12 @@ export { DestTokenBalance, ErrorMessage, CommunityPool, + SFuelWarning, cls, styles, cmn, getMetaportTheme, useWagmiAccount, PROXY_ENDPOINTS, + chainBg } diff --git a/src/metadata/metaportConfigStaging.ts b/src/metadata/metaportConfigStaging.ts index 7e43ae6..d3f34f2 100644 --- a/src/metadata/metaportConfigStaging.ts +++ b/src/metadata/metaportConfigStaging.ts @@ -289,5 +289,6 @@ export const METAPORT_CONFIG: interfaces.MetaportConfig = { }, theme: { mode: 'dark', - }, + vibrant: true, + } } diff --git a/src/store/SFuelStore.ts b/src/store/SFuelStore.ts index 9938ca5..d464896 100644 --- a/src/store/SFuelStore.ts +++ b/src/store/SFuelStore.ts @@ -48,15 +48,6 @@ interface SFuelState { sFuelOk: boolean setSFuelOk: (loading: boolean) => void - - fromStationData: StationData - setFromStationData: (data: StationData) => void - - toStationData: StationData - setToStationData: (data: StationData) => void - - hubStationData: StationData - setHubStationData: (data: StationData) => void } export const useSFuelStore = create()((set, get) => ({ @@ -78,14 +69,5 @@ export const useSFuelStore = create()((set, get) => ({ setSFuelStatus: (status: 'action' | 'warning' | 'error') => set({ sFuelStatus: status }), sFuelOk: false, - setSFuelOk: (sFuelOk: boolean) => set(() => ({ sFuelOk: sFuelOk })), - - fromStationData: { ok: false, balance: null }, - setFromStationData: (data: StationData) => set({ fromStationData: data }), - - toStationData: { ok: false, balance: null }, - setToStationData: (data: StationData) => set({ toStationData: data }), - - hubStationData: { ok: false, balance: null }, - setHubStationData: (data: StationData) => set({ hubStationData: data }), + setSFuelOk: (sFuelOk: boolean) => set(() => ({ sFuelOk: sFuelOk })) })) diff --git a/src/styles/cmn.module.scss b/src/styles/cmn.module.scss index 8efd048..eb499ad 100644 --- a/src/styles/cmn.module.scss +++ b/src/styles/cmn.module.scss @@ -61,6 +61,10 @@ margin-right: 10px !important; } +.mri15 { + margin-right: 15px !important; +} + .mri5 { margin-right: 5px !important; } diff --git a/src/styles/styles.module.scss b/src/styles/styles.module.scss index 3c1a742..a788335 100644 --- a/src/styles/styles.module.scss +++ b/src/styles/styles.module.scss @@ -120,6 +120,10 @@ button { } + :global(.MuiLinearProgress-root) { + border-radius: 20px; + } + // .accordionSm { // :global(.MuiAccordionSummary-content) { // margin: 0 !important; From b76537ab3ed489f717b5821ebf9a4e10fd7fd76c Mon Sep 17 00:00:00 2001 From: Dmytro Date: Wed, 30 Aug 2023 22:15:41 +0100 Subject: [PATCH 35/54] Add ETH M2S, S2M methods, add ETH balance check --- .../DestTokenBalance/DestTokenBalance.tsx | 1 + src/components/TokenList/TokenList.tsx | 5 +- .../TokenListSection/TokenListSection.tsx | 2 +- src/components/WidgetBody/WidgetBody.tsx | 1 + src/core/actions/eth.ts | 123 ++++++++++++++++++ src/core/actions/index.ts | 9 +- src/core/dataclasses/StepMetadata.ts | 4 +- src/core/metaport.ts | 12 +- src/metadata/metaportConfigStaging.ts | 26 +++- src/store/MetaportState.ts | 14 +- 10 files changed, 186 insertions(+), 11 deletions(-) create mode 100644 src/core/actions/eth.ts diff --git a/src/components/DestTokenBalance/DestTokenBalance.tsx b/src/components/DestTokenBalance/DestTokenBalance.tsx index 7fb4684..9f67408 100644 --- a/src/components/DestTokenBalance/DestTokenBalance.tsx +++ b/src/components/DestTokenBalance/DestTokenBalance.tsx @@ -28,6 +28,7 @@ export default function DestTokenBalance() { balance={destTokenBalance} symbol={token.meta.symbol} decimals={token.meta.decimals} + truncate={9} /> ) } diff --git a/src/components/TokenList/TokenList.tsx b/src/components/TokenList/TokenList.tsx index ff81587..91dc1e1 100644 --- a/src/components/TokenList/TokenList.tsx +++ b/src/components/TokenList/TokenList.tsx @@ -114,12 +114,13 @@ export default function TokenList() { {expandedTokens ? ( - {/* */} + tokenBalances={tokenBalances} + />
diff --git a/src/components/WidgetBody/WidgetBody.tsx b/src/components/WidgetBody/WidgetBody.tsx index b4529f4..7c5d372 100644 --- a/src/components/WidgetBody/WidgetBody.tsx +++ b/src/components/WidgetBody/WidgetBody.tsx @@ -96,6 +96,7 @@ export function WidgetBody(props) { balance={tokenBalances[token.keyname]} symbol={token.meta.symbol} decimals={token.meta.decimals} + truncate={9} /> ) : null}
diff --git a/src/core/actions/eth.ts b/src/core/actions/eth.ts new file mode 100644 index 0000000..ccd650e --- /dev/null +++ b/src/core/actions/eth.ts @@ -0,0 +1,123 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/** + * @file eth.ts + * @copyright SKALE Labs 2022-Present + */ + + +import debug from 'debug'; +import { MainnetChain, SChain } from '@skalenetwork/ima-js' + +import { externalEvents } from '../events'; +import { toWei } from '../convertation'; +import { TransferAction, Action } from './action'; +import { checkEthBalance } from './checks'; + + +debug.enable('*'); +const log = debug('metaport:actions:eth'); + + +export class TransferEthM2S extends TransferAction { + async execute() { + this.updateState('init') + const amountWei = toWei(this.amount, this.token.meta.decimals) + const sChainBalanceBefore = await this.sChain2.ethBalance(this.address); + const mainnet = (await this.getConnectedChain(this.mainnet.provider)) as MainnetChain + this.updateState('transferETH'); + const tx = await mainnet.eth.deposit( + this.chainName2, + { + address: this.address, + value: amountWei + } + ); + const block = await this.mainnet.provider.getBlock(tx.blockNumber); + this.updateState('transferETHDone', tx.hash, block.timestamp); + await this.sChain2.waitETHBalanceChange(this.address, sChainBalanceBefore); + this.updateState('receivedETH'); + } + + async preAction() { + const checkResBalance = await checkEthBalance( + this.mainnet, + this.address, + this.amount, + this.token + ); + if (!checkResBalance.res) { + this.setAmountErrorMessage(checkResBalance.msg); + return + } + this.setAmountErrorMessage(null) + } +} + + +export class TransferEthS2M extends TransferAction { + async execute() { + log('TransferEthS2M: started'); + this.updateState('init'); + const amountWei = toWei(this.amount, this.token.meta.decimals); + const lockedETHAmount = await this.mainnet.eth.lockedETHAmount(this.address); + const sChain = (await this.getConnectedChain(this.sChain1.provider)) as SChain + this.updateState('transferETH'); + const tx = await sChain.eth.withdraw( + amountWei, + { address: this.address } + ); + const block = await this.sChain1.provider.getBlock(tx.blockNumber); + this.updateState('transferETHDone', tx.hash, block.timestamp); + await this.mainnet.eth.waitLockedETHAmountChange(this.address, lockedETHAmount); + this.updateState('receivedETH'); + } + + async preAction() { + const checkResBalance = await checkEthBalance( + this.sChain1, + this.address, + this.amount, + this.token + ); + if (!checkResBalance.res) { + this.setAmountErrorMessage(checkResBalance.msg); + } + this.setAmountErrorMessage(null); + } +} + + +export class UnlockEthM extends Action { + static label = 'Unlock ETH' + static buttonText = 'Unlock' + static loadingText = 'Unlocking' + + async execute() { + this.updateState('init'); + const mainnet = (await this.getConnectedChain(this.mainnet.provider)) as MainnetChain + this.updateState('unlock'); + const tx = await mainnet.eth.getMyEth( + { address: this.address } + ); + const block = await this.mainnet.provider.getBlock(tx.blockNumber); + this.updateState('unlockDone', tx.hash, block.timestamp); + } +} + diff --git a/src/core/actions/index.ts b/src/core/actions/index.ts index 8af3f83..8fcad64 100644 --- a/src/core/actions/index.ts +++ b/src/core/actions/index.ts @@ -23,6 +23,11 @@ import debug from 'debug' +import { + TransferEthM2S, + TransferEthS2M, + UnlockEthM +} from './eth'; import { TransferERC20S2S, WrapERC20S, @@ -60,8 +65,8 @@ export function getActionName( } export const ACTIONS: { [actionType in ActionType]: typeof Action } = { - // eth_m2s: [TransferEthM2S], - // eth_s2m: [TransferEthS2M, UnlockEthM], + eth_m2s: TransferEthM2S, + eth_s2m: TransferEthS2M, // eth_s2s: [], wrap: WrapERC20S, diff --git a/src/core/dataclasses/StepMetadata.ts b/src/core/dataclasses/StepMetadata.ts index 380162c..52e196f 100644 --- a/src/core/dataclasses/StepMetadata.ts +++ b/src/core/dataclasses/StepMetadata.ts @@ -36,6 +36,8 @@ export enum ActionType { erc20_s2s = 'erc20_s2s', wrap = 'wrap', unwrap = 'unwrap', + eth_m2s = 'eth_m2s', + eth_s2m = 'eth_s2m' } export function getActionType( @@ -68,7 +70,7 @@ export abstract class StepMetadata { public type: ActionType, public from: string, public to: string, - ) {} + ) { } } export class TransferStepMetadata extends StepMetadata { diff --git a/src/core/metaport.ts b/src/core/metaport.ts index 9d1d45d..a1b0726 100644 --- a/src/core/metaport.ts +++ b/src/core/metaport.ts @@ -160,9 +160,17 @@ export default class MetaportCore { provider: Provider, customAbiTokenType?: CustomAbiTokenType, destChainName?: string, - ): Contract { + ): Contract | undefined { + let type = tokenType const token = this._config.connections[chainName][tokenType][tokenKeyname] - const abi = customAbiTokenType ? ERC_ABIS[customAbiTokenType].abi : ERC_ABIS[tokenType].abi + if (tokenType === TokenType.eth) { + if (destChainName && token.chains[destChainName].clone) { + type = TokenType.erc20 + } else { + return + } + } + const abi = customAbiTokenType ? ERC_ABIS[customAbiTokenType].abi : ERC_ABIS[type].abi const address = customAbiTokenType ? token.chains[destChainName].wrapper : token.address // TODO: add sFUEL address support! return new Contract(address, abi, provider) diff --git a/src/metadata/metaportConfigStaging.ts b/src/metadata/metaportConfigStaging.ts index d3f34f2..07bf879 100644 --- a/src/metadata/metaportConfigStaging.ts +++ b/src/metadata/metaportConfigStaging.ts @@ -16,7 +16,7 @@ export const METAPORT_CONFIG: interfaces.MetaportConfig = { ], tokens: { eth: { - symbol: 'eth', + symbol: 'ETH' }, skl: { decimals: '18', @@ -72,6 +72,18 @@ export const METAPORT_CONFIG: interfaces.MetaportConfig = { }, connections: { mainnet: { + eth: { + eth: { + chains: { + 'staging-legal-crazy-castor': {}, + // "staging-utter-unripe-menkar": {}, + // "staging-faint-slimy-achird": {}, + // "staging-perfect-parallel-gacrux": {}, + // "staging-severe-violet-wezen": {}, + // "staging-weepy-fitting-caph": {} + } + } + }, erc20: { skl: { address: '0x493D4442013717189C9963a2e275Ad33bfAFcE11', @@ -197,6 +209,16 @@ export const METAPORT_CONFIG: interfaces.MetaportConfig = { }, 'staging-legal-crazy-castor': { // Europa connections + eth: { + eth: { + address: '0xD2Aaa00700000000000000000000000000000000', + chains: { + mainnet: { + clone: true + } + } + } + }, erc20: { skl: { address: '0xbA1E9BA7CDd4815Da6a51586bE56e8643d1bEAb6', @@ -289,6 +311,6 @@ export const METAPORT_CONFIG: interfaces.MetaportConfig = { }, theme: { mode: 'dark', - vibrant: true, + vibrant: true } } diff --git a/src/store/MetaportState.ts b/src/store/MetaportState.ts index afba2f8..08ddb2d 100644 --- a/src/store/MetaportState.ts +++ b/src/store/MetaportState.ts @@ -304,6 +304,8 @@ export const useMetaportStore = create()((set, get) => ({ token.keyname, token.type, provider, + null, + get().chainName1 ) set({ token: token, @@ -319,16 +321,26 @@ export const useMetaportStore = create()((set, get) => ({ destTokenContract: null, destTokenBalance: null, + updateDestTokenBalance: async (address: string) => { if (get().destTokenContract) { const balance = await get().mpc.tokenBalance(get().destTokenContract, address) set({ destTokenBalance: balance }) + } else { + if (get().token && get().token.type === dataclasses.TokenType.eth && get().chainName2 === MAINNET_CHAIN_NAME) { + const chain = get().mpc.mainnet() + set({ destTokenBalance: await chain.ethBalance(address) }) + } } }, updateTokenBalances: async (address: string) => { const tokenBalances = await get().mpc.tokenBalances(get().tokenContracts, address) - set({ tokenBalances: tokenBalances }) + const chain = get().mpc.ima(get().chainName1) + tokenBalances.eth = await chain.ethBalance(address) + set({ + tokenBalances: tokenBalances + }) }, amountErrorMessage: null, From 75406614f5dac17534cb7280f219833daa159b9e Mon Sep 17 00:00:00 2001 From: Dmytro Date: Thu, 31 Aug 2023 16:04:25 +0100 Subject: [PATCH 36/54] Update eth unlock step, update wallet connector --- src/components/SkConnect/SkConnect.tsx | 10 +++++----- src/components/WidgetBody/WidgetBody.tsx | 12 ++++++++---- src/components/WidgetUI/WidgetUI.tsx | 6 ++++-- src/core/actions/checks.ts | 13 +++++++++---- src/core/actions/eth.ts | 3 ++- src/core/actions/index.ts | 2 +- src/core/community_pool.ts | 4 ++-- src/core/dataclasses/StepMetadata.ts | 19 ++++++++++++++++++- src/core/transfer_steps.ts | 3 ++- src/store/MetaportState.ts | 15 ++++++++++++--- 10 files changed, 63 insertions(+), 24 deletions(-) diff --git a/src/components/SkConnect/SkConnect.tsx b/src/components/SkConnect/SkConnect.tsx index 322cd11..819d0f9 100644 --- a/src/components/SkConnect/SkConnect.tsx +++ b/src/components/SkConnect/SkConnect.tsx @@ -73,7 +73,7 @@ export default function SkConnect() { if (!connected) { return (
-
+ {/*
@@ -127,8 +127,8 @@ export default function SkConnect() { chainName="wan-red-ain" size="xs" /> -
-

*/} + {/*

Connect a wallet to use SKALE Metaport -

+

*/}
- + {!!address ? : null} - {address ? :
} + {/* {address ? :
} */} +
+ {!address ? : null}
{fabTop ? null : fabButton}
diff --git a/src/core/actions/checks.ts b/src/core/actions/checks.ts index af93a66..eac8498 100644 --- a/src/core/actions/checks.ts +++ b/src/core/actions/checks.ts @@ -45,10 +45,15 @@ export async function checkEthBalance( // TODO: optimize balance checks try { const balance = await chain.ethBalance(address) log(`address: ${address}, eth balance: ${balance}, amount: ${amount}`) - const balanceEther = fromWei(balance, tokenData.meta.decimals) - if (Number(amount) + SFUEL_RESERVE_AMOUNT > Number(balanceEther)) { - checkRes.msg = `Current balance: ${balanceEther} ${tokenData.meta.symbol}. \ - ${SFUEL_RESERVE_AMOUNT} ETH will be reserved to cover transfer costs.` + const balanceEther = Number(fromWei(balance, tokenData.meta.decimals)) + let checkedAmount = Number(amount) + let msg = `Current balance: ${balanceEther} ${tokenData.meta.symbol}.` + if (chain instanceof MainnetChain) { + checkedAmount += SFUEL_RESERVE_AMOUNT + msg += ` ${SFUEL_RESERVE_AMOUNT} ETH will be reserved to cover transfer costs.` + } + if (checkedAmount > balanceEther) { + checkRes.msg = msg } else { checkRes.res = true } diff --git a/src/core/actions/eth.ts b/src/core/actions/eth.ts index ccd650e..8ce4979 100644 --- a/src/core/actions/eth.ts +++ b/src/core/actions/eth.ts @@ -98,8 +98,9 @@ export class TransferEthS2M extends TransferAction { ); if (!checkResBalance.res) { this.setAmountErrorMessage(checkResBalance.msg); + return } - this.setAmountErrorMessage(null); + this.setAmountErrorMessage(null) } } diff --git a/src/core/actions/index.ts b/src/core/actions/index.ts index 8fcad64..2312302 100644 --- a/src/core/actions/index.ts +++ b/src/core/actions/index.ts @@ -67,7 +67,7 @@ export function getActionName( export const ACTIONS: { [actionType in ActionType]: typeof Action } = { eth_m2s: TransferEthM2S, eth_s2m: TransferEthS2M, - // eth_s2s: [], + eth_unlock: UnlockEthM, wrap: WrapERC20S, unwrap: UnWrapERC20S, diff --git a/src/core/community_pool.ts b/src/core/community_pool.ts index 4345cef..9201aca 100644 --- a/src/core/community_pool.ts +++ b/src/core/community_pool.ts @@ -79,7 +79,7 @@ export async function getCommunityPoolData( } } - log('Getting community pool data', address, chainName1) + // log('Getting community pool data', address, chainName1) const balanceWei = await mainnet.communityPool.balance(address, chainName1) const accountBalanceWei = await mainnet.ethBalance(address) const activeS = await sChain.communityLocker.contract.activeUsers(address) @@ -103,7 +103,7 @@ export async function getCommunityPoolData( recommendedRechargeAmount: recommendedAmount, originalRecommendedRechargeAmount: rraWei, } - log('communityPoolData:', communityPoolData) + // log('communityPoolData:', communityPoolData) return communityPoolData } diff --git a/src/core/dataclasses/StepMetadata.ts b/src/core/dataclasses/StepMetadata.ts index 52e196f..7172453 100644 --- a/src/core/dataclasses/StepMetadata.ts +++ b/src/core/dataclasses/StepMetadata.ts @@ -37,7 +37,8 @@ export enum ActionType { wrap = 'wrap', unwrap = 'unwrap', eth_m2s = 'eth_m2s', - eth_s2m = 'eth_s2m' + eth_s2m = 'eth_s2m', + eth_unlock = 'eth_unlock' } export function getActionType( @@ -110,3 +111,19 @@ export class UnwrapStepMetadata extends StepMetadata { super(ActionType.unwrap, from, to) } } + + +export class UnlockStepMetadata extends StepMetadata { + headline: string = 'Unlock on' + text: string = 'ETH should be unlocked on Ethereum.' + btnText: string = 'Unlock' + btnLoadingText: string = 'Unlocking' + onSource: boolean = false + + constructor( + public from: string, + public to: string, + ) { + super(ActionType.eth_unlock, from, to) + } +} diff --git a/src/core/transfer_steps.ts b/src/core/transfer_steps.ts index 2ec2049..a0a9e7d 100644 --- a/src/core/transfer_steps.ts +++ b/src/core/transfer_steps.ts @@ -28,6 +28,7 @@ import { WrapStepMetadata, UnwrapStepMetadata, TransferStepMetadata, + UnlockStepMetadata, StepMetadata, getActionType, } from './dataclasses' @@ -71,7 +72,7 @@ export function getStepsMetadata( steps.push(new TransferStepMetadata(getActionType(toChain, to, token.type), toChain, to)) } if (to === MAINNET_CHAIN_NAME && token.keyname === 'eth') { - // todo: add unlock step! + steps.push(new UnlockStepMetadata(token.chain, toChain)) } log(`Action steps metadata:`) diff --git a/src/store/MetaportState.ts b/src/store/MetaportState.ts index 08ddb2d..5cad446 100644 --- a/src/store/MetaportState.ts +++ b/src/store/MetaportState.ts @@ -139,11 +139,11 @@ export const useMetaportStore = create()((set, get) => ({ set((state) => { state.check(amount, address) return { - amount: amount, + amount: amount } }), - execute: async (address: string, switchNetwork: any, walletClient: WalletClient) => { + execute: async (address: `0x${string}`, switchNetwork: any, walletClient: WalletClient) => { log('Running execute') if (get().stepsMetadata[get().currentStep]) { set({ @@ -207,7 +207,7 @@ export const useMetaportStore = create()((set, get) => ({ }, check: async (amount: string, address: string) => { - if (get().stepsMetadata[get().currentStep]) { + if (get().stepsMetadata[get().currentStep] && address) { set({ loading: true, btnText: 'Checking balance...', @@ -313,6 +313,7 @@ export const useMetaportStore = create()((set, get) => ({ destTokenContract: destTokenContract, destTokenBalance: null, destChains: Object.keys(token.connections), + amount: '' }) }, @@ -323,6 +324,10 @@ export const useMetaportStore = create()((set, get) => ({ destTokenBalance: null, updateDestTokenBalance: async (address: string) => { + if (!address) { + set({ destTokenBalance: null }) + return + } if (get().destTokenContract) { const balance = await get().mpc.tokenBalance(get().destTokenContract, address) set({ destTokenBalance: balance }) @@ -335,6 +340,10 @@ export const useMetaportStore = create()((set, get) => ({ }, updateTokenBalances: async (address: string) => { + if (!address) { + set({ tokenBalances: {} }) + return + } const tokenBalances = await get().mpc.tokenBalances(get().tokenContracts, address) const chain = get().mpc.ima(get().chainName1) tokenBalances.eth = await chain.ethBalance(address) From e890973c606128edeb1c9422189d847e83eef0da Mon Sep 17 00:00:00 2001 From: Dmytro Date: Thu, 31 Aug 2023 16:04:56 +0100 Subject: [PATCH 37/54] Run prettier --- src/components/SFuelWarning/SFuelWarning.tsx | 11 +- .../TokenListSection/TokenListSection.tsx | 4 +- src/components/WidgetBody/WidgetBody.tsx | 8 +- src/core/actions/eth.ts | 160 ++++++++---------- src/core/actions/index.ts | 6 +- src/core/dataclasses/StepMetadata.ts | 5 +- src/index.ts | 2 +- src/metadata/metaportConfigStaging.ts | 18 +- src/store/MetaportState.ts | 14 +- src/store/SFuelStore.ts | 2 +- 10 files changed, 113 insertions(+), 117 deletions(-) diff --git a/src/components/SFuelWarning/SFuelWarning.tsx b/src/components/SFuelWarning/SFuelWarning.tsx index 72887af..cff8af1 100644 --- a/src/components/SFuelWarning/SFuelWarning.tsx +++ b/src/components/SFuelWarning/SFuelWarning.tsx @@ -29,7 +29,7 @@ import { useAccount } from 'wagmi' import Button from '@mui/material/Button' import LoadingButton from '@mui/lab/LoadingButton' import { Collapse } from '@mui/material' -import LinearProgress from '@mui/material/LinearProgress'; +import LinearProgress from '@mui/material/LinearProgress' import { MAINNET_CHAIN_NAME, SFUEL_TEXT } from '../../core/constants' import { Station } from '../../core/sfuel' @@ -191,9 +191,12 @@ export default function SFuelWarning(props: {}) { return SFUEL_TEXT['sfuel'][sFuelStatus] } - if (loading) return
- -
+ if (loading) + return ( +
+ +
+ ) return ( diff --git a/src/components/TokenListSection/TokenListSection.tsx b/src/components/TokenListSection/TokenListSection.tsx index 4fe340f..9670b54 100644 --- a/src/components/TokenListSection/TokenListSection.tsx +++ b/src/components/TokenListSection/TokenListSection.tsx @@ -65,7 +65,9 @@ export default function TokenListSection(props: {

diff --git a/src/components/WidgetBody/WidgetBody.tsx b/src/components/WidgetBody/WidgetBody.tsx index 9b47304..6f51cc5 100644 --- a/src/components/WidgetBody/WidgetBody.tsx +++ b/src/components/WidgetBody/WidgetBody.tsx @@ -75,7 +75,13 @@ export function WidgetBody(props) { const showInput = !expandedFrom && !expandedTo && !errorMessage && !expandedCP const showSwitch = !expandedFrom && !expandedTo && !expandedTokens && !errorMessage && !expandedCP const showStepper = - !expandedFrom && !expandedTo && !expandedTokens && !errorMessage && !expandedCP && sFuelOk && !!address + !expandedFrom && + !expandedTo && + !expandedTokens && + !errorMessage && + !expandedCP && + sFuelOk && + !!address const showCP = !expandedFrom && !expandedTo && !expandedTokens && chainName2 === MAINNET_CHAIN_NAME const showError = !!errorMessage diff --git a/src/core/actions/eth.ts b/src/core/actions/eth.ts index 8ce4979..7902c76 100644 --- a/src/core/actions/eth.ts +++ b/src/core/actions/eth.ts @@ -21,104 +21,90 @@ * @copyright SKALE Labs 2022-Present */ - -import debug from 'debug'; +import debug from 'debug' import { MainnetChain, SChain } from '@skalenetwork/ima-js' -import { externalEvents } from '../events'; -import { toWei } from '../convertation'; -import { TransferAction, Action } from './action'; -import { checkEthBalance } from './checks'; - - -debug.enable('*'); -const log = debug('metaport:actions:eth'); +import { externalEvents } from '../events' +import { toWei } from '../convertation' +import { TransferAction, Action } from './action' +import { checkEthBalance } from './checks' +debug.enable('*') +const log = debug('metaport:actions:eth') export class TransferEthM2S extends TransferAction { - async execute() { - this.updateState('init') - const amountWei = toWei(this.amount, this.token.meta.decimals) - const sChainBalanceBefore = await this.sChain2.ethBalance(this.address); - const mainnet = (await this.getConnectedChain(this.mainnet.provider)) as MainnetChain - this.updateState('transferETH'); - const tx = await mainnet.eth.deposit( - this.chainName2, - { - address: this.address, - value: amountWei - } - ); - const block = await this.mainnet.provider.getBlock(tx.blockNumber); - this.updateState('transferETHDone', tx.hash, block.timestamp); - await this.sChain2.waitETHBalanceChange(this.address, sChainBalanceBefore); - this.updateState('receivedETH'); - } - - async preAction() { - const checkResBalance = await checkEthBalance( - this.mainnet, - this.address, - this.amount, - this.token - ); - if (!checkResBalance.res) { - this.setAmountErrorMessage(checkResBalance.msg); - return - } - this.setAmountErrorMessage(null) + async execute() { + this.updateState('init') + const amountWei = toWei(this.amount, this.token.meta.decimals) + const sChainBalanceBefore = await this.sChain2.ethBalance(this.address) + const mainnet = (await this.getConnectedChain(this.mainnet.provider)) as MainnetChain + this.updateState('transferETH') + const tx = await mainnet.eth.deposit(this.chainName2, { + address: this.address, + value: amountWei, + }) + const block = await this.mainnet.provider.getBlock(tx.blockNumber) + this.updateState('transferETHDone', tx.hash, block.timestamp) + await this.sChain2.waitETHBalanceChange(this.address, sChainBalanceBefore) + this.updateState('receivedETH') + } + + async preAction() { + const checkResBalance = await checkEthBalance( + this.mainnet, + this.address, + this.amount, + this.token, + ) + if (!checkResBalance.res) { + this.setAmountErrorMessage(checkResBalance.msg) + return } + this.setAmountErrorMessage(null) + } } - export class TransferEthS2M extends TransferAction { - async execute() { - log('TransferEthS2M: started'); - this.updateState('init'); - const amountWei = toWei(this.amount, this.token.meta.decimals); - const lockedETHAmount = await this.mainnet.eth.lockedETHAmount(this.address); - const sChain = (await this.getConnectedChain(this.sChain1.provider)) as SChain - this.updateState('transferETH'); - const tx = await sChain.eth.withdraw( - amountWei, - { address: this.address } - ); - const block = await this.sChain1.provider.getBlock(tx.blockNumber); - this.updateState('transferETHDone', tx.hash, block.timestamp); - await this.mainnet.eth.waitLockedETHAmountChange(this.address, lockedETHAmount); - this.updateState('receivedETH'); - } - - async preAction() { - const checkResBalance = await checkEthBalance( - this.sChain1, - this.address, - this.amount, - this.token - ); - if (!checkResBalance.res) { - this.setAmountErrorMessage(checkResBalance.msg); - return - } - this.setAmountErrorMessage(null) + async execute() { + log('TransferEthS2M: started') + this.updateState('init') + const amountWei = toWei(this.amount, this.token.meta.decimals) + const lockedETHAmount = await this.mainnet.eth.lockedETHAmount(this.address) + const sChain = (await this.getConnectedChain(this.sChain1.provider)) as SChain + this.updateState('transferETH') + const tx = await sChain.eth.withdraw(amountWei, { address: this.address }) + const block = await this.sChain1.provider.getBlock(tx.blockNumber) + this.updateState('transferETHDone', tx.hash, block.timestamp) + await this.mainnet.eth.waitLockedETHAmountChange(this.address, lockedETHAmount) + this.updateState('receivedETH') + } + + async preAction() { + const checkResBalance = await checkEthBalance( + this.sChain1, + this.address, + this.amount, + this.token, + ) + if (!checkResBalance.res) { + this.setAmountErrorMessage(checkResBalance.msg) + return } + this.setAmountErrorMessage(null) + } } - export class UnlockEthM extends Action { - static label = 'Unlock ETH' - static buttonText = 'Unlock' - static loadingText = 'Unlocking' - - async execute() { - this.updateState('init'); - const mainnet = (await this.getConnectedChain(this.mainnet.provider)) as MainnetChain - this.updateState('unlock'); - const tx = await mainnet.eth.getMyEth( - { address: this.address } - ); - const block = await this.mainnet.provider.getBlock(tx.blockNumber); - this.updateState('unlockDone', tx.hash, block.timestamp); - } + static label = 'Unlock ETH' + static buttonText = 'Unlock' + static loadingText = 'Unlocking' + + async execute() { + this.updateState('init') + const mainnet = (await this.getConnectedChain(this.mainnet.provider)) as MainnetChain + this.updateState('unlock') + const tx = await mainnet.eth.getMyEth({ address: this.address }) + const block = await this.mainnet.provider.getBlock(tx.blockNumber) + this.updateState('unlockDone', tx.hash, block.timestamp) + } } - diff --git a/src/core/actions/index.ts b/src/core/actions/index.ts index 2312302..88f4a87 100644 --- a/src/core/actions/index.ts +++ b/src/core/actions/index.ts @@ -23,11 +23,7 @@ import debug from 'debug' -import { - TransferEthM2S, - TransferEthS2M, - UnlockEthM -} from './eth'; +import { TransferEthM2S, TransferEthS2M, UnlockEthM } from './eth' import { TransferERC20S2S, WrapERC20S, diff --git a/src/core/dataclasses/StepMetadata.ts b/src/core/dataclasses/StepMetadata.ts index 7172453..9a87491 100644 --- a/src/core/dataclasses/StepMetadata.ts +++ b/src/core/dataclasses/StepMetadata.ts @@ -38,7 +38,7 @@ export enum ActionType { unwrap = 'unwrap', eth_m2s = 'eth_m2s', eth_s2m = 'eth_s2m', - eth_unlock = 'eth_unlock' + eth_unlock = 'eth_unlock', } export function getActionType( @@ -71,7 +71,7 @@ export abstract class StepMetadata { public type: ActionType, public from: string, public to: string, - ) { } + ) {} } export class TransferStepMetadata extends StepMetadata { @@ -112,7 +112,6 @@ export class UnwrapStepMetadata extends StepMetadata { } } - export class UnlockStepMetadata extends StepMetadata { headline: string = 'Unlock on' text: string = 'ETH should be unlocked on Ethereum.' diff --git a/src/index.ts b/src/index.ts index 42f89c2..5bf1482 100644 --- a/src/index.ts +++ b/src/index.ts @@ -63,5 +63,5 @@ export { getMetaportTheme, useWagmiAccount, PROXY_ENDPOINTS, - chainBg + chainBg, } diff --git a/src/metadata/metaportConfigStaging.ts b/src/metadata/metaportConfigStaging.ts index 07bf879..d806482 100644 --- a/src/metadata/metaportConfigStaging.ts +++ b/src/metadata/metaportConfigStaging.ts @@ -16,7 +16,7 @@ export const METAPORT_CONFIG: interfaces.MetaportConfig = { ], tokens: { eth: { - symbol: 'ETH' + symbol: 'ETH', }, skl: { decimals: '18', @@ -81,8 +81,8 @@ export const METAPORT_CONFIG: interfaces.MetaportConfig = { // "staging-perfect-parallel-gacrux": {}, // "staging-severe-violet-wezen": {}, // "staging-weepy-fitting-caph": {} - } - } + }, + }, }, erc20: { skl: { @@ -214,10 +214,10 @@ export const METAPORT_CONFIG: interfaces.MetaportConfig = { address: '0xD2Aaa00700000000000000000000000000000000', chains: { mainnet: { - clone: true - } - } - } + clone: true, + }, + }, + }, }, erc20: { skl: { @@ -311,6 +311,6 @@ export const METAPORT_CONFIG: interfaces.MetaportConfig = { }, theme: { mode: 'dark', - vibrant: true - } + vibrant: true, + }, } diff --git a/src/store/MetaportState.ts b/src/store/MetaportState.ts index 5cad446..b50acf0 100644 --- a/src/store/MetaportState.ts +++ b/src/store/MetaportState.ts @@ -139,7 +139,7 @@ export const useMetaportStore = create()((set, get) => ({ set((state) => { state.check(amount, address) return { - amount: amount + amount: amount, } }), @@ -305,7 +305,7 @@ export const useMetaportStore = create()((set, get) => ({ token.type, provider, null, - get().chainName1 + get().chainName1, ) set({ token: token, @@ -313,7 +313,7 @@ export const useMetaportStore = create()((set, get) => ({ destTokenContract: destTokenContract, destTokenBalance: null, destChains: Object.keys(token.connections), - amount: '' + amount: '', }) }, @@ -332,7 +332,11 @@ export const useMetaportStore = create()((set, get) => ({ const balance = await get().mpc.tokenBalance(get().destTokenContract, address) set({ destTokenBalance: balance }) } else { - if (get().token && get().token.type === dataclasses.TokenType.eth && get().chainName2 === MAINNET_CHAIN_NAME) { + if ( + get().token && + get().token.type === dataclasses.TokenType.eth && + get().chainName2 === MAINNET_CHAIN_NAME + ) { const chain = get().mpc.mainnet() set({ destTokenBalance: await chain.ethBalance(address) }) } @@ -348,7 +352,7 @@ export const useMetaportStore = create()((set, get) => ({ const chain = get().mpc.ima(get().chainName1) tokenBalances.eth = await chain.ethBalance(address) set({ - tokenBalances: tokenBalances + tokenBalances: tokenBalances, }) }, diff --git a/src/store/SFuelStore.ts b/src/store/SFuelStore.ts index d464896..1aec7ad 100644 --- a/src/store/SFuelStore.ts +++ b/src/store/SFuelStore.ts @@ -69,5 +69,5 @@ export const useSFuelStore = create()((set, get) => ({ setSFuelStatus: (status: 'action' | 'warning' | 'error') => set({ sFuelStatus: status }), sFuelOk: false, - setSFuelOk: (sFuelOk: boolean) => set(() => ({ sFuelOk: sFuelOk })) + setSFuelOk: (sFuelOk: boolean) => set(() => ({ sFuelOk: sFuelOk })), })) From 7ea7643305818ebc53fffe3803701bc62eec68d3 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Tue, 5 Sep 2023 16:45:20 +0100 Subject: [PATCH 38/54] Add wrapped tokens module --- .storybook/preview.ts | 10 + package.json | 2 +- .../CommunityPool/CommunityPool.tsx | 4 +- .../DestTokenBalance/DestTokenBalance.tsx | 3 +- .../MetaportProvider/MetaportProvider.tsx | 8 +- src/components/SFuelWarning/SFuelWarning.tsx | 4 +- src/components/TokenList/TokenList.tsx | 11 +- src/components/WidgetBody/WidgetBody.tsx | 33 ++- src/components/WidgetUI/WidgetUI.tsx | 1 - .../WrappedTokens/WrappedTokens.tsx | 200 ++++++++++++++++++ src/components/WrappedTokens/index.ts | 1 + src/core/actions/action.ts | 66 +++--- src/core/actions/erc20.ts | 71 ++----- src/core/actions/index.ts | 2 + src/core/community_pool.ts | 4 +- src/core/constants.ts | 3 +- src/core/dataclasses/StepMetadata.ts | 1 + src/core/interfaces/ChainsMetadata.ts | 1 + src/core/interfaces/Tokens.ts | 2 +- src/core/metaport.ts | 56 ++++- src/index.ts | 10 +- src/store/MetaportState.ts | 79 ++++++- src/store/Store.ts | 16 ++ src/styles/styles.module.scss | 1 + 24 files changed, 471 insertions(+), 118 deletions(-) create mode 100644 src/components/WrappedTokens/WrappedTokens.tsx create mode 100644 src/components/WrappedTokens/index.ts diff --git a/.storybook/preview.ts b/.storybook/preview.ts index f3f8a70..d20699d 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.ts @@ -2,6 +2,16 @@ import type { Preview } from '@storybook/react' const preview: Preview = { parameters: { + grid: true, + backgrounds: { + default: 'dark', + values: [ + { + name: 'dark', + value: '#222425', + } + ] + }, actions: { argTypesRegex: '^on[A-Z].*' }, controls: { matchers: { diff --git a/package.json b/package.json index 01296b6..a92e70e 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,7 @@ "@mui/icons-material": "^5.8.0", "@mui/lab": "^5.0.0-alpha.88", "@mui/material": "^5.8.1", - "@rainbow-me/rainbowkit": "^1.0.8", + "@rainbow-me/rainbowkit": "^1.0.9", "@skalenetwork/ima-js": "2.0.0-develop.3", "coingecko-api-v3": "^0.0.28", "react-jazzicon": "^1.0.4", diff --git a/src/components/CommunityPool/CommunityPool.tsx b/src/components/CommunityPool/CommunityPool.tsx index 90a3f65..2a1aaba 100644 --- a/src/components/CommunityPool/CommunityPool.tsx +++ b/src/components/CommunityPool/CommunityPool.tsx @@ -45,7 +45,7 @@ import ErrorIcon from '@mui/icons-material/Error' import { fromWei } from '../../core/convertation' import { withdraw, recharge } from '../../core/community_pool' -import { DEFAULT_ERC20_DECIMALS } from '../../core/constants' +import { BALANCE_UPDATE_INTERVAL_MS, DEFAULT_ERC20_DECIMALS } from '../../core/constants' import { cls } from '../../core/helper' import cmn from '../../styles/cmn.module.scss' @@ -104,7 +104,7 @@ export default function CommunityPool() { updateCPData(address, chainName, chainName2, mpc) const intervalId = setInterval(() => { updateCPData(address, chainName, chainName2, mpc) - }, 10000) + }, BALANCE_UPDATE_INTERVAL_MS) return () => { clearInterval(intervalId) // Clear interval on component unmount diff --git a/src/components/DestTokenBalance/DestTokenBalance.tsx b/src/components/DestTokenBalance/DestTokenBalance.tsx index 9f67408..ad4b9ba 100644 --- a/src/components/DestTokenBalance/DestTokenBalance.tsx +++ b/src/components/DestTokenBalance/DestTokenBalance.tsx @@ -3,6 +3,7 @@ import { useAccount } from 'wagmi' import { TokenBalance } from '../TokenList' import { useMetaportStore } from '../../store/MetaportState' +import { BALANCE_UPDATE_INTERVAL_MS } from '../../core/constants' export default function DestTokenBalance() { const { address } = useAccount() @@ -15,7 +16,7 @@ export default function DestTokenBalance() { updateDestTokenBalance(address) // Fetch users immediately on component mount const intervalId = setInterval(() => { updateDestTokenBalance(address) - }, 10000) + }, BALANCE_UPDATE_INTERVAL_MS) return () => { clearInterval(intervalId) // Clear interval on component unmount } diff --git a/src/components/MetaportProvider/MetaportProvider.tsx b/src/components/MetaportProvider/MetaportProvider.tsx index 108458c..2e23c07 100644 --- a/src/components/MetaportProvider/MetaportProvider.tsx +++ b/src/components/MetaportProvider/MetaportProvider.tsx @@ -22,14 +22,14 @@ import { ReactElement, useEffect } from 'react' -import { RainbowKitProvider } from '@rainbow-me/rainbowkit' +import { RainbowKitProvider, darkTheme, lightTheme } from '@rainbow-me/rainbowkit' import { configureChains, createConfig, WagmiConfig } from 'wagmi' import { mainnet, goerli } from 'wagmi/chains' import { jsonRpcProvider } from 'wagmi/providers/jsonRpc' import { connectorsForWallets } from '@rainbow-me/rainbowkit' import { PaletteMode } from '@mui/material' -import { injectedWallet, coinbaseWallet, metaMaskWallet } from '@rainbow-me/rainbowkit/wallets' +import { injectedWallet, coinbaseWallet, metaMaskWallet, enkryptWallet } from '@rainbow-me/rainbowkit/wallets' import { MetaportConfig } from '../../core/interfaces' @@ -81,6 +81,7 @@ const connectors = connectorsForWallets([ groupName: 'Supported Wallets', wallets: [ metaMaskWallet({ chains, projectId: '' }), + enkryptWallet({ chains }), injectedWallet({ chains }), coinbaseWallet({ chains, appName: 'TEST' }), ], @@ -90,7 +91,7 @@ const connectors = connectorsForWallets([ const wagmiConfig = createConfig({ autoConnect: true, connectors, - publicClient: webSocketPublicClient, + publicClient: webSocketPublicClient }) export default function MetaportProvider(props: { @@ -147,6 +148,7 @@ export default function MetaportProvider(props: { }} showRecentTransactions={true} chains={chains} + theme={widgetTheme.mode === 'dark' ? darkTheme() : lightTheme()} > diff --git a/src/components/SFuelWarning/SFuelWarning.tsx b/src/components/SFuelWarning/SFuelWarning.tsx index cff8af1..5f7e8f3 100644 --- a/src/components/SFuelWarning/SFuelWarning.tsx +++ b/src/components/SFuelWarning/SFuelWarning.tsx @@ -31,7 +31,7 @@ import LoadingButton from '@mui/lab/LoadingButton' import { Collapse } from '@mui/material' import LinearProgress from '@mui/material/LinearProgress' -import { MAINNET_CHAIN_NAME, SFUEL_TEXT } from '../../core/constants' +import { BALANCE_UPDATE_INTERVAL_MS, MAINNET_CHAIN_NAME, SFUEL_TEXT } from '../../core/constants' import { Station } from '../../core/sfuel' import { useMetaportStore } from '../../store/MetaportState' @@ -93,7 +93,7 @@ export default function SFuelWarning(props: {}) { updateStationsData() const intervalId = setInterval(() => { updateStationsData() - }, 10000) + }, BALANCE_UPDATE_INTERVAL_MS) return () => { clearInterval(intervalId) // Clear interval on component unmount } diff --git a/src/components/TokenList/TokenList.tsx b/src/components/TokenList/TokenList.tsx index 91dc1e1..49c8851 100644 --- a/src/components/TokenList/TokenList.tsx +++ b/src/components/TokenList/TokenList.tsx @@ -13,19 +13,16 @@ import { getAvailableTokensTotal, getDefaultToken } from '../../core/tokens/help import { cls } from '../../core/helper' -import ErrorMessage from '../ErrorMessage' - import TokenListSection from '../TokenListSection' -import TokenBalance from './TokenBalance' import TokenIcon from '../TokenIcon' import styles from '../../styles/styles.module.scss' import cmn from '../../styles/cmn.module.scss' -import { getTokenName } from '../../core/metadata' import { useCollapseStore } from '../../store/Store' import { useMetaportStore } from '../../store/MetaportState' -import { TokenType, NoTokenPairsMessage } from '../../core/dataclasses' +import { TokenType } from '../../core/dataclasses' +import { BALANCE_UPDATE_INTERVAL_MS } from '../../core/constants' export default function TokenList() { const token = useMetaportStore((state) => state.token) @@ -43,10 +40,10 @@ export default function TokenList() { const { address } = useAccount() useEffect(() => { - updateTokenBalances(address) // Fetch users immediately on component mount + updateTokenBalances(address) const intervalId = setInterval(() => { updateTokenBalances(address) - }, 10000) + }, BALANCE_UPDATE_INTERVAL_MS) return () => { clearInterval(intervalId) // Clear interval on component unmount diff --git a/src/components/WidgetBody/WidgetBody.tsx b/src/components/WidgetBody/WidgetBody.tsx index 6f51cc5..5ff2a72 100644 --- a/src/components/WidgetBody/WidgetBody.tsx +++ b/src/components/WidgetBody/WidgetBody.tsx @@ -17,9 +17,10 @@ import DestTokenBalance from '../DestTokenBalance' import ErrorMessage from '../ErrorMessage' import CommunityPool from '../CommunityPool' import SFuelWarning from '../SFuelWarning' +import SkConnect from '../SkConnect' +import WrappedTokens from '../WrappedTokens' import cmn from '../../styles/cmn.module.scss' -import styles from '../../styles/styles.module.scss' import { cls } from '../../core/helper' import { Collapse } from '@mui/material' import { MAINNET_CHAIN_NAME } from '../../core/constants' @@ -33,6 +34,7 @@ export function WidgetBody(props) { const setExpandedTo = useCollapseStore((state) => state.setExpandedTo) const expandedCP = useCollapseStore((state) => state.expandedCP) + const expandedWT = useCollapseStore((state) => state.expandedWT) const expandedTokens = useCollapseStore((state) => state.expandedTokens) const destChains = useMetaportStore((state) => state.destChains) @@ -50,6 +52,7 @@ export function WidgetBody(props) { const tokenBalances = useMetaportStore((state) => state.tokenBalances) const errorMessage = useMetaportStore((state) => state.errorMessage) + const loading = useMetaportStore((state) => state.loading) const transferInProgress = useMetaportStore((state) => state.transferInProgress) @@ -71,9 +74,9 @@ export function WidgetBody(props) { }, [tokens]) const showFrom = !expandedTo && !expandedTokens && !errorMessage && !expandedCP - const showTo = !expandedFrom && !expandedTokens && !errorMessage && !expandedCP - const showInput = !expandedFrom && !expandedTo && !errorMessage && !expandedCP - const showSwitch = !expandedFrom && !expandedTo && !expandedTokens && !errorMessage && !expandedCP + const showTo = !expandedFrom && !expandedTokens && !errorMessage && !expandedCP && !expandedWT + const showInput = !expandedFrom && !expandedTo && !errorMessage && !expandedCP && !expandedWT + const showSwitch = !expandedFrom && !expandedTo && !expandedTokens && !errorMessage && !expandedCP && !expandedWT const showStepper = !expandedFrom && !expandedTo && @@ -81,9 +84,17 @@ export function WidgetBody(props) { !errorMessage && !expandedCP && sFuelOk && + !expandedWT && !!address const showCP = - !expandedFrom && !expandedTo && !expandedTokens && chainName2 === MAINNET_CHAIN_NAME + !expandedFrom && !expandedTo && !expandedTokens && chainName2 === MAINNET_CHAIN_NAME && !expandedWT + const showWT = !expandedFrom && + !expandedTo && + !expandedTokens && + !errorMessage && + !expandedCP && + sFuelOk && + !!address const showError = !!errorMessage const grayBg = 'rgb(136 135 135 / 15%)' @@ -119,7 +130,7 @@ export function WidgetBody(props) { chains={props.config.chains} setChain={setChainName1} disabledChain={chainName2} - disabled={transferInProgress} + disabled={transferInProgress || loading} from={true} /> @@ -149,7 +160,7 @@ export function WidgetBody(props) { chains={destChains} setChain={setChainName2} disabledChain={chainName1} - disabled={transferInProgress} + disabled={transferInProgress || loading} /> @@ -160,6 +171,13 @@ export function WidgetBody(props) { + + + + + + + @@ -168,6 +186,7 @@ export function WidgetBody(props) { + {!address ? : null}
) } diff --git a/src/components/WidgetUI/WidgetUI.tsx b/src/components/WidgetUI/WidgetUI.tsx index 97bacfc..00221c6 100644 --- a/src/components/WidgetUI/WidgetUI.tsx +++ b/src/components/WidgetUI/WidgetUI.tsx @@ -109,7 +109,6 @@ export function WidgetUI(props: { config: MetaportConfig }) { {/* {address ? :
} */}
- {!address ? : null}
{fabTop ? null : fabButton}
diff --git a/src/components/WrappedTokens/WrappedTokens.tsx b/src/components/WrappedTokens/WrappedTokens.tsx new file mode 100644 index 0000000..0071682 --- /dev/null +++ b/src/components/WrappedTokens/WrappedTokens.tsx @@ -0,0 +1,200 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/** + * @file WrappedTokens.ts + * @copyright SKALE Labs 2023-Present + */ + +import React, { useEffect, useState } from 'react' + +import { useAccount, useWalletClient, useSwitchNetwork } from 'wagmi' + +import Accordion from '@mui/material/Accordion' +import AccordionSummary from '@mui/material/AccordionSummary' +import AccordionDetails from '@mui/material/AccordionDetails' +import LoadingButton from '@mui/lab/LoadingButton' +import Button from '@mui/material/Button' +import ExpandMoreIcon from '@mui/icons-material/ExpandMore' +import ErrorIcon from '@mui/icons-material/Error' + +import SkPaper from '../SkPaper/SkPaper' +import { TokenBalance } from '../TokenList' +import TokenIcon from '../TokenIcon' + +import { getTokenName } from '../../core/metadata' +import { BALANCE_UPDATE_INTERVAL_MS } from '../../core/constants' + +import { cls, getChainAlias } from '../../core/helper' +import cmn from '../../styles/cmn.module.scss' +import styles from '../../styles/styles.module.scss' + +import { useCollapseStore } from '../../store/Store' +import { useMetaportStore } from '../../store/MetaportState' +import { TokenDataMap } from '../../core/interfaces' + +export default function WrappedTokens() { + const { data: walletClient } = useWalletClient() + const { switchNetworkAsync } = useSwitchNetwork() + + const wrappedTokens = useMetaportStore((state) => state.wrappedTokens) + const updateWrappedTokenBalances = useMetaportStore((state) => state.updateWrappedTokenBalances) + const wrappedTokenBalances = useMetaportStore((state) => state.wrappedTokenBalances) + const wrappedTokenContracts = useMetaportStore((state) => state.wrappedTokenContracts) + const unwrapAll = useMetaportStore((state) => state.unwrapAll) + + const loading = useMetaportStore((state) => state.loading) + const setLoading = useMetaportStore((state) => state.setLoading) + + const currentStep = useMetaportStore((state) => state.currentStep) + const chainName1 = useMetaportStore((state) => state.chainName1) + const mpc = useMetaportStore((state) => state.mpc) + + const { address } = useAccount() + + const expandedWT = useCollapseStore((state) => state.expandedWT) + const setExpandedWT = useCollapseStore((state) => state.setExpandedWT) + + + const [filteredTokens, setFilteredTokens] = useState({}) + + useEffect(() => { + updateWrappedTokenBalances(address) + const intervalId = setInterval(() => { + updateWrappedTokenBalances(address) + }, BALANCE_UPDATE_INTERVAL_MS) + return () => { + clearInterval(intervalId) // Clear interval on component unmount + } + }, [updateWrappedTokenBalances, wrappedTokenContracts, address]) + + useEffect(() => { + setFilteredTokens(Object.keys(wrappedTokenBalances).reduce((acc, key) => { + if (wrappedTokenBalances[key] !== 0n) { + acc[key] = wrappedTokens.erc20[key]; + } + return acc; + }, {})); + }, [wrappedTokens, wrappedTokenBalances]) + + useEffect(() => { + if (Object.keys(filteredTokens).length === 0) { + if (expandedWT && loading) { + setExpandedWT(false) + setLoading(false) + } + } + }, [filteredTokens]) + + const handleChange = (panel: string) => (_: React.SyntheticEvent, isExpanded: boolean) => { + setExpandedWT(isExpanded ? panel : false) + } + + if (Object.keys(filteredTokens).length === 0 || currentStep !== 0) return + return ( +
+ + } + aria-controls="panel1a-content" + id="panel1a-header" + > +
+
+

Wrapped tokens found

+
+
+ + +

+ ❗ You have wrapped tokens on {getChainAlias(mpc.config.skaleNetwork, chainName1)}. + Unwrap them before proceeding with your transfer. +

+
+ {Object.keys(filteredTokens).map((key, _) => ( +
+
+ +
+

+ Wrapped {getTokenName(filteredTokens[key])} +

+
+ +
+
+ ))} + +
+ {loading ? ( + + Unwrapping... + + ) : ( + + )} +
+ +
+
+
+
+
+ + ) +} diff --git a/src/components/WrappedTokens/index.ts b/src/components/WrappedTokens/index.ts new file mode 100644 index 0000000..d63087b --- /dev/null +++ b/src/components/WrappedTokens/index.ts @@ -0,0 +1 @@ +export { default } from './WrappedTokens' diff --git a/src/core/actions/action.ts b/src/core/actions/action.ts index 8cfa2f0..f8abe22 100644 --- a/src/core/actions/action.ts +++ b/src/core/actions/action.ts @@ -100,9 +100,7 @@ export class Action { walletClient: WalletClient, ) { this.mpc = mpc - // this.mainnet = mainnet; - // this.sChain1 = sChain1; - // this.sChain2 = sChain2; + this.chainName1 = chainName1 this.chainName2 = chainName2 this.address = address @@ -111,9 +109,6 @@ export class Action { this.tokenId = Number(tokenId) this.token = createTokenData(token.keyname, chainName1, token.type, this.mpc.config) - //! todo: init token here!!!!!, do not pass !!! - - // todo: init token contracts! if (isMainnet(chainName1)) { this.mainnet = this.mpc.mainnet() @@ -129,43 +124,40 @@ export class Action { const provider1 = isMainnet(chainName1) ? this.mainnet.provider : this.sChain1.provider const provider2 = isMainnet(chainName2) ? this.mainnet.provider : this.sChain2.provider - this.sourceToken = mpc.tokenContract( - chainName1, - token.keyname, - token.type, - provider1, - this.token.wrapper(this.chainName2) ? CustomAbiTokenType.erc20wrap : null, - this.token.wrapper(this.chainName2) ? this.chainName2 : null, - ) - - this.originAddress = this.mpc.originAddress(chainName1, chainName2, token.keyname, token.type) - - if (this.token.wrapper(this.chainName2)) { - this.unwrappedToken = mpc.tokenContract(chainName1, token.keyname, token.type, provider1) - } - - // todo: use wrapper address! - const destWrapperAddress = - this.mpc.config.connections[this.chainName2][this.token.type][this.token.keyname].chains[ - this.chainName1 - ].wrapper - if (this.token.isClone(this.chainName2) && destWrapperAddress) { - this.destToken = mpc.tokenContract( - chainName2, + if (this.chainName2) { + this.sourceToken = mpc.tokenContract( + chainName1, token.keyname, token.type, - provider2, - CustomAbiTokenType.erc20wrap, - this.chainName1, + provider1, + this.token.wrapper(this.chainName2) ? CustomAbiTokenType.erc20wrap : null, + this.token.wrapper(this.chainName2) ? this.chainName2 : null, ) - } else { - this.destToken = mpc.tokenContract(chainName2, token.keyname, token.type, provider2) + this.originAddress = this.mpc.originAddress(chainName1, chainName2, token.keyname, token.type) + + if (this.token.wrapper(this.chainName2)) { + this.unwrappedToken = mpc.tokenContract(chainName1, token.keyname, token.type, provider1) + } + + const destWrapperAddress = + this.mpc.config.connections[this.chainName2][this.token.type][this.token.keyname].chains[ + this.chainName1 + ].wrapper + if (this.token.isClone(this.chainName2) && destWrapperAddress) { + this.destToken = mpc.tokenContract( + chainName2, + token.keyname, + token.type, + provider2, + CustomAbiTokenType.erc20wrap, + this.chainName1, + ) + } else { + this.destToken = mpc.tokenContract(chainName2, token.keyname, token.type, provider2) + } } - // this.switchMetamaskChain = switchMetamaskChain; - // this.setActiveStep = setActiveStep; - // this.activeStep = activeStep; this.setAmountErrorMessage = setAmountErrorMessage this.setBtnText = setBtnText diff --git a/src/core/actions/erc20.ts b/src/core/actions/erc20.ts index 6ee8587..41210f7 100644 --- a/src/core/actions/erc20.ts +++ b/src/core/actions/erc20.ts @@ -25,6 +25,7 @@ import debug from 'debug' import { MainnetChain, SChain } from '@skalenetwork/ima-js' +import { findFirstWrapperChainName } from '../metaport' import { externalEvents } from '../events' import { toWei } from '../convertation' import { MAX_APPROVE_AMOUNT } from '../constants' @@ -194,48 +195,29 @@ export class WrapERC20S extends Action { } } -// export class UnWrapERC20S2S123 extends Action { -// static label = 'Unwrap' -// static buttonText = 'Unwrap' -// static loadingText = 'Unwrapping' -// async execute() { -// log('UnWrapERC20S2S:execute - starting'); -// const sChain = await this.getConnectedChain(this.sChain2.provider) as SChain; -// this.updateState('unwrap'); -// try { -// const amountWei = toWei(this.amount, this.token.meta.decimals); -// const tx = await sChain.erc20.unwrap( -// this.token.keyname, -// amountWei, -// { address: this.address } -// ); -// const block = await sChain.provider.getBlock(tx.blockNumber); -// this.updateState('unwrapDone', tx.hash, block.timestamp); -// externalEvents.transactionCompleted(tx, block.timestamp, this.chainName2, 'unwrap'); -// externalEvents.unwrapComplete(tx.hash, this.chainName2, this.token.keyname); -// log('UnWrapERC20S2S:execute - tx completed %O', tx); -// } finally { -// // log('UnWrapERC20S2S:execute - switchMetamaskChain back'); -// // this.switchMetamaskChain(true); -// } -// } +export class UnWrapERC20 extends Action { + async execute() { + const sChain = (await this.getConnectedChain(this.sChain1.provider)) as SChain + this.updateState('unwrap') + const tokenContract = this.mpc.tokenContract( + this.chainName1, + this.token.keyname, + this.token.type, + sChain.provider, + CustomAbiTokenType.erc20wrap, + findFirstWrapperChainName(this.token) + ) + sChain.erc20.addToken(this.token.keyname, tokenContract) + const amountWei = await tokenContract.balanceOf(this.address) + const tx = await sChain.erc20.unwrap(this.token.keyname, amountWei, { address: this.address }) + const block = await sChain.provider.getBlock(tx.blockNumber) + this.updateState('unwrapDone', tx.hash, block.timestamp) + } + + async preAction() { } +} -// async preAction() { -// log('preAction: UnWrapERC20S2S'); -// const tokenContract = this.sChain2.erc20.tokens[this.token.keyname]; -// const checkResBalance = await checkERC20Balance( -// this.address, -// this.amount, -// this.token, -// tokenContract -// ); -// if (!checkResBalance.res) { -// this.setAmountErrorMessage(checkResBalance.msg); -// return -// } -// } -// } export class UnWrapERC20S extends Action { async execute() { @@ -244,15 +226,6 @@ export class UnWrapERC20S extends Action { CustomAbiTokenType.erc20wrap, this.chainName1, )) as SChain - // const token = this.mpc.tokenContract( - // this.chainName2, - // this.token.keyname, - // this.token.type, - // sChain.provider, - // CustomAbiTokenType.erc20wrap, - // this.chainName1 - // ); - // sChain.erc20.addToken(this.token.keyname, token); this.updateState('unwrap') let tx if (this.token.connections[this.chainName2].wrapsSFuel) { diff --git a/src/core/actions/index.ts b/src/core/actions/index.ts index 88f4a87..e4b9ed7 100644 --- a/src/core/actions/index.ts +++ b/src/core/actions/index.ts @@ -28,6 +28,7 @@ import { TransferERC20S2S, WrapERC20S, UnWrapERC20S, + UnWrapERC20, TransferERC20M2S, TransferERC20S2M, } from './erc20' @@ -67,6 +68,7 @@ export const ACTIONS: { [actionType in ActionType]: typeof Action } = { wrap: WrapERC20S, unwrap: UnWrapERC20S, + unwrap_stuck: UnWrapERC20, erc20_m2s: TransferERC20M2S, erc20_s2m: TransferERC20S2M, diff --git a/src/core/community_pool.ts b/src/core/community_pool.ts index 9201aca..081071f 100644 --- a/src/core/community_pool.ts +++ b/src/core/community_pool.ts @@ -38,7 +38,7 @@ import { MINIMUM_RECHARGE_AMOUNT, COMMUNITY_POOL_WITHDRAW_GAS_LIMIT, DEFAULT_ERROR_MSG, - BALANCE_UPDATE_INTERVAL_SECONDS, + BALANCE_UPDATE_INTERVAL_MS, } from './constants' import { delay } from './helper' import { CHAIN_IDS, isMainnetChainId, getMainnetAbi } from './network' @@ -184,7 +184,7 @@ export async function recharge( let activeM = await mainnetMetamask.communityPool.contract.activeUsers(address, chainHash) let activeS = await sChain.communityLocker.contract.activeUsers(address) active = activeS && activeM - await delay(BALANCE_UPDATE_INTERVAL_SECONDS * 1000) + await delay(BALANCE_UPDATE_INTERVAL_MS) counter++ if (counter >= 10) break } diff --git a/src/core/constants.ts b/src/core/constants.ts index dff456a..bfd26cc 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -100,7 +100,8 @@ export const FAUCET_DATA = faucetJson export const RECHARGE_MULTIPLIER = 1.2 export const MINIMUM_RECHARGE_AMOUNT = 0.005 export const COMMUNITY_POOL_WITHDRAW_GAS_LIMIT = 1500000n -export const BALANCE_UPDATE_INTERVAL_SECONDS = 10 +export const _BALANCE_UPDATE_INTERVAL_SECONDS = 10 +export const BALANCE_UPDATE_INTERVAL_MS = _BALANCE_UPDATE_INTERVAL_SECONDS * 1000 export const SFUEL_RESERVE_AMOUNT = 0.02 diff --git a/src/core/dataclasses/StepMetadata.ts b/src/core/dataclasses/StepMetadata.ts index 9a87491..def4b25 100644 --- a/src/core/dataclasses/StepMetadata.ts +++ b/src/core/dataclasses/StepMetadata.ts @@ -36,6 +36,7 @@ export enum ActionType { erc20_s2s = 'erc20_s2s', wrap = 'wrap', unwrap = 'unwrap', + unwrap_stuck = 'unwrap_stuck', eth_m2s = 'eth_m2s', eth_s2m = 'eth_s2m', eth_unlock = 'eth_unlock', diff --git a/src/core/interfaces/ChainsMetadata.ts b/src/core/interfaces/ChainsMetadata.ts index f67b6dd..92a43cc 100644 --- a/src/core/interfaces/ChainsMetadata.ts +++ b/src/core/interfaces/ChainsMetadata.ts @@ -25,6 +25,7 @@ export interface ChainMetadata { alias?: string minSfuelWei?: string faucetUrl?: string + category: string apps?: { [appName: string]: { alias: string diff --git a/src/core/interfaces/Tokens.ts b/src/core/interfaces/Tokens.ts index 262870e..4dbaa6f 100644 --- a/src/core/interfaces/Tokens.ts +++ b/src/core/interfaces/Tokens.ts @@ -32,7 +32,7 @@ export interface Token { export interface ConnectedChain { hub?: string - wrapper?: string + wrapper?: `0x${string}` wrapsSFuel?: boolean clone?: boolean } diff --git a/src/core/metaport.ts b/src/core/metaport.ts index a1b0726..eb6e5a2 100644 --- a/src/core/metaport.ts +++ b/src/core/metaport.ts @@ -38,6 +38,7 @@ import { ERC_ABIS } from './contracts' import debug from 'debug' import { MainnetChain, SChain } from '@skalenetwork/ima-js' +import { interfaces } from '../Metaport' const log = debug('ima:test:MainnetChain') @@ -90,6 +91,39 @@ export const createTokensMap = ( return tokens } + +export function createWrappedTokensMap( + chainName1: string, + config: MetaportConfig +): TokenDataTypesMap { + const wrappedTokens: TokenDataTypesMap = getEmptyTokenDataMap() + const tokenType = TokenType.erc20 + if (!chainName1) return wrappedTokens + Object.keys(config.connections[chainName1][tokenType]).forEach((tokenKeyname) => { + const token = config.connections[chainName1][tokenType][tokenKeyname] + const wrapperAddress = findFirstWrapperAddress(token) + if (wrapperAddress) { + addTokenData(tokenKeyname, chainName1, tokenType as TokenType, config, wrappedTokens) + } + }) + return wrappedTokens +} + + +const findFirstWrapperAddress = (token: interfaces.Token): `0x${string}` | null => + Object.values(token.chains).find(chain => 'wrapper' in chain)?.wrapper || null; + + +export const findFirstWrapperChainName = (token: TokenData): string | null => { + for (const [chainName, chain] of Object.entries(token.connections)) { + if (chain.wrapper) { + return chainName; + } + } + return null; +}; + + export default class MetaportCore { private _config: MetaportConfig @@ -122,6 +156,10 @@ export default class MetaportCore { return createTokensMap(from, to, this._config) } + wrappedTokens(chainName: string): TokenDataTypesMap { + return createWrappedTokensMap(chainName, this._config) + } + async tokenBalance(tokenContract: Contract, address: string): Promise { return await tokenContract.balanceOf(address) } @@ -143,11 +181,25 @@ export default class MetaportCore { tokenType: TokenType, chainName: string, provider: Provider, + customAbiTokenType?: CustomAbiTokenType, + // destChainName?: string ): TokenContractsMap { const contracts: TokenContractsMap = {} if (tokens[tokenType]) { Object.keys(tokens[tokenType]).forEach((tokenKeyname) => { - contracts[tokenKeyname] = this.tokenContract(chainName, tokenKeyname, tokenType, provider) + let destChainName; + if (customAbiTokenType === CustomAbiTokenType.erc20wrap) { + destChainName = findFirstWrapperChainName(tokens[tokenType][tokenKeyname]) + if (!destChainName) return + } + contracts[tokenKeyname] = this.tokenContract( + chainName, + tokenKeyname, + tokenType, + provider, + customAbiTokenType, + destChainName + ) }) } return contracts @@ -159,7 +211,7 @@ export default class MetaportCore { tokenType: TokenType, provider: Provider, customAbiTokenType?: CustomAbiTokenType, - destChainName?: string, + destChainName?: string ): Contract | undefined { let type = tokenType const token = this._config.connections[chainName][tokenType][tokenKeyname] diff --git a/src/index.ts b/src/index.ts index 5bf1482..95bdcec 100644 --- a/src/index.ts +++ b/src/index.ts @@ -25,9 +25,12 @@ import DestTokenBalance from './components/DestTokenBalance' import ErrorMessage from './components/ErrorMessage' import CommunityPool from './components/CommunityPool' import SFuelWarning from './components/SFuelWarning' +import WrappedTokens from './components/WrappedTokens' -import { cls } from './core/helper' +import { cls, CHAINS_META, getChainAlias } from './core/helper' +import MetaportCore from './core/metaport' import { chainBg } from './core/metadata' +import { BASE_EXPLORER_URLS } from './core/constants' import styles from './styles/styles.module.scss' import cmn from './styles/cmn.module.scss' @@ -40,6 +43,7 @@ import { PROXY_ENDPOINTS } from './core/network' export { Metaport, MetaportProvider, + MetaportCore, SkPaper, SkConnect, ChainIcon, @@ -57,11 +61,15 @@ export { ErrorMessage, CommunityPool, SFuelWarning, + WrappedTokens, cls, styles, cmn, getMetaportTheme, useWagmiAccount, PROXY_ENDPOINTS, + BASE_EXPLORER_URLS, + CHAINS_META, chainBg, + getChainAlias } diff --git a/src/store/MetaportState.ts b/src/store/MetaportState.ts index b50acf0..13344ca 100644 --- a/src/store/MetaportState.ts +++ b/src/store/MetaportState.ts @@ -62,6 +62,14 @@ interface MetaportState { switchNetwork: (chainId: number) => void, walletClient: WalletClient, ) => void + + unwrapAll: ( + address: string, + switchNetwork: (chainId: number) => void, + walletClient: WalletClient, + tokens: interfaces.TokenDataMap + ) => void + check: (amount: string, address: `0x${string}`) => void currentStep: number @@ -87,6 +95,11 @@ interface MetaportState { tokenBalances: interfaces.TokenBalancesMap updateTokenBalances: (address: string) => Promise + wrappedTokens: interfaces.TokenDataTypesMap + wrappedTokenContracts: interfaces.TokenContractsMap + wrappedTokenBalances: interfaces.TokenBalancesMap + updateWrappedTokenBalances: (address: string) => Promise + destTokenContract: Contract destTokenBalance: bigint updateDestTokenBalance: (address: string) => Promise @@ -139,10 +152,50 @@ export const useMetaportStore = create()((set, get) => ({ set((state) => { state.check(amount, address) return { - amount: amount, + amount: amount } }), + + unwrapAll: async ( + address: `0x${string}`, + switchNetwork: any, + walletClient: WalletClient, + tokens: interfaces.TokenDataMap + ) => { + log('Running unwrapAll') + set({ loading: true }) + try { + for (const key of Object.keys(tokens)) { + await new ACTIONS.unwrap_stuck( + get().mpc, + get().chainName1, + null, + address, + get().amount, + get().tokenId, + tokens[key], + get().setAmountErrorMessage, + get().setBtnText, + switchNetwork, + walletClient, + ).execute() + } + } catch (err) { + console.error(err) + const msg = err.message ? err.message : DEFAULT_ERROR_MSG + set({ + errorMessage: new dataclasses.TransactionErrorMessage( + msg, + get().errorMessageClosedFallback + ) + }) + return + } finally { + set({ loading: false }) + } + }, + execute: async (address: `0x${string}`, switchNetwork: any, walletClient: WalletClient) => { log('Running execute') if (get().stepsMetadata[get().currentStep]) { @@ -262,6 +315,13 @@ export const useMetaportStore = create()((set, get) => ({ name, provider, ) + const wrappedTokenContracts = state.mpc.tokenContracts( + tokens, + dataclasses.TokenType.erc20, + name, + provider, + dataclasses.CustomAbiTokenType.erc20wrap + ) return { currentStep: 0, token: null, @@ -270,6 +330,9 @@ export const useMetaportStore = create()((set, get) => ({ tokenContracts: tokenContracts, tokenBalances: {}, destChains: get().mpc.config.chains, + wrappedTokens: get().mpc.wrappedTokens(name), + wrappedTokenContracts: wrappedTokenContracts, + wrappedTokenBalances: {}, ...updState, } }), @@ -317,9 +380,13 @@ export const useMetaportStore = create()((set, get) => ({ }) }, + wrappedTokens: getEmptyTokenDataMap(), tokenContracts: {}, tokenBalances: {}, + wrappedTokenContracts: {}, + wrappedTokenBalances: {}, + destTokenContract: null, destTokenBalance: null, @@ -356,6 +423,16 @@ export const useMetaportStore = create()((set, get) => ({ }) }, + updateWrappedTokenBalances: async (address: string) => { + if (!address) { + set({ wrappedTokenBalances: {} }) + return + } + set({ + wrappedTokenBalances: await get().mpc.tokenBalances(get().wrappedTokenContracts, address) + }) + }, + amountErrorMessage: null, setAmountErrorMessage: (em: string) => set(() => ({ amountErrorMessage: em })), diff --git a/src/store/Store.ts b/src/store/Store.ts index cb63089..e695a72 100644 --- a/src/store/Store.ts +++ b/src/store/Store.ts @@ -50,6 +50,9 @@ interface CollapseState { expandedCP: string | false setExpandedCP: (expanded: string | false) => void + + expandedWT: string | false + setExpandedWT: (expanded: string | false) => void } export const useCollapseStore = create()((set) => ({ @@ -60,6 +63,7 @@ export const useCollapseStore = create()((set) => ({ expandedTo: false, expandedTokens: false, expandedCP: false, + expandedWT: false })), expandedTo: false, setExpandedTo: (expanded: string | false) => @@ -68,6 +72,7 @@ export const useCollapseStore = create()((set) => ({ expandedFrom: false, expandedTokens: false, expandedCP: false, + expandedWT: false })), expandedTokens: false, setExpandedTokens: (expanded: string | false) => @@ -76,6 +81,7 @@ export const useCollapseStore = create()((set) => ({ expandedFrom: false, expandedTo: false, expandedCP: false, + expandedWT: false })), expandedCP: false, setExpandedCP: (expanded: string | false) => @@ -84,5 +90,15 @@ export const useCollapseStore = create()((set) => ({ expandedFrom: false, expandedTo: false, expandedTokens: false, + expandedWT: false + })), + expandedWT: false, + setExpandedWT: (expanded: string | false) => + set(() => ({ + expandedCP: false, + expandedFrom: false, + expandedTo: false, + expandedTokens: false, + expandedWT: expanded })), })) diff --git a/src/styles/styles.module.scss b/src/styles/styles.module.scss index a788335..d270baa 100644 --- a/src/styles/styles.module.scss +++ b/src/styles/styles.module.scss @@ -152,6 +152,7 @@ button { .widgetContent { max-height: calc(100vh - 180px); overflow-y: auto; + border-radius: $sk-border-radius-outter !important; } From 4fd600903ced1d86be5ebfc51901ca6c46a45060 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Tue, 5 Sep 2023 16:46:23 +0100 Subject: [PATCH 39/54] Run prettier --- .../MetaportProvider/MetaportProvider.tsx | 9 +++-- src/components/WidgetBody/WidgetBody.tsx | 12 +++++-- .../WrappedTokens/WrappedTokens.tsx | 33 +++++++++++-------- src/core/actions/action.ts | 2 -- src/core/actions/erc20.ts | 6 ++-- src/core/metaport.ts | 20 +++++------ src/index.ts | 2 +- src/store/MetaportState.ts | 15 ++++----- src/store/Store.ts | 10 +++--- 9 files changed, 59 insertions(+), 50 deletions(-) diff --git a/src/components/MetaportProvider/MetaportProvider.tsx b/src/components/MetaportProvider/MetaportProvider.tsx index 2e23c07..4e8bf84 100644 --- a/src/components/MetaportProvider/MetaportProvider.tsx +++ b/src/components/MetaportProvider/MetaportProvider.tsx @@ -29,7 +29,12 @@ import { jsonRpcProvider } from 'wagmi/providers/jsonRpc' import { connectorsForWallets } from '@rainbow-me/rainbowkit' import { PaletteMode } from '@mui/material' -import { injectedWallet, coinbaseWallet, metaMaskWallet, enkryptWallet } from '@rainbow-me/rainbowkit/wallets' +import { + injectedWallet, + coinbaseWallet, + metaMaskWallet, + enkryptWallet, +} from '@rainbow-me/rainbowkit/wallets' import { MetaportConfig } from '../../core/interfaces' @@ -91,7 +96,7 @@ const connectors = connectorsForWallets([ const wagmiConfig = createConfig({ autoConnect: true, connectors, - publicClient: webSocketPublicClient + publicClient: webSocketPublicClient, }) export default function MetaportProvider(props: { diff --git a/src/components/WidgetBody/WidgetBody.tsx b/src/components/WidgetBody/WidgetBody.tsx index 5ff2a72..04fbd48 100644 --- a/src/components/WidgetBody/WidgetBody.tsx +++ b/src/components/WidgetBody/WidgetBody.tsx @@ -76,7 +76,8 @@ export function WidgetBody(props) { const showFrom = !expandedTo && !expandedTokens && !errorMessage && !expandedCP const showTo = !expandedFrom && !expandedTokens && !errorMessage && !expandedCP && !expandedWT const showInput = !expandedFrom && !expandedTo && !errorMessage && !expandedCP && !expandedWT - const showSwitch = !expandedFrom && !expandedTo && !expandedTokens && !errorMessage && !expandedCP && !expandedWT + const showSwitch = + !expandedFrom && !expandedTo && !expandedTokens && !errorMessage && !expandedCP && !expandedWT const showStepper = !expandedFrom && !expandedTo && @@ -87,8 +88,13 @@ export function WidgetBody(props) { !expandedWT && !!address const showCP = - !expandedFrom && !expandedTo && !expandedTokens && chainName2 === MAINNET_CHAIN_NAME && !expandedWT - const showWT = !expandedFrom && + !expandedFrom && + !expandedTo && + !expandedTokens && + chainName2 === MAINNET_CHAIN_NAME && + !expandedWT + const showWT = + !expandedFrom && !expandedTo && !expandedTokens && !errorMessage && diff --git a/src/components/WrappedTokens/WrappedTokens.tsx b/src/components/WrappedTokens/WrappedTokens.tsx index 0071682..869b876 100644 --- a/src/components/WrappedTokens/WrappedTokens.tsx +++ b/src/components/WrappedTokens/WrappedTokens.tsx @@ -70,7 +70,6 @@ export default function WrappedTokens() { const expandedWT = useCollapseStore((state) => state.expandedWT) const setExpandedWT = useCollapseStore((state) => state.setExpandedWT) - const [filteredTokens, setFilteredTokens] = useState({}) useEffect(() => { @@ -84,12 +83,14 @@ export default function WrappedTokens() { }, [updateWrappedTokenBalances, wrappedTokenContracts, address]) useEffect(() => { - setFilteredTokens(Object.keys(wrappedTokenBalances).reduce((acc, key) => { - if (wrappedTokenBalances[key] !== 0n) { - acc[key] = wrappedTokens.erc20[key]; - } - return acc; - }, {})); + setFilteredTokens( + Object.keys(wrappedTokenBalances).reduce((acc, key) => { + if (wrappedTokenBalances[key] !== 0n) { + acc[key] = wrappedTokens.erc20[key] + } + return acc + }, {}), + ) }, [wrappedTokens, wrappedTokenBalances]) useEffect(() => { @@ -120,8 +121,12 @@ export default function WrappedTokens() { id="panel1a-header" >
-
-

Wrapped tokens found

+
+ +
+

+ Wrapped tokens found +

@@ -156,7 +161,9 @@ export default function WrappedTokens() {
unwrapAll(address, switchNetworkAsync, walletClient, filteredTokens)} + onClick={() => + unwrapAll(address, switchNetworkAsync, walletClient, filteredTokens) + } > Unwrap all )}
-
- ) } diff --git a/src/core/actions/action.ts b/src/core/actions/action.ts index f8abe22..ed7e920 100644 --- a/src/core/actions/action.ts +++ b/src/core/actions/action.ts @@ -157,8 +157,6 @@ export class Action { } } - - this.setAmountErrorMessage = setAmountErrorMessage this.setBtnText = setBtnText this._switchNetwork = switchNetwork diff --git a/src/core/actions/erc20.ts b/src/core/actions/erc20.ts index 41210f7..61e663c 100644 --- a/src/core/actions/erc20.ts +++ b/src/core/actions/erc20.ts @@ -195,7 +195,6 @@ export class WrapERC20S extends Action { } } - export class UnWrapERC20 extends Action { async execute() { const sChain = (await this.getConnectedChain(this.sChain1.provider)) as SChain @@ -206,7 +205,7 @@ export class UnWrapERC20 extends Action { this.token.type, sChain.provider, CustomAbiTokenType.erc20wrap, - findFirstWrapperChainName(this.token) + findFirstWrapperChainName(this.token), ) sChain.erc20.addToken(this.token.keyname, tokenContract) const amountWei = await tokenContract.balanceOf(this.address) @@ -215,10 +214,9 @@ export class UnWrapERC20 extends Action { this.updateState('unwrapDone', tx.hash, block.timestamp) } - async preAction() { } + async preAction() {} } - export class UnWrapERC20S extends Action { async execute() { const sChain = (await this.getConnectedChain( diff --git a/src/core/metaport.ts b/src/core/metaport.ts index eb6e5a2..4b12a4f 100644 --- a/src/core/metaport.ts +++ b/src/core/metaport.ts @@ -91,10 +91,9 @@ export const createTokensMap = ( return tokens } - export function createWrappedTokensMap( chainName1: string, - config: MetaportConfig + config: MetaportConfig, ): TokenDataTypesMap { const wrappedTokens: TokenDataTypesMap = getEmptyTokenDataMap() const tokenType = TokenType.erc20 @@ -109,20 +108,17 @@ export function createWrappedTokensMap( return wrappedTokens } - const findFirstWrapperAddress = (token: interfaces.Token): `0x${string}` | null => - Object.values(token.chains).find(chain => 'wrapper' in chain)?.wrapper || null; - + Object.values(token.chains).find((chain) => 'wrapper' in chain)?.wrapper || null export const findFirstWrapperChainName = (token: TokenData): string | null => { for (const [chainName, chain] of Object.entries(token.connections)) { if (chain.wrapper) { - return chainName; + return chainName } } - return null; -}; - + return null +} export default class MetaportCore { private _config: MetaportConfig @@ -187,7 +183,7 @@ export default class MetaportCore { const contracts: TokenContractsMap = {} if (tokens[tokenType]) { Object.keys(tokens[tokenType]).forEach((tokenKeyname) => { - let destChainName; + let destChainName if (customAbiTokenType === CustomAbiTokenType.erc20wrap) { destChainName = findFirstWrapperChainName(tokens[tokenType][tokenKeyname]) if (!destChainName) return @@ -198,7 +194,7 @@ export default class MetaportCore { tokenType, provider, customAbiTokenType, - destChainName + destChainName, ) }) } @@ -211,7 +207,7 @@ export default class MetaportCore { tokenType: TokenType, provider: Provider, customAbiTokenType?: CustomAbiTokenType, - destChainName?: string + destChainName?: string, ): Contract | undefined { let type = tokenType const token = this._config.connections[chainName][tokenType][tokenKeyname] diff --git a/src/index.ts b/src/index.ts index 95bdcec..c1b6042 100644 --- a/src/index.ts +++ b/src/index.ts @@ -71,5 +71,5 @@ export { BASE_EXPLORER_URLS, CHAINS_META, chainBg, - getChainAlias + getChainAlias, } diff --git a/src/store/MetaportState.ts b/src/store/MetaportState.ts index 13344ca..ac764f2 100644 --- a/src/store/MetaportState.ts +++ b/src/store/MetaportState.ts @@ -67,7 +67,7 @@ interface MetaportState { address: string, switchNetwork: (chainId: number) => void, walletClient: WalletClient, - tokens: interfaces.TokenDataMap + tokens: interfaces.TokenDataMap, ) => void check: (amount: string, address: `0x${string}`) => void @@ -152,16 +152,15 @@ export const useMetaportStore = create()((set, get) => ({ set((state) => { state.check(amount, address) return { - amount: amount + amount: amount, } }), - unwrapAll: async ( address: `0x${string}`, switchNetwork: any, walletClient: WalletClient, - tokens: interfaces.TokenDataMap + tokens: interfaces.TokenDataMap, ) => { log('Running unwrapAll') set({ loading: true }) @@ -187,8 +186,8 @@ export const useMetaportStore = create()((set, get) => ({ set({ errorMessage: new dataclasses.TransactionErrorMessage( msg, - get().errorMessageClosedFallback - ) + get().errorMessageClosedFallback, + ), }) return } finally { @@ -320,7 +319,7 @@ export const useMetaportStore = create()((set, get) => ({ dataclasses.TokenType.erc20, name, provider, - dataclasses.CustomAbiTokenType.erc20wrap + dataclasses.CustomAbiTokenType.erc20wrap, ) return { currentStep: 0, @@ -429,7 +428,7 @@ export const useMetaportStore = create()((set, get) => ({ return } set({ - wrappedTokenBalances: await get().mpc.tokenBalances(get().wrappedTokenContracts, address) + wrappedTokenBalances: await get().mpc.tokenBalances(get().wrappedTokenContracts, address), }) }, diff --git a/src/store/Store.ts b/src/store/Store.ts index e695a72..b97b73c 100644 --- a/src/store/Store.ts +++ b/src/store/Store.ts @@ -63,7 +63,7 @@ export const useCollapseStore = create()((set) => ({ expandedTo: false, expandedTokens: false, expandedCP: false, - expandedWT: false + expandedWT: false, })), expandedTo: false, setExpandedTo: (expanded: string | false) => @@ -72,7 +72,7 @@ export const useCollapseStore = create()((set) => ({ expandedFrom: false, expandedTokens: false, expandedCP: false, - expandedWT: false + expandedWT: false, })), expandedTokens: false, setExpandedTokens: (expanded: string | false) => @@ -81,7 +81,7 @@ export const useCollapseStore = create()((set) => ({ expandedFrom: false, expandedTo: false, expandedCP: false, - expandedWT: false + expandedWT: false, })), expandedCP: false, setExpandedCP: (expanded: string | false) => @@ -90,7 +90,7 @@ export const useCollapseStore = create()((set) => ({ expandedFrom: false, expandedTo: false, expandedTokens: false, - expandedWT: false + expandedWT: false, })), expandedWT: false, setExpandedWT: (expanded: string | false) => @@ -99,6 +99,6 @@ export const useCollapseStore = create()((set) => ({ expandedFrom: false, expandedTo: false, expandedTokens: false, - expandedWT: expanded + expandedWT: expanded, })), })) From abe40aa3b05521ea0fb5f04b6f0af1c6f6c0ff26 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Thu, 7 Sep 2023 21:54:35 +0100 Subject: [PATCH 40/54] Add an ability to select apps --- package.json | 2 +- src/components/ChainApps/ChainApps.tsx | 80 ++++++++++++------- src/components/ChainsList/ChainsList.tsx | 60 +++++++++----- .../CommunityPool/CommunityPool.tsx | 2 +- src/components/SFuelWarning/SFuelWarning.tsx | 4 +- src/components/Stepper/SkStepper.tsx | 32 +++++--- .../SwitchDirection/SwitchDirection.tsx | 12 ++- src/components/WidgetBody/WidgetBody.tsx | 19 +++-- .../WrappedTokens/WrappedTokens.tsx | 3 +- src/core/metadata.ts | 2 +- src/index.ts | 6 +- src/store/MetaportState.ts | 43 +++++++--- src/store/SFuelStore.ts | 8 +- src/store/Store.ts | 5 +- src/styles/cmn.module.scss | 11 +++ src/styles/styles.module.scss | 15 ++++ 16 files changed, 209 insertions(+), 95 deletions(-) diff --git a/package.json b/package.json index a92e70e..b1b0a86 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "prettier": "prettier --write \"src/**/*.{ts,tsx,js,mdx}\"", "test": "vitest", "test:cov": "vitest run --coverage", - "prepack": "json -f package.json -I -e \"delete this.devDependencies; delete this.dependencies\"" + "dprepack": "json -f package.json -I -e \"delete this.devDependencies; delete this.dependencies\"" }, "devDependencies": { "@storybook/addon-essentials": "7.3.2", diff --git a/src/components/ChainApps/ChainApps.tsx b/src/components/ChainApps/ChainApps.tsx index 245edd4..67c3196 100644 --- a/src/components/ChainApps/ChainApps.tsx +++ b/src/components/ChainApps/ChainApps.tsx @@ -6,10 +6,13 @@ import cmn from '../../styles/cmn.module.scss' import { SkaleNetwork } from '../../core/interfaces' import ChainIcon from '../ChainIcon' +import { Button } from '@mui/material' +import KeyboardArrowRightRoundedIcon from '@mui/icons-material/KeyboardArrowRightRounded' export default function ChainApps(props: { skaleNetwork: SkaleNetwork chain: string + handle?: (schainName: string, app?: string) => void size?: 'sm' | 'md' }) { const apps = getChainAppsMeta(props.chain, props.skaleNetwork) @@ -20,41 +23,58 @@ export default function ChainApps(props: { return (
-
+
{Object.keys(apps).map((key, _) => ( -
props.handle(props.chain, key)} + size="small" + color="inherit" + className={cls([cmn.mleft10, size === 'sm'], [cmn.mleft20, size === 'md'], cmn.mbott5)} > - -

- {getChainAlias(props.skaleNetwork, props.chain, key)} -

-
+ +

+ {getChainAlias(props.skaleNetwork, props.chain, key)} +

+
+ +
+ ))}
diff --git a/src/components/ChainsList/ChainsList.tsx b/src/components/ChainsList/ChainsList.tsx index 3acfed5..3fa9429 100644 --- a/src/components/ChainsList/ChainsList.tsx +++ b/src/components/ChainsList/ChainsList.tsx @@ -4,7 +4,6 @@ import AccordionDetails from '@mui/material/AccordionDetails' import AccordionSummary from '@mui/material/AccordionSummary' import Typography from '@mui/material/Typography' import ExpandMoreIcon from '@mui/icons-material/ExpandMore' -import Tooltip from '@mui/material/Tooltip' import Button from '@mui/material/Button' import KeyboardArrowRightRoundedIcon from '@mui/icons-material/KeyboardArrowRightRounded' @@ -13,9 +12,10 @@ import ChainIcon from '../ChainIcon' import { MetaportConfig } from '../../core/interfaces' -import { cls, getChainAlias } from '../../core/helper' +import { cls, getChainAlias, getChainAppsMeta } from '../../core/helper' import cmn from '../../styles/cmn.module.scss' import styles from '../../styles/styles.module.scss' +import SkPaper from '../SkPaper/SkPaper' export default function ChainsList(props: { config: MetaportConfig @@ -23,6 +23,8 @@ export default function ChainsList(props: { setExpanded: (expanded: string | false) => void setChain: (chain: string) => void chain: string + setApp: (chain: string) => void + app: string chains: string[] disabledChain: string from?: boolean @@ -36,14 +38,16 @@ export default function ChainsList(props: { const schainNames = [] for (let chain of props.chains) { - if (chain != props.disabledChain && chain != props.chain) { + const isHub = chain == props.chain && getChainAppsMeta(props.chain, props.config.skaleNetwork) + if (chain !== props.disabledChain && (chain != props.chain || isHub)) { schainNames.push(chain) } } - function handle(schainName) { + function handle(schainName: string, app?: string) { props.setExpanded(false) props.setChain(schainName) + props.setApp(app) } const size = props.size ?? 'sm' @@ -76,6 +80,7 @@ export default function ChainsList(props: { skaleNetwork={props.config.skaleNetwork} chainName={props.chain} size={size} + app={props.app} />

- {getChainAlias(props.config.skaleNetwork, props.chain)} + {getChainAlias(props.config.skaleNetwork, props.chain, props.app)}

- {/*
- -
*/} +
+ {props.app ? ( + +

+ on {getChainAlias(props.config.skaleNetwork, props.chain)?.split(' ')[0]} +

+
+ ) : null} +
) : (
@@ -116,9 +138,9 @@ export default function ChainsList(props: { className={cls(cmn.chainsList, cmn.mbott10, cmn.mri10)} style={{ marginLeft: '8px' }} > -
- -
+ {/*
+ +
*/} {schainNames.map((name) => (
- +
))} diff --git a/src/components/CommunityPool/CommunityPool.tsx b/src/components/CommunityPool/CommunityPool.tsx index 2a1aaba..0d7a316 100644 --- a/src/components/CommunityPool/CommunityPool.tsx +++ b/src/components/CommunityPool/CommunityPool.tsx @@ -79,7 +79,7 @@ export default function CommunityPool() { const { address } = useAccount() let chainName - if (token) { + if (token && chainName2) { chainName = chainName1 if (token.connections[chainName2].hub) chainName = token.connections[chainName2].hub } diff --git a/src/components/SFuelWarning/SFuelWarning.tsx b/src/components/SFuelWarning/SFuelWarning.tsx index 5f7e8f3..7d52a3d 100644 --- a/src/components/SFuelWarning/SFuelWarning.tsx +++ b/src/components/SFuelWarning/SFuelWarning.tsx @@ -74,7 +74,7 @@ export default function SFuelWarning(props: {}) { let hubChain - if (token && token.connections[chainName2].hub) { + if (token && chainName2 && token.connections[chainName2].hub) { hubChain = token.connections[chainName2].hub } @@ -191,7 +191,7 @@ export default function SFuelWarning(props: {}) { return SFUEL_TEXT['sfuel'][sFuelStatus] } - if (loading) + if (loading && chainName2) return (
diff --git a/src/components/Stepper/SkStepper.tsx b/src/components/Stepper/SkStepper.tsx index 07c7b84..22859a3 100644 --- a/src/components/Stepper/SkStepper.tsx +++ b/src/components/Stepper/SkStepper.tsx @@ -22,6 +22,7 @@ import { SkaleNetwork } from '../../core/interfaces' import { useWalletClient } from 'wagmi' import SettingsBackupRestoreRoundedIcon from '@mui/icons-material/SettingsBackupRestoreRounded' +import TollIcon from '@mui/icons-material/Toll' import { useSwitchNetwork, useAccount } from 'wagmi' import { SUCCESS_EMOJIS } from '../../core/constants' @@ -137,15 +138,28 @@ export default function SkStepper(props: { skaleNetwork: SkaleNetwork }) { {emoji} Transfer completed

- +
+ + +
)} diff --git a/src/components/SwitchDirection/SwitchDirection.tsx b/src/components/SwitchDirection/SwitchDirection.tsx index 93be651..5c5c08f 100644 --- a/src/components/SwitchDirection/SwitchDirection.tsx +++ b/src/components/SwitchDirection/SwitchDirection.tsx @@ -16,9 +16,14 @@ export default function SwitchDirection() { const chainName1 = useMetaportStore((state) => state.chainName1) const chainName2 = useMetaportStore((state) => state.chainName2) - const setChainName1 = useMetaportStore((state) => state.setChainName1) const setChainName2 = useMetaportStore((state) => state.setChainName2) + + const appName1 = useMetaportStore((state) => state.appName1) + const appName2 = useMetaportStore((state) => state.appName2) + const setAppName1 = useMetaportStore((state) => state.setAppName1) + const setAppName2 = useMetaportStore((state) => state.setAppName2) + const startOver = useMetaportStore((state) => state.startOver) const loading = useMetaportStore((state) => state.loading) const transferInProgress = useMetaportStore((state) => state.transferInProgress) @@ -55,9 +60,12 @@ export default function SwitchDirection() { } } rotate() - let chain1 = chainName1 + const chain1 = chainName1 + const app1 = appName1 setChainName1(chainName2) + setAppName1(appName2) setChainName2(chain1) + setAppName2(app1) startOver() }} > diff --git a/src/components/WidgetBody/WidgetBody.tsx b/src/components/WidgetBody/WidgetBody.tsx index 04fbd48..17d5a8d 100644 --- a/src/components/WidgetBody/WidgetBody.tsx +++ b/src/components/WidgetBody/WidgetBody.tsx @@ -40,12 +40,17 @@ export function WidgetBody(props) { const destChains = useMetaportStore((state) => state.destChains) const token = useMetaportStore((state) => state.token) + const chainName1 = useMetaportStore((state) => state.chainName1) const chainName2 = useMetaportStore((state) => state.chainName2) - const setChainName1 = useMetaportStore((state) => state.setChainName1) const setChainName2 = useMetaportStore((state) => state.setChainName2) + const appName1 = useMetaportStore((state) => state.appName1) + const appName2 = useMetaportStore((state) => state.appName2) + const setAppName1 = useMetaportStore((state) => state.setAppName1) + const setAppName2 = useMetaportStore((state) => state.setAppName2) + const mpc = useMetaportStore((state) => state.mpc) const tokens = useMetaportStore((state) => state.tokens) const setToken = useMetaportStore((state) => state.setToken) @@ -104,8 +109,8 @@ export function WidgetBody(props) { const showError = !!errorMessage const grayBg = 'rgb(136 135 135 / 15%)' - const sourceBg = theme.vibrant ? chainBg(mpc.config.skaleNetwork, chainName1) : grayBg - const destBg = theme.vibrant ? chainBg(mpc.config.skaleNetwork, chainName2) : grayBg + const sourceBg = theme.vibrant ? chainBg(mpc.config.skaleNetwork, chainName1, appName1) : grayBg + const destBg = theme.vibrant ? chainBg(mpc.config.skaleNetwork, chainName2, appName2) : grayBg return (
@@ -135,8 +140,10 @@ export function WidgetBody(props) { chain={chainName1} chains={props.config.chains} setChain={setChainName1} + setApp={setAppName1} + app={appName1} disabledChain={chainName2} - disabled={transferInProgress || loading} + disabled={transferInProgress} from={true} /> @@ -165,8 +172,10 @@ export function WidgetBody(props) { chain={chainName2} chains={destChains} setChain={setChainName2} + setApp={setAppName2} + app={appName2} disabledChain={chainName1} - disabled={transferInProgress || loading} + disabled={transferInProgress} /> diff --git a/src/components/WrappedTokens/WrappedTokens.tsx b/src/components/WrappedTokens/WrappedTokens.tsx index 869b876..671df9c 100644 --- a/src/components/WrappedTokens/WrappedTokens.tsx +++ b/src/components/WrappedTokens/WrappedTokens.tsx @@ -64,6 +64,7 @@ export default function WrappedTokens() { const currentStep = useMetaportStore((state) => state.currentStep) const chainName1 = useMetaportStore((state) => state.chainName1) const mpc = useMetaportStore((state) => state.mpc) + const transferInProgress = useMetaportStore((state) => state.transferInProgress) const { address } = useAccount() @@ -106,7 +107,7 @@ export default function WrappedTokens() { setExpandedWT(isExpanded ? panel : false) } - if (Object.keys(filteredTokens).length === 0 || currentStep !== 0) return + if (Object.keys(filteredTokens).length === 0 || currentStep !== 0 || transferInProgress) return return (
void sChain1: SChain @@ -81,11 +81,17 @@ interface MetaportState { chainName1: string chainName2: string - destChains: string[] - setChainName1: (name: string) => void setChainName2: (name: string) => void + appName1: string + appName2: string + + setAppName1: (name: string) => void + setAppName2: (name: string) => void + + destChains: string[] + tokens: interfaces.TokenDataTypesMap token: dataclasses.TokenData @@ -294,6 +300,12 @@ export const useMetaportStore = create()((set, get) => ({ chainName1: '', chainName2: '', + appName1: null, + appName2: null, + + setAppName1: (name: string) => set(() => ({ appName1: name })), + setAppName2: (name: string) => set(() => ({ appName2: name })), + destChains: [], setChainName1: (name: string) => @@ -359,16 +371,21 @@ export const useMetaportStore = create()((set, get) => ({ token: null, setToken: async (token: dataclasses.TokenData) => { - const provider = - get().chainName2 === MAINNET_CHAIN_NAME ? get().mainnetChain.provider : get().sChain2.provider - const destTokenContract = get().mpc.tokenContract( - get().chainName2, - token.keyname, - token.type, - provider, - null, - get().chainName1, - ) + let destTokenContract + if (get().chainName2) { + const provider = + get().chainName2 === MAINNET_CHAIN_NAME + ? get().mainnetChain.provider + : get().sChain2.provider + destTokenContract = get().mpc.tokenContract( + get().chainName2, + token.keyname, + token.type, + provider, + null, + get().chainName1, + ) + } set({ token: token, stepsMetadata: getStepsMetadata(get().mpc.config, token, get().chainName2), diff --git a/src/store/SFuelStore.ts b/src/store/SFuelStore.ts index 1aec7ad..fd36951 100644 --- a/src/store/SFuelStore.ts +++ b/src/store/SFuelStore.ts @@ -22,13 +22,9 @@ */ import { create } from 'zustand' -import { MainnetChain, SChain } from '@skalenetwork/ima-js' +import { Station } from '../core/sfuel' -import * as interfaces from '../core/interfaces' -import { Station, StationData } from '../core/sfuel' -import MetaportCore from '../core/metaport' - -interface SFuelState { +export interface SFuelState { loading: boolean setLoading: (loading: boolean) => void mining: boolean diff --git a/src/store/Store.ts b/src/store/Store.ts index b97b73c..eb8dabf 100644 --- a/src/store/Store.ts +++ b/src/store/Store.ts @@ -22,10 +22,9 @@ */ import { create } from 'zustand' - import * as interfaces from '../core/interfaces' -interface UIState { +export interface UIState { theme: interfaces.MetaportTheme setTheme: (theme: interfaces.MetaportTheme) => void open: boolean @@ -39,7 +38,7 @@ export const useUIStore = create()((set) => ({ setOpen: (isOpen: boolean) => set(() => ({ open: isOpen })), })) -interface CollapseState { +export interface CollapseState { expandedFrom: string | false setExpandedFrom: (expanded: string | false) => void expandedTo: string | false diff --git a/src/styles/cmn.module.scss b/src/styles/cmn.module.scss index eb499ad..b3cc0e1 100644 --- a/src/styles/cmn.module.scss +++ b/src/styles/cmn.module.scss @@ -160,6 +160,17 @@ letter-spacing: 0.04857em !important; } +.p5 { + font-size: 0.6025rem !important; + letter-spacing: 0.03857em !important; +} + +.pWrap { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} + .darkTheme { .pPrim { color: white !important; diff --git a/src/styles/styles.module.scss b/src/styles/styles.module.scss index d270baa..15fb923 100644 --- a/src/styles/styles.module.scss +++ b/src/styles/styles.module.scss @@ -171,6 +171,16 @@ button { } } +.chainIcons { + width: 20px; + height: 20px; + + svg { + width: 20px; + height: 20px; + } +} + .chainIconsm { width: 26px; height: 26px; @@ -242,6 +252,11 @@ button { box-shadow: none !important; } +.btnApp { + background-color: rgba(0, 0, 0, 0.08) !important; + +} + .btnChain { width: 100%; text-align: left; From ff97ca4c39012239bfb66374c337443507dc8b53 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Fri, 8 Sep 2023 16:57:20 +0100 Subject: [PATCH 41/54] Update dependencies --- package.json | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/package.json b/package.json index b1b0a86..0012981 100644 --- a/package.json +++ b/package.json @@ -34,13 +34,13 @@ "dprepack": "json -f package.json -I -e \"delete this.devDependencies; delete this.dependencies\"" }, "devDependencies": { - "@storybook/addon-essentials": "7.3.2", - "@storybook/addon-interactions": "7.3.2", - "@storybook/addon-links": "7.3.2", - "@storybook/addon-styling": "1.3.6", - "@storybook/blocks": "7.3.2", - "@storybook/react": "7.3.2", - "@storybook/react-vite": "7.3.2", + "@storybook/addon-essentials": "7.4.0", + "@storybook/addon-interactions": "7.4.0", + "@storybook/addon-links": "7.4.0", + "@storybook/addon-styling": "1.3.7", + "@storybook/blocks": "7.4.0", + "@storybook/react": "7.4.0", + "@storybook/react-vite": "7.4.0", "@storybook/testing-library": "0.2.0", "@testing-library/react": "14.0.0", "@types/node": "20.4.9", @@ -67,7 +67,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "sass": "^1.65.1", - "storybook": "7.3.2", + "storybook": "7.4.0", "typescript": "5.1.6", "vite": "4.4.9", "vite-plugin-dts": "3.5.1", @@ -75,18 +75,17 @@ "vitest": "0.34.1" }, "dependencies": { - "@emotion/react": "^11.9.0", - "@emotion/styled": "^11.8.1", - "@fontsource/roboto": "^4.5.7", - "@mui/icons-material": "^5.8.0", - "@mui/lab": "^5.0.0-alpha.88", - "@mui/material": "^5.8.1", - "@rainbow-me/rainbowkit": "^1.0.9", + "@mui/material": "^5.14.8", + "@mui/lab": "^5.0.0-alpha.143", + "@mui/icons-material": "^5.14.8", + "@emotion/react": "^11.11.1", + "@emotion/styled": "^11.11.0", + "@rainbow-me/rainbowkit": "^1.0.11", "@skalenetwork/ima-js": "2.0.0-develop.3", - "coingecko-api-v3": "^0.0.28", + "coingecko-api-v3": "^0.0.29", "react-jazzicon": "^1.0.4", - "viem": "^1.5.3", - "wagmi": "^1.3.9", + "viem": "^1.10.8", + "wagmi": "^1.4.1", "zustand": "^4.4.1" }, "peerDependencies": { @@ -101,4 +100,4 @@ "prettier -w" ] } -} +} \ No newline at end of file From d4b47d08cd8c41f93d2cc0828062041a5213cb1a Mon Sep 17 00:00:00 2001 From: Dmytro Date: Sun, 10 Sep 2023 17:52:08 +0100 Subject: [PATCH 42/54] Refactor tokens and chains state --- src/components/ChainApps/ChainApps.tsx | 1 + src/components/WidgetBody/WidgetBody.tsx | 2 +- src/core/metaport.ts | 74 +++++++++++++++ src/metadata/metaportConfigStaging.ts | 21 ++++- src/store/MetaportState.ts | 112 ++++------------------- 5 files changed, 115 insertions(+), 95 deletions(-) diff --git a/src/components/ChainApps/ChainApps.tsx b/src/components/ChainApps/ChainApps.tsx index 67c3196..d51ec67 100644 --- a/src/components/ChainApps/ChainApps.tsx +++ b/src/components/ChainApps/ChainApps.tsx @@ -26,6 +26,7 @@ export default function ChainApps(props: {
{Object.keys(apps).map((key, _) => (
diff --git a/src/components/ChainsList/ChainsList.tsx b/src/components/ChainsList/ChainsList.tsx index 3fa9429..aeddc11 100644 --- a/src/components/ChainsList/ChainsList.tsx +++ b/src/components/ChainsList/ChainsList.tsx @@ -73,7 +73,7 @@ export default function ChainsList(props: { cmn.flex, cmn.flexc, [cmn.mri10, size === 'sm'], - [cmn.mri15, size === 'md'], + [cmn.mri15, size === 'md'] )} > {getChainAlias(props.config.skaleNetwork, props.chain, props.app)} @@ -113,7 +113,7 @@ export default function ChainsList(props: { cmn.mbott5, cmn.mleft10, cmn.mri10, - cmn.pWrap, + cmn.pWrap )} > on {getChainAlias(props.config.skaleNetwork, props.chain)?.split(' ')[0]} @@ -157,7 +157,7 @@ export default function ChainsList(props: { [cmn.mbott5, size === 'sm'], [cmn.mtop10, size === 'md'], [cmn.mbott10, size === 'md'], - cmn.fullWidth, + cmn.fullWidth )} >
{getChainAlias(props.config.skaleNetwork, name)} diff --git a/src/components/CommunityPool/CommunityPool.tsx b/src/components/CommunityPool/CommunityPool.tsx index 0d7a316..94b18e6 100644 --- a/src/components/CommunityPool/CommunityPool.tsx +++ b/src/components/CommunityPool/CommunityPool.tsx @@ -53,7 +53,7 @@ import styles from '../../styles/styles.module.scss' import { useCPStore } from '../../store/CommunityPoolStore' import { useCollapseStore } from '../../store/Store' -import { useMetaportStore } from '../../store/MetaportState' +import { useMetaportStore } from '../../store/MetaportStore' export default function CommunityPool() { const { data: walletClient } = useWalletClient() @@ -147,7 +147,7 @@ export default function CommunityPool() { async () => { setLoading(false) setErrorMessage(null) - }, + } ) } @@ -164,7 +164,7 @@ export default function CommunityPool() { async () => { setLoading(false) setErrorMessage(null) - }, + } ) setExpandedCP(false) } @@ -244,7 +244,7 @@ export default function CommunityPool() { cmn.pPrim, [cmn.pDisabled, loading], cmn.flex, - cmn.mri20, + cmn.mri20 )} > ETH diff --git a/src/components/DestTokenBalance/DestTokenBalance.tsx b/src/components/DestTokenBalance/DestTokenBalance.tsx index ad4b9ba..d108d22 100644 --- a/src/components/DestTokenBalance/DestTokenBalance.tsx +++ b/src/components/DestTokenBalance/DestTokenBalance.tsx @@ -2,7 +2,7 @@ import { useEffect } from 'react' import { useAccount } from 'wagmi' import { TokenBalance } from '../TokenList' -import { useMetaportStore } from '../../store/MetaportState' +import { useMetaportStore } from '../../store/MetaportStore' import { BALANCE_UPDATE_INTERVAL_MS } from '../../core/constants' export default function DestTokenBalance() { diff --git a/src/components/ErrorMessage/ErrorMessage.tsx b/src/components/ErrorMessage/ErrorMessage.tsx index 52d34a5..a57c879 100644 --- a/src/components/ErrorMessage/ErrorMessage.tsx +++ b/src/components/ErrorMessage/ErrorMessage.tsx @@ -16,7 +16,7 @@ const ERROR_ICONS = { 'link-off': , 'public-off': , sentiment: , - error: , + error: } export default function Error(props: { errorMessage: ErrorMessage }) { diff --git a/src/components/Metaport/Metaport.stories.tsx b/src/components/Metaport/Metaport.stories.tsx index 04c5abd..b339ee6 100644 --- a/src/components/Metaport/Metaport.stories.tsx +++ b/src/components/Metaport/Metaport.stories.tsx @@ -6,7 +6,7 @@ METAPORT_CONFIG.mainnetEndpoint = import.meta.env.VITE_MAINNET_ENDPOINT const meta: Meta = { title: 'Functional/Metaport', - component: Metaport, + component: Metaport // decorators: [storyDecorator], } @@ -15,6 +15,6 @@ type Story = StoryObj export const WidgetDemo: Story = { args: { - config: METAPORT_CONFIG, - }, + config: METAPORT_CONFIG + } } diff --git a/src/components/MetaportProvider/MetaportProvider.tsx b/src/components/MetaportProvider/MetaportProvider.tsx index 4e8bf84..91b10ec 100644 --- a/src/components/MetaportProvider/MetaportProvider.tsx +++ b/src/components/MetaportProvider/MetaportProvider.tsx @@ -33,7 +33,7 @@ import { injectedWallet, coinbaseWallet, metaMaskWallet, - enkryptWallet, + enkryptWallet } from '@rainbow-me/rainbowkit/wallets' import { MetaportConfig } from '../../core/interfaces' @@ -50,7 +50,7 @@ import { getWidgetTheme, getMuiZIndex } from '../../core/themes' import { cls } from '../../core/helper' import { useUIStore } from '../../store/Store' -import { useMetaportStore } from '../../store/MetaportState' +import { useMetaportStore } from '../../store/MetaportStore' import MetaportCore from '../../core/metaport' import styles from '../../styles/styles.module.scss' @@ -69,16 +69,16 @@ const { chains, webSocketPublicClient } = configureChains( constructWagmiChain('mainnet', 'honorable-steel-rasalhague'), constructWagmiChain('mainnet', 'elated-tan-skat'), - constructWagmiChain('mainnet', 'affectionate-immediate-pollux'), + constructWagmiChain('mainnet', 'affectionate-immediate-pollux') ], [ jsonRpcProvider({ rpc: (chain) => ({ http: chain.rpcUrls.default.http[0], - webSocket: getWebSocketUrl(chain), - }), - }), - ], + webSocket: getWebSocketUrl(chain) + }) + }) + ] ) const connectors = connectorsForWallets([ @@ -88,15 +88,15 @@ const connectors = connectorsForWallets([ metaMaskWallet({ chains, projectId: '' }), enkryptWallet({ chains }), injectedWallet({ chains }), - coinbaseWallet({ chains, appName: 'TEST' }), - ], - }, + coinbaseWallet({ chains, appName: 'TEST' }) + ] + } ]) const wagmiConfig = createConfig({ autoConnect: true, connectors, - publicClient: webSocketPublicClient, + publicClient: webSocketPublicClient }) export default function MetaportProvider(props: { @@ -131,15 +131,15 @@ export default function MetaportProvider(props: { palette: { mode: widgetTheme.mode as PaletteMode, background: { - paper: widgetTheme.background, + paper: widgetTheme.background }, primary: { - main: widgetTheme.primary, + main: widgetTheme.primary }, secondary: { - main: widgetTheme.background, - }, - }, + main: widgetTheme.background + } + } }) if (!metaportTheme) return
@@ -149,7 +149,7 @@ export default function MetaportProvider(props: { { // Note: If your app doesn't use authentication, you // can remove all 'authenticationStatus' checks @@ -65,8 +65,8 @@ export default function SkConnect() { style: { opacity: 0, pointerEvents: 'none', - userSelect: 'none', - }, + userSelect: 'none' + } })} > {(() => { diff --git a/src/components/SkPaper/SkPaper.tsx b/src/components/SkPaper/SkPaper.tsx index de06ad8..e122ec0 100644 --- a/src/components/SkPaper/SkPaper.tsx +++ b/src/components/SkPaper/SkPaper.tsx @@ -40,7 +40,7 @@ export default function SkPaper(props: { }) { const metaportTheme = useUIStore((state) => state.theme) const localStyle = { - background: props.background ?? metaportTheme.background, + background: props.background ?? metaportTheme.background } return (
{props.children} diff --git a/src/components/Stepper/SkStepper.tsx b/src/components/Stepper/SkStepper.tsx index 22859a3..c2ce37c 100644 --- a/src/components/Stepper/SkStepper.tsx +++ b/src/components/Stepper/SkStepper.tsx @@ -14,7 +14,7 @@ import styles from '../../styles/styles.module.scss' import localStyles from './SkStepper.module.scss' import ChainIcon from '../ChainIcon' -import { useMetaportStore } from '../../store/MetaportState' +import { useMetaportStore } from '../../store/MetaportStore' import { useCPStore } from '../../store/CommunityPoolStore' import { Collapse } from '@mui/material' import { SkaleNetwork } from '../../core/interfaces' @@ -36,7 +36,6 @@ export default function SkStepper(props: { skaleNetwork: SkaleNetwork }) { const stepsMetadata = useMetaportStore((state) => state.stepsMetadata) const currentStep = useMetaportStore((state) => state.currentStep) const amountErrorMessage = useMetaportStore((state) => state.amountErrorMessage) - const actionBtnDisabled = useMetaportStore((state) => state.actionBtnDisabled) const loading = useMetaportStore((state) => state.loading) const btnText = useMetaportStore((state) => state.btnText) @@ -103,7 +102,6 @@ export default function SkStepper(props: { skaleNetwork: SkaleNetwork }) { disabled={ !!( amountErrorMessage || - actionBtnDisabled || loading || amount == '' || !cpData.exitGasOk @@ -132,7 +130,7 @@ export default function SkStepper(props: { skaleNetwork: SkaleNetwork }) { cmn.pPrim, cmn.flexg, cmn.pCent, - cmn.mtop20, + cmn.mtop20 )} > {emoji} Transfer completed diff --git a/src/components/SwitchDirection/SwitchDirection.tsx b/src/components/SwitchDirection/SwitchDirection.tsx index 5c5c08f..f82dca5 100644 --- a/src/components/SwitchDirection/SwitchDirection.tsx +++ b/src/components/SwitchDirection/SwitchDirection.tsx @@ -7,7 +7,7 @@ import cmn from '../../styles/cmn.module.scss' import { cls } from '../../core/helper' import { useUIStore } from '../../store/Store' -import { useMetaportStore } from '../../store/MetaportState' +import { useMetaportStore } from '../../store/MetaportStore' export default function SwitchDirection() { const myElement = useRef(null) @@ -37,7 +37,7 @@ export default function SwitchDirection() { style={{ background: metaportTheme.background, borderRadius: '50%', - zIndex: metaportTheme.zIndex, + zIndex: metaportTheme.zIndex }} > { diff --git a/src/components/TokenList/TokenBalance.tsx b/src/components/TokenList/TokenBalance.tsx index be28657..860219f 100644 --- a/src/components/TokenList/TokenBalance.tsx +++ b/src/components/TokenList/TokenBalance.tsx @@ -40,7 +40,7 @@ export default function TokenBalance(props: { [cmn.pPrim, props.primary], cmn.flex, cmn.flexcv, - cmn.mri5, + cmn.mri5 )} > {balance} {props.symbol} diff --git a/src/components/TokenList/TokenList.tsx b/src/components/TokenList/TokenList.tsx index 49c8851..6b23ce6 100644 --- a/src/components/TokenList/TokenList.tsx +++ b/src/components/TokenList/TokenList.tsx @@ -20,7 +20,7 @@ import styles from '../../styles/styles.module.scss' import cmn from '../../styles/cmn.module.scss' import { useCollapseStore } from '../../store/Store' -import { useMetaportStore } from '../../store/MetaportState' +import { useMetaportStore } from '../../store/MetaportStore' import { TokenType } from '../../core/dataclasses' import { BALANCE_UPDATE_INTERVAL_MS } from '../../core/constants' @@ -97,7 +97,7 @@ export default function TokenList() { [cmn.pDisabled, noTokens], cmn.flex, cmn.flexg, - cmn.mri10, + cmn.mri10 )} > {tokensText} diff --git a/src/components/TokenListSection/TokenListSection.tsx b/src/components/TokenListSection/TokenListSection.tsx index 9670b54..063c407 100644 --- a/src/components/TokenListSection/TokenListSection.tsx +++ b/src/components/TokenListSection/TokenListSection.tsx @@ -58,7 +58,7 @@ export default function TokenListSection(props: { cmn.flex, cmn.flexg, cmn.mri10, - cmn.mleft10, + cmn.mleft10 )} > {getTokenName(props.tokens[key])} diff --git a/src/components/WidgetBody/WidgetBody.tsx b/src/components/WidgetBody/WidgetBody.tsx index a427db9..7a057cb 100644 --- a/src/components/WidgetBody/WidgetBody.tsx +++ b/src/components/WidgetBody/WidgetBody.tsx @@ -2,7 +2,7 @@ import React, { useEffect } from 'react' import { useAccount } from 'wagmi' import { useCollapseStore } from '../../store/Store' -import { useMetaportStore } from '../../store/MetaportState' +import { useMetaportStore } from '../../store/MetaportStore' import { useSFuelStore } from '../../store/SFuelStore' import { useUIStore } from '../../store/Store' diff --git a/src/components/WidgetUI/WidgetUI.tsx b/src/components/WidgetUI/WidgetUI.tsx index 00221c6..e3bab31 100644 --- a/src/components/WidgetUI/WidgetUI.tsx +++ b/src/components/WidgetUI/WidgetUI.tsx @@ -32,7 +32,7 @@ import CloseIcon from '@mui/icons-material/Close' import skaleLogo from './skale_logo_short.svg' import { useUIStore } from '../../store/Store' -import { useMetaportStore } from '../../store/MetaportState' +import { useMetaportStore } from '../../store/MetaportStore' import SkPaper from '../SkPaper' import WidgetBody from '../WidgetBody' @@ -80,7 +80,7 @@ export function WidgetUI(props: { config: MetaportConfig }) { {isOpen ? ( ) : ( diff --git a/src/components/WrappedTokens/WrappedTokens.tsx b/src/components/WrappedTokens/WrappedTokens.tsx index 671df9c..6825005 100644 --- a/src/components/WrappedTokens/WrappedTokens.tsx +++ b/src/components/WrappedTokens/WrappedTokens.tsx @@ -45,7 +45,7 @@ import cmn from '../../styles/cmn.module.scss' import styles from '../../styles/styles.module.scss' import { useCollapseStore } from '../../store/Store' -import { useMetaportStore } from '../../store/MetaportState' +import { useMetaportStore } from '../../store/MetaportStore' import { TokenDataMap } from '../../core/interfaces' export default function WrappedTokens() { @@ -90,7 +90,7 @@ export default function WrappedTokens() { acc[key] = wrappedTokens.erc20[key] } return acc - }, {}), + }, {}) ) }, [wrappedTokens, wrappedTokenBalances]) @@ -138,7 +138,10 @@ export default function WrappedTokens() {

{Object.keys(filteredTokens).map((key, _) => ( -
+
Wrapped {getTokenName(filteredTokens[key])} diff --git a/src/core/actions/action.ts b/src/core/actions/action.ts index ed7e920..4b7cea4 100644 --- a/src/core/actions/action.ts +++ b/src/core/actions/action.ts @@ -97,7 +97,7 @@ export class Action { setAmountErrorMessage: (amountErrorMessage: string) => void, setBtnText: (btnText: string) => void, switchNetwork: (chainId: number | bigint) => Chain | undefined, - walletClient: WalletClient, + walletClient: WalletClient ) { this.mpc = mpc @@ -131,7 +131,7 @@ export class Action { token.type, provider1, this.token.wrapper(this.chainName2) ? CustomAbiTokenType.erc20wrap : null, - this.token.wrapper(this.chainName2) ? this.chainName2 : null, + this.token.wrapper(this.chainName2) ? this.chainName2 : null ) this.originAddress = this.mpc.originAddress(chainName1, chainName2, token.keyname, token.type) @@ -150,7 +150,7 @@ export class Action { token.type, provider2, CustomAbiTokenType.erc20wrap, - this.chainName1, + this.chainName1 ) } else { this.destToken = mpc.tokenContract(chainName2, token.keyname, token.type, provider2) @@ -189,10 +189,10 @@ export class Action { address: this.address, amount: this.amount, amountWei: this.amountWei, - tokenId: this.tokenId, + tokenId: this.tokenId }, transactionHash, - timestamp, + timestamp ) this.setBtnText(LOADING_BUTTON_TEXT[currentState]) } @@ -200,7 +200,7 @@ export class Action { async getConnectedChain( provider: Provider, customAbiTokenType?: CustomAbiTokenType, - destChainName?: string, + destChainName?: string ): Promise { let chain: MainnetChain | SChain this.updateState('switch') @@ -227,7 +227,7 @@ export class Action { this.token.type, chain.provider, customAbiTokenType, - destChainName, + destChainName ) chain.erc20.addToken(this.token.keyname, token) return chain diff --git a/src/core/actions/actionState.ts b/src/core/actions/actionState.ts index 415e888..913aff9 100644 --- a/src/core/actions/actionState.ts +++ b/src/core/actions/actionState.ts @@ -63,5 +63,5 @@ export const LOADING_BUTTON_TEXT: LoadingButtonTextMap = { unwrapDone: 'Tokens unwrapped', switch: 'Waiting for network switch', unlock: 'Unlocking ETH', - unlockDone: 'ETH unlocked', + unlockDone: 'ETH unlocked' } diff --git a/src/core/actions/checks.ts b/src/core/actions/checks.ts index eac8498..1470b8b 100644 --- a/src/core/actions/checks.ts +++ b/src/core/actions/checks.ts @@ -38,7 +38,7 @@ export async function checkEthBalance( // TODO: optimize balance checks chain: MainnetChain | SChain, address: string, amount: string, - tokenData: TokenData, + tokenData: TokenData ): Promise { const checkRes: interfaces.CheckRes = { res: false } @@ -69,7 +69,7 @@ export async function checkERC20Balance( address: string, amount: string, tokenData: TokenData, - tokenContract: Contract, + tokenContract: Contract ): Promise { const checkRes: interfaces.CheckRes = { res: false } if (!amount || Number(amount) === 0) return checkRes @@ -93,7 +93,7 @@ export async function checkERC20Balance( export async function checkSFuelBalance( address: string, amount: string, - sChain: SChain, + sChain: SChain ): Promise { const checkRes: interfaces.CheckRes = { res: false } if (!amount || Number(amount) === 0) return checkRes @@ -120,7 +120,7 @@ export async function checkERC20Allowance( approvalAddress: string, amount: string, tokenData: TokenData, - tokenContract: Contract, + tokenContract: Contract ): Promise { const checkRes: interfaces.CheckRes = { res: false } if (!amount || Number(amount) === 0) return checkRes @@ -141,7 +141,7 @@ export async function checkERC721( address: string, approvalAddress: string, tokenId: number, - tokenContract: Contract, + tokenContract: Contract ): Promise { let approvedAddress: string const checkRes: interfaces.CheckRes = { res: true, approved: false } @@ -176,7 +176,7 @@ export async function checkERC1155( tokenId: number, amount: string, tokenData: TokenData, - tokenContract: Contract, + tokenContract: Contract ): Promise { const checkRes: interfaces.CheckRes = { res: true, approved: false } if (!tokenId || !amount) return checkRes diff --git a/src/core/actions/erc20.ts b/src/core/actions/erc20.ts index 61e663c..fa39cc2 100644 --- a/src/core/actions/erc20.ts +++ b/src/core/actions/erc20.ts @@ -45,12 +45,12 @@ export class TransferERC20S2S extends TransferAction { this.sChain1.erc20.address, this.amount, this.token, - this.sourceToken, + this.sourceToken ) const sChain = (await this.getConnectedChain( this.sChain1.provider, this.token.wrapper(this.chainName2) ? CustomAbiTokenType.erc20wrap : null, - this.token.wrapper(this.chainName2) ? this.chainName2 : null, + this.token.wrapper(this.chainName2) ? this.chainName2 : null )) as SChain if (!checkResAllowance.res) { this.updateState('approve') @@ -59,8 +59,8 @@ export class TransferERC20S2S extends TransferAction { MAX_APPROVE_AMOUNT, sChain.erc20.address, { - address: this.address, - }, + address: this.address + } ) const txBlock = await sChain.provider.getBlock(approveTx.blockNumber) this.updateState('approveDone', approveTx.hash, txBlock.timestamp) @@ -86,7 +86,7 @@ export class TransferERC20S2S extends TransferAction { balanceOnDestination = await this.sChain2.getERC20Balance(this.destToken, this.address) } const tx = await sChain.erc20.transferToSchain(this.chainName2, this.originAddress, amountWei, { - address: this.address, + address: this.address }) const block = await sChain.provider.getBlock(tx.blockNumber) this.updateState('transferDone', tx.hash, block.timestamp) @@ -103,7 +103,7 @@ export class TransferERC20S2S extends TransferAction { this.address, this.amount, this.token, - this.sourceToken, + this.sourceToken ) if (!checkResBalance.res) { this.setAmountErrorMessage(checkResBalance.msg) @@ -119,7 +119,7 @@ export class WrapSFuelERC20S extends Action { this.updateState('wrap') const tx = await this.sChain1.erc20.fundExit(this.token.keyname, { address: this.address, - value: this.amountWei, + value: this.amountWei }) const block = await this.sChain1.provider.getBlock(tx.blockNumber) this.updateState('wrapDone', tx.hash, block.timestamp) @@ -146,7 +146,7 @@ export class WrapERC20S extends Action { this.token.connections[this.chainName2].wrapper, this.amount, this.token, - this.unwrappedToken, + this.unwrappedToken ) const sChain = (await this.getConnectedChain(this.sChain1.provider)) as SChain const wrapperToken = this.mpc.tokenContract( @@ -155,7 +155,7 @@ export class WrapERC20S extends Action { this.token.type, sChain.provider, CustomAbiTokenType.erc20wrap, - this.chainName2, + this.chainName2 ) sChain.erc20.addToken(`wrap_${this.token.keyname}`, wrapperToken) if (!checkResAllowance.res) { @@ -165,8 +165,8 @@ export class WrapERC20S extends Action { MAX_APPROVE_AMOUNT, this.token.address, { - address: this.address, - }, + address: this.address + } ) const txBlock = await this.sChain1.provider.getBlock(approveTx.blockNumber) this.updateState('approveWrapDone', approveTx.hash, txBlock.timestamp) @@ -174,7 +174,7 @@ export class WrapERC20S extends Action { this.updateState('wrap') const amountWei = toWei(this.amount, this.token.meta.decimals) const tx = await sChain.erc20.wrap(`wrap_${this.token.keyname}`, amountWei, { - address: this.address, + address: this.address }) const block = await this.sChain1.provider.getBlock(tx.blockNumber) this.updateState('wrapDone', tx.hash, block.timestamp) @@ -185,7 +185,7 @@ export class WrapERC20S extends Action { this.address, this.amount, this.token, - this.unwrappedToken, + this.unwrappedToken ) if (!checkResBalance.res) { this.setAmountErrorMessage(checkResBalance.msg) @@ -205,7 +205,7 @@ export class UnWrapERC20 extends Action { this.token.type, sChain.provider, CustomAbiTokenType.erc20wrap, - findFirstWrapperChainName(this.token), + findFirstWrapperChainName(this.token) ) sChain.erc20.addToken(this.token.keyname, tokenContract) const amountWei = await tokenContract.balanceOf(this.address) @@ -222,7 +222,7 @@ export class UnWrapERC20S extends Action { const sChain = (await this.getConnectedChain( this.sChain2.provider, CustomAbiTokenType.erc20wrap, - this.chainName1, + this.chainName1 )) as SChain this.updateState('unwrap') let tx @@ -246,7 +246,7 @@ export class UnWrapERC20S extends Action { this.address, this.amount, this.token, - tokenContract, + tokenContract ) if (!checkResBalance.res) { this.setAmountErrorMessage(checkResBalance.msg) @@ -265,13 +265,13 @@ export class TransferERC20M2S extends TransferAction { this.mainnet.erc20.address, this.amount, this.token, - this.sourceToken, + this.sourceToken ) const mainnet = (await this.getConnectedChain(this.mainnet.provider)) as MainnetChain if (!checkResAllowance.res) { this.updateState('approve') const approveTx = await mainnet.erc20.approve(this.token.keyname, MAX_APPROVE_AMOUNT, { - address: this.address, + address: this.address }) const txBlock = await mainnet.provider.getBlock(approveTx.blockNumber) this.updateState('approveDone', approveTx.hash, txBlock.timestamp) @@ -281,7 +281,7 @@ export class TransferERC20M2S extends TransferAction { // const destTokenContract = this.sChain2.erc20.tokens[this.token.keyname]; const balanceOnDestination = await this.sChain2.getERC20Balance(this.destToken, this.address) const tx = await await mainnet.erc20.deposit(this.chainName2, this.token.keyname, amountWei, { - address: this.address, + address: this.address }) const block = await mainnet.provider.getBlock(tx.blockNumber) this.updateState('transferDone', tx.hash, block.timestamp) @@ -295,7 +295,7 @@ export class TransferERC20M2S extends TransferAction { this.chainName1, this.chainName2, this.token.keyname, - false, + false ) } @@ -304,7 +304,7 @@ export class TransferERC20M2S extends TransferAction { this.address, this.amount, this.token, - this.sourceToken, + this.sourceToken ) if (!checkResBalance.res) { this.setAmountErrorMessage(checkResBalance.msg) @@ -324,7 +324,7 @@ export class TransferERC20S2M extends TransferAction { this.sChain1.erc20.address, this.amount, this.token, - this.sourceToken, + this.sourceToken ) const sChain = (await this.getConnectedChain(this.sChain1.provider)) as SChain if (!checkResAllowance.res) { @@ -334,8 +334,8 @@ export class TransferERC20S2M extends TransferAction { MAX_APPROVE_AMOUNT, sChain.erc20.address, { - address: this.address, - }, + address: this.address + } ) const txBlock = await sChain.provider.getBlock(approveTx.blockNumber) this.updateState('approveDone', approveTx.hash, txBlock.timestamp) @@ -358,7 +358,7 @@ export class TransferERC20S2M extends TransferAction { this.chainName1, this.chainName2, this.token.keyname, - false, + false ) } @@ -367,7 +367,7 @@ export class TransferERC20S2M extends TransferAction { this.address, this.amount, this.token, - this.sourceToken, + this.sourceToken ) if (!checkResBalance.res) { this.setAmountErrorMessage(checkResBalance.msg) diff --git a/src/core/actions/eth.ts b/src/core/actions/eth.ts index 7902c76..d1fd378 100644 --- a/src/core/actions/eth.ts +++ b/src/core/actions/eth.ts @@ -41,7 +41,7 @@ export class TransferEthM2S extends TransferAction { this.updateState('transferETH') const tx = await mainnet.eth.deposit(this.chainName2, { address: this.address, - value: amountWei, + value: amountWei }) const block = await this.mainnet.provider.getBlock(tx.blockNumber) this.updateState('transferETHDone', tx.hash, block.timestamp) @@ -54,7 +54,7 @@ export class TransferEthM2S extends TransferAction { this.mainnet, this.address, this.amount, - this.token, + this.token ) if (!checkResBalance.res) { this.setAmountErrorMessage(checkResBalance.msg) @@ -84,7 +84,7 @@ export class TransferEthS2M extends TransferAction { this.sChain1, this.address, this.amount, - this.token, + this.token ) if (!checkResBalance.res) { this.setAmountErrorMessage(checkResBalance.msg) diff --git a/src/core/actions/index.ts b/src/core/actions/index.ts index e4b9ed7..be0ddcd 100644 --- a/src/core/actions/index.ts +++ b/src/core/actions/index.ts @@ -30,7 +30,7 @@ import { UnWrapERC20S, UnWrapERC20, TransferERC20M2S, - TransferERC20S2M, + TransferERC20S2M } from './erc20' import { Action } from './action' @@ -45,7 +45,7 @@ const log = debug('metaport:actions') export function getActionName( chainName1: string, chainName2: string, - tokenType: TokenType, + tokenType: TokenType ): string { if (!chainName1 || !chainName2 || !tokenType) return log(`Getting action name: ${chainName1} ${chainName2} ${tokenType}`) @@ -64,6 +64,7 @@ export function getActionName( export const ACTIONS: { [actionType in ActionType]: typeof Action } = { eth_m2s: TransferEthM2S, eth_s2m: TransferEthS2M, + eth_s2s: TransferERC20S2S, eth_unlock: UnlockEthM, wrap: WrapERC20S, @@ -72,7 +73,7 @@ export const ACTIONS: { [actionType in ActionType]: typeof Action } = { erc20_m2s: TransferERC20M2S, erc20_s2m: TransferERC20S2M, - erc20_s2s: TransferERC20S2S, + erc20_s2s: TransferERC20S2S // erc721_m2s: [TransferERC721M2S], // erc721_s2m: [TransferERC721S2M], diff --git a/src/core/community_pool.ts b/src/core/community_pool.ts index 081071f..7666340 100644 --- a/src/core/community_pool.ts +++ b/src/core/community_pool.ts @@ -38,7 +38,7 @@ import { MINIMUM_RECHARGE_AMOUNT, COMMUNITY_POOL_WITHDRAW_GAS_LIMIT, DEFAULT_ERROR_MSG, - BALANCE_UPDATE_INTERVAL_MS, + BALANCE_UPDATE_INTERVAL_MS } from './constants' import { delay } from './helper' import { CHAIN_IDS, isMainnetChainId, getMainnetAbi } from './network' @@ -56,7 +56,7 @@ export function getEmptyCommunityPoolData(): CommunityPoolData { balance: null, accountBalance: null, recommendedRechargeAmount: null, - originalRecommendedRechargeAmount: null, + originalRecommendedRechargeAmount: null } } @@ -65,7 +65,7 @@ export async function getCommunityPoolData( chainName1: string, chainName2: string, mainnet: MainnetChain, - sChain: SChain, + sChain: SChain ): Promise { if (chainName2 !== MAINNET_CHAIN_NAME) { // log('not a S2M transfer, skipping community pool check') @@ -75,7 +75,7 @@ export async function getCommunityPoolData( balance: null, accountBalance: null, recommendedRechargeAmount: null, - originalRecommendedRechargeAmount: null, + originalRecommendedRechargeAmount: null } } @@ -88,7 +88,7 @@ export async function getCommunityPoolData( const rraWei = await mainnet.communityPool.contract.getRecommendedRechargeAmount( chainHash, - address, + address ) const rraEther = fromWei(rraWei as string, DEFAULT_ERC20_DECIMALS) @@ -101,7 +101,7 @@ export async function getCommunityPoolData( balance: balanceWei, accountBalance: accountBalanceWei, recommendedRechargeAmount: recommendedAmount, - originalRecommendedRechargeAmount: rraWei, + originalRecommendedRechargeAmount: rraWei } // log('communityPoolData:', communityPoolData) return communityPoolData @@ -110,7 +110,7 @@ export async function getCommunityPoolData( export async function connectedMainnetChain( mpc: MetaportCore, walletClient: WalletClient, - switchNetwork: (chainId: number | bigint) => Promise, + switchNetwork: (chainId: number | bigint) => Promise ): Promise { const currentChainId = walletClient.chain.id const chainId = CHAIN_IDS[mpc.config.skaleNetwork] @@ -136,7 +136,7 @@ export async function withdraw( switchNetwork: (chainId: number | bigint) => Promise, setLoading: (loading: string | false) => void, setErrorMessage: (errorMessage: dataclasses.ErrorMessage) => void, - errorMessageClosedFallback: () => void, + errorMessageClosedFallback: () => void ) { setLoading('withdraw') try { @@ -144,7 +144,7 @@ export async function withdraw( const mainnetMetamask = await connectedMainnetChain(mpc, walletClient, switchNetwork) await mainnetMetamask.communityPool.withdraw(chainName, amount, { address: address, - customGasLimit: COMMUNITY_POOL_WITHDRAW_GAS_LIMIT, + customGasLimit: COMMUNITY_POOL_WITHDRAW_GAS_LIMIT }) setLoading(false) } catch (err) { @@ -163,7 +163,7 @@ export async function recharge( switchNetwork: (chainId: number | bigint) => Promise, setLoading: (loading: string | false) => void, setErrorMessage: (errorMessage: dataclasses.ErrorMessage) => void, - errorMessageClosedFallback: () => void, + errorMessageClosedFallback: () => void ) { setLoading('recharge') try { @@ -173,7 +173,7 @@ export async function recharge( const mainnetMetamask = await connectedMainnetChain(mpc, walletClient, switchNetwork) await mainnetMetamask.communityPool.recharge(chainName, address, { address: address, - value: toWei(amount, DEFAULT_ERC20_DECIMALS), + value: toWei(amount, DEFAULT_ERC20_DECIMALS) }) setLoading('activate') let active = false diff --git a/src/core/constants.ts b/src/core/constants.ts index bfd26cc..472c179 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -52,14 +52,14 @@ export const MAINNET_EXPLORER_URLS: { [skaleNetwork: string]: string } = { mainnet: 'https://etherscan.io', staging: 'https://goerli.etherscan.io/', legacy: 'https://goerli.etherscan.io/', - regression: 'https://goerli.etherscan.io/', + regression: 'https://goerli.etherscan.io/' } export const BASE_EXPLORER_URLS = { mainnet: 'explorer.mainnet.skalenodes.com', staging: 'explorer.staging-v3.skalenodes.com', legacy: 'explorer.staging-v3.skalenodes.com', - regression: 'regression-explorer.skalenodes.com', + regression: 'regression-explorer.skalenodes.com' } // ETA constants @@ -80,12 +80,12 @@ export const SFUEL_CHECKS_INTERVAL = 8 export const SFUEL_TEXT = { sfuel: { warning: 'You need sFUEL on the destination chain', - error: 'You need sFUEL to perform a transfer', + error: 'You need sFUEL to perform a transfer' }, gas: { warning: 'You need ETH on the destination chain', - error: 'You need ETH to perform a transfer', - }, + error: 'You need ETH to perform a transfer' + } } // faucet constants diff --git a/src/core/contracts.ts b/src/core/contracts.ts index 9ada13d..3dd8614 100644 --- a/src/core/contracts.ts +++ b/src/core/contracts.ts @@ -45,17 +45,17 @@ export const ERC_ABIS: { [tokenType in CustomAbiTokenType | TokenType]: { ['abi' sfuelwrap: sFuelWrapperAbi, erc721: erc721Abi, erc721meta: erc721MetaAbi, - erc1155: erc1155Abi, + erc1155: erc1155Abi } export const IMA_ADDRESSES = { mainnet: mainnetAddresses, staging: stagingAddresses, legacy: legacyAddresses, - regression: regressionAddresses, + regression: regressionAddresses } export const IMA_ABIS = { mainnet: mainnetAbi, - schain: sChainAbi, + schain: sChainAbi } diff --git a/src/core/dataclasses/Position.ts b/src/core/dataclasses/Position.ts index 16abbf0..9757dc0 100644 --- a/src/core/dataclasses/Position.ts +++ b/src/core/dataclasses/Position.ts @@ -38,5 +38,5 @@ export const Positions: PositionMap = { topLeft: { top: DEFAULT_MP_MARGIN, left: DEFAULT_MP_MARGIN, right: 'auto', bottom: 'auto' }, topRight: { top: DEFAULT_MP_MARGIN, left: 'auto', right: DEFAULT_MP_MARGIN, bottom: 'auto' }, bottomRight: { top: 'auto', left: 'auto', right: DEFAULT_MP_MARGIN, bottom: DEFAULT_MP_MARGIN }, - bottomLeft: { top: 'auto', left: DEFAULT_MP_MARGIN, right: 'auto', bottom: DEFAULT_MP_MARGIN }, + bottomLeft: { top: 'auto', left: DEFAULT_MP_MARGIN, right: 'auto', bottom: DEFAULT_MP_MARGIN } } diff --git a/src/core/dataclasses/StepMetadata.ts b/src/core/dataclasses/StepMetadata.ts index def4b25..31b0b4b 100644 --- a/src/core/dataclasses/StepMetadata.ts +++ b/src/core/dataclasses/StepMetadata.ts @@ -39,13 +39,14 @@ export enum ActionType { unwrap_stuck = 'unwrap_stuck', eth_m2s = 'eth_m2s', eth_s2m = 'eth_s2m', - eth_unlock = 'eth_unlock', + eth_s2s = 'eth_s2s', + eth_unlock = 'eth_unlock' } export function getActionType( chainName1: string, chainName2: string, - tokenType: TokenType, + tokenType: TokenType ): ActionType { if (!chainName1 || !chainName2 || !tokenType) return let postfix = S2S_POSTFIX @@ -71,7 +72,7 @@ export abstract class StepMetadata { constructor( public type: ActionType, public from: string, - public to: string, + public to: string ) {} } @@ -92,7 +93,7 @@ export class WrapStepMetadata extends StepMetadata { constructor( public from: string, - public to: string, + public to: string ) { super(ActionType.wrap, from, to) } @@ -107,7 +108,7 @@ export class UnwrapStepMetadata extends StepMetadata { constructor( public from: string, - public to: string, + public to: string ) { super(ActionType.unwrap, from, to) } @@ -122,7 +123,7 @@ export class UnlockStepMetadata extends StepMetadata { constructor( public from: string, - public to: string, + public to: string ) { super(ActionType.eth_unlock, from, to) } diff --git a/src/core/dataclasses/TokenData.ts b/src/core/dataclasses/TokenData.ts index f5694d2..88f17f6 100644 --- a/src/core/dataclasses/TokenData.ts +++ b/src/core/dataclasses/TokenData.ts @@ -39,7 +39,7 @@ export class TokenData { tokenKeyname: string, metadata: TokenMetadata, connections: ConnectedChainMap, - chain: string, + chain: string ) { this.address = address this.meta = metadata diff --git a/src/core/dataclasses/TokenType.ts b/src/core/dataclasses/TokenType.ts index d41e9c0..5b7d717 100644 --- a/src/core/dataclasses/TokenType.ts +++ b/src/core/dataclasses/TokenType.ts @@ -26,10 +26,10 @@ export enum TokenType { erc20 = 'erc20', erc721 = 'erc721', erc721meta = 'erc721meta', - erc1155 = 'erc1155', + erc1155 = 'erc1155' } export enum CustomAbiTokenType { erc20wrap = 'erc20wrap', - sfuelwrap = 'sfuelwrap', + sfuelwrap = 'sfuelwrap' } diff --git a/src/core/dataclasses/TransferRequestStatus.ts b/src/core/dataclasses/TransferRequestStatus.ts index 42c56a0..cd4ffad 100644 --- a/src/core/dataclasses/TransferRequestStatus.ts +++ b/src/core/dataclasses/TransferRequestStatus.ts @@ -27,5 +27,5 @@ export enum TransferRequestStatus { IN_PROGRESS = 2, IN_PROGRESS_HUB = 3, DONE = 4, - ERROR = 5, + ERROR = 5 } diff --git a/src/core/dataclasses/View.ts b/src/core/dataclasses/View.ts index b6e8d89..6c4632d 100644 --- a/src/core/dataclasses/View.ts +++ b/src/core/dataclasses/View.ts @@ -26,5 +26,5 @@ export enum View { UNWRAP = 'UNWRAP', TRANSFER_REQUEST_SUMMARY = 'TRANSFER_REQUEST_SUMMARY', TRANSFER_REQUEST_STEPS = 'TRANSFER_REQUEST_STEPS', - ERROR = 'ERROR', + ERROR = 'ERROR' } diff --git a/src/core/ethers.ts b/src/core/ethers.ts index 8c2fa91..b748877 100644 --- a/src/core/ethers.ts +++ b/src/core/ethers.ts @@ -18,7 +18,7 @@ export function useEthersSigner({ chainId }: { chainId?: number } = {}) { const { data: walletClient } = useWalletClient({ chainId }) return React.useMemo( () => (walletClient ? walletClientToSigner(walletClient) : undefined), - [walletClient], + [walletClient] ) } @@ -27,11 +27,11 @@ export function publicClientToProvider(publicClient: PublicClient) { const network = { chainId: chain.id, name: chain.name, - ensAddress: chain.contracts?.ensRegistry?.address, + ensAddress: chain.contracts?.ensRegistry?.address } if (transport.type === 'fallback') { const providers = (transport.transports as ReturnType[]).map( - ({ value }) => new JsonRpcProvider(value?.url, network), + ({ value }) => new JsonRpcProvider(value?.url, network) ) if (providers.length === 1) return providers[0] return new FallbackProvider(providers) diff --git a/src/core/events.ts b/src/core/events.ts index 3f66ae1..fdf3285 100644 --- a/src/core/events.ts +++ b/src/core/events.ts @@ -39,7 +39,7 @@ export namespace externalEvents { dispatchEvent('metaport_balance', { tokenSymbol: tokenSymbol, schainName: schainName, - balance: _balance, + balance: _balance }) } @@ -48,14 +48,14 @@ export namespace externalEvents { chainName1: string, chainName2: string, tokenSymbol: string, - unwrap: boolean = false, + unwrap: boolean = false ) { dispatchEvent('metaport_transferComplete', { tokenSymbol: tokenSymbol, from: chainName1, to: chainName2, tx: tx, - unwrap: unwrap, + unwrap: unwrap }) } @@ -67,17 +67,17 @@ export namespace externalEvents { txData: any, timestamp: string | number, chainName: string, - txName: string, + txName: string ): void { log('WARNING: Event metaport_transactionCompleted will be removed in the next version') dispatchEvent('metaport_transactionCompleted', { tx: { gasUsed: txData.gasUsed, - transactionHash: txData.transactionHash, + transactionHash: txData.transactionHash }, timestamp, chainName, - txName, + txName }) } @@ -93,14 +93,14 @@ export namespace externalEvents { tokenId: number }, transactionHash?: string, - timestamp?: string | number, + timestamp?: string | number ): void { dispatchEvent('metaport_actionStateUpdated', { actionState, actionName, actionData, transactionHash, - timestamp, + timestamp }) } @@ -108,13 +108,13 @@ export namespace externalEvents { dispatchEvent('metaport_unwrapComplete', { tokenSymbol: tokenSymbol, chain: chainName1, - tx: tx, + tx: tx }) } export function ethUnlocked(tx: string) { dispatchEvent('metaport_ethUnlocked', { - tx: tx, + tx: tx }) } @@ -127,13 +127,13 @@ export namespace internalEvents { export function updateParams(params) { dispatchEvent('_metaport_updateParams', { tokens: params.tokens, - chains: params.chains, + chains: params.chains }) } export function transfer(params: interfaces.TransferParams): void { dispatchEvent('_metaport_transfer', { - params: params, + params: params }) } @@ -141,7 +141,7 @@ export namespace internalEvents { dispatchEvent('_metaport_wrap', { amount: params.amount, chain: params.chain, - tokens: params.tokens, + tokens: params.tokens }) } @@ -149,7 +149,7 @@ export namespace internalEvents { dispatchEvent('_metaport_unwrap', { amount: params.amount, chain: params.chain, - tokens: params.tokens, + tokens: params.tokens }) } @@ -157,7 +157,7 @@ export namespace internalEvents { dispatchEvent('_metaport_swap', { amount: params.amount, chain: params.chain, - tokens: params.tokens, // todo! + tokens: params.tokens // todo! }) } @@ -176,13 +176,13 @@ export namespace internalEvents { export function requestBalance(params) { dispatchEvent('_metaport_requestBalance', { schainName: params.schainName, - tokenSymbol: params.tokenSymbol, + tokenSymbol: params.tokenSymbol }) } export function setTheme(theme) { dispatchEvent('_metaport_setTheme', { - theme: theme, + theme: theme }) } } diff --git a/src/core/explorer.ts b/src/core/explorer.ts index f51fcb6..1c60292 100644 --- a/src/core/explorer.ts +++ b/src/core/explorer.ts @@ -25,7 +25,7 @@ import { HTTPS_PREFIX, MAINNET_CHAIN_NAME, MAINNET_EXPLORER_URLS, - BASE_EXPLORER_URLS, + BASE_EXPLORER_URLS } from './constants' import { SkaleNetwork } from './interfaces' diff --git a/src/core/faucet.ts b/src/core/faucet.ts index 8bcbefd..93ba4f7 100644 --- a/src/core/faucet.ts +++ b/src/core/faucet.ts @@ -57,7 +57,7 @@ function getFuncData(chainName: string, address: string, skaleNetwork: string) { export async function getSFuel( chainName: string, address: AddressType, - mpc: MetaportCore, + mpc: MetaportCore ): Promise { const endpoint = mpc.endpoint(chainName) const miner = new SkalePowMiner() @@ -71,6 +71,6 @@ export async function getSFuel( to, data, nonce, - gasPrice: mineFreeGasResult, + gasPrice: mineFreeGasResult }) } diff --git a/src/core/fee_calculator.ts b/src/core/fee_calculator.ts index a9e5e2a..ab9d6c4 100644 --- a/src/core/fee_calculator.ts +++ b/src/core/fee_calculator.ts @@ -40,7 +40,7 @@ export async function getTransactionFee(): Promise { const client = new CoinGeckoClient({ timeout: 10000, - autoRetry: true, + autoRetry: true }) const res = await client.simplePrice({ ids: 'ethereum', vs_currencies: 'usd' }) const ethToUsdRate = res.ethereum.usd diff --git a/src/core/helper.ts b/src/core/helper.ts index 0f89f6a..34fd62a 100644 --- a/src/core/helper.ts +++ b/src/core/helper.ts @@ -37,7 +37,7 @@ export const CHAINS_META = { mainnet: mainnetMeta, staging: stagingMeta, legacy: legacyMeta, - regression: regressionMeta, + regression: regressionMeta } export function cls(...args: any): string { diff --git a/src/core/metadata.ts b/src/core/metadata.ts index 9be3b9f..19b5bea 100644 --- a/src/core/metadata.ts +++ b/src/core/metadata.ts @@ -45,7 +45,7 @@ const CHAIN_ICONS = { mainnet: MAINNET_CHAIN_ICONS, staging: STAGING_CHAIN_ICONS, legacy: LEGACY_CHAIN_ICONS, - regression: REGRESSION_CHAIN_ICONS, + regression: REGRESSION_CHAIN_ICONS } export function chainIconPath(skaleNetwork: SkaleNetwork, name: string, app?: string) { diff --git a/src/core/metaport.ts b/src/core/metaport.ts index 2dce059..013adac 100644 --- a/src/core/metaport.ts +++ b/src/core/metaport.ts @@ -28,7 +28,7 @@ import { TokenDataTypesMap, Token, TokenContractsMap, - TokenBalancesMap, + TokenBalancesMap } from './interfaces' import { TokenType, TokenData, CustomAbiTokenType } from './dataclasses' @@ -49,7 +49,7 @@ export const createTokenData = ( tokenKeyname: string, chainName: string, tokenType: TokenType, - config: MetaportConfig, + config: MetaportConfig ): TokenData => { const configToken: Token = config.connections[chainName][tokenType][tokenKeyname] return new TokenData( @@ -58,7 +58,7 @@ export const createTokenData = ( tokenKeyname, config.tokens[tokenKeyname], configToken.chains, - chainName, + chainName ) } @@ -67,7 +67,7 @@ export const addTokenData = ( chainName: string, tokenType: TokenType, config: MetaportConfig, - tokens: TokenDataTypesMap, + tokens: TokenDataTypesMap ) => { tokens[tokenType][tokenKeyname] = createTokenData(tokenKeyname, chainName, tokenType, config) } @@ -75,7 +75,7 @@ export const addTokenData = ( export const createTokensMap = ( chainName1: string, chainName2: string | null | undefined, - config: MetaportConfig, + config: MetaportConfig ): TokenDataTypesMap => { const tokens = getEmptyTokenDataMap() log(`updating tokens map for ${chainName1} -> ${chainName2}`) @@ -96,7 +96,7 @@ export const createTokensMap = ( export function createWrappedTokensMap( chainName1: string, - config: MetaportConfig, + config: MetaportConfig ): TokenDataTypesMap { const wrappedTokens: TokenDataTypesMap = getEmptyTokenDataMap() const tokenType = TokenType.erc20 @@ -165,7 +165,7 @@ export default class MetaportCore { async tokenBalances( tokenContracts: TokenContractsMap, - address: string, + address: string ): Promise { const balances: TokenBalancesMap = {} const tokenKeynames = Object.keys(tokenContracts) @@ -180,8 +180,7 @@ export default class MetaportCore { tokenType: TokenType, chainName: string, provider: Provider, - customAbiTokenType?: CustomAbiTokenType, - // destChainName?: string + customAbiTokenType?: CustomAbiTokenType ): TokenContractsMap { const contracts: TokenContractsMap = {} if (tokens[tokenType]) { @@ -197,7 +196,7 @@ export default class MetaportCore { tokenType, provider, customAbiTokenType, - destChainName, + destChainName ) }) } @@ -210,7 +209,7 @@ export default class MetaportCore { tokenType: TokenType, provider: Provider, customAbiTokenType?: CustomAbiTokenType, - destChainName?: string, + destChainName?: string ): Contract | undefined { const token = this._config.connections[chainName][tokenType][tokenKeyname] if (!token.address) return @@ -224,7 +223,7 @@ export default class MetaportCore { chainName1: string, chainName2: string, tokenKeyname: string, - tokenType: TokenType, + tokenType: TokenType ) { let token = this._config.connections[chainName1][tokenType][tokenKeyname] const isClone = token.chains[chainName2].clone @@ -304,9 +303,9 @@ export default class MetaportCore { CustomAbiTokenType.erc20wrap ) - const prevTokenKeyname = prevToken?.keyname; - const prevTokenType = prevToken?.type; - const token = prevTokenKeyname ? tokens[prevTokenType][prevTokenKeyname] : null; + const prevTokenKeyname = prevToken?.keyname + const prevTokenType = prevToken?.type + const token = prevTokenKeyname ? tokens[prevTokenType][prevTokenKeyname] : null return { ima1, diff --git a/src/core/miner.ts b/src/core/miner.ts index d889df9..abb4fcd 100644 --- a/src/core/miner.ts +++ b/src/core/miner.ts @@ -38,7 +38,7 @@ export default class SkalePowMiner { public async mineGasForTransaction( nonce: string | number, gas: string | number, - from: string, + from: string ): Promise { let address = from nonce = isHexString(nonce) ? getNumber(nonce) : (nonce as number) diff --git a/src/core/network.ts b/src/core/network.ts index 40aaba5..b991c03 100644 --- a/src/core/network.ts +++ b/src/core/network.ts @@ -33,14 +33,14 @@ export { proxyEndpoints as PROXY_ENDPOINTS } const PROTOCOL: { [protocol in 'http' | 'ws']: string } = { http: 'https://', - ws: 'wss://', + ws: 'wss://' } export const CHAIN_IDS: { [network in SkaleNetwork]: number } = { staging: 5, legacy: 5, regression: 5, - mainnet: 5, + mainnet: 5 } export function isMainnetChainId(chainId: number | BigInt, skaleNetwork: SkaleNetwork): boolean { @@ -50,7 +50,7 @@ export function isMainnetChainId(chainId: number | BigInt, skaleNetwork: SkaleNe export function getChainEndpoint( mainnetEndpoint: string, network: SkaleNetwork, - chainName: string, + chainName: string ): string { if (chainName === MAINNET_CHAIN_NAME) return mainnetEndpoint return getSChainEndpoint(network, chainName) @@ -59,7 +59,7 @@ export function getChainEndpoint( export function getSChainEndpoint( network: SkaleNetwork, sChainName: string, - protocol: 'http' | 'ws' = 'http', + protocol: 'http' | 'ws' = 'http' ): string { return ( PROTOCOL[protocol] + @@ -90,7 +90,7 @@ export function getMainnetAbi(network: string) { export function initIMA( mainnetEndpoint: string, network: SkaleNetwork, - chainName: string, + chainName: string ): MainnetChain | SChain { if (chainName === MAINNET_CHAIN_NAME) return initMainnet(mainnetEndpoint, network) return initSChain(network, chainName) diff --git a/src/core/sfuel.ts b/src/core/sfuel.ts index 965fb23..bec48f0 100644 --- a/src/core/sfuel.ts +++ b/src/core/sfuel.ts @@ -48,7 +48,7 @@ export class Station { constructor( public chainName: string, - public mpc: MetaportCore, + public mpc: MetaportCore ) { this.chainName = chainName this.mpc = mpc diff --git a/src/core/themes.ts b/src/core/themes.ts index 3f2603a..b5c7b74 100644 --- a/src/core/themes.ts +++ b/src/core/themes.ts @@ -31,15 +31,15 @@ const defaultThemes = { background: '#000000', mode: 'dark', position: Positions.bottomRight, - zIndex: DEFAULT_MP_Z_INDEX, + zIndex: DEFAULT_MP_Z_INDEX }, light: { primary: '#173CFF', background: '#EFEFEF', mode: 'light', position: Positions.bottomRight, - zIndex: DEFAULT_MP_Z_INDEX, - }, + zIndex: DEFAULT_MP_Z_INDEX + } } // warning: order is important here @@ -51,7 +51,7 @@ const MUI_ELEMENTS = [ 'drawer', 'modal', 'snackbar', - 'tooltip', + 'tooltip' ] const INDEX_STEP = 50 diff --git a/src/core/transfer_steps.ts b/src/core/transfer_steps.ts index a0a9e7d..8e1c5d3 100644 --- a/src/core/transfer_steps.ts +++ b/src/core/transfer_steps.ts @@ -30,7 +30,7 @@ import { TransferStepMetadata, UnlockStepMetadata, StepMetadata, - getActionType, + getActionType } from './dataclasses' import { MetaportConfig } from './interfaces/index' @@ -43,7 +43,7 @@ const log = debug('metaport:core:transferSteps') export function getStepsMetadata( config: MetaportConfig, token: TokenData, - to: string, + to: string ): StepMetadata[] { const steps: StepMetadata[] = [] if (token === undefined || token === null || to === null || to === '') return steps @@ -59,7 +59,7 @@ export function getStepsMetadata( steps.push(new WrapStepMetadata(token.chain, to)) } steps.push( - new TransferStepMetadata(getActionType(token.chain, toChain, token.type), token.chain, toChain), + new TransferStepMetadata(getActionType(token.chain, toChain, token.type), token.chain, toChain) ) if (hubTokenOptions.wrapper && !isCloneToClone) { steps.push(new UnwrapStepMetadata(token.chain, toChain)) @@ -72,7 +72,7 @@ export function getStepsMetadata( steps.push(new TransferStepMetadata(getActionType(toChain, to, token.type), toChain, to)) } if (to === MAINNET_CHAIN_NAME && token.keyname === 'eth') { - steps.push(new UnlockStepMetadata(token.chain, toChain)) + steps.push(new UnlockStepMetadata(token.chain, to)) } log(`Action steps metadata:`) diff --git a/src/core/wagmi_network.ts b/src/core/wagmi_network.ts index 2491124..2c89ef8 100644 --- a/src/core/wagmi_network.ts +++ b/src/core/wagmi_network.ts @@ -43,17 +43,17 @@ export function constructWagmiChain(network: SkaleNetwork, chainName: string): C nativeCurrency: { decimals: 18, name: 'sFUEL', - symbol: 'sFUEL', + symbol: 'sFUEL' }, rpcUrls: { public: { http: [endpointHttp], webSocket: [endpointWs] }, - default: { http: [endpointHttp], webSocket: [endpointWs] }, + default: { http: [endpointHttp], webSocket: [endpointWs] } }, blockExplorers: { etherscan: { name: 'SKALE Explorer', url: explorerUrl }, - default: { name: 'SKALE Explorer', url: explorerUrl }, + default: { name: 'SKALE Explorer', url: explorerUrl } }, - contracts: {}, + contracts: {} } as const satisfies Chain } diff --git a/src/index.ts b/src/index.ts index 6351997..bcd01c8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,7 @@ export { interfaces, dataclasses } from './Metaport' -export { useMetaportStore, type MetaportState } from './store/MetaportState' +export { useMetaportStore } from './store/MetaportStore' +export { type MetaportState } from './store/MetaportState' export { useUIStore, useCollapseStore, type UIState, type CollapseState } from './store/Store' export { useSFuelStore, type SFuelState } from './store/SFuelStore' @@ -71,5 +72,5 @@ export { BASE_EXPLORER_URLS, CHAINS_META, chainBg, - getChainAlias, + getChainAlias } diff --git a/src/metadata/metaportConfigStaging.ts b/src/metadata/metaportConfigStaging.ts index 62ff005..1499a45 100644 --- a/src/metadata/metaportConfigStaging.ts +++ b/src/metadata/metaportConfigStaging.ts @@ -12,63 +12,63 @@ export const METAPORT_CONFIG: interfaces.MetaportConfig = { 'staging-faint-slimy-achird', // Nebula 'staging-perfect-parallel-gacrux', // Test Chain 1 'staging-severe-violet-wezen', // Test Chain 2 - 'staging-weepy-fitting-caph', // Tank War Zone + 'staging-weepy-fitting-caph' // Tank War Zone ], tokens: { eth: { - symbol: 'ETH', + symbol: 'ETH' }, skl: { decimals: '18', name: 'SKALE', - symbol: 'SKL', + symbol: 'SKL' }, usdc: { decimals: '6', symbol: 'USDC', - name: 'USD Coin', + name: 'USD Coin' }, usdt: { decimals: '6', symbol: 'USDT', - name: 'Tether USD', + name: 'Tether USD' }, wbtc: { decimals: '18', symbol: 'WBTC', - name: 'WBTC', + name: 'WBTC' }, _SPACE_1: { name: 'SKALE Space', symbol: 'SPACE', iconUrl: - 'https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Rocket/3D/rocket_3d.png', + 'https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Rocket/3D/rocket_3d.png' }, _SKALIENS_1: { name: 'SKALIENS Collection', symbol: 'SKALIENS', iconUrl: - 'https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Alien/3D/alien_3d.png', + 'https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Alien/3D/alien_3d.png' }, ruby: { name: 'Ruby Token', iconUrl: 'https://ruby.exchange/images/tokens/ruby-square.png', - symbol: 'RUBY', + symbol: 'RUBY' }, dai: { name: 'DAI Stablecoin', - symbol: 'DAI', + symbol: 'DAI' }, usdp: { name: 'Pax Dollar', symbol: 'USDP', - iconUrl: 'https://ruby.exchange/images/tokens/usdp-square.png', + iconUrl: 'https://ruby.exchange/images/tokens/usdp-square.png' }, hmt: { name: 'Human Token', symbol: 'HMT', - iconUrl: 'https://s2.coinmarketcap.com/static/img/coins/64x64/10347.png', - }, + iconUrl: 'https://s2.coinmarketcap.com/static/img/coins/64x64/10347.png' + } }, connections: { mainnet: { @@ -78,13 +78,12 @@ export const METAPORT_CONFIG: interfaces.MetaportConfig = { 'staging-legal-crazy-castor': {}, 'staging-utter-unripe-menkar': { hub: 'staging-legal-crazy-castor' - } - // "staging-faint-slimy-achird": {}, - // "staging-perfect-parallel-gacrux": {}, - // "staging-severe-violet-wezen": {}, - // "staging-weepy-fitting-caph": {} - }, - }, + }, + // 'staging-faint-slimy-achird': { + // hub: 'staging-legal-crazy-castor' + // } + } + } }, erc20: { skl: { @@ -92,69 +91,69 @@ export const METAPORT_CONFIG: interfaces.MetaportConfig = { chains: { 'staging-legal-crazy-castor': {}, 'staging-utter-unripe-menkar': { - hub: 'staging-legal-crazy-castor', + hub: 'staging-legal-crazy-castor' }, 'staging-faint-slimy-achird': { - hub: 'staging-legal-crazy-castor', - }, - }, + hub: 'staging-legal-crazy-castor' + } + } }, ruby: { address: '0xd66641E25E9D36A995682572eaD74E24C11Bb422', chains: { - 'staging-legal-crazy-castor': {}, - }, + 'staging-legal-crazy-castor': {} + } }, dai: { address: '0x83B38f79cFFB47CF74f7eC8a5F8D7DD69349fBf7', chains: { - 'staging-legal-crazy-castor': {}, - }, + 'staging-legal-crazy-castor': {} + } }, usdp: { address: '0x66259E472f8d09083ecB51D42F9F872A61001426', chains: { - 'staging-legal-crazy-castor': {}, - }, + 'staging-legal-crazy-castor': {} + } }, usdt: { address: '0xD1E44e3afd6d3F155e7704c67705E3bAC2e491b6', chains: { - 'staging-legal-crazy-castor': {}, - }, + 'staging-legal-crazy-castor': {} + } }, usdc: { address: '0x85dedAA65D33210E15911Da5E9dc29F5C93a50A9', chains: { 'staging-legal-crazy-castor': {}, 'staging-utter-unripe-menkar': { - hub: 'staging-legal-crazy-castor', - }, - }, + hub: 'staging-legal-crazy-castor' + } + } }, wbtc: { address: '0xd80BC0126A38c9F7b915e1B2B9f78280639cadb3', chains: { - 'staging-legal-crazy-castor': {}, - }, + 'staging-legal-crazy-castor': {} + } }, hmt: { address: '0x4058d058ff62ED347dB8a69c43Ae9C67268B50b0', - chains: {}, - }, + chains: {} + } }, erc721meta: { _SPACE_1: { address: '0x1b7729d7E1025A031aF9D6E68598b57f4C2adfF6', - chains: {}, - }, + chains: {} + } }, erc1155: { _SKALIENS_1: { address: '0x6cb73D413970ae9379560aA45c769b417Fbf33D6', - chains: {}, - }, - }, + chains: {} + } + } }, 'staging-utter-unripe-menkar': { // Calypso connections @@ -165,7 +164,7 @@ export const METAPORT_CONFIG: interfaces.MetaportConfig = { 'staging-legal-crazy-castor': { clone: true }, - 'mainnet': { + mainnet: { clone: true, hub: 'staging-legal-crazy-castor' } @@ -177,51 +176,66 @@ export const METAPORT_CONFIG: interfaces.MetaportConfig = { address: '0x7E1B8750C21AebC3bb2a0bDf40be104C609a9852', chains: { 'staging-legal-crazy-castor': { - clone: true, + clone: true }, 'staging-faint-slimy-achird': { hub: 'staging-legal-crazy-castor', - clone: true, + clone: true }, mainnet: { hub: 'staging-legal-crazy-castor', - clone: true, - }, - }, + clone: true + } + } }, usdc: { address: '0x49c37d0Bb6238933eEe2157e9Df417fd62723fF6', chains: { 'staging-legal-crazy-castor': { - clone: true, + clone: true }, mainnet: { hub: 'staging-legal-crazy-castor', - clone: true, - }, - }, - }, - }, + clone: true + } + } + } + } }, 'staging-faint-slimy-achird': { + // Nebula connections + // eth: { + // eth: { + // address: '0x', + // chains: { + // 'staging-legal-crazy-castor': { + // clone: true + // }, + // mainnet: { + // hub: 'staging-legal-crazy-castor', + // clone: true + // }, + // } + // } + // }, erc20: { skl: { address: '0x7F73B66d4e6e67bCdeaF277b9962addcDabBFC4d', chains: { 'staging-legal-crazy-castor': { - clone: true, + clone: true }, mainnet: { hub: 'staging-legal-crazy-castor', - clone: true, + clone: true }, 'staging-utter-unripe-menkar': { hub: 'staging-legal-crazy-castor', - clone: true, - }, - }, - }, - }, + clone: true + } + } + } + } }, 'staging-legal-crazy-castor': { // Europa connections @@ -230,84 +244,87 @@ export const METAPORT_CONFIG: interfaces.MetaportConfig = { address: '0xD2Aaa00700000000000000000000000000000000', chains: { mainnet: { - clone: true, + clone: true }, 'staging-utter-unripe-menkar': { wrapper: '0xa270484784f043e159f74C03B691F80B6F6e3c24' - } - }, - }, + }, + // 'staging-faint-slimy-achird': { + // wrapper: '0xa270484784f043e159f74C03B691F80B6F6e3c24' + // } + } + } }, erc20: { skl: { address: '0xbA1E9BA7CDd4815Da6a51586bE56e8643d1bEAb6', chains: { mainnet: { - clone: true, + clone: true }, 'staging-utter-unripe-menkar': { - wrapper: '0x6a679eF80aF3fE01A646F858Ca1e26D58b5430B6', + wrapper: '0x6a679eF80aF3fE01A646F858Ca1e26D58b5430B6' }, 'staging-faint-slimy-achird': { - wrapper: '0x6a679eF80aF3fE01A646F858Ca1e26D58b5430B6', - }, - }, + wrapper: '0x6a679eF80aF3fE01A646F858Ca1e26D58b5430B6' + } + } }, ruby: { address: '0xf06De9214B1Db39fFE9db2AebFA74E52f1e46e39', chains: { mainnet: { - clone: true, - }, - }, + clone: true + } + } }, dai: { address: '0x3595E2f313780cb2f23e197B8e297066fd410d30', chains: { mainnet: { - clone: true, - }, - }, + clone: true + } + } }, usdp: { address: '0xe0E2cb3A5d6f94a5bc2D00FAa3e64460A9D241E1', chains: { mainnet: { - clone: true, - }, - }, + clone: true + } + } }, usdt: { address: '0xa388F9783d8E5B0502548061c3b06bf4300Fc0E1', chains: { mainnet: { - clone: true, - }, - }, + clone: true + } + } }, usdc: { address: '0x5d42495D417fcd9ECf42F3EA8a55FcEf44eD9B33', chains: { mainnet: { - clone: true, + clone: true }, 'staging-utter-unripe-menkar': { - wrapper: '0x4f250cCE5b8B39caA96D1144b9A32E1c6a9f97b0', - }, - }, + wrapper: '0x4f250cCE5b8B39caA96D1144b9A32E1c6a9f97b0' + } + } }, wbtc: { address: '0xf5E880E1066DDc90471B9BAE6f183D5344fd289F', chains: { mainnet: { - clone: true, - }, - }, - }, - }, + clone: true + } + } + } + } }, 'staging-severe-violet-wezen': { - erc20: {}, + erc20: {} }, 'staging-perfect-parallel-gacrux': { erc20: {}, @@ -325,11 +342,11 @@ export const METAPORT_CONFIG: interfaces.MetaportConfig = { // "address": "0xDf87EEF0977148129969b01b329379b17756cdDE", // "chains": {} // } - }, - }, + } + } }, theme: { mode: 'dark', - vibrant: true, - }, + vibrant: true + } } diff --git a/src/store/CommunityPoolStore.ts b/src/store/CommunityPoolStore.ts index 18d219d..4f185ce 100644 --- a/src/store/CommunityPoolStore.ts +++ b/src/store/CommunityPoolStore.ts @@ -60,7 +60,7 @@ export const useCPStore = create()((set, get) => ({ address: string, chainName1: string, chainName2: string, - mpc: MetaportCore, + mpc: MetaportCore ) => { if (!chainName1 || !chainName2) return if (!get().mainnet) { @@ -74,12 +74,12 @@ export const useCPStore = create()((set, get) => ({ chainName1, chainName2, get().mainnet, - get().sChain, + get().sChain ) set({ chainName: chainName1, cpData: cpData, - amount: cpData.recommendedRechargeAmount ? cpData.recommendedRechargeAmount.toString() : '', + amount: cpData.recommendedRechargeAmount ? cpData.recommendedRechargeAmount.toString() : '' }) - }, + } })) diff --git a/src/store/MetaportState.ts b/src/store/MetaportState.ts index 28e0f52..469644f 100644 --- a/src/store/MetaportState.ts +++ b/src/store/MetaportState.ts @@ -17,27 +17,18 @@ */ /** - * @file MetaportState.ts + * @file IMetaportState.ts * @copyright SKALE Labs 2023-Present */ -import debug from 'debug' - import { Contract } from 'ethers' - +import { WalletClient } from 'viem' import { MainnetChain, SChain } from '@skalenetwork/ima-js' -import { create } from 'zustand' import MetaportCore from '../core/metaport' import * as interfaces from '../core/interfaces' import * as dataclasses from '../core/dataclasses' -import { getEmptyTokenDataMap } from '../core/tokens/helper' -import { MAINNET_CHAIN_NAME, DEFAULT_ERROR_MSG } from '../core/constants' -import { ACTIONS } from '../core/actions' -import { WalletClient } from 'viem' -debug.enable('*') -const log = debug('metaport:state') export interface MetaportState { ima1: MainnetChain | SChain @@ -58,14 +49,14 @@ export interface MetaportState { execute: ( address: string, switchNetwork: (chainId: number) => void, - walletClient: WalletClient, + walletClient: WalletClient ) => void unwrapAll: ( address: string, switchNetwork: (chainId: number) => void, walletClient: WalletClient, - tokens: interfaces.TokenDataMap, + tokens: interfaces.TokenDataMap ) => void check: (amount: string, address: `0x${string}`) => void @@ -114,9 +105,6 @@ export interface MetaportState { errorMessage: dataclasses.ErrorMessage setErrorMessage: (errorMessage: dataclasses.ErrorMessage) => void - actionBtnDisabled: boolean - setActionBtnDisabled: (actionBtnDisabled: boolean) => void - loading: boolean setLoading: (loading: boolean) => void @@ -129,265 +117,3 @@ export interface MetaportState { errorMessageClosedFallback: () => void startOver: () => void } - -export const useMetaportStore = create()((set, get) => ({ - ima1: null, - ima2: null, - setIma1: (ima: MainnetChain | SChain) => set(() => ({ ima1: ima })), - setIma2: (ima: MainnetChain | SChain) => set(() => ({ ima2: ima })), - - mpc: null, - setMpc: (mpc: MetaportCore) => set(() => ({ mpc: mpc })), - - tokenId: null, - setTokenId: (tokenId: number) => - set(() => { - return { - tokenId: tokenId, - } - }), - - amount: '', - setAmount: (amount: string, address: `0x${string}`) => - set((state) => { - state.check(amount, address) - return { - amount: amount, - } - }), - - unwrapAll: async ( - address: `0x${string}`, - switchNetwork: any, - walletClient: WalletClient, - tokens: interfaces.TokenDataMap, - ) => { - log('Running unwrapAll') - set({ loading: true }) - try { - for (const key of Object.keys(tokens)) { - await new ACTIONS.unwrap_stuck( - get().mpc, - get().chainName1, - null, - address, - get().amount, - get().tokenId, - tokens[key], - get().setAmountErrorMessage, - get().setBtnText, - switchNetwork, - walletClient, - ).execute() - } - } catch (err) { - console.error(err) - const msg = err.message ? err.message : DEFAULT_ERROR_MSG - set({ - errorMessage: new dataclasses.TransactionErrorMessage( - msg, - get().errorMessageClosedFallback, - ), - }) - return - } finally { - set({ loading: false }) - } - }, - - execute: async (address: `0x${string}`, switchNetwork: any, walletClient: WalletClient) => { - log('Running execute') - if (get().stepsMetadata[get().currentStep]) { - set({ - loading: true, - transferInProgress: true, - }) - try { - const stepMetadata = get().stepsMetadata[get().currentStep] - const actionClass = ACTIONS[stepMetadata.type] - await new actionClass( - get().mpc, - stepMetadata.from, - stepMetadata.to, - address, - get().amount, - get().tokenId, - get().token, - get().setAmountErrorMessage, - get().setBtnText, - switchNetwork, - walletClient, - ).execute() - } catch (err) { - console.error(err) - const msg = err.message ? err.message : DEFAULT_ERROR_MSG - set({ - errorMessage: new dataclasses.TransactionErrorMessage( - msg, - get().errorMessageClosedFallback, - ), - }) - return - } finally { - set({ loading: false }) - } - set({ - transferInProgress: get().currentStep + 1 !== get().stepsMetadata.length, - currentStep: get().currentStep + 1, - }) - } - }, - - errorMessageClosedFallback() { - set({ - loading: false, - errorMessage: undefined, - transferInProgress: get().currentStep !== 0, - }) - }, - - startOver() { - set({ - loading: false, - errorMessage: undefined, - amount: '', - tokenId: null, - currentStep: 0, - transferInProgress: false, - destTokenBalance: null, - }) - }, - - check: async (amount: string, address: string) => { - if (get().stepsMetadata[get().currentStep] && address) { - set({ - 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() - } - set({ loading: false }) - }, - - currentStep: 0, - setCurrentStep: (currentStep: number) => set(() => ({ currentStep: currentStep })), - - stepsMetadata: [], - setStepsMetadata: (steps: dataclasses.StepMetadata[]) => set(() => ({ stepsMetadata: steps })), - - chainName1: '', - chainName2: '', - - appName1: null, - appName2: null, - - setAppName1: (name: string) => set(() => ({ appName1: name })), - setAppName2: (name: string) => set(() => ({ appName2: name })), - - destChains: [], - - setChainName1: (name: string) => { - set(get().mpc.chainChanged(name, get().chainName2, get().token)) - }, - setChainName2: (name: string) => { - set(get().mpc.chainChanged(get().chainName1, name, get().token)) - }, - - tokens: getEmptyTokenDataMap(), - - token: null, - - setToken: async (token: dataclasses.TokenData) => { - set(get().mpc.tokenChanged( - get().chainName1, - get().ima2, - token, - get().chainName2 - )) - }, - - wrappedTokens: getEmptyTokenDataMap(), - tokenContracts: {}, - tokenBalances: {}, - - wrappedTokenContracts: {}, - wrappedTokenBalances: {}, - - destTokenContract: null, - destTokenBalance: null, - - updateDestTokenBalance: async (address: string) => { - if (!address) { - set({ destTokenBalance: null }) - return - } - if (get().destTokenContract) { - const balance = await get().mpc.tokenBalance(get().destTokenContract, address) - set({ destTokenBalance: balance }) - } else { - if ( - get().token && - get().token.type === dataclasses.TokenType.eth && - get().chainName2 === MAINNET_CHAIN_NAME - ) { - set({ destTokenBalance: await get().ima2.ethBalance(address) }) - } - } - }, - - updateTokenBalances: async (address: string) => { - if (!address) { - set({ tokenBalances: {} }) - return - } - const tokenBalances = await get().mpc.tokenBalances(get().tokenContracts, address) - if (get().chainName1 === MAINNET_CHAIN_NAME || get().chainName2 === MAINNET_CHAIN_NAME) { - tokenBalances.eth = await get().ima1.ethBalance(address) - } - set({ - tokenBalances: tokenBalances, - }) - }, - - updateWrappedTokenBalances: async (address: string) => { - if (!address) { - set({ wrappedTokenBalances: {} }) - return - } - set({ - wrappedTokenBalances: await get().mpc.tokenBalances(get().wrappedTokenContracts, address), - }) - }, - - amountErrorMessage: null, - setAmountErrorMessage: (em: string) => set(() => ({ amountErrorMessage: em })), - - errorMessage: null, - setErrorMessage: (em: dataclasses.ErrorMessage) => set(() => ({ errorMessage: em })), - - actionBtnDisabled: false, - setActionBtnDisabled: (disabled: boolean) => set(() => ({ actionBtnDisabled: disabled })), - - loading: false, - setLoading: (loading: boolean) => set(() => ({ loading: loading })), - - transferInProgress: false, - setTransferInProgress: (inProgress: boolean) => set(() => ({ transferInProgress: inProgress })), - - btnText: null, - setBtnText: (btnText: string) => set(() => ({ btnText: btnText })), -})) diff --git a/src/store/MetaportStore.ts b/src/store/MetaportStore.ts new file mode 100644 index 0000000..817da97 --- /dev/null +++ b/src/store/MetaportStore.ts @@ -0,0 +1,283 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/** + * @file MetaportState.ts + * @copyright SKALE Labs 2023-Present + */ + +import debug from 'debug' +import { WalletClient } from 'viem' +import { create } from 'zustand' +import { MainnetChain, SChain } from '@skalenetwork/ima-js' + +import { MetaportState } from './MetaportState' + +import MetaportCore from '../core/metaport' +import * as interfaces from '../core/interfaces' +import * as dataclasses from '../core/dataclasses' +import { getEmptyTokenDataMap } from '../core/tokens/helper' +import { MAINNET_CHAIN_NAME, DEFAULT_ERROR_MSG } from '../core/constants' +import { ACTIONS } from '../core/actions' + + +debug.enable('*') +const log = debug('metaport:state') + + +export const useMetaportStore = create()((set, get) => ({ + ima1: null, + ima2: null, + setIma1: (ima: MainnetChain | SChain) => set(() => ({ ima1: ima })), + setIma2: (ima: MainnetChain | SChain) => set(() => ({ ima2: ima })), + + mpc: null, + setMpc: (mpc: MetaportCore) => set(() => ({ mpc: mpc })), + + tokenId: null, + setTokenId: (tokenId: number) => set(() => { return { tokenId: tokenId } }), + + amount: '', + setAmount: (amount: string, address: `0x${string}`) => + set((state) => { + state.check(amount, address) + return { + amount: amount + } + }), + + unwrapAll: async ( + address: `0x${string}`, + switchNetwork: any, + walletClient: WalletClient, + tokens: interfaces.TokenDataMap + ) => { + log('Running unwrapAll') + set({ loading: true }) + try { + for (const key of Object.keys(tokens)) { + await new ACTIONS.unwrap_stuck( + get().mpc, + get().chainName1, + null, + address, + get().amount, + get().tokenId, + tokens[key], + get().setAmountErrorMessage, + get().setBtnText, + switchNetwork, + walletClient + ).execute() + } + } catch (err) { + console.error(err) + const msg = err.message ? err.message : DEFAULT_ERROR_MSG + set({ + errorMessage: new dataclasses.TransactionErrorMessage(msg, get().errorMessageClosedFallback) + }) + return + } finally { + set({ loading: false }) + } + }, + + execute: async (address: `0x${string}`, switchNetwork: any, walletClient: WalletClient) => { + log('Running execute') + if (get().stepsMetadata[get().currentStep]) { + set({ + loading: true, + transferInProgress: true + }) + try { + const stepMetadata = get().stepsMetadata[get().currentStep] + const actionClass = ACTIONS[stepMetadata.type] + await new actionClass( + get().mpc, + stepMetadata.from, + stepMetadata.to, + address, + get().amount, + get().tokenId, + get().token, + get().setAmountErrorMessage, + get().setBtnText, + switchNetwork, + walletClient + ).execute() + } catch (err) { + console.error(err) + const msg = err.message ? err.message : DEFAULT_ERROR_MSG + set({ + errorMessage: new dataclasses.TransactionErrorMessage( + msg, + get().errorMessageClosedFallback + ) + }) + return + } finally { + set({ loading: false }) + } + set({ + transferInProgress: get().currentStep + 1 !== get().stepsMetadata.length, + currentStep: get().currentStep + 1 + }) + } + }, + + errorMessageClosedFallback() { + set({ loading: false, errorMessage: undefined, transferInProgress: get().currentStep !== 0 }) + }, + + startOver() { + set({ + loading: false, + errorMessage: undefined, + amount: '', + tokenId: null, + currentStep: 0, + transferInProgress: false, + destTokenBalance: null + }) + }, + + check: async (amount: string, address: string) => { + if (get().stepsMetadata[get().currentStep] && address) { + set({ + 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() + } + set({ loading: false }) + }, + + currentStep: 0, + setCurrentStep: (currentStep: number) => set(() => ({ currentStep: currentStep })), + + stepsMetadata: [], + setStepsMetadata: (steps: dataclasses.StepMetadata[]) => set(() => ({ stepsMetadata: steps })), + + chainName1: '', + chainName2: '', + + appName1: null, + appName2: null, + + setAppName1: (name: string) => set(() => ({ appName1: name })), + setAppName2: (name: string) => set(() => ({ appName2: name })), + + destChains: [], + + setChainName1: (name: string) => { + set(get().mpc.chainChanged(name, get().chainName2, get().token)) + }, + setChainName2: (name: string) => { + set(get().mpc.chainChanged(get().chainName1, name, get().token)) + }, + + tokens: getEmptyTokenDataMap(), + + token: null, + + setToken: async (token: dataclasses.TokenData) => { + set(get().mpc.tokenChanged(get().chainName1, get().ima2, token, get().chainName2)) + }, + + wrappedTokens: getEmptyTokenDataMap(), + tokenContracts: {}, + tokenBalances: {}, + + wrappedTokenContracts: {}, + wrappedTokenBalances: {}, + + destTokenContract: null, + destTokenBalance: null, + + updateDestTokenBalance: async (address: string) => { + if (!address) { + set({ destTokenBalance: null }) + return + } + if (get().destTokenContract) { + const balance = await get().mpc.tokenBalance(get().destTokenContract, address) + set({ destTokenBalance: balance }) + } else { + if ( + get().token && + get().token.type === dataclasses.TokenType.eth && + get().chainName2 === MAINNET_CHAIN_NAME + ) { + set({ destTokenBalance: await get().ima2.ethBalance(address) }) + } + } + }, + + updateTokenBalances: async (address: string) => { + if (!address) { + set({ tokenBalances: {} }) + return + } + const tokenBalances = await get().mpc.tokenBalances(get().tokenContracts, address) + if (get().chainName1 === MAINNET_CHAIN_NAME) { + tokenBalances.eth = await get().ima1.ethBalance(address) + } + set({ + tokenBalances: tokenBalances + }) + }, + + updateWrappedTokenBalances: async (address: string) => { + if (!address) { + set({ wrappedTokenBalances: {} }) + return + } + set({ + wrappedTokenBalances: await get().mpc.tokenBalances(get().wrappedTokenContracts, address) + }) + }, + + amountErrorMessage: null, + setAmountErrorMessage: (em: string) => set(() => ({ amountErrorMessage: em })), + + errorMessage: null, + setErrorMessage: (em: dataclasses.ErrorMessage) => set(() => ({ errorMessage: em })), + + loading: false, + setLoading: (loading: boolean) => set(() => ({ loading: loading })), + + transferInProgress: false, + setTransferInProgress: (inProgress: boolean) => set(() => ({ transferInProgress: inProgress })), + + btnText: null, + setBtnText: (btnText: string) => set(() => ({ btnText: btnText })) +})) diff --git a/src/store/SFuelStore.ts b/src/store/SFuelStore.ts index fd36951..3bbc3f0 100644 --- a/src/store/SFuelStore.ts +++ b/src/store/SFuelStore.ts @@ -65,5 +65,5 @@ export const useSFuelStore = create()((set, get) => ({ setSFuelStatus: (status: 'action' | 'warning' | 'error') => set({ sFuelStatus: status }), sFuelOk: false, - setSFuelOk: (sFuelOk: boolean) => set(() => ({ sFuelOk: sFuelOk })), + setSFuelOk: (sFuelOk: boolean) => set(() => ({ sFuelOk: sFuelOk })) })) diff --git a/src/store/Store.ts b/src/store/Store.ts index eb8dabf..fb0b9b3 100644 --- a/src/store/Store.ts +++ b/src/store/Store.ts @@ -35,7 +35,7 @@ export const useUIStore = create()((set) => ({ theme: null, setTheme: (theme: interfaces.MetaportTheme) => set(() => ({ theme: theme })), open: false, - setOpen: (isOpen: boolean) => set(() => ({ open: isOpen })), + setOpen: (isOpen: boolean) => set(() => ({ open: isOpen })) })) export interface CollapseState { @@ -62,7 +62,7 @@ export const useCollapseStore = create()((set) => ({ expandedTo: false, expandedTokens: false, expandedCP: false, - expandedWT: false, + expandedWT: false })), expandedTo: false, setExpandedTo: (expanded: string | false) => @@ -71,7 +71,7 @@ export const useCollapseStore = create()((set) => ({ expandedFrom: false, expandedTokens: false, expandedCP: false, - expandedWT: false, + expandedWT: false })), expandedTokens: false, setExpandedTokens: (expanded: string | false) => @@ -80,7 +80,7 @@ export const useCollapseStore = create()((set) => ({ expandedFrom: false, expandedTo: false, expandedCP: false, - expandedWT: false, + expandedWT: false })), expandedCP: false, setExpandedCP: (expanded: string | false) => @@ -89,7 +89,7 @@ export const useCollapseStore = create()((set) => ({ expandedFrom: false, expandedTo: false, expandedTokens: false, - expandedWT: false, + expandedWT: false })), expandedWT: false, setExpandedWT: (expanded: string | false) => @@ -98,6 +98,6 @@ export const useCollapseStore = create()((set) => ({ expandedFrom: false, expandedTo: false, expandedTokens: false, - expandedWT: expanded, - })), + expandedWT: expanded + })) })) From 4dcf13b80ff61497e53e0eb8752b4fb44bc06f6a Mon Sep 17 00:00:00 2001 From: Dmytro Date: Mon, 11 Sep 2023 13:27:25 +0100 Subject: [PATCH 45/54] Add unwrap for eth token --- .../WrappedTokens/WrappedTokens.tsx | 2 +- src/core/metadata.ts | 7 ------ src/core/metaport.ts | 25 ++++++++++++++++--- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/components/WrappedTokens/WrappedTokens.tsx b/src/components/WrappedTokens/WrappedTokens.tsx index 6825005..f7121b1 100644 --- a/src/components/WrappedTokens/WrappedTokens.tsx +++ b/src/components/WrappedTokens/WrappedTokens.tsx @@ -87,7 +87,7 @@ export default function WrappedTokens() { setFilteredTokens( Object.keys(wrappedTokenBalances).reduce((acc, key) => { if (wrappedTokenBalances[key] !== 0n) { - acc[key] = wrappedTokens.erc20[key] + acc[key] = wrappedTokens.erc20[key] ?? wrappedTokens.eth[key] } return acc }, {}) diff --git a/src/core/metadata.ts b/src/core/metadata.ts index 19b5bea..4009297 100644 --- a/src/core/metadata.ts +++ b/src/core/metadata.ts @@ -33,13 +33,6 @@ import * as REGRESSION_CHAIN_ICONS from '../meta/regression/icons' import * as icons from '../icons' -// const icons = { -// eth: { default: '' }, -// skl: { -// default: -// 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHZpZXdCb3g9IjAgMCAzMiAzMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSJub25lIj48Y2lyY2xlIGZpbGw9IiMwMDAiIGN4PSIxNiIgY3k9IjE2IiByPSIxNiIvPjxnIGZpbGw9IiNGRkYiPjxwYXRoIGQ9Ik0yMi41MTQgOC40OTJ2Ljk5MUg5LjgxdjEzLjAzNGgxMi43MDRWMjQuNWwtNy40Mi0uMDU3LTcuNDUtLjA4NS0uMDg2LTguNDQzTDcuNSA3LjVoMTUuMDE0eiIvPjxwYXRoIGQ9Ik0yMy42OTggMTAuOWMxLjEyNi4zMTIgMi4xMDggMS4xOSAyLjQyNSAyLjE4Mi4xNzMuNTk1LjA4Ny42NTEtLjkyNC42NTEtLjc4IDAtMS4yMTItLjE3LTEuNDcyLS41NjYtLjQzMy0uNzA5LTIuMzk3LS43OTQtMi45NzQtLjExNC0uNjM1Ljc2NS4wNTggMS4zMzIgMi4zMSAxLjg0MiAxLjEyNi4yNTUgMi4zMS42OCAyLjYyNy45NjMgMS40NDQgMS4yNzUuODY2IDQuMDgtMS4wMSA0Ljg0NS0xLjI3LjUxLTMuMzUuNTEtNC42MiAwLS44NjYtLjM2OC0xLjg3Ny0xLjY0My0xLjg3Ny0yLjQzNiAwLS41MSAxLjg3Ny0uMzEyIDIuMzY4LjI4MyAxLjA0IDEuMTYyIDMuNDY0Ljk5MiAzLjYzOC0uMjU1LjE0NC0uOTYzLS40MDUtMS4zODgtMi4wNS0xLjU4Ny0yLjY4NS0uMzY4LTMuNjY3LTEuMTktMy42NjctMy4wNiAwLTIuMjEgMi40MjUtMy41MTMgNS4yMjYtMi43NDh6Ii8+PC9nPjwvZz48L3N2Zz4=', -// }, -// } // TODO: storybook fix const CHAIN_ICONS = { mainnet: MAINNET_CHAIN_ICONS, diff --git a/src/core/metaport.ts b/src/core/metaport.ts index 013adac..874e481 100644 --- a/src/core/metaport.ts +++ b/src/core/metaport.ts @@ -108,6 +108,13 @@ export function createWrappedTokensMap( addTokenData(tokenKeyname, chainName1, tokenType as TokenType, config, wrappedTokens) } }) + const ethToken = config.connections[chainName1].eth?.eth + if (ethToken) { + const wrapperAddress = findFirstWrapperAddress(ethToken) + if (wrapperAddress) { + addTokenData('eth', chainName1, TokenType.eth, config, wrappedTokens) + } + } return wrappedTokens } @@ -291,10 +298,6 @@ export default class MetaportCore { const tokens = this.tokens(chainName1, chainName2) const tokenContracts = this.tokenContracts(tokens, TokenType.erc20, chainName1, ima1.provider) - if (tokens.eth.eth && chainName1 !== MAINNET_CHAIN_NAME) { - tokenContracts.eth = this.tokenContract(chainName1, 'eth', TokenType.eth, ima1.provider) - } - const wrappedTokenContracts = this.tokenContracts( tokens, TokenType.erc20, @@ -303,6 +306,20 @@ export default class MetaportCore { CustomAbiTokenType.erc20wrap ) + if (tokens.eth?.eth && chainName1 !== MAINNET_CHAIN_NAME) { + tokenContracts.eth = this.tokenContract(chainName1, 'eth', TokenType.eth, ima1.provider) + + const destChainName = findFirstWrapperChainName(tokens.eth.eth) + wrappedTokenContracts.eth = this.tokenContract( + chainName1, + 'eth', + TokenType.eth, + ima1.provider, + CustomAbiTokenType.erc20wrap, + destChainName + ) + } + const prevTokenKeyname = prevToken?.keyname const prevTokenType = prevToken?.type const token = prevTokenKeyname ? tokens[prevTokenType][prevTokenKeyname] : null From c9c04fe64485845a0c61468459c3b15a2aeadabb Mon Sep 17 00:00:00 2001 From: Dmytro Date: Mon, 11 Sep 2023 17:07:24 +0100 Subject: [PATCH 46/54] Restructure CSS imports --- src/components/AddToken.tsx | 42 +++++++++++++++++++ .../AmountErrorMessage.tsx | 8 ++-- src/components/AmountErrorMessage/index.ts | 1 - src/components/AmountInput/AmountInput.tsx | 3 +- src/components/{ChainApps => }/ChainApps.tsx | 15 ++++--- src/components/ChainApps/index.ts | 1 - src/components/{ChainIcon => }/ChainIcon.tsx | 9 ++-- src/components/ChainIcon/index.ts | 1 - .../{ChainsList => }/ChainsList.tsx | 15 +++---- src/components/ChainsList/index.ts | 1 - .../CommunityPool/CommunityPool.tsx | 4 +- src/components/ErrorMessage/ErrorMessage.tsx | 4 +- .../MetaportProvider/MetaportProvider.tsx | 5 +-- src/components/SFuelWarning/SFuelWarning.tsx | 6 +-- src/components/SkConnect/SkConnect.tsx | 5 +-- src/components/SkPaper/SkPaper.tsx | 5 +-- src/components/Stepper/SkStepper.tsx | 34 ++++++--------- .../SwitchDirection/SwitchDirection.tsx | 4 +- src/components/TokenList/TokenBalance.tsx | 3 +- src/components/TokenList/TokenList.tsx | 6 +-- .../TokenListSection/TokenListSection.tsx | 4 +- src/components/TransferETA/TransferETA.tsx | 7 ++-- src/components/TransferETF/TransferETF.tsx | 4 +- src/components/WidgetBody/WidgetBody.tsx | 3 +- src/components/WidgetUI/WidgetUI.tsx | 5 +-- .../WrappedTokens/WrappedTokens.tsx | 5 +-- src/core/css.ts | 36 ++++++++++++++++ src/core/helper.ts | 8 ---- src/core/metaport.ts | 18 ++++---- src/index.ts | 5 +-- 30 files changed, 148 insertions(+), 119 deletions(-) create mode 100644 src/components/AddToken.tsx rename src/components/{AmountErrorMessage => }/AmountErrorMessage.tsx (74%) delete mode 100644 src/components/AmountErrorMessage/index.ts rename src/components/{ChainApps => }/ChainApps.tsx (89%) delete mode 100644 src/components/ChainApps/index.ts rename src/components/{ChainIcon => }/ChainIcon.tsx (76%) delete mode 100644 src/components/ChainIcon/index.ts rename src/components/{ChainsList => }/ChainsList.tsx (95%) delete mode 100644 src/components/ChainsList/index.ts create mode 100644 src/core/css.ts diff --git a/src/components/AddToken.tsx b/src/components/AddToken.tsx new file mode 100644 index 0000000..eee5a27 --- /dev/null +++ b/src/components/AddToken.tsx @@ -0,0 +1,42 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +/** + * @file AddToken.ts + * @copyright SKALE Labs 2023-Present + */ + +import { cls, cmn, styles } from '../core/css' + +import Button from '@mui/material/Button' +import TollIcon from '@mui/icons-material/Toll' + + +export default function AddToken(props: {}) { + return ( + + ) +} diff --git a/src/components/AmountErrorMessage/AmountErrorMessage.tsx b/src/components/AmountErrorMessage.tsx similarity index 74% rename from src/components/AmountErrorMessage/AmountErrorMessage.tsx rename to src/components/AmountErrorMessage.tsx index d134370..6d5d6c6 100644 --- a/src/components/AmountErrorMessage/AmountErrorMessage.tsx +++ b/src/components/AmountErrorMessage.tsx @@ -1,10 +1,9 @@ -import React from 'react' import Collapse from '@mui/material/Collapse' -import { cls } from '../../core/helper' -import cmn from '../../styles/cmn.module.scss' +import { cls, cmn } from '../core/css' -import { useMetaportStore } from '../../store/MetaportStore' + +import { useMetaportStore } from '../store/MetaportStore' export default function AmountErrorMessage() { const amountErrorMessage = useMetaportStore((state) => state.amountErrorMessage) @@ -20,7 +19,6 @@ export default function AmountErrorMessage() { cmn.flexg, cmn.mtop10, cmn.mleft10 - // cmn.upp )} > 🔴 {amountErrorMessage} diff --git a/src/components/AmountErrorMessage/index.ts b/src/components/AmountErrorMessage/index.ts deleted file mode 100644 index 0944661..0000000 --- a/src/components/AmountErrorMessage/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './AmountErrorMessage' diff --git a/src/components/AmountInput/AmountInput.tsx b/src/components/AmountInput/AmountInput.tsx index ae3aeab..440cb33 100644 --- a/src/components/AmountInput/AmountInput.tsx +++ b/src/components/AmountInput/AmountInput.tsx @@ -3,8 +3,7 @@ import { useAccount } from 'wagmi' import TextField from '@mui/material/TextField' -import { cls } from '../../core/helper' -import cmn from '../../styles/cmn.module.scss' +import { cls, cmn } from '../../core/css' import localStyles from './AmountInput.module.scss' import TokenList from '../TokenList' diff --git a/src/components/ChainApps/ChainApps.tsx b/src/components/ChainApps.tsx similarity index 89% rename from src/components/ChainApps/ChainApps.tsx rename to src/components/ChainApps.tsx index c3d1920..ae33d8f 100644 --- a/src/components/ChainApps/ChainApps.tsx +++ b/src/components/ChainApps.tsx @@ -1,14 +1,13 @@ -import React from 'react' -import { cls, getChainAppsMeta, getChainAlias } from '../../core/helper' - -import styles from '../../styles/styles.module.scss' -import cmn from '../../styles/cmn.module.scss' -import { SkaleNetwork } from '../../core/interfaces' - -import ChainIcon from '../ChainIcon' import { Button } from '@mui/material' import KeyboardArrowRightRoundedIcon from '@mui/icons-material/KeyboardArrowRightRounded' +import { cls, cmn, styles } from '../core/css' +import { SkaleNetwork } from '../core/interfaces' +import { getChainAppsMeta, getChainAlias } from '../core/helper' + +import ChainIcon from './ChainIcon' + + export default function ChainApps(props: { skaleNetwork: SkaleNetwork chain: string diff --git a/src/components/ChainApps/index.ts b/src/components/ChainApps/index.ts deleted file mode 100644 index 47b61bd..0000000 --- a/src/components/ChainApps/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './ChainApps' diff --git a/src/components/ChainIcon/ChainIcon.tsx b/src/components/ChainIcon.tsx similarity index 76% rename from src/components/ChainIcon/ChainIcon.tsx rename to src/components/ChainIcon.tsx index 739ef13..b1e1e97 100644 --- a/src/components/ChainIcon/ChainIcon.tsx +++ b/src/components/ChainIcon.tsx @@ -1,10 +1,9 @@ -import React from 'react' import OfflineBoltRoundedIcon from '@mui/icons-material/OfflineBoltRounded' -import { SkaleNetwork } from '../../core/interfaces' -import { chainIconPath } from '../../core/metadata' +import { SkaleNetwork } from '../core/interfaces' +import { chainIconPath } from '../core/metadata' + +import { cls, styles } from '../core/css' -import { cls } from '../../core/helper' -import styles from '../../styles/styles.module.scss' export default function ChainIcon(props: { skaleNetwork: SkaleNetwork diff --git a/src/components/ChainIcon/index.ts b/src/components/ChainIcon/index.ts deleted file mode 100644 index afe24d4..0000000 --- a/src/components/ChainIcon/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './ChainIcon' diff --git a/src/components/ChainsList/ChainsList.tsx b/src/components/ChainsList.tsx similarity index 95% rename from src/components/ChainsList/ChainsList.tsx rename to src/components/ChainsList.tsx index aeddc11..85fc3dc 100644 --- a/src/components/ChainsList/ChainsList.tsx +++ b/src/components/ChainsList.tsx @@ -7,15 +7,16 @@ import ExpandMoreIcon from '@mui/icons-material/ExpandMore' import Button from '@mui/material/Button' import KeyboardArrowRightRoundedIcon from '@mui/icons-material/KeyboardArrowRightRounded' -import ChainApps from '../ChainApps' -import ChainIcon from '../ChainIcon' +import ChainApps from './ChainApps' +import ChainIcon from './ChainIcon' -import { MetaportConfig } from '../../core/interfaces' +import { MetaportConfig } from '../core/interfaces' + +import { getChainAlias, getChainAppsMeta } from '../core/helper' +import { cls, cmn, styles } from '../core/css' + +import SkPaper from './SkPaper/SkPaper' -import { cls, getChainAlias, getChainAppsMeta } from '../../core/helper' -import cmn from '../../styles/cmn.module.scss' -import styles from '../../styles/styles.module.scss' -import SkPaper from '../SkPaper/SkPaper' export default function ChainsList(props: { config: MetaportConfig diff --git a/src/components/ChainsList/index.ts b/src/components/ChainsList/index.ts deleted file mode 100644 index 04f8e63..0000000 --- a/src/components/ChainsList/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './ChainsList' diff --git a/src/components/CommunityPool/CommunityPool.tsx b/src/components/CommunityPool/CommunityPool.tsx index 94b18e6..09fb295 100644 --- a/src/components/CommunityPool/CommunityPool.tsx +++ b/src/components/CommunityPool/CommunityPool.tsx @@ -47,9 +47,7 @@ import { fromWei } from '../../core/convertation' import { withdraw, recharge } from '../../core/community_pool' import { BALANCE_UPDATE_INTERVAL_MS, DEFAULT_ERC20_DECIMALS } from '../../core/constants' -import { cls } from '../../core/helper' -import cmn from '../../styles/cmn.module.scss' -import styles from '../../styles/styles.module.scss' +import { cls, cmn, styles } from '../../core/css' import { useCPStore } from '../../store/CommunityPoolStore' import { useCollapseStore } from '../../store/Store' diff --git a/src/components/ErrorMessage/ErrorMessage.tsx b/src/components/ErrorMessage/ErrorMessage.tsx index a57c879..4c57631 100644 --- a/src/components/ErrorMessage/ErrorMessage.tsx +++ b/src/components/ErrorMessage/ErrorMessage.tsx @@ -1,9 +1,7 @@ import React from 'react' import Button from '@mui/material/Button' -import { cls } from '../../core/helper' -import cmn from '../../styles/cmn.module.scss' -import styles from '../../styles/styles.module.scss' +import { cls, cmn, styles } from '../../core/css' import { ErrorMessage } from '../../core/dataclasses' diff --git a/src/components/MetaportProvider/MetaportProvider.tsx b/src/components/MetaportProvider/MetaportProvider.tsx index 91b10ec..64153c6 100644 --- a/src/components/MetaportProvider/MetaportProvider.tsx +++ b/src/components/MetaportProvider/MetaportProvider.tsx @@ -47,15 +47,12 @@ import { constructWagmiChain, getWebSocketUrl } from '../../core/wagmi_network' import { getWidgetTheme, getMuiZIndex } from '../../core/themes' -import { cls } from '../../core/helper' +import { cls, cmn, styles } from '../../core/css' import { useUIStore } from '../../store/Store' import { useMetaportStore } from '../../store/MetaportStore' import MetaportCore from '../../core/metaport' -import styles from '../../styles/styles.module.scss' -import cmn from '../../styles/cmn.module.scss' - const { chains, webSocketPublicClient } = configureChains( [ mainnet, diff --git a/src/components/SFuelWarning/SFuelWarning.tsx b/src/components/SFuelWarning/SFuelWarning.tsx index 48a60a1..d4e21f4 100644 --- a/src/components/SFuelWarning/SFuelWarning.tsx +++ b/src/components/SFuelWarning/SFuelWarning.tsx @@ -37,13 +37,13 @@ import { Station } from '../../core/sfuel' import { useMetaportStore } from '../../store/MetaportStore' import { useSFuelStore } from '../../store/SFuelStore' -import { cls } from '../../core/helper' -import cmn from '../../styles/cmn.module.scss' -import styles from '../../styles/styles.module.scss' +import { cls, cmn, styles } from '../../core/css' + debug.enable('*') const log = debug('metaport:components:SFuel') + export default function SFuelWarning(props: {}) { const mpc = useMetaportStore((state) => state.mpc) const chainName1 = useMetaportStore((state) => state.chainName1) diff --git a/src/components/SkConnect/SkConnect.tsx b/src/components/SkConnect/SkConnect.tsx index 23d1dc4..0ffb169 100644 --- a/src/components/SkConnect/SkConnect.tsx +++ b/src/components/SkConnect/SkConnect.tsx @@ -27,10 +27,7 @@ import Jazzicon, { jsNumberForAddress } from 'react-jazzicon' import Button from '@mui/material/Button' import ExpandMoreIcon from '@mui/icons-material/ExpandMore' -import { cls } from '../../core/helper' - -import styles from '../../styles/styles.module.scss' -import cmn from '../../styles/cmn.module.scss' +import { cls, cmn, styles } from '../../core/css' import skaleLogoFull from '../WidgetUI/skale_logo.svg' import { useMetaportStore } from '../../store/MetaportStore' diff --git a/src/components/SkPaper/SkPaper.tsx b/src/components/SkPaper/SkPaper.tsx index e122ec0..11509ba 100644 --- a/src/components/SkPaper/SkPaper.tsx +++ b/src/components/SkPaper/SkPaper.tsx @@ -22,10 +22,7 @@ */ import React, { ReactElement } from 'react' -import { cls } from '../../core/helper' - -import styles from '../../styles/styles.module.scss' -import cmn from '../../styles/cmn.module.scss' +import { cls, cmn, styles } from '../../core/css' import { useUIStore } from '../../store/Store' diff --git a/src/components/Stepper/SkStepper.tsx b/src/components/Stepper/SkStepper.tsx index c2ce37c..c2d5921 100644 --- a/src/components/Stepper/SkStepper.tsx +++ b/src/components/Stepper/SkStepper.tsx @@ -1,4 +1,5 @@ -import React, { useEffect, useState } from 'react' +import { useEffect, useState } from 'react' +import { useWalletClient, useSwitchNetwork, useAccount } from 'wagmi' import Box from '@mui/material/Box' import Stepper from '@mui/material/Stepper' @@ -7,26 +8,24 @@ import StepLabel from '@mui/material/StepLabel' import StepContent from '@mui/material/StepContent' import Button from '@mui/material/Button' import LoadingButton from '@mui/lab/LoadingButton' +import Collapse from '@mui/material/Collapse' -import { cls, getChainAlias, getRandom } from '../../core/helper' -import cmn from '../../styles/cmn.module.scss' -import styles from '../../styles/styles.module.scss' +import SettingsBackupRestoreRoundedIcon from '@mui/icons-material/SettingsBackupRestoreRounded' +import TollIcon from '@mui/icons-material/Toll' + +import { getChainAlias, getRandom } from '../../core/helper' +import { cls, cmn, styles } from '../../core/css' import localStyles from './SkStepper.module.scss' + import ChainIcon from '../ChainIcon' +import AddToken from '../AddToken' import { useMetaportStore } from '../../store/MetaportStore' import { useCPStore } from '../../store/CommunityPoolStore' -import { Collapse } from '@mui/material' import { SkaleNetwork } from '../../core/interfaces' - -import { useWalletClient } from 'wagmi' - -import SettingsBackupRestoreRoundedIcon from '@mui/icons-material/SettingsBackupRestoreRounded' -import TollIcon from '@mui/icons-material/Toll' - -import { useSwitchNetwork, useAccount } from 'wagmi' import { SUCCESS_EMOJIS } from '../../core/constants' + export default function SkStepper(props: { skaleNetwork: SkaleNetwork }) { const { address } = useAccount() const { switchNetworkAsync } = useSwitchNetwork() @@ -137,16 +136,7 @@ export default function SkStepper(props: { skaleNetwork: SkaleNetwork }) {

- + ) } diff --git a/src/components/AmountErrorMessage.tsx b/src/components/AmountErrorMessage.tsx index 6d5d6c6..f7a4627 100644 --- a/src/components/AmountErrorMessage.tsx +++ b/src/components/AmountErrorMessage.tsx @@ -2,7 +2,6 @@ import Collapse from '@mui/material/Collapse' import { cls, cmn } from '../core/css' - import { useMetaportStore } from '../store/MetaportStore' export default function AmountErrorMessage() { diff --git a/src/components/ChainApps.tsx b/src/components/ChainApps.tsx index ae33d8f..4016e8e 100644 --- a/src/components/ChainApps.tsx +++ b/src/components/ChainApps.tsx @@ -7,7 +7,6 @@ import { getChainAppsMeta, getChainAlias } from '../core/helper' import ChainIcon from './ChainIcon' - export default function ChainApps(props: { skaleNetwork: SkaleNetwork chain: string diff --git a/src/components/ChainIcon.tsx b/src/components/ChainIcon.tsx index b1e1e97..024ce44 100644 --- a/src/components/ChainIcon.tsx +++ b/src/components/ChainIcon.tsx @@ -4,7 +4,6 @@ import { chainIconPath } from '../core/metadata' import { cls, styles } from '../core/css' - export default function ChainIcon(props: { skaleNetwork: SkaleNetwork chainName: string diff --git a/src/components/ChainsList.tsx b/src/components/ChainsList.tsx index 07777b3..1bc770a 100644 --- a/src/components/ChainsList.tsx +++ b/src/components/ChainsList.tsx @@ -17,7 +17,6 @@ import { cls, cmn, styles } from '../core/css' import SkPaper from './SkPaper' - export default function ChainsList(props: { config: MetaportConfig expanded: string | false diff --git a/src/components/SFuelWarning.tsx b/src/components/SFuelWarning.tsx index c077e2d..fe5e320 100644 --- a/src/components/SFuelWarning.tsx +++ b/src/components/SFuelWarning.tsx @@ -39,11 +39,9 @@ import { useSFuelStore } from '../store/SFuelStore' import { cls, cmn, styles } from '../core/css' - debug.enable('*') const log = debug('metaport:components:SFuel') - export default function SFuelWarning(props: {}) { const mpc = useMetaportStore((state) => state.mpc) const chainName1 = useMetaportStore((state) => state.chainName1) diff --git a/src/components/SkConnect.tsx b/src/components/SkConnect.tsx index 38d5800..4667c92 100644 --- a/src/components/SkConnect.tsx +++ b/src/components/SkConnect.tsx @@ -31,7 +31,6 @@ import { cls, cmn, styles } from '../core/css' import { useMetaportStore } from '../store/MetaportStore' - export default function SkConnect() { const transferInProgress = useMetaportStore((state) => state.transferInProgress) return ( diff --git a/src/components/Stepper/SkStepper.tsx b/src/components/Stepper/SkStepper.tsx index c2d5921..d0a4076 100644 --- a/src/components/Stepper/SkStepper.tsx +++ b/src/components/Stepper/SkStepper.tsx @@ -25,7 +25,6 @@ import { useCPStore } from '../../store/CommunityPoolStore' import { SkaleNetwork } from '../../core/interfaces' import { SUCCESS_EMOJIS } from '../../core/constants' - export default function SkStepper(props: { skaleNetwork: SkaleNetwork }) { const { address } = useAccount() const { switchNetworkAsync } = useSwitchNetwork() @@ -41,6 +40,11 @@ export default function SkStepper(props: { skaleNetwork: SkaleNetwork }) { const execute = useMetaportStore((state) => state.execute) const startOver = useMetaportStore((state) => state.startOver) + const token = useMetaportStore((state) => state.token) + const mpc = useMetaportStore((state) => state.mpc) + const chainName2 = useMetaportStore((state) => state.chainName2) + const ima2 = useMetaportStore((state) => state.ima2) + const amount = useMetaportStore((state) => state.amount) const cpData = useCPStore((state) => state.cpData) @@ -99,12 +103,7 @@ export default function SkStepper(props: { skaleNetwork: SkaleNetwork }) { className={cls(styles.btnAction, cmn.mtop5)} onClick={() => execute(address, switchNetworkAsync, walletClient)} disabled={ - !!( - amountErrorMessage || - loading || - amount == '' || - !cpData.exitGasOk - ) + !!(amountErrorMessage || loading || amount == '' || !cpData.exitGasOk) } > {step.btnText} @@ -136,7 +135,7 @@ export default function SkStepper(props: { skaleNetwork: SkaleNetwork }) {

- + +
+ ) +} diff --git a/src/components/MetaportProvider.tsx b/src/components/MetaportProvider.tsx index 5621ba2..43cbadf 100644 --- a/src/components/MetaportProvider.tsx +++ b/src/components/MetaportProvider.tsx @@ -36,7 +36,7 @@ import { enkryptWallet } from '@rainbow-me/rainbowkit/wallets' -import { MetaportConfig } from '../core/interfaces' +import { MetaportConfig, ActionStateUpdate } from '../core/interfaces' import { StyledEngineProvider } from '@mui/material/styles' import { createTheme, ThemeProvider } from '@mui/material/styles' @@ -105,6 +105,7 @@ export default function MetaportProvider(props: { const setTheme = useUIStore((state) => state.setTheme) const setMpc = useMetaportStore((state) => state.setMpc) + const addTransaction = useMetaportStore((state) => state.addTransaction) const setOpen = useUIStore((state) => state.setOpen) const metaportTheme = useUIStore((state) => state.theme) @@ -113,6 +114,7 @@ export default function MetaportProvider(props: { useEffect(() => { setOpen(props.config.openOnLoad) + window.addEventListener('metaport_actionStateUpdated', actionStateUpdated, false) }, []) useEffect(() => { @@ -123,6 +125,28 @@ export default function MetaportProvider(props: { setMpc(new MetaportCore(props.config)) }, [setMpc]) + function actionStateUpdated(e: CustomEvent) { + const actionStateUpdate: ActionStateUpdate = e.detail + if (actionStateUpdate.transactionHash) { + let chainName = actionStateUpdate.actionData.chainName1 + if ( + actionStateUpdate.actionState === 'transferETHDone' || + actionStateUpdate.actionState === 'unwrapDone' + ) { + chainName = actionStateUpdate.actionData.chainName2 + } + addTransaction({ + tx: { + transactionHash: actionStateUpdate.transactionHash, + gasUsed: 1000 + }, + timestamp: actionStateUpdate.timestamp, + chainName, + txName: actionStateUpdate.actionState + }) + } + } + let theme = createTheme({ zIndex: getMuiZIndex(widgetTheme), palette: { diff --git a/src/components/SkConnect.tsx b/src/components/SkConnect.tsx index 4667c92..0e1dc37 100644 --- a/src/components/SkConnect.tsx +++ b/src/components/SkConnect.tsx @@ -93,14 +93,8 @@ export default function SkConnect() { ) } return ( -
-
- {/* */} -
+
+
{account.displayName} - {/* {account.displayBalance - ? ` (${account.displayBalance})` - : ''} */} - +
diff --git a/src/components/TransactionData/TransactionData.module.scss b/src/components/TransactionData/TransactionData.module.scss new file mode 100644 index 0000000..ad6f404 --- /dev/null +++ b/src/components/TransactionData/TransactionData.module.scss @@ -0,0 +1,26 @@ +@import '../../styles/variables'; + +.transactionDataIcon { + width: 30px; + height: 30px; + border-radius: 50%; + + svg, + img { + width: 15px !important; + height: 15px !important; + } +} + + +.sk__openExplorerBtn { + svg { + width: 15px !important; + height: 15px !important; + } + + background-color: $sk-paper-color !important; + + height: 30px; + width: 30px; +} \ No newline at end of file diff --git a/src/components/TransactionData/TransactionData.tsx b/src/components/TransactionData/TransactionData.tsx new file mode 100644 index 0000000..3afe1fd --- /dev/null +++ b/src/components/TransactionData/TransactionData.tsx @@ -0,0 +1,138 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +/** + * @file TransactionData.ts + * @copyright SKALE Labs 2023-Present + */ + +import { ReactElement } from 'react' + +import IconButton from '@mui/material/IconButton' + +import MoveUpIcon from '@mui/icons-material/MoveUp' +import MoveDownIcon from '@mui/icons-material/MoveDown' +import LockOpenIcon from '@mui/icons-material/LockOpen' +import ArrowOutwardIcon from '@mui/icons-material/ArrowOutward' +import OpenInNewIcon from '@mui/icons-material/OpenInNew' +import DoneRoundedIcon from '@mui/icons-material/DoneRounded' + +import { getTxUrl } from '../../core/explorer' +import { ActionState, MetaportConfig, TransactionHistory } from '../../core/interfaces' + +import localStyles from './TransactionData.module.scss' +import { cls, styles, cmn } from '../../core/css' + +type ActionStateIconMap = { + [key in ActionState]: ReactElement | null +} + +type ActionStateAliasMap = { + [key in ActionState]: string | null +} + +const actionIcons: ActionStateIconMap = { + approveDone: , + transferDone: , + transferETHDone: , + approveWrapDone: , + wrapDone: , + unwrapDone: , + unlockDone: , + receivedETH: null, + init: null, + approve: null, + transfer: null, + received: null, + transferETH: null, + approveWrap: null, + wrap: null, + unwrap: null, + switch: null, + unlock: null +} + +const actionAliases: ActionStateAliasMap = { + approveDone: 'Approve', + transferDone: 'Transfer', + transferETHDone: 'Transfer ETH', + approveWrapDone: 'Approve wrap', + wrapDone: 'Wrap', + unwrapDone: 'Unwrap', + unlockDone: 'Unlock ETH', + receivedETH: null, + init: null, + approve: null, + transfer: null, + received: null, + transferETH: null, + approveWrap: null, + wrap: null, + unwrap: null, + switch: null, + unlock: null +} + +export default function TransactionData(props: { + transactionData: TransactionHistory + config: MetaportConfig +}) { + const explorerUrl = getTxUrl( + props.transactionData.chainName, + props.config.skaleNetwork, + props.transactionData.tx.transactionHash + ) + return ( +
+
+
+ {actionIcons[props.transactionData.txName]} +
+
+
+
+

+ {actionAliases[props.transactionData.txName]} +

+

+ {new Date(props.transactionData.timestamp * 1000).toUTCString()} +

+
+
+
+ + + +
+
+ ) +} diff --git a/src/components/TransactionData/index.ts b/src/components/TransactionData/index.ts new file mode 100644 index 0000000..2824e61 --- /dev/null +++ b/src/components/TransactionData/index.ts @@ -0,0 +1 @@ +export { default } from './TransactionData' diff --git a/src/components/TransactionsHistory.tsx b/src/components/TransactionsHistory.tsx new file mode 100644 index 0000000..9fd8b18 --- /dev/null +++ b/src/components/TransactionsHistory.tsx @@ -0,0 +1,171 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/** + * @file TransactionsHistory.ts + * @copyright SKALE Labs 2023-Present + */ + +import { Collapse } from '@mui/material' +import Button from '@mui/material/Button' + +import ArrowForwardRoundedIcon from '@mui/icons-material/ArrowForwardRounded' +import DeleteRoundedIcon from '@mui/icons-material/DeleteRounded' +import CloseRoundedIcon from '@mui/icons-material/CloseRounded' + +import TokenIcon from './TokenIcon' +import ChainIcon from './ChainIcon' +import TransactionData from './TransactionData' + +import { useMetaportStore } from '../store/MetaportStore' +import { useCollapseStore } from '../store/Store' +import { cls, styles, cmn } from '../core/css' +import { interfaces, SkPaper } from '../Metaport' + +import { getChainAlias } from '../core/helper' + +export default function TransactionsHistory() { + const transactionsHistory = useMetaportStore((state) => state.transactionsHistory) + const transfersHistory = useMetaportStore((state) => state.transfersHistory) + + const clearTransactionsHistory = useMetaportStore((state) => state.clearTransactionsHistory) + const mpc = useMetaportStore((state) => state.mpc) + const expandedTH = useCollapseStore((state) => state.expandedTH) + const setExpandedTH = useCollapseStore((state) => state.setExpandedTH) + + function clearTransferHistory() { + clearTransactionsHistory() + setExpandedTH(false) + } + + if (transactionsHistory.length === 0 && transfersHistory.length === 0) return + return ( + +
+ + +
+ {transactionsHistory.length !== 0 ? ( + +

+ Current transfer +

+ + {transactionsHistory.map((transactionData: any) => ( + + ))} + +
+ ) : null} +
+ {transfersHistory.map((transferHistory: interfaces.TransferHistory, key: number) => ( + +
+ +

+ {getChainAlias(mpc.config.skaleNetwork, transferHistory.chainName1)} +

+ + +

+ {getChainAlias(mpc.config.skaleNetwork, transferHistory.chainName2)} +

+
+
+
+ +
+

+ {transferHistory.amount} {transferHistory.tokenKeyname} +

+

+ •{' '} + {transferHistory.address.substring(0, 6) + + '...' + + transferHistory.address.substring(transferHistory.address.length - 4)} +

+
+ + {transferHistory.transactions.map((transactionData: any) => ( + + ))} + +
+ ))} +
+
+ ) +} diff --git a/src/components/WidgetBody.tsx b/src/components/WidgetBody.tsx index 4d4c481..949bca2 100644 --- a/src/components/WidgetBody.tsx +++ b/src/components/WidgetBody.tsx @@ -19,6 +19,8 @@ import CommunityPool from './CommunityPool' import SFuelWarning from './SFuelWarning' import SkConnect from './SkConnect' import WrappedTokens from './WrappedTokens' +import TransactionsHistory from './TransactionsHistory' +import HistoryButton from './HistoryButton' import { cls, cmn } from '../core/css' import { Collapse } from '@mui/material' @@ -35,6 +37,7 @@ export function WidgetBody(props) { const expandedCP = useCollapseStore((state) => state.expandedCP) const expandedWT = useCollapseStore((state) => state.expandedWT) const expandedTokens = useCollapseStore((state) => state.expandedTokens) + const expandedTH = useCollapseStore((state) => state.expandedTH) const destChains = useMetaportStore((state) => state.destChains) @@ -77,11 +80,19 @@ export function WidgetBody(props) { } }, [tokens]) - const showFrom = !expandedTo && !expandedTokens && !errorMessage && !expandedCP - const showTo = !expandedFrom && !expandedTokens && !errorMessage && !expandedCP && !expandedWT - const showInput = !expandedFrom && !expandedTo && !errorMessage && !expandedCP && !expandedWT + const showFrom = !expandedTo && !expandedTokens && !errorMessage && !expandedCP && !expandedTH + const showTo = + !expandedFrom && !expandedTokens && !errorMessage && !expandedCP && !expandedWT && !expandedTH + const showInput = + !expandedFrom && !expandedTo && !errorMessage && !expandedCP && !expandedWT && !expandedTH const showSwitch = - !expandedFrom && !expandedTo && !expandedTokens && !errorMessage && !expandedCP && !expandedWT + !expandedFrom && + !expandedTo && + !expandedTokens && + !errorMessage && + !expandedCP && + !expandedWT && + !expandedTH const showStepper = !expandedFrom && !expandedTo && @@ -90,11 +101,13 @@ export function WidgetBody(props) { !expandedCP && sFuelOk && !expandedWT && + !expandedTH && !!address const showCP = !expandedFrom && !expandedTo && !expandedTokens && + !expandedTH && chainName2 === MAINNET_CHAIN_NAME && !expandedWT const showWT = @@ -103,8 +116,17 @@ export function WidgetBody(props) { !expandedTokens && !errorMessage && !expandedCP && + !expandedTH && sFuelOk && !!address + const showTH = + !expandedFrom && + !expandedTo && + !expandedTokens && + !errorMessage && + !expandedCP && + !expandedWT && + !!address const showError = !!errorMessage const grayBg = 'rgb(136 135 135 / 15%)' @@ -113,6 +135,16 @@ export function WidgetBody(props) { return (
+ {!!address ? ( +
+
+
+ +
+ +
+ ) : null} + @@ -192,6 +224,12 @@ export function WidgetBody(props) { + + + + + + diff --git a/src/components/WidgetUI/WidgetUI.tsx b/src/components/WidgetUI/WidgetUI.tsx index 287c78f..c241a6a 100644 --- a/src/components/WidgetUI/WidgetUI.tsx +++ b/src/components/WidgetUI/WidgetUI.tsx @@ -98,12 +98,10 @@ export function WidgetUI(props: { config: MetaportConfig }) {
- {!!address ? : null} - {/* {address ? :
} */}
diff --git a/src/core/actions/action.ts b/src/core/actions/action.ts index 4b7cea4..b6fc0e9 100644 --- a/src/core/actions/action.ts +++ b/src/core/actions/action.ts @@ -32,13 +32,14 @@ import { TokenData, CustomAbiTokenType } from '../dataclasses' import MetaportCore, { createTokenData } from '../metaport' import { externalEvents } from '../events' import { toWei } from '../convertation' -import { ActionState, LOADING_BUTTON_TEXT } from './actionState' +import { LOADING_BUTTON_TEXT } from './actionState' import { isMainnet } from '../helper' import { IMA_ABIS } from '../contracts' import { isMainnetChainId, getMainnetAbi } from '../network' import { walletClientToSigner } from '../ethers' +import { interfaces } from '../../Metaport' debug.enable('*') const log = debug('metaport:actions') @@ -161,29 +162,15 @@ export class Action { this.setBtnText = setBtnText this._switchNetwork = switchNetwork this.walletClient = walletClient - - // if (this.tokenData) this.wrap = !!this.token.unwrappedSymbol && !this.token.clone; } - // tokenContract( - // provider: Provider, - // source: boolean = true - // ): Contract { - // return this.mpc.tokenContract( - // source ? this.chainName1 : this.chainName2, - // this.token.keyname, - // this.token.type, - // provider - // ) - // } - - updateState(currentState: ActionState, transactionHash?: string, timestamp?: string | number) { + updateState(currentState: interfaces.ActionState, transactionHash?: string, timestamp?: number) { log(`actionStateUpd: ${this.constructor.name} - ${currentState} - ${this.token.keyname} \ - ${this.chainName1} -> ${this.chainName2}`) - externalEvents.actionStateUpdated( - this.constructor.name, - currentState, - { + externalEvents.actionStateUpdated({ + actionName: this.constructor.name, + actionState: currentState, + actionData: { chainName1: this.chainName1, chainName2: this.chainName2, address: this.address, @@ -193,7 +180,7 @@ export class Action { }, transactionHash, timestamp - ) + }) this.setBtnText(LOADING_BUTTON_TEXT[currentState]) } @@ -233,9 +220,3 @@ export class Action { return chain } } - -export abstract class TransferAction extends Action { - transferComplete(tx): void { - externalEvents.transferComplete(tx, this.chainName1, this.chainName2, this.token.keyname, false) - } -} diff --git a/src/core/actions/actionState.ts b/src/core/actions/actionState.ts index 913aff9..788e901 100644 --- a/src/core/actions/actionState.ts +++ b/src/core/actions/actionState.ts @@ -21,25 +21,7 @@ * @copyright SKALE Labs 2023-Present */ -export type ActionState = - | 'init' - | 'approve' - | 'approveDone' - | 'transfer' - | 'transferDone' - | 'received' - | 'transferETH' - | 'transferETHDone' - | 'receivedETH' - | 'approveWrap' - | 'approveWrapDone' - | 'wrap' - | 'wrapDone' - | 'unwrap' - | 'unwrapDone' - | 'switch' - | 'unlock' - | 'unlockDone' +import { ActionState } from '../interfaces' type LoadingButtonTextMap = { [key in ActionState]: string diff --git a/src/core/actions/erc20.ts b/src/core/actions/erc20.ts index fa39cc2..eff3335 100644 --- a/src/core/actions/erc20.ts +++ b/src/core/actions/erc20.ts @@ -30,14 +30,14 @@ import { externalEvents } from '../events' import { toWei } from '../convertation' import { MAX_APPROVE_AMOUNT } from '../constants' -import { TransferAction, Action } from '../actions/action' +import { Action } from '../actions/action' import { checkERC20Balance, checkERC20Allowance, checkSFuelBalance } from './checks' import { CustomAbiTokenType } from '../dataclasses' debug.enable('*') const log = debug('metaport:actions:erc20') -export class TransferERC20S2S extends TransferAction { +export class TransferERC20S2S extends Action { async execute() { this.updateState('init') const checkResAllowance = await checkERC20Allowance( @@ -64,7 +64,6 @@ export class TransferERC20S2S extends TransferAction { ) const txBlock = await sChain.provider.getBlock(approveTx.blockNumber) this.updateState('approveDone', approveTx.hash, txBlock.timestamp) - externalEvents.transactionCompleted(approveTx, txBlock.timestamp, this.chainName1, 'approve') log('ApproveERC20S:execute - tx completed: %O', approveTx) } @@ -123,7 +122,6 @@ export class WrapSFuelERC20S extends Action { }) const block = await this.sChain1.provider.getBlock(tx.blockNumber) this.updateState('wrapDone', tx.hash, block.timestamp) - externalEvents.transactionCompleted(tx, block.timestamp, this.chainName1, 'wrapsfuel') log('WrapSFuelERC20S:execute - tx completed %O', tx) } @@ -235,7 +233,6 @@ export class UnWrapERC20S extends Action { log('UnWrapERC20S:execute - tx completed %O', tx) const block = await sChain.provider.getBlock(tx.blockNumber) this.updateState('unwrapDone', tx.hash, block.timestamp) - externalEvents.transactionCompleted(tx, block.timestamp, this.chainName1, 'unwrap') externalEvents.unwrapComplete(tx, this.chainName2, this.token.keyname) } @@ -255,7 +252,7 @@ export class UnWrapERC20S extends Action { } } -export class TransferERC20M2S extends TransferAction { +export class TransferERC20M2S extends Action { async execute() { this.updateState('init') @@ -285,18 +282,10 @@ export class TransferERC20M2S extends TransferAction { }) const block = await mainnet.provider.getBlock(tx.blockNumber) this.updateState('transferDone', tx.hash, block.timestamp) - externalEvents.transactionCompleted(tx, block.timestamp, this.chainName1, 'deposit') log('TransferERC20M2S:execute - tx completed %O', tx) await this.sChain2.waitERC20BalanceChange(this.destToken, this.address, balanceOnDestination) this.updateState('received') log('TransferERC20M2S:execute - tokens received to destination chain') - externalEvents.transferComplete( - tx.hash, - this.chainName1, - this.chainName2, - this.token.keyname, - false - ) } async preAction() { @@ -314,7 +303,7 @@ export class TransferERC20M2S extends TransferAction { } } -export class TransferERC20S2M extends TransferAction { +export class TransferERC20S2M extends Action { async execute() { this.updateState('init') // check approve + approve @@ -339,7 +328,6 @@ export class TransferERC20S2M extends TransferAction { ) const txBlock = await sChain.provider.getBlock(approveTx.blockNumber) this.updateState('approveDone', approveTx.hash, txBlock.timestamp) - externalEvents.transactionCompleted(approveTx, txBlock.timestamp, this.chainName1, 'approve') log('ApproveERC20S:execute - tx completed: %O', approveTx) } this.updateState('transfer') @@ -348,18 +336,10 @@ export class TransferERC20S2M extends TransferAction { const tx = await sChain.erc20.withdraw(this.originAddress, amountWei, { address: this.address }) const block = await sChain.provider.getBlock(tx.blockNumber) this.updateState('transferDone', tx.hash, block.timestamp) - externalEvents.transactionCompleted(tx, block.timestamp, this.chainName1, 'withdraw') log('TransferERC20S2M:execute - tx completed %O', tx) this.mainnet.waitERC20BalanceChange(this.destToken, this.address, balanceOnDestination) this.updateState('received') log('TransferERC20S2M:execute - tokens received to destination chain') - externalEvents.transferComplete( - tx.hash, - this.chainName1, - this.chainName2, - this.token.keyname, - false - ) } async preAction() { diff --git a/src/core/actions/eth.ts b/src/core/actions/eth.ts index d1fd378..b0dbcff 100644 --- a/src/core/actions/eth.ts +++ b/src/core/actions/eth.ts @@ -24,15 +24,14 @@ import debug from 'debug' import { MainnetChain, SChain } from '@skalenetwork/ima-js' -import { externalEvents } from '../events' import { toWei } from '../convertation' -import { TransferAction, Action } from './action' +import { Action } from './action' import { checkEthBalance } from './checks' debug.enable('*') const log = debug('metaport:actions:eth') -export class TransferEthM2S extends TransferAction { +export class TransferEthM2S extends Action { async execute() { this.updateState('init') const amountWei = toWei(this.amount, this.token.meta.decimals) @@ -64,7 +63,7 @@ export class TransferEthM2S extends TransferAction { } } -export class TransferEthS2M extends TransferAction { +export class TransferEthS2M extends Action { async execute() { log('TransferEthS2M: started') this.updateState('init') diff --git a/src/core/events.ts b/src/core/events.ts index fdf3285..a5023c4 100644 --- a/src/core/events.ts +++ b/src/core/events.ts @@ -23,7 +23,6 @@ import debug from 'debug' import * as interfaces from './interfaces/index' -import { ActionState } from './actions/actionState' debug.enable('*') const log = debug('metaport:core:events') @@ -63,45 +62,8 @@ export namespace externalEvents { dispatchEvent('metaport_transferRequestCompleted', { transferRequest: transferRequest }) } - export function transactionCompleted( - txData: any, - timestamp: string | number, - chainName: string, - txName: string - ): void { - log('WARNING: Event metaport_transactionCompleted will be removed in the next version') - dispatchEvent('metaport_transactionCompleted', { - tx: { - gasUsed: txData.gasUsed, - transactionHash: txData.transactionHash - }, - timestamp, - chainName, - txName - }) - } - - export function actionStateUpdated( - actionName: string, - actionState: ActionState, - actionData: { - chainName1: string - chainName2: string - address: string - amount: string - amountWei: bigint - tokenId: number - }, - transactionHash?: string, - timestamp?: string | number - ): void { - dispatchEvent('metaport_actionStateUpdated', { - actionState, - actionName, - actionData, - transactionHash, - timestamp - }) + export function actionStateUpdated(actionStateUpdate: interfaces.ActionStateUpdate): void { + dispatchEvent('metaport_actionStateUpdated', actionStateUpdate) } export function unwrapComplete(tx: string, chainName1: string, tokenSymbol: string) { diff --git a/src/core/interfaces/ActionState.ts b/src/core/interfaces/ActionState.ts new file mode 100644 index 0000000..e8e3563 --- /dev/null +++ b/src/core/interfaces/ActionState.ts @@ -0,0 +1,42 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/** + * @file ActionState.ts + * @copyright SKALE Labs 2023-Present + */ + +export type ActionState = + | 'init' + | 'approve' + | 'approveDone' + | 'transfer' + | 'transferDone' + | 'received' + | 'transferETH' + | 'transferETHDone' + | 'receivedETH' + | 'approveWrap' + | 'approveWrapDone' + | 'wrap' + | 'wrapDone' + | 'unwrap' + | 'unwrapDone' + | 'switch' + | 'unlock' + | 'unlockDone' diff --git a/src/core/interfaces/ActionStateUpdate.ts b/src/core/interfaces/ActionStateUpdate.ts new file mode 100644 index 0000000..3a796bd --- /dev/null +++ b/src/core/interfaces/ActionStateUpdate.ts @@ -0,0 +1,39 @@ +/** + * @license + * SKALE Metaport + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/** + * @file ActionStateUpdate.ts + * @copyright SKALE Labs 2023-Present + */ + +import { ActionState } from './ActionState' + +export interface ActionStateUpdate { + actionName: string + actionState: ActionState + actionData: { + chainName1: string + chainName2: string + address: string + amount: string + amountWei: bigint + tokenId: number + } + transactionHash?: string + timestamp?: number +} diff --git a/src/core/interfaces/TransactionHistory.ts b/src/core/interfaces/TransactionHistory.ts index 0b03e6a..109014a 100644 --- a/src/core/interfaces/TransactionHistory.ts +++ b/src/core/interfaces/TransactionHistory.ts @@ -21,6 +21,8 @@ * @copyright SKALE Labs 2023-Present */ +import { AddressType } from '.' + interface TxData { gasUsed: number transactionHash: string @@ -32,3 +34,12 @@ export interface TransactionHistory { chainName: string txName: string } + +export interface TransferHistory { + transactions: TransactionHistory[] + tokenKeyname: string + address: AddressType + chainName1: string + chainName2: string + amount: string +} diff --git a/src/core/interfaces/index.ts b/src/core/interfaces/index.ts index b8a8543..b64abb8 100644 --- a/src/core/interfaces/index.ts +++ b/src/core/interfaces/index.ts @@ -31,5 +31,7 @@ export * from './CheckRes' export * from './TransactionHistory' export * from './CommunityPoolData' export * from './TokenMetadata' +export * from './ActionStateUpdate' +export * from './ActionState' export type AddressType = `0x${string}` diff --git a/src/index.ts b/src/index.ts index cda7d20..db94f55 100644 --- a/src/index.ts +++ b/src/index.ts @@ -27,6 +27,8 @@ import ErrorMessage from './components/ErrorMessage' import CommunityPool from './components/CommunityPool' import SFuelWarning from './components/SFuelWarning' import WrappedTokens from './components/WrappedTokens' +import HistoryButton from './components/HistoryButton' +import TransactionsHistory from './components/TransactionsHistory' import { CHAINS_META, getChainAlias } from './core/helper' import { cls, styles, cmn } from './core/css' @@ -62,6 +64,8 @@ export { CommunityPool, SFuelWarning, WrappedTokens, + TransactionsHistory, + HistoryButton, cls, styles, cmn, diff --git a/src/store/MetaportState.ts b/src/store/MetaportState.ts index 8aa92f8..060eb0d 100644 --- a/src/store/MetaportState.ts +++ b/src/store/MetaportState.ts @@ -113,6 +113,14 @@ export interface MetaportState { btnText: string setBtnText: (btnText: string) => void + transactionsHistory: interfaces.TransactionHistory[] + setTransactionsHistory: (transactionsHistory: interfaces.TransactionHistory[]) => void + addTransaction: (transaction: interfaces.TransactionHistory) => void + clearTransactionsHistory: () => void + + transfersHistory: interfaces.TransferHistory[] + setTransfersHistory: (transfersHistory: interfaces.TransferHistory[]) => void + errorMessageClosedFallback: () => void startOver: () => void } diff --git a/src/store/MetaportStore.ts b/src/store/MetaportStore.ts index 7f71fa6..d34ba86 100644 --- a/src/store/MetaportStore.ts +++ b/src/store/MetaportStore.ts @@ -134,8 +134,25 @@ export const useMetaportStore = create()((set, get) => ({ } finally { set({ loading: false }) } + + const isTransferFinished = get().currentStep + 1 === get().stepsMetadata.length + + if (isTransferFinished) { + get().setTransfersHistory([ + ...get().transfersHistory, + { + transactions: get().transactionsHistory, + chainName1: get().chainName1, + chainName2: get().chainName2, + amount: get().amount, + tokenKeyname: get().token.keyname, + address: address + } + ]) + } + set({ - transferInProgress: get().currentStep + 1 !== get().stepsMetadata.length, + transferInProgress: !isTransferFinished, currentStep: get().currentStep + 1 }) } @@ -280,5 +297,27 @@ export const useMetaportStore = create()((set, get) => ({ setTransferInProgress: (inProgress: boolean) => set(() => ({ transferInProgress: inProgress })), btnText: null, - setBtnText: (btnText: string) => set(() => ({ btnText: btnText })) + setBtnText: (btnText: string) => set(() => ({ btnText: btnText })), + + transactionsHistory: [], + setTransactionsHistory: (transactionsHistory: interfaces.TransactionHistory[]) => { + set({ transactionsHistory: transactionsHistory }) + }, + + addTransaction(transaction: interfaces.TransactionHistory): void { + const history = get().transactionsHistory + history.push(transaction) + set({ transactionsHistory: [...history] }) + }, + clearTransactionsHistory(): void { + set({ transactionsHistory: [], transfersHistory: [] }) + }, + + transfersHistory: [], + setTransfersHistory: (transfersHistory: interfaces.TransferHistory[]) => { + set({ + transfersHistory: transfersHistory, + transactionsHistory: [] + }) + } })) diff --git a/src/store/Store.ts b/src/store/Store.ts index fb0b9b3..4b2a269 100644 --- a/src/store/Store.ts +++ b/src/store/Store.ts @@ -52,6 +52,9 @@ export interface CollapseState { expandedWT: string | false setExpandedWT: (expanded: string | false) => void + + expandedTH: boolean + setExpandedTH: (expanded: boolean) => void } export const useCollapseStore = create()((set) => ({ @@ -62,7 +65,8 @@ export const useCollapseStore = create()((set) => ({ expandedTo: false, expandedTokens: false, expandedCP: false, - expandedWT: false + expandedWT: false, + expandedTH: false })), expandedTo: false, setExpandedTo: (expanded: string | false) => @@ -71,7 +75,8 @@ export const useCollapseStore = create()((set) => ({ expandedFrom: false, expandedTokens: false, expandedCP: false, - expandedWT: false + expandedWT: false, + expandedTH: false })), expandedTokens: false, setExpandedTokens: (expanded: string | false) => @@ -80,7 +85,8 @@ export const useCollapseStore = create()((set) => ({ expandedFrom: false, expandedTo: false, expandedCP: false, - expandedWT: false + expandedWT: false, + expandedTH: false })), expandedCP: false, setExpandedCP: (expanded: string | false) => @@ -89,7 +95,8 @@ export const useCollapseStore = create()((set) => ({ expandedFrom: false, expandedTo: false, expandedTokens: false, - expandedWT: false + expandedWT: false, + expandedTH: false })), expandedWT: false, setExpandedWT: (expanded: string | false) => @@ -98,6 +105,17 @@ export const useCollapseStore = create()((set) => ({ expandedFrom: false, expandedTo: false, expandedTokens: false, - expandedWT: expanded + expandedWT: expanded, + expandedTH: false + })), + expandedTH: false, + setExpandedTH: (expanded: boolean) => + set(() => ({ + expandedCP: false, + expandedFrom: false, + expandedTo: false, + expandedTokens: false, + expandedWT: false, + expandedTH: expanded })) })) diff --git a/src/styles/cmn.module.scss b/src/styles/cmn.module.scss index b3cc0e1..e721ca9 100644 --- a/src/styles/cmn.module.scss +++ b/src/styles/cmn.module.scss @@ -27,11 +27,50 @@ flex-wrap: wrap; } +.rotate180 { + transform: rotate(180deg); +} + +.bord { + border: 1px $sk-paper-color solid; +} + +.bordtop { + border-top: 1px $sk-paper-color solid; +} + +.bordbott { + border-top: 1px $sk-paper-color solid; +} + +.bordleft { + border-left: 1px $sk-paper-color solid; +} + +.bordri { + border-right: 1px $sk-paper-color solid; +} .padd10 { padding: 10px !important; } +.pleft10 { + padding-left: 10px !important; +} + +.pri10 { + padding-right: 10px !important; +} + +.ptop10 { + padding-top: 10px !important; +} + + +.ptop20 { + padding-top: 20px !important; +} .mtop10 { margin-top: 10px !important; @@ -49,6 +88,10 @@ margin-left: 10px !important; } +.mleft15 { + margin-left: 15px !important; +} + .mleft20 { margin-left: 20px !important; } @@ -105,6 +148,11 @@ padding-top: 20px !important; } + +.ptop15 { + padding-top: 15px !important; +} + .nop { padding: 0 !important; } diff --git a/src/styles/styles.module.scss b/src/styles/styles.module.scss index 15fb923..6f6c1f7 100644 --- a/src/styles/styles.module.scss +++ b/src/styles/styles.module.scss @@ -54,9 +54,58 @@ color: $sk-disabled-dark; } + .action_transferDone, + .action_transferETHDone { + background-image: linear-gradient(45deg, #8A463C 0%, #b02d50 100%); + } + + .action_wrapDone { + background-image: linear-gradient(160deg, #237bc3 0%, #1a3b94 100%); + } + + .action_unwrapDone { + background-image: linear-gradient(160deg, #1a3b94 0%, #237bc3 100%); + } + + .action_unlockDone { + background-image: linear-gradient(45deg, #009688 0%, #0c5f57 100%); + } + + .action_approveDone { + background-image: linear-gradient(135deg, #29b1a9 0%, #14532a 100%); + } + + .action_approveWrapDone { + background-image: linear-gradient(135deg, #14532a 0%, #29b1a9 100%); + } } .lightTheme { + .action_transferDone, + .action_transferETHDone { + background-image: linear-gradient(45deg, #f7c9b1 0%, #f8d4da 100%); + } + + .action_wrapDone { + background-image: linear-gradient(160deg, #9dcff1 0%, #8ab1dd 100%); + } + + .action_unwrapDone { + background-image: linear-gradient(160deg, #8ab1dd 0%, #9dcff1 100%); + } + + .action_unlockDone { + background-image: linear-gradient(45deg, #92f7e1 0%, #76afaa 100%); + } + + .action_approveDone { + background-image: linear-gradient(135deg, #89e0ce 0%, #58a47c 100%); + } + + .action_approveWrapDone { + background-image: linear-gradient(135deg, #58a47c 0%, #89e0ce 100%); + } + .skaleLogoLg { filter: invert(1); } @@ -254,7 +303,6 @@ button { .btnApp { background-color: rgba(0, 0, 0, 0.08) !important; - } .btnChain { From 788fefd46b3ae5b95872ebfa63bc6f823b9a2b41 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Fri, 15 Sep 2023 15:22:58 +0100 Subject: [PATCH 50/54] Add dynamic skale chains support, move chains metadata --- src/components/ChainApps.tsx | 2 +- src/components/ChainsList.tsx | 2 +- src/components/MetaportProvider.tsx | 81 ++++++++----------- src/components/Stepper/SkStepper.tsx | 3 +- .../TransactionData/TransactionData.tsx | 2 +- src/components/TransactionsHistory.tsx | 2 +- src/components/WrappedTokens.tsx | 3 +- src/core/helper.ts | 39 --------- src/core/interfaces/TransactionHistory.ts | 7 +- src/core/metadata.ts | 46 ++++++++++- src/core/wagmi_network.ts | 2 +- src/index.ts | 2 +- 12 files changed, 89 insertions(+), 102 deletions(-) diff --git a/src/components/ChainApps.tsx b/src/components/ChainApps.tsx index 4016e8e..a4069e2 100644 --- a/src/components/ChainApps.tsx +++ b/src/components/ChainApps.tsx @@ -3,7 +3,7 @@ import KeyboardArrowRightRoundedIcon from '@mui/icons-material/KeyboardArrowRigh import { cls, cmn, styles } from '../core/css' import { SkaleNetwork } from '../core/interfaces' -import { getChainAppsMeta, getChainAlias } from '../core/helper' +import { getChainAppsMeta, getChainAlias } from '../core/metadata' import ChainIcon from './ChainIcon' diff --git a/src/components/ChainsList.tsx b/src/components/ChainsList.tsx index 1bc770a..7756bb8 100644 --- a/src/components/ChainsList.tsx +++ b/src/components/ChainsList.tsx @@ -12,7 +12,7 @@ import ChainIcon from './ChainIcon' import { MetaportConfig } from '../core/interfaces' -import { getChainAlias, getChainAppsMeta } from '../core/helper' +import { getChainAlias, getChainAppsMeta } from '../core/metadata' import { cls, cmn, styles } from '../core/css' import SkPaper from './SkPaper' diff --git a/src/components/MetaportProvider.tsx b/src/components/MetaportProvider.tsx index 43cbadf..20e3ee8 100644 --- a/src/components/MetaportProvider.tsx +++ b/src/components/MetaportProvider.tsx @@ -53,54 +53,44 @@ import { useUIStore } from '../store/Store' import { useMetaportStore } from '../store/MetaportStore' import MetaportCore from '../core/metaport' -const { chains, webSocketPublicClient } = configureChains( - [ - mainnet, - goerli, - constructWagmiChain('staging', 'staging-legal-crazy-castor'), - constructWagmiChain('staging', 'staging-utter-unripe-menkar'), - constructWagmiChain('staging', 'staging-faint-slimy-achird'), - constructWagmiChain('staging', 'staging-perfect-parallel-gacrux'), - constructWagmiChain('staging', 'staging-severe-violet-wezen'), - constructWagmiChain('staging', 'staging-weepy-fitting-caph'), - - constructWagmiChain('mainnet', 'honorable-steel-rasalhague'), - constructWagmiChain('mainnet', 'elated-tan-skat'), - constructWagmiChain('mainnet', 'affectionate-immediate-pollux') - ], - [ - jsonRpcProvider({ - rpc: (chain) => ({ - http: chain.rpcUrls.default.http[0], - webSocket: getWebSocketUrl(chain) - }) - }) - ] -) - -const connectors = connectorsForWallets([ - { - groupName: 'Supported Wallets', - wallets: [ - metaMaskWallet({ chains, projectId: '' }), - enkryptWallet({ chains }), - injectedWallet({ chains }), - coinbaseWallet({ chains, appName: 'TEST' }) - ] - } -]) - -const wagmiConfig = createConfig({ - autoConnect: true, - connectors, - publicClient: webSocketPublicClient -}) - export default function MetaportProvider(props: { config: MetaportConfig className?: string children?: ReactElement | ReactElement[] }) { + const skaleChains = props.config.chains.map((chain) => + constructWagmiChain(props.config.skaleNetwork, chain) + ) + const { chains, webSocketPublicClient } = configureChains( + [mainnet, goerli, ...skaleChains], + [ + jsonRpcProvider({ + rpc: (chain) => ({ + http: chain.rpcUrls.default.http[0], + webSocket: getWebSocketUrl(chain) + }) + }) + ] + ) + + const connectors = connectorsForWallets([ + { + groupName: 'Supported Wallets', + wallets: [ + metaMaskWallet({ chains, projectId: '' }), + enkryptWallet({ chains }), + injectedWallet({ chains }), + coinbaseWallet({ chains, appName: 'SKALE Bridge' }) + ] + } + ]) + + const wagmiConfig = createConfig({ + autoConnect: true, + connectors, + publicClient: webSocketPublicClient + }) + const widgetTheme = getWidgetTheme(props.config.theme) const setTheme = useUIStore((state) => state.setTheme) @@ -136,10 +126,7 @@ export default function MetaportProvider(props: { chainName = actionStateUpdate.actionData.chainName2 } addTransaction({ - tx: { - transactionHash: actionStateUpdate.transactionHash, - gasUsed: 1000 - }, + transactionHash: actionStateUpdate.transactionHash, timestamp: actionStateUpdate.timestamp, chainName, txName: actionStateUpdate.actionState diff --git a/src/components/Stepper/SkStepper.tsx b/src/components/Stepper/SkStepper.tsx index d0a4076..ecef961 100644 --- a/src/components/Stepper/SkStepper.tsx +++ b/src/components/Stepper/SkStepper.tsx @@ -13,7 +13,8 @@ import Collapse from '@mui/material/Collapse' import SettingsBackupRestoreRoundedIcon from '@mui/icons-material/SettingsBackupRestoreRounded' import TollIcon from '@mui/icons-material/Toll' -import { getChainAlias, getRandom } from '../../core/helper' +import { getRandom } from '../../core/helper' +import { getChainAlias } from '../../core/metadata' import { cls, cmn, styles } from '../../core/css' import localStyles from './SkStepper.module.scss' diff --git a/src/components/TransactionData/TransactionData.tsx b/src/components/TransactionData/TransactionData.tsx index 3afe1fd..b6b7cd0 100644 --- a/src/components/TransactionData/TransactionData.tsx +++ b/src/components/TransactionData/TransactionData.tsx @@ -95,7 +95,7 @@ export default function TransactionData(props: { const explorerUrl = getTxUrl( props.transactionData.chainName, props.config.skaleNetwork, - props.transactionData.tx.transactionHash + props.transactionData.transactionHash ) return (
diff --git a/src/components/TransactionsHistory.tsx b/src/components/TransactionsHistory.tsx index 9fd8b18..6ff33b6 100644 --- a/src/components/TransactionsHistory.tsx +++ b/src/components/TransactionsHistory.tsx @@ -37,7 +37,7 @@ import { useCollapseStore } from '../store/Store' import { cls, styles, cmn } from '../core/css' import { interfaces, SkPaper } from '../Metaport' -import { getChainAlias } from '../core/helper' +import { getChainAlias } from '../core/metadata' export default function TransactionsHistory() { const transactionsHistory = useMetaportStore((state) => state.transactionsHistory) diff --git a/src/components/WrappedTokens.tsx b/src/components/WrappedTokens.tsx index 2b3b710..9668805 100644 --- a/src/components/WrappedTokens.tsx +++ b/src/components/WrappedTokens.tsx @@ -37,10 +37,9 @@ import SkPaper from './SkPaper' import { TokenBalance } from './TokenList' import TokenIcon from './TokenIcon' -import { getTokenName } from '../core/metadata' +import { getTokenName, getChainAlias } from '../core/metadata' import { BALANCE_UPDATE_INTERVAL_MS } from '../core/constants' -import { getChainAlias } from '../core/helper' import { cls, cmn, styles } from '../core/css' import { useCollapseStore } from '../store/Store' diff --git a/src/core/helper.ts b/src/core/helper.ts index 9f66ce9..ac29597 100644 --- a/src/core/helper.ts +++ b/src/core/helper.ts @@ -28,18 +28,6 @@ import { MAINNET_CHAIN_NAME } from './constants' import { TransferRequestStatus } from './dataclasses' import { SkaleNetwork } from './interfaces' -import mainnetMeta from '../meta/mainnet/chains.json' -import stagingMeta from '../meta/staging/chains.json' -import legacyMeta from '../meta/legacy/chains.json' -import regressionMeta from '../meta/regression/chains.json' - -export const CHAINS_META = { - mainnet: mainnetMeta, - staging: stagingMeta, - legacy: legacyMeta, - regression: regressionMeta -} - export function eqArrays(arr1, arr2) { return JSON.stringify(arr1) === JSON.stringify(arr2) } @@ -63,33 +51,6 @@ export function delay(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)) } -export function getChainAlias(skaleNetwork: SkaleNetwork, chainName: string, app?: string): string { - if (chainName === MAINNET_CHAIN_NAME) { - if (skaleNetwork != MAINNET_CHAIN_NAME) { - const network = skaleNetwork === 'staging' ? 'Goerli' : skaleNetwork - return `Ethereum (${network})` - } - return 'Ethereum' - } - if (CHAINS_META[skaleNetwork] && CHAINS_META[skaleNetwork][chainName]) { - if ( - app && - CHAINS_META[skaleNetwork][chainName].apps && - CHAINS_META[skaleNetwork][chainName].apps[app] - ) { - return CHAINS_META[skaleNetwork][chainName].apps[app].alias - } - return CHAINS_META[skaleNetwork][chainName].alias - } - return chainName -} - -export function getChainAppsMeta(chainName: string, skaleNetwork: SkaleNetwork) { - if (CHAINS_META[skaleNetwork][chainName] && CHAINS_META[skaleNetwork][chainName].apps) { - return CHAINS_META[skaleNetwork][chainName].apps - } -} - export function getRandom(list: Array) { return list[Math.floor(Math.random() * list.length)] } diff --git a/src/core/interfaces/TransactionHistory.ts b/src/core/interfaces/TransactionHistory.ts index 109014a..f5399ca 100644 --- a/src/core/interfaces/TransactionHistory.ts +++ b/src/core/interfaces/TransactionHistory.ts @@ -23,13 +23,8 @@ import { AddressType } from '.' -interface TxData { - gasUsed: number - transactionHash: string -} - export interface TransactionHistory { - tx: TxData + transactionHash: string timestamp: number chainName: string txName: string diff --git a/src/core/metadata.ts b/src/core/metadata.ts index c98de9d..393d6c9 100644 --- a/src/core/metadata.ts +++ b/src/core/metadata.ts @@ -24,7 +24,11 @@ import { TokenData } from './dataclasses' import { SkaleNetwork } from './interfaces' import { MAINNET_CHAIN_NAME } from './constants' -import { CHAINS_META } from './helper' + +import mainnetMeta from '../meta/mainnet/chains.json' +import stagingMeta from '../meta/staging/chains.json' +import legacyMeta from '../meta/legacy/chains.json' +import regressionMeta from '../meta/regression/chains.json' import * as MAINNET_CHAIN_ICONS from '../meta/mainnet/icons' import * as STAGING_CHAIN_ICONS from '../meta/staging/icons' @@ -40,6 +44,43 @@ const CHAIN_ICONS = { regression: REGRESSION_CHAIN_ICONS } +export const CHAINS_META = { + mainnet: mainnetMeta, + staging: stagingMeta, + legacy: legacyMeta, + regression: regressionMeta +} + + +export function getChainAlias(skaleNetwork: SkaleNetwork, chainName: string, app?: string): string { + if (chainName === MAINNET_CHAIN_NAME) { + if (skaleNetwork != MAINNET_CHAIN_NAME) { + const network = skaleNetwork === 'staging' ? 'Goerli' : skaleNetwork + return `Ethereum (${network})` + } + return 'Ethereum' + } + if (CHAINS_META[skaleNetwork] && CHAINS_META[skaleNetwork][chainName]) { + if ( + app && + CHAINS_META[skaleNetwork][chainName].apps && + CHAINS_META[skaleNetwork][chainName].apps[app] + ) { + return CHAINS_META[skaleNetwork][chainName].apps[app].alias + } + return CHAINS_META[skaleNetwork][chainName].alias + } + return chainName +} + + +export function getChainAppsMeta(chainName: string, skaleNetwork: SkaleNetwork) { + if (CHAINS_META[skaleNetwork][chainName] && CHAINS_META[skaleNetwork][chainName].apps) { + return CHAINS_META[skaleNetwork][chainName].apps + } +} + + export function chainIconPath(skaleNetwork: SkaleNetwork, name: string, app?: string) { if (!name) return let filename = name.toLowerCase() @@ -53,6 +94,7 @@ export function chainIconPath(skaleNetwork: SkaleNetwork, name: string, app?: st } } + export function chainBg(skaleNetwork: SkaleNetwork, chainName: string, app?: string): string { if (CHAINS_META[skaleNetwork][chainName]) { if (app && CHAINS_META[skaleNetwork][chainName]['apps'][app]) { @@ -69,6 +111,7 @@ export function chainBg(skaleNetwork: SkaleNetwork, chainName: string, app?: str return 'linear-gradient(273.67deg, rgb(47 50 80), rgb(39 43 68))' } + export function tokenIcon(tokenSymbol: string) { if (!tokenSymbol) return const key = tokenSymbol.toLowerCase() @@ -79,6 +122,7 @@ export function tokenIcon(tokenSymbol: string) { } } + export function getTokenName(token: TokenData): string { return token.meta.name ?? token.meta.symbol } diff --git a/src/core/wagmi_network.ts b/src/core/wagmi_network.ts index 2c89ef8..f817485 100644 --- a/src/core/wagmi_network.ts +++ b/src/core/wagmi_network.ts @@ -25,7 +25,7 @@ import { Chain } from 'wagmi' import { getSChainEndpoint } from './network' import { getExplorerUrl } from './explorer' -import { getChainAlias } from './helper' +import { getChainAlias } from './metadata' import { getChainId } from './chain_id' import { SkaleNetwork } from './interfaces' diff --git a/src/index.ts b/src/index.ts index db94f55..69e38f2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -30,7 +30,7 @@ import WrappedTokens from './components/WrappedTokens' import HistoryButton from './components/HistoryButton' import TransactionsHistory from './components/TransactionsHistory' -import { CHAINS_META, getChainAlias } from './core/helper' +import { CHAINS_META, getChainAlias } from './core/metadata' import { cls, styles, cmn } from './core/css' import MetaportCore from './core/metaport' import { chainBg } from './core/metadata' From 08042cbdbc5593c89c0c06268f16f7736e171609 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Fri, 15 Sep 2023 17:10:28 +0100 Subject: [PATCH 51/54] Restructure imports --- package.json | 3 +- src/Metaport.tsx | 49 +------------- src/components/AmountInput/AmountInput.tsx | 2 - src/components/CommunityPool.tsx | 2 +- src/components/DestTokenBalance.tsx | 2 +- src/components/ErrorMessage.tsx | 1 - src/components/Metaport/Metaport.stories.tsx | 1 - src/components/SFuelWarning.tsx | 2 +- src/components/SkConnect.tsx | 1 - src/components/SkPaper.tsx | 2 +- src/components/SkeletonLoader.tsx | 1 - src/components/Stepper/SkStepper.tsx | 1 - src/components/SwitchDirection.tsx | 2 +- .../{TokenList => }/TokenBalance.tsx | 5 +- src/components/TokenIcon.tsx | 1 - src/components/{TokenList => }/TokenList.tsx | 16 ++--- src/components/TokenList/TokenList.scss | 15 ----- src/components/TokenList/index.ts | 4 -- .../TokenListSection.tsx | 13 ++-- .../TokenListSection/TokenListSection.scss | 17 ----- src/components/TokenListSection/index.ts | 1 - src/components/TransactionsHistory.tsx | 4 +- src/components/WidgetBody.tsx | 5 +- src/components/WidgetUI/WidgetUI.tsx | 9 +-- src/components/WrappedTokens.tsx | 2 +- src/core/actions/action.ts | 2 +- src/core/community_pool.ts | 2 +- src/core/events.ts | 64 +------------------ src/core/faucet.ts | 4 +- src/core/fee_calculator.ts | 3 - src/core/helper.ts | 2 - src/core/metadata.ts | 6 -- src/core/metaport.ts | 3 +- src/core/miner.ts | 2 +- src/icons/sberbank.svg | 1 - src/index.ts | 8 ++- tsconfig.json | 1 + 37 files changed, 44 insertions(+), 215 deletions(-) rename src/components/{TokenList => }/TokenBalance.tsx (90%) rename src/components/{TokenList => }/TokenList.tsx (90%) delete mode 100644 src/components/TokenList/TokenList.scss delete mode 100644 src/components/TokenList/index.ts rename src/components/{TokenListSection => }/TokenListSection.tsx (85%) delete mode 100644 src/components/TokenListSection/TokenListSection.scss delete mode 100644 src/components/TokenListSection/index.ts delete mode 100644 src/icons/sberbank.svg diff --git a/package.json b/package.json index 0012981..126d9ec 100644 --- a/package.json +++ b/package.json @@ -30,8 +30,7 @@ "lint": "eslint --ext .js,.jsx,.ts,.tsx --fix", "prettier": "prettier --write \"src/**/*.{ts,tsx,js,mdx}\"", "test": "vitest", - "test:cov": "vitest run --coverage", - "dprepack": "json -f package.json -I -e \"delete this.devDependencies; delete this.dependencies\"" + "test:cov": "vitest run --coverage" }, "devDependencies": { "@storybook/addon-essentials": "7.4.0", diff --git a/src/Metaport.tsx b/src/Metaport.tsx index 97751fd..9686f9d 100644 --- a/src/Metaport.tsx +++ b/src/Metaport.tsx @@ -24,32 +24,7 @@ // @ts-ignore import React from 'react' // import { createRoot } from 'react-dom/client'; - -import { internalEvents } from './core/events' - -import * as interfaces from './core/interfaces/index' -export * as dataclasses from './core/dataclasses/index' -export * as interfaces from './core/interfaces/index' - -import ChainIcon from './components/ChainIcon' -export { ChainIcon } - -import WidgetUI from './components/WidgetUI' -export { WidgetUI } - -import Metaport from './components/Metaport' -export { Metaport } - -import MetaportProvider from './components/MetaportProvider' -export { MetaportProvider } - -import SkPaper from './components/SkPaper' -export { SkPaper } - -import SkConnect from './components/SkConnect' -export { SkConnect } - -// export * as sfuel from './core/sfuel'; +import * as interfaces from './core/interfaces' export class InjectedMetaport { constructor(config: interfaces.MetaportConfig) { @@ -64,26 +39,4 @@ export class InjectedMetaport { console.log('div with id="metaport" does not exist') } } - - transfer(params: interfaces.TransferParams): void { - internalEvents.transfer(params) - } - // wrap(params) { internalEvents.wrap(params) } - // unwrap(params) { internalEvents.unwrap(params) } - // swap(params) { internalEvents.swap(params) } - - // updateParams(params) { internalEvents.updateParams(params) } - // requestBalance(params) { internalEvents.requestBalance(params) } - setTheme(theme: any) { - internalEvents.setTheme(theme) - } - close() { - internalEvents.close() - } - open() { - internalEvents.open() - } - reset() { - internalEvents.reset() - } } diff --git a/src/components/AmountInput/AmountInput.tsx b/src/components/AmountInput/AmountInput.tsx index 440cb33..0ec8b89 100644 --- a/src/components/AmountInput/AmountInput.tsx +++ b/src/components/AmountInput/AmountInput.tsx @@ -12,8 +12,6 @@ import { useCollapseStore } from '../../store/Store' export default function AmountInput() { const { address } = useAccount() - - const token = useMetaportStore((state) => state.token) const transferInProgress = useMetaportStore((state) => state.transferInProgress) const setAmount = useMetaportStore((state) => state.setAmount) const amount = useMetaportStore((state) => state.amount) diff --git a/src/components/CommunityPool.tsx b/src/components/CommunityPool.tsx index be5b89a..c2233c1 100644 --- a/src/components/CommunityPool.tsx +++ b/src/components/CommunityPool.tsx @@ -34,7 +34,7 @@ import TextField from '@mui/material/TextField' import localStyles from './AmountInput/AmountInput.module.scss' import SkPaper from './SkPaper' -import { TokenBalance } from './TokenList' +import TokenBalance from './TokenBalance' import Button from '@mui/material/Button' diff --git a/src/components/DestTokenBalance.tsx b/src/components/DestTokenBalance.tsx index b7b9818..1b7f44c 100644 --- a/src/components/DestTokenBalance.tsx +++ b/src/components/DestTokenBalance.tsx @@ -1,7 +1,7 @@ import { useEffect } from 'react' import { useAccount } from 'wagmi' -import { TokenBalance } from './TokenList' +import TokenBalance from './TokenBalance' import { useMetaportStore } from '../store/MetaportStore' import { BALANCE_UPDATE_INTERVAL_MS } from '../core/constants' diff --git a/src/components/ErrorMessage.tsx b/src/components/ErrorMessage.tsx index 0fd6333..af3c9b4 100644 --- a/src/components/ErrorMessage.tsx +++ b/src/components/ErrorMessage.tsx @@ -1,4 +1,3 @@ -import React from 'react' import Button from '@mui/material/Button' import { cls, cmn, styles } from '../core/css' diff --git a/src/components/Metaport/Metaport.stories.tsx b/src/components/Metaport/Metaport.stories.tsx index b339ee6..8b2a84e 100644 --- a/src/components/Metaport/Metaport.stories.tsx +++ b/src/components/Metaport/Metaport.stories.tsx @@ -7,7 +7,6 @@ METAPORT_CONFIG.mainnetEndpoint = import.meta.env.VITE_MAINNET_ENDPOINT const meta: Meta = { title: 'Functional/Metaport', component: Metaport - // decorators: [storyDecorator], } export default meta diff --git a/src/components/SFuelWarning.tsx b/src/components/SFuelWarning.tsx index fe5e320..0d3e1d1 100644 --- a/src/components/SFuelWarning.tsx +++ b/src/components/SFuelWarning.tsx @@ -21,7 +21,7 @@ * @copyright SKALE Labs 2023-Present */ -import React, { useEffect } from 'react' +import { useEffect } from 'react' import debug from 'debug' import { useAccount } from 'wagmi' diff --git a/src/components/SkConnect.tsx b/src/components/SkConnect.tsx index 0e1dc37..89b93e7 100644 --- a/src/components/SkConnect.tsx +++ b/src/components/SkConnect.tsx @@ -20,7 +20,6 @@ * @copyright SKALE Labs 2023-Present */ -import React from 'react' import { ConnectButton } from '@rainbow-me/rainbowkit' import Jazzicon, { jsNumberForAddress } from 'react-jazzicon' diff --git a/src/components/SkPaper.tsx b/src/components/SkPaper.tsx index 0e88319..ea74bc1 100644 --- a/src/components/SkPaper.tsx +++ b/src/components/SkPaper.tsx @@ -21,7 +21,7 @@ * @copyright SKALE Labs 2023-Present */ -import React, { ReactElement } from 'react' +import { ReactElement } from 'react' import { cls, cmn, styles } from '../core/css' import { useUIStore } from '../store/Store' diff --git a/src/components/SkeletonLoader.tsx b/src/components/SkeletonLoader.tsx index bb91a3b..add147c 100644 --- a/src/components/SkeletonLoader.tsx +++ b/src/components/SkeletonLoader.tsx @@ -1,4 +1,3 @@ -import React from 'react' import Skeleton from '@mui/material/Skeleton' export default function SkeletonLoader(props) { diff --git a/src/components/Stepper/SkStepper.tsx b/src/components/Stepper/SkStepper.tsx index ecef961..fd64d3c 100644 --- a/src/components/Stepper/SkStepper.tsx +++ b/src/components/Stepper/SkStepper.tsx @@ -11,7 +11,6 @@ import LoadingButton from '@mui/lab/LoadingButton' import Collapse from '@mui/material/Collapse' import SettingsBackupRestoreRoundedIcon from '@mui/icons-material/SettingsBackupRestoreRounded' -import TollIcon from '@mui/icons-material/Toll' import { getRandom } from '../../core/helper' import { getChainAlias } from '../../core/metadata' diff --git a/src/components/SwitchDirection.tsx b/src/components/SwitchDirection.tsx index a5500ee..41ec161 100644 --- a/src/components/SwitchDirection.tsx +++ b/src/components/SwitchDirection.tsx @@ -1,4 +1,4 @@ -import React, { useRef } from 'react' +import { useRef } from 'react' import IconButton from '@mui/material/IconButton' import ArrowDownwardRoundedIcon from '@mui/icons-material/ArrowDownwardRounded' diff --git a/src/components/TokenList/TokenBalance.tsx b/src/components/TokenBalance.tsx similarity index 90% rename from src/components/TokenList/TokenBalance.tsx rename to src/components/TokenBalance.tsx index 8d62ae0..29f83e4 100644 --- a/src/components/TokenList/TokenBalance.tsx +++ b/src/components/TokenBalance.tsx @@ -1,7 +1,6 @@ -import React from 'react' import { formatUnits } from 'ethers' -import { cls, cmn } from '../../core/css' -import { DEFAULT_ERC20_DECIMALS } from '../../core/constants' +import { cls, cmn } from '../core/css' +import { DEFAULT_ERC20_DECIMALS } from '../core/constants' function formatBalance(balance: bigint, decimals?: string): string { const tokenDecimals = decimals ?? DEFAULT_ERC20_DECIMALS diff --git a/src/components/TokenIcon.tsx b/src/components/TokenIcon.tsx index 72b2e3e..0c4813d 100644 --- a/src/components/TokenIcon.tsx +++ b/src/components/TokenIcon.tsx @@ -21,7 +21,6 @@ * @copyright SKALE Labs 2023-Present */ -import React from 'react' import TollRoundedIcon from '@mui/icons-material/TollRounded' import { tokenIcon } from '../core/metadata' diff --git a/src/components/TokenList/TokenList.tsx b/src/components/TokenList.tsx similarity index 90% rename from src/components/TokenList/TokenList.tsx rename to src/components/TokenList.tsx index ff9fb34..5ba2a13 100644 --- a/src/components/TokenList/TokenList.tsx +++ b/src/components/TokenList.tsx @@ -9,17 +9,17 @@ import AccordionSummary from '@mui/material/AccordionSummary' import ExpandMoreIcon from '@mui/icons-material/ExpandMore' -import { getAvailableTokensTotal, getDefaultToken } from '../../core/tokens/helper' +import { getAvailableTokensTotal, getDefaultToken } from '../core/tokens/helper' -import { cls, cmn, styles } from '../../core/css' +import { cls, cmn, styles } from '../core/css' -import TokenListSection from '../TokenListSection' -import TokenIcon from '../TokenIcon' +import TokenListSection from './TokenListSection' +import TokenIcon from './TokenIcon' -import { useCollapseStore } from '../../store/Store' -import { useMetaportStore } from '../../store/MetaportStore' -import { TokenType } from '../../core/dataclasses' -import { BALANCE_UPDATE_INTERVAL_MS } from '../../core/constants' +import { useCollapseStore } from '../store/Store' +import { useMetaportStore } from '../store/MetaportStore' +import { TokenType } from '../core/dataclasses' +import { BALANCE_UPDATE_INTERVAL_MS } from '../core/constants' export default function TokenList() { const token = useMetaportStore((state) => state.token) diff --git a/src/components/TokenList/TokenList.scss b/src/components/TokenList/TokenList.scss deleted file mode 100644 index a93d6e6..0000000 --- a/src/components/TokenList/TokenList.scss +++ /dev/null @@ -1,15 +0,0 @@ - - -.iconToken { - width: 22px; - height: 22px; -} - -.default-iconToken { - color: black; - background-color: #dbe106; - padding: 4px; - border-radius: 50%; - width: 22px; - height: 22px; -} \ No newline at end of file diff --git a/src/components/TokenList/index.ts b/src/components/TokenList/index.ts deleted file mode 100644 index a555ff1..0000000 --- a/src/components/TokenList/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { default } from './TokenList' - -import TokenBalance from './TokenBalance' -export { TokenBalance } diff --git a/src/components/TokenListSection/TokenListSection.tsx b/src/components/TokenListSection.tsx similarity index 85% rename from src/components/TokenListSection/TokenListSection.tsx rename to src/components/TokenListSection.tsx index 78aa0ee..29cea40 100644 --- a/src/components/TokenListSection/TokenListSection.tsx +++ b/src/components/TokenListSection.tsx @@ -1,14 +1,13 @@ -import React from 'react' import Button from '@mui/material/Button' -import { TokenData, TokenType } from '../../core/dataclasses' -import { TokenBalancesMap, TokenDataMap } from '../../core/interfaces' -import { cls, cmn } from '../../core/css' +import { TokenData, TokenType } from '../core/dataclasses' +import { TokenBalancesMap, TokenDataMap } from '../core/interfaces' +import { cls, cmn } from '../core/css' -import TokenBalance from '../TokenList/TokenBalance' -import TokenIcon from '../TokenIcon' +import TokenBalance from './TokenBalance' +import TokenIcon from './TokenIcon' -import { getTokenName } from '../../core/metadata' +import { getTokenName } from '../core/metadata' export default function TokenListSection(props: { setExpanded: (expanded: string | false) => void diff --git a/src/components/TokenListSection/TokenListSection.scss b/src/components/TokenListSection/TokenListSection.scss deleted file mode 100644 index 0377d29..0000000 --- a/src/components/TokenListSection/TokenListSection.scss +++ /dev/null @@ -1,17 +0,0 @@ - - -.iconToken { - width: 21px; - height: 21px; - margin-left: 2px; - margin-right: 2px; -} - -.default-iconToken { - color: black; - background-color: #dbe106; - padding: 4px; - border-radius: 50%; - width: 22px; - height: 22px; -} \ No newline at end of file diff --git a/src/components/TokenListSection/index.ts b/src/components/TokenListSection/index.ts deleted file mode 100644 index 76e5a12..0000000 --- a/src/components/TokenListSection/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './TokenListSection' diff --git a/src/components/TransactionsHistory.tsx b/src/components/TransactionsHistory.tsx index 6ff33b6..579e418 100644 --- a/src/components/TransactionsHistory.tsx +++ b/src/components/TransactionsHistory.tsx @@ -31,14 +31,16 @@ import CloseRoundedIcon from '@mui/icons-material/CloseRounded' import TokenIcon from './TokenIcon' import ChainIcon from './ChainIcon' import TransactionData from './TransactionData' +import SkPaper from './SkPaper' import { useMetaportStore } from '../store/MetaportStore' import { useCollapseStore } from '../store/Store' import { cls, styles, cmn } from '../core/css' -import { interfaces, SkPaper } from '../Metaport' import { getChainAlias } from '../core/metadata' +import * as interfaces from '../core/interfaces' + export default function TransactionsHistory() { const transactionsHistory = useMetaportStore((state) => state.transactionsHistory) const transfersHistory = useMetaportStore((state) => state.transfersHistory) diff --git a/src/components/WidgetBody.tsx b/src/components/WidgetBody.tsx index 949bca2..d396138 100644 --- a/src/components/WidgetBody.tsx +++ b/src/components/WidgetBody.tsx @@ -1,4 +1,4 @@ -import React, { useEffect } from 'react' +import { useEffect } from 'react' import { useAccount } from 'wagmi' import { useCollapseStore } from '../store/Store' @@ -12,7 +12,7 @@ import SkStepper from './Stepper' import SkPaper from './SkPaper' import AmountErrorMessage from './AmountErrorMessage' import SwitchDirection from './SwitchDirection' -import { TokenBalance } from './TokenList' +import TokenBalance from './TokenBalance' import DestTokenBalance from './DestTokenBalance' import ErrorMessage from './ErrorMessage' import CommunityPool from './CommunityPool' @@ -59,7 +59,6 @@ export function WidgetBody(props) { const tokenBalances = useMetaportStore((state) => state.tokenBalances) const errorMessage = useMetaportStore((state) => state.errorMessage) - const loading = useMetaportStore((state) => state.loading) const transferInProgress = useMetaportStore((state) => state.transferInProgress) diff --git a/src/components/WidgetUI/WidgetUI.tsx b/src/components/WidgetUI/WidgetUI.tsx index c241a6a..38a094a 100644 --- a/src/components/WidgetUI/WidgetUI.tsx +++ b/src/components/WidgetUI/WidgetUI.tsx @@ -20,10 +20,7 @@ * @copyright SKALE Labs 2023-Present */ -import React, { useEffect } from 'react' -import { StyledEngineProvider } from '@mui/material/styles' - -import { useAccount } from 'wagmi' +import React from 'react' import Collapse from '@mui/material/Collapse' import Fab from '@mui/material/Fab' @@ -39,7 +36,6 @@ import WidgetBody from '../WidgetBody' import { cls, cmn, styles } from '../../core/css' -import SkConnect from '../SkConnect' import ErrorMessage from '../ErrorMessage' import { MetaportConfig } from '../../core/interfaces' @@ -47,9 +43,6 @@ export function WidgetUI(props: { config: MetaportConfig }) { const metaportTheme = useUIStore((state) => state.theme) const isOpen = useUIStore((state) => state.open) const setOpen = useUIStore((state) => state.setOpen) - - const { address } = useAccount() - const errorMessage = useMetaportStore((state) => state.errorMessage) const handleClick = (_: React.MouseEvent) => { diff --git a/src/components/WrappedTokens.tsx b/src/components/WrappedTokens.tsx index 9668805..fb26b7a 100644 --- a/src/components/WrappedTokens.tsx +++ b/src/components/WrappedTokens.tsx @@ -34,7 +34,7 @@ import ExpandMoreIcon from '@mui/icons-material/ExpandMore' import ErrorIcon from '@mui/icons-material/Error' import SkPaper from './SkPaper' -import { TokenBalance } from './TokenList' +import TokenBalance from './TokenBalance' import TokenIcon from './TokenIcon' import { getTokenName, getChainAlias } from '../core/metadata' diff --git a/src/core/actions/action.ts b/src/core/actions/action.ts index b6fc0e9..4a72f92 100644 --- a/src/core/actions/action.ts +++ b/src/core/actions/action.ts @@ -29,6 +29,7 @@ import { Contract, Provider } from 'ethers' import { MainnetChain, SChain } from '@skalenetwork/ima-js' import { TokenData, CustomAbiTokenType } from '../dataclasses' +import * as interfaces from '../interfaces' import MetaportCore, { createTokenData } from '../metaport' import { externalEvents } from '../events' import { toWei } from '../convertation' @@ -39,7 +40,6 @@ import { IMA_ABIS } from '../contracts' import { isMainnetChainId, getMainnetAbi } from '../network' import { walletClientToSigner } from '../ethers' -import { interfaces } from '../../Metaport' debug.enable('*') const log = debug('metaport:actions') diff --git a/src/core/community_pool.ts b/src/core/community_pool.ts index 7666340..3c04413 100644 --- a/src/core/community_pool.ts +++ b/src/core/community_pool.ts @@ -41,7 +41,7 @@ import { BALANCE_UPDATE_INTERVAL_MS } from './constants' import { delay } from './helper' -import { CHAIN_IDS, isMainnetChainId, getMainnetAbi } from './network' +import { CHAIN_IDS, getMainnetAbi } from './network' import MetaportCore from './metaport' import * as dataclasses from '../core/dataclasses' diff --git a/src/core/events.ts b/src/core/events.ts index a5023c4..1002fe9 100644 --- a/src/core/events.ts +++ b/src/core/events.ts @@ -85,66 +85,4 @@ export namespace externalEvents { } } -export namespace internalEvents { - export function updateParams(params) { - dispatchEvent('_metaport_updateParams', { - tokens: params.tokens, - chains: params.chains - }) - } - - export function transfer(params: interfaces.TransferParams): void { - dispatchEvent('_metaport_transfer', { - params: params - }) - } - - export function wrap(params) { - dispatchEvent('_metaport_wrap', { - amount: params.amount, - chain: params.chain, - tokens: params.tokens - }) - } - - export function unwrap(params) { - dispatchEvent('_metaport_unwrap', { - amount: params.amount, - chain: params.chain, - tokens: params.tokens - }) - } - - export function swap(params) { - dispatchEvent('_metaport_swap', { - amount: params.amount, - chain: params.chain, - tokens: params.tokens // todo! - }) - } - - export function close() { - dispatchEvent('_metaport_close') - } - - export function open() { - dispatchEvent('_metaport_open') - } - - export function reset() { - dispatchEvent('_metaport_reset') - } - - export function requestBalance(params) { - dispatchEvent('_metaport_requestBalance', { - schainName: params.schainName, - tokenSymbol: params.tokenSymbol - }) - } - - export function setTheme(theme) { - dispatchEvent('_metaport_setTheme', { - theme: theme - }) - } -} +export namespace internalEvents {} diff --git a/src/core/faucet.ts b/src/core/faucet.ts index 93ba4f7..f51fe27 100644 --- a/src/core/faucet.ts +++ b/src/core/faucet.ts @@ -21,11 +21,11 @@ * @copyright SKALE Labs 2023-Present */ -import { Provider, Wallet, JsonRpcProvider, AbiCoder, TransactionResponse } from 'ethers' +import { Wallet, JsonRpcProvider, AbiCoder, TransactionResponse } from 'ethers' import SkalePowMiner from './miner' import { ZERO_ADDRESS, ZERO_FUNCSIG, FAUCET_DATA } from './constants' -import { AddressType, SkaleNetwork } from './interfaces' +import { AddressType } from './interfaces' import MetaportCore from './metaport' function getAddress(chainName: string, skaleNetwork: string) { diff --git a/src/core/fee_calculator.ts b/src/core/fee_calculator.ts index ab9d6c4..6eeeaeb 100644 --- a/src/core/fee_calculator.ts +++ b/src/core/fee_calculator.ts @@ -21,13 +21,10 @@ * @copyright SKALE Labs 2022-Present */ -import debug from 'debug' import { fromWei } from './convertation' import { CoinGeckoClient } from 'coingecko-api-v3' import { DEFAULT_ERC20_DECIMALS } from './constants' -debug.enable('*') -const log = debug('metaport:components:fee_calculator') export async function getTransactionFee(): Promise { // todo: get actual gas limit for transfer diff --git a/src/core/helper.ts b/src/core/helper.ts index ac29597..eedd40b 100644 --- a/src/core/helper.ts +++ b/src/core/helper.ts @@ -24,9 +24,7 @@ import { getAddress } from 'ethers' import { MAINNET_CHAIN_NAME } from './constants' -// import utils from 'web3-utils'; import { TransferRequestStatus } from './dataclasses' -import { SkaleNetwork } from './interfaces' export function eqArrays(arr1, arr2) { return JSON.stringify(arr1) === JSON.stringify(arr2) diff --git a/src/core/metadata.ts b/src/core/metadata.ts index 393d6c9..89b5329 100644 --- a/src/core/metadata.ts +++ b/src/core/metadata.ts @@ -51,7 +51,6 @@ export const CHAINS_META = { regression: regressionMeta } - export function getChainAlias(skaleNetwork: SkaleNetwork, chainName: string, app?: string): string { if (chainName === MAINNET_CHAIN_NAME) { if (skaleNetwork != MAINNET_CHAIN_NAME) { @@ -73,14 +72,12 @@ export function getChainAlias(skaleNetwork: SkaleNetwork, chainName: string, app return chainName } - export function getChainAppsMeta(chainName: string, skaleNetwork: SkaleNetwork) { if (CHAINS_META[skaleNetwork][chainName] && CHAINS_META[skaleNetwork][chainName].apps) { return CHAINS_META[skaleNetwork][chainName].apps } } - export function chainIconPath(skaleNetwork: SkaleNetwork, name: string, app?: string) { if (!name) return let filename = name.toLowerCase() @@ -94,7 +91,6 @@ export function chainIconPath(skaleNetwork: SkaleNetwork, name: string, app?: st } } - export function chainBg(skaleNetwork: SkaleNetwork, chainName: string, app?: string): string { if (CHAINS_META[skaleNetwork][chainName]) { if (app && CHAINS_META[skaleNetwork][chainName]['apps'][app]) { @@ -111,7 +107,6 @@ export function chainBg(skaleNetwork: SkaleNetwork, chainName: string, app?: str return 'linear-gradient(273.67deg, rgb(47 50 80), rgb(39 43 68))' } - export function tokenIcon(tokenSymbol: string) { if (!tokenSymbol) return const key = tokenSymbol.toLowerCase() @@ -122,7 +117,6 @@ export function tokenIcon(tokenSymbol: string) { } } - export function getTokenName(token: TokenData): string { return token.meta.name ?? token.meta.symbol } diff --git a/src/core/metaport.ts b/src/core/metaport.ts index 209720c..158bc57 100644 --- a/src/core/metaport.ts +++ b/src/core/metaport.ts @@ -40,7 +40,6 @@ import { ERC_ABIS } from './contracts' import debug from 'debug' import { MainnetChain, SChain } from '@skalenetwork/ima-js' -import { interfaces } from '../Metaport' import { MAINNET_CHAIN_NAME } from './constants' const log = debug('ima:test:MainnetChain') @@ -118,7 +117,7 @@ export function createWrappedTokensMap( return wrappedTokens } -const findFirstWrapperAddress = (token: interfaces.Token): `0x${string}` | null => +const findFirstWrapperAddress = (token: Token): `0x${string}` | null => Object.values(token.chains).find((chain) => 'wrapper' in chain)?.wrapper || null export const findFirstWrapperChainName = (token: TokenData): string | null => { diff --git a/src/core/miner.ts b/src/core/miner.ts index abb4fcd..7a8ba21 100644 --- a/src/core/miner.ts +++ b/src/core/miner.ts @@ -21,7 +21,7 @@ * @copyright SKALE Labs 2023-Present */ -import { isHexString, getNumber, randomBytes, keccak256, hexlify, toBeHex, toBigInt } from 'ethers' +import { isHexString, getNumber, randomBytes, keccak256, toBeHex, toBigInt } from 'ethers' import { MAX_NUMBER } from './constants' interface Params { diff --git a/src/icons/sberbank.svg b/src/icons/sberbank.svg deleted file mode 100644 index 007e4c1..0000000 --- a/src/icons/sberbank.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 69e38f2..bdc027e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ -export { interfaces, dataclasses } from './Metaport' +import * as interfaces from './core/interfaces' +import * as dataclasses from './core/dataclasses' export { useMetaportStore } from './store/MetaportStore' export { type MetaportState } from './store/MetaportState' @@ -15,7 +16,8 @@ import ChainIcon from './components/ChainIcon' import TokenIcon from './components/TokenIcon' import ChainsList from './components/ChainsList' -import TokenList, { TokenBalance } from './components/TokenList' +import TokenList from './components/TokenList' +import TokenBalance from './components/TokenBalance' import AmountInput from './components/AmountInput' import SwitchDirection from './components/SwitchDirection' import SkStepper from './components/Stepper' @@ -69,6 +71,8 @@ export { cls, styles, cmn, + interfaces, + dataclasses, getMetaportTheme, useWagmiAccount, PROXY_ENDPOINTS, diff --git a/tsconfig.json b/tsconfig.json index ad5b433..2238d89 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,6 +14,7 @@ "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, + "noUnusedLocals": true, "jsx": "react-jsx", "typeRoots": ["./src/vite-env.d.ts", "./src/types", "./node_modules/@types"], }, From 2c478696ff8d38df4c00fe29f07112382dc5f80b Mon Sep 17 00:00:00 2001 From: Dmytro Date: Wed, 20 Sep 2023 17:05:48 +0100 Subject: [PATCH 52/54] Update submodules --- .gitmodules | 1 + helper-scripts | 2 +- skale-network | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 3aea469..5343ec4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,3 +5,4 @@ [submodule "skale-network"] path = skale-network url = https://github.com/skalenetwork/skale-network.git + branch = add-additional-metadata diff --git a/helper-scripts b/helper-scripts index e9de03b..45d533e 160000 --- a/helper-scripts +++ b/helper-scripts @@ -1 +1 @@ -Subproject commit e9de03b8ec07223e0d28313353ab1aa8c0219586 +Subproject commit 45d533ea5d3895ce79ebc275fa1cbeab11fe5036 diff --git a/skale-network b/skale-network index 5b00cae..d49a336 160000 --- a/skale-network +++ b/skale-network @@ -1 +1 @@ -Subproject commit 5b00cae6736322f302c3a75331b19ee02b0a3596 +Subproject commit d49a33606bebe32e7803ba732aacba70a4ee4a21 From e51339a12df1ede4e6aa266f12b51f1f32f32a37 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Thu, 21 Sep 2023 19:40:26 +0100 Subject: [PATCH 53/54] Minor changes --- .github/workflows/test.yml | 3 --- skale-network | 2 +- src/components/ChainsList.tsx | 3 --- src/components/TokenList.tsx | 4 ---- src/components/WidgetBody.tsx | 4 ++-- src/core/interfaces/Config.ts | 2 +- src/index.ts | 3 +++ src/styles/cmn.module.scss | 15 ++++++++++++++- 8 files changed, 21 insertions(+), 15 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index afac8d6..377cd5e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,9 +17,6 @@ jobs: uses: actions/setup-node@v1 with: node-version: ${{ matrix.node }} - - name: Update submodules - run: | - git submodule update --remote - name: Prepare metadata run: | bash prepare_meta.sh diff --git a/skale-network b/skale-network index d49a336..8c27b43 160000 --- a/skale-network +++ b/skale-network @@ -1 +1 @@ -Subproject commit d49a33606bebe32e7803ba732aacba70a4ee4a21 +Subproject commit 8c27b4390bc22beaabe4107bea9b5e1f8e0f79de diff --git a/src/components/ChainsList.tsx b/src/components/ChainsList.tsx index 7756bb8..d41734a 100644 --- a/src/components/ChainsList.tsx +++ b/src/components/ChainsList.tsx @@ -138,9 +138,6 @@ export default function ChainsList(props: { className={cls(cmn.chainsList, cmn.mbott10, cmn.mri10)} style={{ marginLeft: '8px' }} > - {/*
- -
*/} {schainNames.map((name) => (
diff --git a/src/components/WidgetBody.tsx b/src/components/WidgetBody.tsx index d396138..76aed1e 100644 --- a/src/components/WidgetBody.tsx +++ b/src/components/WidgetBody.tsx @@ -151,7 +151,7 @@ export function WidgetBody(props) {
-

From

+

From {appName1 ? 'app' : ''}

{token ? (
-

To

+

To {appName2 ? 'app' : ''}

Date: Fri, 22 Sep 2023 19:29:35 +0100 Subject: [PATCH 54/54] Update WS endpoint func, general cleanup --- src/components/AmountErrorMessage.tsx | 2 +- .../{AmountInput => }/AmountInput.tsx | 11 ++-- .../AmountInput/AmountInput.module.scss | 51 ------------------- src/components/AmountInput/index.ts | 1 - src/components/ChainApps.tsx | 10 ++-- src/components/ChainIcon.tsx | 5 +- src/components/ChainsList.tsx | 2 +- src/components/CommunityPool.tsx | 10 ++-- src/components/ErrorMessage.tsx | 4 +- src/components/MetaportProvider.tsx | 4 +- src/components/SFuelWarning.tsx | 2 - src/components/SkConnect.tsx | 2 - src/components/Stepper/SkStepper.module.scss | 3 -- src/components/Stepper/SkStepper.tsx | 2 - src/components/SwitchDirection.tsx | 40 ++++++++------- src/components/TransferETF.tsx | 3 -- src/components/WidgetBody.tsx | 8 ++- src/core/chain_id.ts | 2 - src/core/community_pool.ts | 3 -- src/core/constants.ts | 14 ++--- src/core/dataclasses/EthTokenData.ts | 45 ---------------- src/core/fee_calculator.ts | 1 - src/core/interfaces/TokenDataMap.ts | 6 +-- src/core/metaport.ts | 2 +- src/core/wagmi_network.ts | 7 ++- src/metadata/metaportConfigStaging.ts | 38 +------------- src/styles/styles.module.scss | 33 ++++++++++++ 27 files changed, 96 insertions(+), 215 deletions(-) rename src/components/{AmountInput => }/AmountInput.tsx (79%) delete mode 100644 src/components/AmountInput/AmountInput.module.scss delete mode 100644 src/components/AmountInput/index.ts delete mode 100644 src/core/dataclasses/EthTokenData.ts diff --git a/src/components/AmountErrorMessage.tsx b/src/components/AmountErrorMessage.tsx index f7a4627..1231aca 100644 --- a/src/components/AmountErrorMessage.tsx +++ b/src/components/AmountErrorMessage.tsx @@ -7,7 +7,7 @@ import { useMetaportStore } from '../store/MetaportStore' export default function AmountErrorMessage() { const amountErrorMessage = useMetaportStore((state) => state.amountErrorMessage) return ( - +

+

{expandedTokens ? null : (