mirror of https://github.com/certusone/oyster.git
feat: bridge
This commit is contained in:
parent
f634558f9c
commit
752f342781
|
@ -0,0 +1,117 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { contexts, utils, ParsedAccount, NumericInput, TokenIcon, TokenDisplay } from '@oyster/common';
|
||||
import { Card, Select } from 'antd';
|
||||
import './style.less';
|
||||
const { getTokenName } = utils;
|
||||
const { cache } = contexts.Accounts;
|
||||
const { useConnectionConfig } = contexts.Connection;
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
// User can choose a collateral they want to use, and then this will display the balance they have in Oyster's lending
|
||||
// reserve for that collateral type.
|
||||
export function EthereumInput(props: {
|
||||
title: string;
|
||||
amount?: number | null;
|
||||
disabled?: boolean;
|
||||
onInputChange: (value: number | null) => void;
|
||||
hideBalance?: boolean;
|
||||
useWalletBalance?: boolean;
|
||||
useFirstReserve?: boolean;
|
||||
showLeverageSelector?: boolean;
|
||||
leverage?: number;
|
||||
}) {
|
||||
const { tokenMap } = useConnectionConfig();
|
||||
const [acco, setCollateralReserve] = useState<string>();
|
||||
const [balance, setBalance] = useState<number>(0);
|
||||
const [lastAmount, setLastAmount] = useState<string>('');
|
||||
|
||||
|
||||
const renderReserveAccounts = [].map((reserve: any) => {
|
||||
const mint = reserve.info.liquidityMint.toBase58();
|
||||
const address = reserve.pubkey.toBase58();
|
||||
const name = getTokenName(tokenMap, mint);
|
||||
return (
|
||||
<Option key={address} value={address} name={name} title={address}>
|
||||
<div key={address} style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<TokenIcon mintAddress={mint} />
|
||||
{name}
|
||||
</div>
|
||||
</Option>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<Card
|
||||
className="ccy-input"
|
||||
style={{ borderRadius: 20 }}
|
||||
bodyStyle={{ padding: 0 }}
|
||||
>
|
||||
<div className="ccy-input-header">
|
||||
<div className="ccy-input-header-left">{props.title}</div>
|
||||
|
||||
{!props.hideBalance && (
|
||||
<div
|
||||
className="ccy-input-header-right"
|
||||
onClick={e => props.onInputChange && props.onInputChange(balance)}
|
||||
>
|
||||
Balance: {balance.toFixed(6)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="ccy-input-header" style={{ padding: '0px 10px 5px 7px' }}>
|
||||
<NumericInput
|
||||
value={
|
||||
parseFloat(lastAmount || '0.00') === props.amount
|
||||
? lastAmount
|
||||
: props.amount?.toFixed(6)?.toString()
|
||||
}
|
||||
onChange={(val: string) => {
|
||||
if (props.onInputChange && parseFloat(val) !== props.amount) {
|
||||
if (!val || !parseFloat(val)) props.onInputChange(null);
|
||||
else props.onInputChange(parseFloat(val));
|
||||
}
|
||||
setLastAmount(val);
|
||||
}}
|
||||
style={{
|
||||
fontSize: 20,
|
||||
boxShadow: 'none',
|
||||
borderColor: 'transparent',
|
||||
outline: 'transparent',
|
||||
}}
|
||||
placeholder="0.00"
|
||||
/>
|
||||
<div className="ccy-input-header-right" style={{ display: 'flex' }}>
|
||||
{!props.disabled ? (
|
||||
<Select
|
||||
size="large"
|
||||
showSearch
|
||||
style={{ minWidth: 150 }}
|
||||
placeholder="CCY"
|
||||
// value={collateralReserve}
|
||||
// onChange={item => {
|
||||
// if (props.onCollateralReserve) props.onCollateralReserve(item);
|
||||
// setCollateralReserve(item);
|
||||
// }}
|
||||
filterOption={(input, option) =>
|
||||
option?.name?.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}
|
||||
>
|
||||
{renderReserveAccounts}
|
||||
</Select>
|
||||
) : (
|
||||
<TokenDisplay
|
||||
// key={props.reserve.liquidityMint.toBase58()}
|
||||
name={getTokenName(
|
||||
tokenMap,
|
||||
'',
|
||||
)}
|
||||
mintAddress={''}
|
||||
showBalance={false}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export * from './solana';
|
||||
export * from './ethereum';
|
|
@ -0,0 +1,117 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { contexts, utils, ParsedAccount, NumericInput, TokenIcon, TokenDisplay } from '@oyster/common';
|
||||
import { Card, Select } from 'antd';
|
||||
import './style.less';
|
||||
const { getTokenName } = utils;
|
||||
const { cache } = contexts.Accounts;
|
||||
const { useConnectionConfig } = contexts.Connection;
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
// User can choose a collateral they want to use, and then this will display the balance they have in Oyster's lending
|
||||
// reserve for that collateral type.
|
||||
export function SolanaInput(props: {
|
||||
title: string;
|
||||
amount?: number | null;
|
||||
disabled?: boolean;
|
||||
onInputChange: (value: number | null) => void;
|
||||
hideBalance?: boolean;
|
||||
useWalletBalance?: boolean;
|
||||
useFirstReserve?: boolean;
|
||||
showLeverageSelector?: boolean;
|
||||
leverage?: number;
|
||||
}) {
|
||||
const { tokenMap } = useConnectionConfig();
|
||||
const [acco, setCollateralReserve] = useState<string>();
|
||||
const [balance, setBalance] = useState<number>(0);
|
||||
const [lastAmount, setLastAmount] = useState<string>('');
|
||||
|
||||
|
||||
const renderReserveAccounts = [].map((reserve: any) => {
|
||||
const mint = reserve.info.liquidityMint.toBase58();
|
||||
const address = reserve.pubkey.toBase58();
|
||||
const name = getTokenName(tokenMap, mint);
|
||||
return (
|
||||
<Option key={address} value={address} name={name} title={address}>
|
||||
<div key={address} style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<TokenIcon mintAddress={mint} />
|
||||
{name}
|
||||
</div>
|
||||
</Option>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<Card
|
||||
className="ccy-input"
|
||||
style={{ borderRadius: 20 }}
|
||||
bodyStyle={{ padding: 0 }}
|
||||
>
|
||||
<div className="ccy-input-header">
|
||||
<div className="ccy-input-header-left">{props.title}</div>
|
||||
|
||||
{!props.hideBalance && (
|
||||
<div
|
||||
className="ccy-input-header-right"
|
||||
onClick={e => props.onInputChange && props.onInputChange(balance)}
|
||||
>
|
||||
Balance: {balance.toFixed(6)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="ccy-input-header" style={{ padding: '0px 10px 5px 7px' }}>
|
||||
<NumericInput
|
||||
value={
|
||||
parseFloat(lastAmount || '0.00') === props.amount
|
||||
? lastAmount
|
||||
: props.amount?.toFixed(6)?.toString()
|
||||
}
|
||||
onChange={(val: string) => {
|
||||
if (props.onInputChange && parseFloat(val) !== props.amount) {
|
||||
if (!val || !parseFloat(val)) props.onInputChange(null);
|
||||
else props.onInputChange(parseFloat(val));
|
||||
}
|
||||
setLastAmount(val);
|
||||
}}
|
||||
style={{
|
||||
fontSize: 20,
|
||||
boxShadow: 'none',
|
||||
borderColor: 'transparent',
|
||||
outline: 'transparent',
|
||||
}}
|
||||
placeholder="0.00"
|
||||
/>
|
||||
<div className="ccy-input-header-right" style={{ display: 'flex' }}>
|
||||
{!props.disabled ? (
|
||||
<Select
|
||||
size="large"
|
||||
showSearch
|
||||
style={{ minWidth: 150 }}
|
||||
placeholder="CCY"
|
||||
// value={collateralReserve}
|
||||
// onChange={item => {
|
||||
// if (props.onCollateralReserve) props.onCollateralReserve(item);
|
||||
// setCollateralReserve(item);
|
||||
// }}
|
||||
filterOption={(input, option) =>
|
||||
option?.name?.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}
|
||||
>
|
||||
{renderReserveAccounts}
|
||||
</Select>
|
||||
) : (
|
||||
<TokenDisplay
|
||||
// key={props.reserve.liquidityMint.toBase58()}
|
||||
name={getTokenName(
|
||||
tokenMap,
|
||||
'',
|
||||
)}
|
||||
mintAddress={''}
|
||||
showBalance={false}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
.ccy-input {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.ant-select-selector,
|
||||
.ant-select-selector:focus,
|
||||
.ant-select-selector:active {
|
||||
border-color: transparent !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
.ant-select-selection-item {
|
||||
display: flex;
|
||||
|
||||
.token-balance {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.token-balance {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.ccy-input-header {
|
||||
display: grid;
|
||||
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
grid-column-gap: 10px;
|
||||
|
||||
-webkit-box-pack: justify;
|
||||
justify-content: space-between;
|
||||
-webkit-box-align: center;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
padding: 10px 20px 0px 20px;
|
||||
}
|
||||
|
||||
.ccy-input-header-left {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
margin: 0px;
|
||||
min-width: 0px;
|
||||
display: flex;
|
||||
padding: 0px;
|
||||
-webkit-box-align: center;
|
||||
align-items: center;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.ccy-input-header-right {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
-webkit-box-align: center;
|
||||
align-items: center;
|
||||
justify-self: flex-end;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.ant-select-dropdown {
|
||||
width: 150px !important;
|
||||
}
|
|
@ -4,6 +4,7 @@ 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 { SolanaInput, EthereumInput } from "./../Input";
|
||||
|
||||
import './style.less';
|
||||
|
||||
|
@ -15,46 +16,21 @@ 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="exchange-card">
|
||||
INPUT
|
||||
<EthereumInput
|
||||
title="From Ethereum"
|
||||
onInputChange={() => {}}
|
||||
/>
|
||||
<Button type="primary" className="swap-button">
|
||||
⇅
|
||||
</Button>
|
||||
OUTPUT
|
||||
<SolanaInput
|
||||
title="To Solana"
|
||||
onInputChange={() => {}}
|
||||
/>
|
||||
</div>
|
||||
<ConnectButton type="primary">
|
||||
Transfer
|
||||
|
|
|
@ -0,0 +1,259 @@
|
|||
import React, {
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from "react";
|
||||
import { MintInfo } from "@solana/spl-token";
|
||||
import { useHistory, useLocation } from "react-router-dom";
|
||||
import bs58 from "bs58";
|
||||
import { KnownToken, TokenAccount } from "@oyster/common";
|
||||
import { useConnection, useConnectionConfig, useAccountByMint, useMint, getTokenName, getTokenIcon, convert } from "@oyster/common";
|
||||
|
||||
export interface TokenContextState {
|
||||
mintAddress: string;
|
||||
account?: TokenAccount;
|
||||
mint?: MintInfo;
|
||||
amount: string;
|
||||
name: string;
|
||||
icon?: string;
|
||||
setAmount: (val: string) => void;
|
||||
setMint: (mintAddress: string) => void;
|
||||
convertAmount: () => number;
|
||||
sufficientBalance: () => boolean;
|
||||
}
|
||||
|
||||
export interface TokenPairContextState {
|
||||
A: TokenContextState;
|
||||
B: TokenContextState;
|
||||
lastTypedAccount: string;
|
||||
setLastTypedAccount: (mintAddress: string) => void;
|
||||
}
|
||||
|
||||
const TokenPairContext = React.createContext<TokenPairContextState | null>(
|
||||
null
|
||||
);
|
||||
|
||||
const convertAmount = (amount: string, mint?: MintInfo) => {
|
||||
return parseFloat(amount) * Math.pow(10, mint?.decimals || 0);
|
||||
};
|
||||
|
||||
export const useCurrencyLeg = (defaultMint?: string) => {
|
||||
const { tokenMap } = useConnectionConfig();
|
||||
const [amount, setAmount] = useState("");
|
||||
const [mintAddress, setMintAddress] = useState(defaultMint || "");
|
||||
const account = useAccountByMint(mintAddress);
|
||||
const mint = useMint(mintAddress);
|
||||
|
||||
return useMemo(
|
||||
() => ({
|
||||
mintAddress: mintAddress,
|
||||
account: account,
|
||||
mint: mint,
|
||||
amount: amount,
|
||||
name: getTokenName(tokenMap, mintAddress),
|
||||
icon: getTokenIcon(tokenMap, mintAddress),
|
||||
setAmount: setAmount,
|
||||
setMint: setMintAddress,
|
||||
convertAmount: () => convertAmount(amount, mint),
|
||||
sufficientBalance: () =>
|
||||
account !== undefined &&
|
||||
(convert(account, mint) >= parseFloat(amount))
|
||||
}),
|
||||
[
|
||||
mintAddress,
|
||||
account,
|
||||
mint,
|
||||
amount,
|
||||
tokenMap,
|
||||
setAmount,
|
||||
setMintAddress,
|
||||
]
|
||||
);
|
||||
};
|
||||
|
||||
export function CurrencyPairProvider({ children = null as any }) {
|
||||
const connection = useConnection();
|
||||
const { tokens } = useConnectionConfig();
|
||||
|
||||
const history = useHistory();
|
||||
const location = useLocation();
|
||||
const [lastTypedAccount, setLastTypedAccount] = useState("");
|
||||
|
||||
const base = useCurrencyLeg();
|
||||
const mintAddressA = base.mintAddress;
|
||||
const setMintAddressA = base.setMint;
|
||||
const amountA = base.amount;
|
||||
const setAmountA = base.setAmount;
|
||||
|
||||
const quote = useCurrencyLeg();
|
||||
const mintAddressB = quote.mintAddress;
|
||||
const setMintAddressB = quote.setMint;
|
||||
const amountB = quote.amount;
|
||||
const setAmountB = quote.setAmount;
|
||||
|
||||
useEffect(() => {
|
||||
const base =
|
||||
tokens.find((t) => t.mintAddress === mintAddressA)?.tokenSymbol ||
|
||||
mintAddressA;
|
||||
const quote =
|
||||
tokens.find((t) => t.mintAddress === mintAddressB)?.tokenSymbol ||
|
||||
mintAddressB;
|
||||
|
||||
document.title = `Swap | Serum (${base}/${quote})`;
|
||||
}, [mintAddressA, mintAddressB, tokens, location]);
|
||||
|
||||
// updates browser history on token changes
|
||||
useEffect(() => {
|
||||
// set history
|
||||
const base =
|
||||
tokens.find((t) => t.mintAddress === mintAddressA)?.tokenSymbol ||
|
||||
mintAddressA;
|
||||
const quote =
|
||||
tokens.find((t) => t.mintAddress === mintAddressB)?.tokenSymbol ||
|
||||
mintAddressB;
|
||||
|
||||
if (base && quote && location.pathname.indexOf("info") < 0) {
|
||||
history.push({
|
||||
search: `?pair=${base}-${quote}`,
|
||||
});
|
||||
} else {
|
||||
if (mintAddressA && mintAddressB) {
|
||||
history.push({
|
||||
search: ``,
|
||||
});
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}, [mintAddressA, mintAddressB, tokens, history, location.pathname]);
|
||||
|
||||
// Updates tokens on location change
|
||||
useEffect(() => {
|
||||
if (!location.search && mintAddressA && mintAddressB) {
|
||||
return;
|
||||
}
|
||||
|
||||
let { defaultBase, defaultQuote } = getDefaultTokens(
|
||||
tokens,
|
||||
location.search
|
||||
);
|
||||
if (!defaultBase || !defaultQuote) {
|
||||
return;
|
||||
}
|
||||
|
||||
setMintAddressA(
|
||||
tokens.find((t) => t.tokenSymbol === defaultBase)?.mintAddress ||
|
||||
(isValidAddress(defaultBase) ? defaultBase : "") ||
|
||||
""
|
||||
);
|
||||
setMintAddressB(
|
||||
tokens.find((t) => t.tokenSymbol === defaultQuote)?.mintAddress ||
|
||||
(isValidAddress(defaultQuote) ? defaultQuote : "") ||
|
||||
""
|
||||
);
|
||||
// mintAddressA and mintAddressB are not included here to prevent infinite loop
|
||||
// eslint-disable-next-line
|
||||
}, [location, location.search, setMintAddressA, setMintAddressB, tokens]);
|
||||
|
||||
const calculateDependent = useCallback(async () => {
|
||||
if (mintAddressA && mintAddressB) {
|
||||
let setDependent;
|
||||
let amount;
|
||||
let independent;
|
||||
if (lastTypedAccount === mintAddressA) {
|
||||
independent = mintAddressA;
|
||||
setDependent = setAmountB;
|
||||
amount = parseFloat(amountA);
|
||||
} else {
|
||||
independent = mintAddressB;
|
||||
setDependent = setAmountA;
|
||||
amount = parseFloat(amountB);
|
||||
}
|
||||
|
||||
// TODO: calculate
|
||||
const result: number | string = 0;
|
||||
if (typeof result === "string") {
|
||||
setDependent(result);
|
||||
} else if (result !== undefined && Number.isFinite(result)) {
|
||||
setDependent(result.toFixed(6));
|
||||
} else {
|
||||
setDependent("");
|
||||
}
|
||||
}
|
||||
}, [
|
||||
mintAddressA,
|
||||
mintAddressB,
|
||||
setAmountA,
|
||||
setAmountB,
|
||||
amountA,
|
||||
amountB,
|
||||
connection,
|
||||
lastTypedAccount,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
calculateDependent();
|
||||
}, [amountB, amountA, lastTypedAccount, calculateDependent]);
|
||||
|
||||
return (
|
||||
<TokenPairContext.Provider
|
||||
value={{
|
||||
A: base,
|
||||
B: quote,
|
||||
lastTypedAccount,
|
||||
setLastTypedAccount,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</TokenPairContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export const useCurrencyPairState = () => {
|
||||
const context = useContext(TokenPairContext);
|
||||
|
||||
return context as TokenPairContextState;
|
||||
};
|
||||
|
||||
const isValidAddress = (address: string) => {
|
||||
try {
|
||||
const decoded = bs58.decode(address);
|
||||
return decoded.length === 32;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
function getDefaultTokens(tokens: KnownToken[], search: string) {
|
||||
let defaultBase = "SOL";
|
||||
let defaultQuote = "USDC";
|
||||
|
||||
const nameToToken = tokens.reduce((map, item) => {
|
||||
map.set(item.tokenSymbol, item);
|
||||
return map;
|
||||
}, new Map<string, any>());
|
||||
|
||||
if (search) {
|
||||
const urlParams = new URLSearchParams(search);
|
||||
const pair = urlParams.get("pair");
|
||||
if (pair) {
|
||||
let items = pair.split("-");
|
||||
|
||||
if (items.length > 1) {
|
||||
if (nameToToken.has(items[0]) || isValidAddress(items[0])) {
|
||||
defaultBase = items[0];
|
||||
}
|
||||
|
||||
if (nameToToken.has(items[1]) || isValidAddress(items[1])) {
|
||||
defaultQuote = items[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
defaultBase,
|
||||
defaultQuote,
|
||||
};
|
||||
}
|
|
@ -4,6 +4,7 @@ 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 { Transfer } from '../../components/Transfer';
|
||||
const { useConnection } = contexts.Connection;
|
||||
const { useWallet } = contexts.Wallet;
|
||||
const { notify } = utils;
|
||||
|
@ -18,7 +19,7 @@ export const TransferView = () => {
|
|||
key: "eth",
|
||||
tab: <div style={tabStyle}>Transfer</div>,
|
||||
render: () => {
|
||||
return <div>Bring assets to Solana</div>;
|
||||
return <Transfer />;
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -32,7 +33,7 @@ export const TransferView = () => {
|
|||
|
||||
const location = useLocation();
|
||||
const history = useHistory();
|
||||
const activeTab = location.pathname.indexOf("eth") < 0 ? "sol" : "eth";
|
||||
const activeTab = location.pathname.indexOf("sol") >= 0 ? "sol" : "eth";
|
||||
|
||||
const handleTabChange = (key: any) => {
|
||||
if (activeTab !== key) {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"main": "dist/lib/index.js",
|
||||
"types": "dist/lib/index.d.ts",
|
||||
"exports": {
|
||||
".": "./dist/lib/index.js"
|
||||
".": "./dist/lib/"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"publishConfig": {
|
||||
|
|
|
@ -2,3 +2,7 @@ export * as Accounts from './accounts';
|
|||
export * as Connection from './connection';
|
||||
export * as Wallet from './wallet';
|
||||
export { ParsedAccount, ParsedAccountBase } from './accounts';
|
||||
|
||||
export * from './accounts';
|
||||
export * from './wallet';
|
||||
export * from './connection';
|
||||
|
|
|
@ -4,9 +4,12 @@ export * from './components'; // Allow direct exports too
|
|||
export * as config from './config';
|
||||
export * as constants from './constants';
|
||||
export * as hooks from './hooks';
|
||||
export * from './hooks';
|
||||
export * as contexts from './contexts';
|
||||
export * from './contexts';
|
||||
export * as models from './models';
|
||||
export * as utils from './utils';
|
||||
export * from './utils';
|
||||
export * as walletAdapters from './wallet-adapters';
|
||||
|
||||
export { TokenAccount } from './models';
|
||||
|
|
Loading…
Reference in New Issue