Skip to content

Commit

Permalink
Merge pull request #455 from skalenetwork/add-metaport-package
Browse files Browse the repository at this point in the history
Move all base metaport files to packages
  • Loading branch information
dmytrotkk authored Jan 9, 2025
2 parents 36cd761 + 0b63b5f commit 31ded5d
Show file tree
Hide file tree
Showing 117 changed files with 10,334 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ src/assets/validators/index.ts
src/metadata.json
src/metrics.json

packages/*/node_modules
packages/metaport/storybook-static

src/metadata/chainsData.json
src/metadata/faucet.json
.vercel
Expand Down
25 changes: 25 additions & 0 deletions packages/metaport/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
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',
},
}
8 changes: 8 additions & 0 deletions packages/metaport/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"semi": false,
"trailingComma": "none",
"singleQuote": true,
"printWidth": 100,
"endOfLine": "auto",
"bracketSpacing": true
}
22 changes: 22 additions & 0 deletions packages/metaport/.storybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
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/addon-styling',
],
framework: {
name: '@storybook/react-vite',
options: {
builder: {
viteConfigPath: '.storybook/vite.config.ts',
},
},
},
docs: {
autodocs: 'tag',
},
}
export default config
25 changes: 25 additions & 0 deletions packages/metaport/.storybook/preview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
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: {
color: /(background|color)$/i,
date: /Date$/,
},
},
},
}

export default preview
16 changes: 16 additions & 0 deletions packages/metaport/.storybook/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import react from '@vitejs/plugin-react'
import { defineConfig } from 'vitest/config'
import { UserConfigExport } from 'vite'

const app = async (): Promise<UserConfigExport> => {
return defineConfig({
plugins: [react()],
css: {
postcss: {
plugins: [],
},
},
})
}
// https://vitejs.dev/config/
export default app
57 changes: 57 additions & 0 deletions packages/metaport/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# SKALE Metaport Widget

[![Discord](https://img.shields.io/discord/534485763354787851.svg)](https://discord.gg/vvUtWJB)
![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/skalenetwork/metaport/publish.yml)
![npm](https://img.shields.io/npm/dm/@skalenetwork/metaport)
![NPM](https://img.shields.io/npm/l/@skalenetwork/metaport)
![GitHub top language](https://img.shields.io/github/languages/top/skalenetwork/metaport)

Metaport is a Typescript/Javascript widget that could be embeded into a web application to add IMA functionality to any SKALE dApp.


## Documentation

See https://docs.skale.network/metaport/1.1.x/

## Development

### Storybook preview

```
bash prepare_meta.sh && bun install && bun build:lib
bun dev
```

### Debug mode

To enable debug mode, set `debug` environment variable to `true`:

```Javascript
const metaport = new Metaport({
...
debug: false // Enable debug mode (optional, default = false)
...
});
```

Additionally, you can enable debug logs in developer console by enabling `Verbose` level of logs.


#### Linter git hook

Be sure to add pre-commit git hook:

```shell
echo 'bun lint' > .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
```

## Security and Liability

The Metaport UI and code is WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

## License

![GitHub](https://img.shields.io/github/license/skalenetwork/metaport.svg)

All contributions are made under the [GNU Lesser General Public License v3](https://www.gnu.org/licenses/lgpl-3.0.en.html). See [LICENSE](LICENSE).
Binary file added packages/metaport/bun.lockb
Binary file not shown.
104 changes: 104 additions & 0 deletions packages/metaport/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
{
"name": "@skalenetwork/metaport",
"version": "3.2.0",
"description": "SKALE Metaport Widget",
"keywords": [
"skale",
"web3",
"ethereum"
],
"author": "SKALE Labs",
"license": "LGPL-3.0-only",
"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"
},
"engines": {
"node": "20"
},
"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",
"version": "node -e \"console.log(require('./package.json').version);\""
},
"devDependencies": {
"@storybook/addon-essentials": "^7.6.10",
"@storybook/addon-interactions": "^7.6.10",
"@storybook/addon-links": "^7.6.10",
"@storybook/addon-styling": "1.3.7",
"@storybook/blocks": "^7.6.10",
"@storybook/react": "^7.6.10",
"@storybook/react-vite": "^7.6.10",
"@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",
"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",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"sass": "^1.65.1",
"storybook": "^7.6.10",
"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"
},
"dependencies": {
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.15.6",
"@mui/lab": "^5.0.0-alpha.162",
"@mui/material": "^5.15.6",
"@rainbow-me/rainbowkit": "^2.2.1",
"@skalenetwork/ima-js": "2.0.2-develop.0",
"@tanstack/react-query": "^5.54.1",
"coingecko-api-v3": "^0.0.29",
"react-jazzicon": "^1.0.4",
"viem": "2.21.54",
"wagmi": "^2.13.3",
"zustand": "^4.5.0"
},
"peerDependencies": {
"react": "18.2.0",
"react-dom": "18.2.0"
},
"files": [
"dist"
],
"lint-staged": {
"*.{ts,tsx,js,jsx,json,css,md}": [
"prettier -w"
]
}
}
118 changes: 118 additions & 0 deletions packages/metaport/src/components/AddToken.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/**
* @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 <https://www.gnu.org/licenses/>.
*/

