Skip to content

Commit

Permalink
Merge pull request #67 from skalenetwork/add-erc721-tokens-support
Browse files Browse the repository at this point in the history
New Metaport architecture - add ERC721 / ERC721Meta / ERC1155 support
  • Loading branch information
dmytrotkk authored Nov 10, 2022
2 parents 674acbd + 6827d2d commit de52224
Show file tree
Hide file tree
Showing 87 changed files with 4,181 additions and 18,820 deletions.
67 changes: 42 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Metaport is a Typescript/Javascript widget that could be embeded into a web appl
- [Usage with SSR](#usage-with-ssr)
- [Token icons](#token-icons)
- [Type definitions](#type-definitions)
- [Dataclasses](#dataclasses)
- [Events](#events)
- [Available Events](#available-events)
- [Themes](#themes)
Expand Down Expand Up @@ -66,15 +67,15 @@ You can import Metaport into any modern web application (Vue/React/Angular/etc).
```Javascript
import { Metaport } from '@skalenetwork/metaport';

const widget = new Metaport(METAPORT_OPTIONS);
const metaport = new Metaport(METAPORT_OPTIONS);
```

### Initialization options

All currently available options are listed below:

```Javascript
const widget = new Metaport({
const metaport = new Metaport({
openOnLoad: true, // Open Metaport on load (optional, default = false)
openButton: false, // Show open/close action button (optional, default = true)
autoLookup: false, // Automatic token lookup for M2S tokens (default = true)
Expand All @@ -99,6 +100,8 @@ const widget = new Metaport({
'symbol1': { // token symbol
'name': 'TOKEN_NAME1', // token display name
'address': '0x0357', // token origin address
'symbol': 'TST' // token symbol
'cloneSymbol': 'CTST' // optional, symbol of the clone token
'iconUrl': 'https://example.com/my_token_icon.png', // optional
'decimals': '6' // optional (default = '18')
}
Expand All @@ -122,25 +125,21 @@ const widget = new Metaport({

When sending a transfer request you can specify token and chains or keep ones that are already selected in the Metaport UI.

```Javascript
```Typescript
import { interfaces, dataclasses } from '@skalenetwork/metaport';

const TRANSFER_PARAMS = {
amount: '1000', // amount to transfer (in wei)
chains: ['chainName1', 'chainName2'], // 'from' and 'to' chains
tokens: { // optional, if token is already selected in the Metaport UI
'chainName1': {
'erc20': {
'tst': {
'address': '0x0777',
'name': 'TEST_TOKEN'
}
}
}
},
lockAmount: true // optional, boolean - lock the amount in the Metaport UI
}
// token keyname is composed from token symbol and origin token address
const tokenKeyname = `_${tokenSymbol}_${tokenAddress}`;

metaport.transfer(TRANSFER_PARAMS);
const params: interfaces.TransferParams = {
tokenId: tokenId, // for erc721, erc721meta and erc1155 tokens
amount: amount, // amount to transfer (in wei) - for eth, erc20 and erc1155 tokens
chains: chains, // 'from' and 'to' chains (must be present in the list on chains)
tokenKeyname: tokenKeyname, // token that you want to transfer
tokenType: dataclasses.TokenType.erc1155, // available TokenTypes are eth, erc20, erc721, erc721meta and erc1155
lockValue: true // optional, boolean - lock the amount in the Metaport UI
};
props.metaport.transfer(params);
```

Once transfer will be completed, you will receive `metaport_transferComplete` event (see Events section for more details).
Expand Down Expand Up @@ -183,7 +182,7 @@ const TOKENS_OVERRIDE = {
}
};

const widget = new Metaport({
const metaport = new Metaport({
...
autoLookup: true,
tokens: TOKENS_OVERRIDE
Expand All @@ -199,7 +198,7 @@ If you're passing multiple tokens to Metaport constructor or to `updateParams` f
If you want to lock user on a specific token, pass a single entry to `tokens` param:
```Javascript
const widget = new Metaport({
const metaport = new Metaport({
...,
tokens: {
'chainName2': {
Expand Down Expand Up @@ -238,7 +237,7 @@ If you're passing more that 2 chains to Metaport constructor or to `updateParams
If you want to perform/request transfer from one particular chain to another, pass exactly 2 chain names to `schain` param:
```Javascript
const widget = new Metaport({
const metaport = new Metaport({
...,
chains: [
'chainName1', // this one will be set as 'From' chain
Expand All @@ -254,7 +253,7 @@ You can use the same approach for `updateParams` and `transfer` functions.
ETH clone is already pre-deployed on each chain, so to have it in the Metaport UI, you just need to specify token like that:
```Javascript
const widget = new Metaport({
const metaport = new Metaport({
...,
chains: ['mainnet', 'chainName1']
tokens: {
Expand All @@ -280,9 +279,11 @@ const TRANSFER_PARAMS = {
'wreth': { // wrapper token
'address': '0x0123', // wrapper token address
'name': 'wreth', // wrapper token display name
'symbol': 'TST',
'wraps': { // token that needs to be wrapped
'address': '0xD2Aaa00700000000000000000000000000000000', // unwrapped token address
'symbol': 'ethc' // unwrapped token symbol
'symbol': 'ethc', // unwrapped token symbol
'iconUrl': '' // optional, icon URL for the origin token
}
}
}
Expand Down Expand Up @@ -368,6 +369,22 @@ const config: interfaces.MetaportConfig = {
}
```
#### Dataclasses
You can import dataclasses types for the Metaport:
```typescript
import { dataclasses } from '@skalenetwork/metaport';

const params: interfaces.TransferParams = {
amount: amount,
chains: chains,
tokenKeyname: tokenKeyname,
tokenType: dataclasses.TokenType.erc20,
};
```
### Events
You can receive data from the Metaport widget using in-browser events.
Expand Down Expand Up @@ -400,7 +417,7 @@ You can easily modify Metaport color scheme by providing a theme:
```Javascript
// option 1: during the init
const widget = new Metaport({
const metaport = new Metaport({
...
theme: {
primary: '#00d4ff', // primary accent color for action buttons
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@skalenetwork/metaport",
"version": "0.2.0",
"version": "1.0.0",
"description": "SKALE Metaport Widget",
"keywords": [
"skale",
Expand Down
4 changes: 3 additions & 1 deletion src/Metaport.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import defaultTokens from './metadata/tokens.json';
import * as interfaces from './core/interfaces/index';
export * as interfaces from './core/interfaces/index';

export * as dataclasses from './core/dataclasses/index';


export class Metaport {
constructor(config: interfaces.MetaportConfig) {
Expand Down Expand Up @@ -68,7 +70,7 @@ export class Metaport {
);
}

transfer(params) { internalEvents.transfer(params) }
transfer(params: interfaces.TransferParams): void { internalEvents.transfer(params) }
wrap(params) { internalEvents.wrap(params) }
unwrap(params) { internalEvents.unwrap(params) }
swap(params) { internalEvents.swap(params) }
Expand Down
32 changes: 32 additions & 0 deletions src/components/AmountErrorMessage/AmountErrorMessage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from "react";
import LinearProgress from '@mui/material/LinearProgress';

import { clsNames } from '../../core/helper';
import styles from "../WidgetUI/WidgetUI.scss";


export default function AmountErrorMessage(props) {
if (props.actionBtnDisabled) {
return (<div className={clsNames(styles.mp__amountErrorMessage)}>
<div className={clsNames(styles.mp__paddTop10)}>
<LinearProgress className={clsNames(styles.mp__margLeft10, styles.mp__margRi10)} />
</div>
</div>)
}
if (!props.amountErrorMessage) return (<div className={styles.mp__amountErrorMessage}></div>)
return (
<div className={clsNames(styles.mp__flex, styles.mp__amountErrorMessage)}>
<p className={clsNames(
styles.mp__p3,
styles.mp__p,
styles.mp__flexGrow,
styles.mp__textCentered,
styles.mp__margTop5,
styles.mp__noMargBott,
styles.mp__minContent,
styles.mp__errorMessage
)}>
{props.amountErrorMessage}
</p>
</div>)
}
1 change: 1 addition & 0 deletions src/components/AmountErrorMessage/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./AmountErrorMessage";
3 changes: 2 additions & 1 deletion src/components/AmountInput/AmountInput.scss
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
border-radius: 10px;

:global .MuiButton-root {
border-radius: 0 10px 10px 0 !important;
border-radius: 0 !important;
margin-right: 10px;
}

input::-webkit-outer-spin-button,
Expand Down
15 changes: 10 additions & 5 deletions src/components/AmountInput/AmountInput.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React from "react";
import TextField from '@mui/material/TextField';
import Button from '@mui/material/Button';

import { clsNames } from '../../core/helper';
import styles from '../WidgetUI/WidgetUI.scss';
Expand All @@ -14,31 +13,37 @@ export default function AmountInput(props) {
};

const setMaxAmount = () => {
props.setAmount(props.balance);
props.setAmount(props.token.balance);
}

if (!props.token) return;
return (
<div className={clsNames(styles.mp__flex, localStyles.mp__inputAmount)}>
<div className={clsNames(styles.mp__flex, styles.mp__flexGrow)}>
<TextField
type="number"
variant="standard"
placeholder="0.00"
placeholder="0.00"
value={props.amount}
onChange={handleChange}
disabled={props.loading || props.amountLocked}
/>
</div>
<div className={styles.mp__flex}>
{/* <div className={styles.mp__flex}>
<Button
color="primary"
size="small"
className={styles.mp__btnChain}
onClick={setMaxAmount}
disabled={props.loading || !props.balance || props.amountLocked}
disabled={props.loading || !props.token.balance || props.amountLocked}
>
MAX
</Button>
</div> */}
<div className={clsNames(styles.mp__flex, styles.mp__flexCenteredVert, styles.mp__margRi20)}>
<p className={clsNames(styles.mp__p3, styles.mp__p)}>
Amount
</p>
</div>
</div>
)
Expand Down
28 changes: 10 additions & 18 deletions src/components/ChainsList/ChainsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,6 @@ import { clsNames } from '../../core/helper';
import styles from "../WidgetUI/WidgetUI.scss";


function hashCode(str) {
let hash = 0;
for (var i = 0; i < str.length; i++) {
hash = str.charCodeAt(i) + ((hash << 5) - hash);
}
return hash;
}

function stringToColor(str, dark) {
if (dark) {
// return `hsl(${hashCode(str) % 360}, 100%, 80%)`;
Expand All @@ -43,7 +35,7 @@ export default function ChainsList(props) {
const schainNames = [];

for (let chain of props.schains) {
if (chain != props.disabledChain && chain != props.chain){
if (chain != props.disabledChain && chain != props.chain) {
schainNames.push(chain);
}
}
Expand All @@ -57,7 +49,7 @@ export default function ChainsList(props) {
if (chainName == MAINNET_CHAIN_NAME) {
return 'Ethereum Mainnet';
}
if (props.chainsMetadata && props.chainsMetadata[chainName]){
if (props.chainsMetadata && props.chainsMetadata[chainName]) {
return props.chainsMetadata[chainName].alias;
} else {
return chainName;
Expand All @@ -66,9 +58,9 @@ export default function ChainsList(props) {

function getChainIcon(chainName: string) {
if (chainName == MAINNET_CHAIN_NAME) {
return <img src={ethLogo} className='eth-logo' height='20px' width='20px'/>;
return <img src={ethLogo} className='eth-logo' height='20px' width='20px' />;
}
return (<OfflineBoltIcon sx={{ color: stringToColor(props.chain, props.dark) }} width='20px'/>);
return (<OfflineBoltIcon sx={{ color: stringToColor(props.chain, props.dark) }} width='20px' />);
}

return (
Expand Down Expand Up @@ -102,7 +94,7 @@ export default function ChainsList(props) {
) : (
<div className={clsNames(styles.mp__flex, styles.mp__btnChain)}>
<div className={clsNames(styles.mp__flex, styles.mp__flexCentered)}>
<OfflineBoltIcon sx={{ color: stringToColor(props.chain, props.dark) }}/>
<OfflineBoltIcon sx={{ color: stringToColor(props.chain, props.dark) }} />
</div>
<p className={clsNames(styles.mp__flex, styles.mp__chainName, styles.mp__margRi10)}>
Select chain
Expand All @@ -113,7 +105,7 @@ export default function ChainsList(props) {
</AccordionSummary>
<AccordionDetails>
<div className={styles.mp__chainsList}>
{schainNames.map((name) => (
{schainNames.map((name) => (
<Typography key={name}>
<Button
color="secondary"
Expand All @@ -123,15 +115,15 @@ export default function ChainsList(props) {
>
<div className={clsNames(styles.mp__flex, styles.mp__btnChain)}>
<div className={clsNames(styles.mp__flex, styles.mp__flexCentered)}>
{getChainIcon(name)}
{getChainIcon(name)}
</div>
<p className={clsNames(styles.mp__flex, styles.mp__chainName, styles.mp__margRi10)}>
{getChainName(name)}
</p>
</div>
</div>
</Button>
</Typography>
))}
</Typography>
))}
</div>
</AccordionDetails>
</Accordion>
Expand Down
Loading

0 comments on commit de52224

Please sign in to comment.