feat: bridge

This commit is contained in:
bartosz-lipinski 2021-02-12 16:02:09 -06:00
parent 5f55bdf0ef
commit 581bb3ecb7
15 changed files with 309 additions and 91 deletions

View File

@ -0,0 +1,48 @@
{
"name": "@solana/bridge-ethereum",
"version": "0.0.1",
"dependencies": {
"@oyster/common": "0.0.1",
"@solana/spl-token": "0.0.13",
"@solana/spl-token-swap": "0.1.0",
"@solana/web3.js": "^0.86.2",
"bn.js": "^5.1.3",
"bs58": "^4.0.1",
"buffer-layout": "^1.2.0",
"ethers": "^4.0.48",
"eventemitter3": "^4.0.7",
"lodash": "^4.17.20",
"typescript": "^4.1.3",
"web3": "^1.3.0"
},
"scripts": {
"format:fix": "prettier --write \"**/*.+(js|jsx|ts|tsx|json|css|md)\"",
"ethers": "typechain --target ethers-v4 --outDir src/contracts 'contracts/*.json'"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"repository": {
"type": "git",
"url": "https://github.com/solana-labs/oyster"
},
"homepage": ".",
"devDependencies": {
"@typechain/ethers-v4": "^1.0.0",
"@types/bn.js": "^5.1.0",
"@types/bs58": "^4.0.1",
"@types/node": "^12.12.62",
"arweave-deploy": "^1.9.1",
"gh-pages": "^3.1.0",
"prettier": "^2.1.2"
}
}

View File

@ -0,0 +1 @@
// TODO: move bridge interaction code to this library

View File

@ -0,0 +1,22 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"downlevelIteration": true,
"noEmit": true,
"jsx": "react",
"typeRoots": ["../../types"]
},
"include": ["src"]
}

View File