/**
* @file AddToken.ts
* @copyright SKALE Labs 2023-Present
*/

import { useState } from 'react'
import { useWalletClient, useSwitchChain } from 'wagmi'
import { MainnetChain, SChain } from '@skalenetwork/ima-js'

import Button from '@mui/material/Button'
import TollIcon from '@mui/icons-material/Toll'

import { cls, cmn, styles } from '../core/css'
import MetaportCore, { createTokenData } from '../core/metaport'
import { enforceNetwork } from '../core/network'
import { TokenData, TokenType } from '../core/dataclasses'
import { ICONS_BASE_URL, MAINNET_CHAIN_NAME } from '../core/constants'

export default function AddToken(props: {
token: TokenData
destChainName: string
mpc: MetaportCore
ima: MainnetChain | SChain
}) {
const [loading, setLoading] = useState<boolean>(false)

const { data: walletClient } = useWalletClient()
const { switchChainAsync } = useSwitchChain()

function getIconUrl(token: TokenData) {
return `${ICONS_BASE_URL}${token.meta.symbol}.png`
}

async function isIconAvailable(url: string): Promise<boolean> {
try {
const response = await fetch(url, { method: 'HEAD' })
return response.ok
} catch (error) {
console.error('Error retrieving users:', error)
return false
}
}

async function addToken() {
setLoading(true)
const destToken = createTokenData(
props.token.keyname,
props.destChainName,
props.token.type,
props.mpc.config
)
const iconUrl = getIconUrl(props.token)
const { chainId } = await props.ima.provider.getNetwork()
try {
await enforceNetwork(
chainId,
walletClient,
switchChainAsync,
props.mpc.config.skaleNetwork,
props.destChainName
)
const wasAdded = await window.ethereum.request({
method: 'wallet_watchAsset',
params: {
type: 'ERC20',
options: {
address: destToken.address,
symbol: destToken.meta.symbol.toUpperCase(),
decimals: destToken.meta.decimals,
image: (await isIconAvailable(iconUrl)) ? iconUrl : undefined
}
}
})
if (wasAdded) {
console.log('Token added')
} else {
console.log('Something went wrong')
}
} catch (error) {
console.log(error)
} finally {
setLoading(false)
}
}

if (props.destChainName === MAINNET_CHAIN_NAME && props.token.type === TokenType.eth) return

return (
<Button
onClick={addToken}
disabled={loading}
color="primary"
size="medium"
className={cls(styles.btnAction, cmn.mtop10d)}
startIcon={<TollIcon />}
>
{loading ? 'Check wallet' : 'Add token'}
</Button>
)
}
Loading

0 comments on commit 31ded5d

Please sign in to comment.