@ -3,7 +3,6 @@
"version": "0.1.0",
"dependencies": {
"@ant-design/icons": "^4.4.0",
"@ant-design/pro-layout": "^6.7.0",
"@babel/preset-typescript": "^7.12.13",
"@craco/craco": "^5.7.0",
"@oyster/common": "0.0.1",

View File

@ -49,7 +49,7 @@
</style>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css"
href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css"
integrity="sha512-+4zCK9k+qNFUR5X+cKL9EIR+ZOhtIloNl9GIKS57V1MyNsYpYcUrUeQc9vNfzsWfV28IaLL3i96P9sdNyeRssA=="
crossorigin="anonymous"
/>

View File

@ -1,6 +1,8 @@
@import "~antd/dist/antd.dark.less";
@import "./ant-custom.less";
@solana-green: #00FFA3;
body {
--row-highlight: @background-color-base;
}
@ -14,6 +16,36 @@ body {
width: 32px;
}
.app-title {
font-family: "FF Oxide Solid";
font-style: normal;
font-weight: 300;
letter-spacing: 0px;
h1 {
font-size: 48px;
margin: 0px;
}
h2 {
span {
display: inline-block;
font-size: 16px;
background: linear-gradient(270deg, @solana-green 0%, #DC1FFF 101.97%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
}
}
.app-action {
border-color: @solana-green;
color: @solana-green;
padding: 20px 30px;
line-height: 2px;
}
.footer {
background-color: black;
color: lightgray;
@ -216,6 +248,10 @@ em {
}
}
.ant-layout {
background: transparent !important;
}
.ant-layout-content {
display: flex;
overflow: auto;
@ -270,21 +306,13 @@ em {
margin: 20px 15px 40px 15px;
}
.ant-pro-sider.ant-layout-sider-collapsed .ant-pro-sider-logo {
padding: 8px 8px;
}
.ant-pro-global-header {
.ant-pro-global-header-logo a h1 {
color: white !important;
}
background-color: black !important;
color: white !important;
.ant-btn {
color: white !important;
}
.ant-layout-header {
align-items: center;
height: 42px;
padding: 0 20px;
color: rgba(255, 255, 255, 0.85);
line-height: 64px;
display: flex;
}
.ant-statistic {
@ -315,6 +343,7 @@ em {
color: @text-color-secondary;
}
[class="ant-layout-header"] {
height: 16px !important;
}
@ -325,22 +354,22 @@ em {
text-align: right;
}
.small-statisitc {
.home-statistic {
font-family: "FF Oxide Solid";
font-style: normal;
font-weight: 300;
letter-spacing: 0px;
.ant-statistic-title {
font-size: 12px;
display: inline-block;
font-size: 48px !important;
background: linear-gradient(254.55deg, @solana-green 10.02%, #DC1FFF 89.22%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.ant-statistic-content {
max-height: 20px;
line-height: 2px;;
}
.ant-statistic-content-value-int {
font-size: 12px;
}
.ant-statistic-content-value-decimal {
font-size: 10px;
font-size: 20px !important;
}
}

View File

@ -1,5 +1,15 @@
@import '~antd/es/style/themes/dark.less';
@import "~antd/dist/antd.dark.less";
@font-face {
font-family: "FF Oxide Solid";
src: url("//db.onlinewebfonts.com/t/bc30adee89b44a44a5cfdff676aef0fe.eot");
src: url("//db.onlinewebfonts.com/t/bc30adee89b44a44a5cfdff676aef0fe.eot?#iefix") format("embedded-opentype"),
url("//db.onlinewebfonts.com/t/bc30adee89b44a44a5cfdff676aef0fe.woff2") format("woff2"),
url("//db.onlinewebfonts.com/t/bc30adee89b44a44a5cfdff676aef0fe.woff") format("woff"),
url("//db.onlinewebfonts.com/t/bc30adee89b44a44a5cfdff676aef0fe.ttf") format("truetype"),
url("//db.onlinewebfonts.com/t/bc30adee89b44a44a5cfdff676aef0fe.svg#FF Oxide Solid") format("svg");
}
@primary-color: #ff00a8;
@popover-background: #1a2029;

View File

@ -1,26 +1,13 @@
import React from 'react';
import './../../App.less';
import { Menu } from 'antd';
import {
PieChartOutlined,
GithubOutlined,
BankOutlined,
LogoutOutlined,
ShoppingOutlined,
HomeOutlined,
RocketOutlined,
ForkOutlined,
// LineChartOutlined
} from '@ant-design/icons';
import BasicLayout from '@ant-design/pro-layout';
import { AppBar } from './../AppBar';
import { Layout } from 'antd';
import { Link, useLocation } from 'react-router-dom';
import { LABELS } from '../../constants';
import config from './../../../package.json';
import { contexts } from '@oyster/common';
const { Header, Content } = Layout;
const { useConnectionConfig } = contexts.Connection;
export const AppLayout = React.memo((props: any) => {
@ -34,29 +21,18 @@ export const AppLayout = React.memo((props: any) => {
const current =
[...Object.keys(paths)].find(key => location.pathname.startsWith(key)) ||
'';
const defaultKey = paths[current] || '1';
const theme = 'dark';
return (
<div className="App">
{/* <BasicLayout
<div className="App wormhole-bg">
<Layout
title={LABELS.APP_TITLE}
footerRender={() => (
<div className="footer" title={LABELS.FOOTER}>
{LABELS.FOOTER}
</div>
)}
navTheme={theme}
// headerTheme={theme}
theme={theme}
layout="top"
primaryColor="#d83aeb"
logo={<div className="App-logo" />}
// rightContentRender={() => <AppBar />}
links={[]}
> */}
{props.children}
{/* </BasicLayout> */}
>
{location.pathname !== '/' && <Header className="header">
<div className="App-logo" />
</Header>}
<Content style={{ padding: '0 50px' }}>
{props.children}
</Content>
</Layout>
</div>
);
});

View File

@ -0,0 +1,64 @@
import React, { useCallback } from 'react';
import { Button, Card } from 'antd';
import { LAMPORTS_PER_SOL } from '@solana/web3.js';
import { LABELS } from '../../constants';
import { contexts, utils, ConnectButton } from '@oyster/common';
import { useHistory, useLocation } from "react-router-dom";
import './style.less';
const { useConnection } = contexts.Connection;
const { useWallet } = contexts.Wallet;
const { notify } = utils;
export const Transfer = () => {
const connection = useConnection();
const { wallet } = useWallet();
const tabStyle: React.CSSProperties = { width: 120 };
const tabList = [
{
key: "eth",
tab: <div style={tabStyle}>Transfer</div>,
render: () => {
return <div>Bring assets to Solana</div>;
},
},
{
key: "sol",
tab: <div style={tabStyle}>Wrap</div>,
render: () => {
return <div>Bring assets to Solana</div>;
},
},
];
const location = useLocation();
const history = useHistory();
const activeTab = location.pathname.indexOf("eth") < 0 ? "sol" : "eth";
const handleTabChange = (key: any) => {
if (activeTab !== key) {
if (key === "sol") {
history.push("/move/sol");
} else {
history.push("/move/eth");
}
}
};
return (
<>
<div className="input-card">
INPUT
<Button type="primary" className="swap-button">
</Button>
OUTPUT
</div>
<ConnectButton type="primary">
Transfer
</ConnectButton>
</>
);
};

View File

@ -0,0 +1,12 @@
.input-card {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 10px;
}
.swap-button {
border-radius: 2em;
width: 32px;
padding-left: 8px;
}

View File

@ -7,6 +7,7 @@ import { AppLayout } from './components/Layout';
import {
FaucetView,
HomeView,
TransferView,
} from './views';
const { WalletProvider } = contexts.Wallet;
const { ConnectionProvider } = contexts.Connection;
@ -23,6 +24,7 @@ export function Routes() {
<AppLayout>
<Switch>
<Route exact path="/" component={() => <HomeView />} />
<Route path="/move" children={<TransferView />} />
<Route exact path="/faucet" children={<FaucetView />} />
</Switch>
</AppLayout>

View File

@ -1,5 +1,5 @@
import { MintInfo } from '@solana/spl-token';
import { Table, Tag, Space, Card, Col, Row, Statistic } from 'antd';
import { Table, Tag, Space, Card, Col, Row, Statistic, Button } from 'antd';
import React, { useEffect, useState } from 'react';
import { GUTTER, LABELS } from '../../constants';
import { contexts, ParsedAccount, utils } from '@oyster/common';
@ -9,6 +9,7 @@ import { LendingReserveItem } from './item';
import { AppBar } from './../../components/AppBar';
import './itemStyle.less';
import { Totals } from '../../models/totals';
import { Link } from 'react-router-dom';
const { fromLamports, getTokenName, wadToLamports } = utils;
const { cache } = contexts.Accounts;
const { useConnectionConfig } = contexts.Connection;
@ -115,33 +116,21 @@ export const HomeView = () => {
gutter={GUTTER}
justify="center"
align="middle"
className="home-info-row wormhole-bg"
className="home-info-row"
>
<Col xs={24} xl={8}>
<Col xs={24} xl={12} className="app-title">
<h1>Wormhole</h1>
<h2>Ethereum and Solana Bridge</h2>
<AppBar />
<h2><span>Ethereum + Solana Bridge</span></h2>
<Link to="/move">
<Button className="app-action">Get Started</Button>
</Link>
</Col>
<Col xs={24} xl={5}>
<Card>
<Statistic
title="Current market size"
value={totals.marketSize}
precision={2}
valueStyle={{ color: '#3fBB00' }}
prefix="$"
/>
</Card>
</Col>
<Col xs={24} xl={5}>
<Card>
<Statistic
title="Assets"
value={totals.numberOfAssets}
precision={2}
prefix="$"
/>
</Card>
<Col xs={24} xl={12}>
<Statistic
className="home-statistic"
title="$1,231"
value="TOTAL VALUE LOCKED"
/>
</Col>
</Row>
<Table dataSource={dataSource} columns={columns} />

View File

@ -1,2 +1,3 @@
export { HomeView } from "./home";
export { FaucetView } from "./faucet";
export { TransferView } from "./transfer";

View File

@ -0,0 +1,65 @@
import React, { useCallback } from 'react';
import { Card } from 'antd';
import { LAMPORTS_PER_SOL } from '@solana/web3.js';
import { LABELS } from '../../constants';
import { contexts, utils, ConnectButton } from '@oyster/common';
import { useHistory, useLocation } from "react-router-dom";
const { useConnection } = contexts.Connection;
const { useWallet } = contexts.Wallet;
const { notify } = utils;
export const TransferView = () => {
const connection = useConnection();
const { wallet } = useWallet();
const tabStyle: React.CSSProperties = { width: 120 };
const tabList = [
{
key: "eth",
tab: <div style={tabStyle}>Transfer</div>,
render: () => {
return <div>Bring assets to Solana</div>;
},
},
{
key: "sol",
tab: <div style={tabStyle}>Wrap</div>,
render: () => {
return <div>Bring assets to Solana</div>;
},
},
];
const location = useLocation();
const history = useHistory();
const activeTab = location.pathname.indexOf("eth") < 0 ? "sol" : "eth";
const handleTabChange = (key: any) => {
if (activeTab !== key) {
if (key === "sol") {
history.push("/move/sol");
} else {
history.push("/move/eth");
}
}
};
return (
<div className="flexColumn" style={{ flex: 1 }}>
<Card
className="bridge-card"
headStyle={{ padding: 0 }}
bodyStyle={{ position: "relative" }}
tabList={tabList}
tabProps={{
tabBarGutter: 0,
}}
activeTabKey={activeTab}
onTabChange={(key) => {
handleTabChange(key);
}}>
{tabList.find((t) => t.key === activeTab)?.render()}
</Card>
</div>
);
};