Trade route fairs

This commit is contained in:
armaniferrante 2021-05-14 14:29:49 -07:00
parent dc5abad2c0
commit 3ad62023c8
No known key found for this signature in database
GPG Key ID: 58BEF301E91F7828
8 changed files with 248 additions and 189 deletions

View File

@ -6,9 +6,10 @@
"dependencies": { "dependencies": {
"@material-ui/core": "^4.11.4", "@material-ui/core": "^4.11.4",
"@material-ui/icons": "^4.11.2", "@material-ui/icons": "^4.11.2",
"@project-serum/anchor": "^0.5.1-beta.2",
"@project-serum/serum": "^0.13.34", "@project-serum/serum": "^0.13.34",
"@project-serum/sol-wallet-adapter": "^0.2.0", "@project-serum/sol-wallet-adapter": "^0.2.0",
"@project-serum/swap": "^0.1.0-alpha.2", "@project-serum/swap": "^0.1.0-alpha.3",
"@solana/spl-token": "^0.1.4", "@solana/spl-token": "^0.1.4",
"@solana/spl-token-registry": "^0.2.86", "@solana/spl-token-registry": "^0.2.86",
"@solana/web3.js": "^1.10.1", "@solana/web3.js": "^1.10.1",

View File

@ -1,11 +1,22 @@
import { makeStyles, Typography, Link, Popover } from "@material-ui/core"; import {
makeStyles,
Typography,
Link,
Popover,
IconButton,
} from "@material-ui/core";
import { Info } from "@material-ui/icons"; import { Info } from "@material-ui/icons";
import PopupState, { bindTrigger, bindPopover } from "material-ui-popup-state"; import PopupState, { bindTrigger, bindPopover } from "material-ui-popup-state";
import { useFair } from "./context/Dex"; import { PublicKey } from "@solana/web3.js";
import { useTokenList } from "./context/TokenList"; import { useTokenList } from "./context/TokenList";
import { useSwapContext } from "./context/Swap"; import { useSwapContext } from "./context/Swap";
import { useMint } from "./context/Mint"; import { useMint } from "./context/Mint";
import { useMarketRoute } from "./context/Dex"; import {
useDexContext,
useMarketName,
useFair,
useFairRoute,
} from "./context/Dex";
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme) => ({
infoLabel: { infoLabel: {
@ -23,6 +34,9 @@ const useStyles = makeStyles((theme) => ({
flexDirection: "column", flexDirection: "column",
color: theme.palette.text.secondary, color: theme.palette.text.secondary,
}, },
infoButton: {
padding: 0,
},
})); }));
export function InfoLabel() { export function InfoLabel() {
@ -30,7 +44,7 @@ export function InfoLabel() {
const { fromMint, toMint } = useSwapContext(); const { fromMint, toMint } = useSwapContext();
const fromMintInfo = useMint(fromMint); const fromMintInfo = useMint(fromMint);
const fair = useFair(fromMint, toMint); const fair = useFairRoute(fromMint, toMint);
const tokenList = useTokenList(); const tokenList = useTokenList();
let fromTokenInfo = tokenList.filter( let fromTokenInfo = tokenList.filter(
@ -49,33 +63,26 @@ export function InfoLabel() {
)} ${fromTokenInfo.symbol}` )} ${fromTokenInfo.symbol}`
: `-`} : `-`}
</div> </div>
<InfoPopover /> <InfoButton />
</div> </div>
</div> </div>
); );
} }
function InfoPopover() { function InfoButton() {
const { fromMint, toMint } = useSwapContext(); const styles = useStyles();
const route = useMarketRoute(fromMint, toMint);
const tokenList = useTokenList();
const fromMintTicker = tokenList
.filter((t) => t.address === fromMint.toString())
.map((t) => t.symbol)[0];
const toMintTicker = tokenList
.filter((t) => t.address === toMint.toString())
.map((t) => t.symbol)[0];
const addresses = [
{ ticker: fromMintTicker, mint: fromMint },
{ ticker: toMintTicker, mint: toMint },
];
return ( return (
<PopupState variant="popover"> <PopupState variant="popover">
{ {
//@ts-ignore //@ts-ignore
(popupState) => ( (popupState) => (
<div style={{ display: "flex" }}> <div style={{ display: "flex" }}>
<Info {...bindTrigger(popupState)} /> <IconButton
{...bindTrigger(popupState)}
className={styles.infoButton}
>
<Info />
</IconButton>
<Popover <Popover
{...bindPopover(popupState)} {...bindPopover(popupState)}
anchorOrigin={{ anchorOrigin={{
@ -89,68 +96,7 @@ function InfoPopover() {
PaperProps={{ style: { borderRadius: "10px" } }} PaperProps={{ style: { borderRadius: "10px" } }}
disableRestoreFocus disableRestoreFocus
> >
<div style={{ padding: "15px", width: "250px" }}> <InfoDetails />
<div>
<Typography
color="textSecondary"
style={{ fontWeight: "bold", marginBottom: "5px" }}
>
Trade Route
</Typography>
{route.map((market) => {
return (
<div
style={{
display: "flex",
justifyContent: "space-between",
marginTop: "5px",
}}
>
<Link
href={`https://dex.projectserum.com/#/market/${market.address.toString()}`}
target="_blank"
rel="noopener"
>
{market.name}
</Link>
<code style={{ marginLeft: "10px" }}>
{market.fair}
</code>
</div>
);
})}
</div>
<div style={{ marginTop: "15px" }}>
<Typography
color="textSecondary"
style={{ fontWeight: "bold", marginBottom: "5px" }}
>
Tokens
</Typography>
{addresses.map((address) => {
return (
<div
style={{
marginTop: "5px",
display: "flex",
justifyContent: "space-between",
}}
>
<Link
href={`https://explorer.solana.com/address/${address.mint.toString()}`}
target="_blank"
rel="noopener"
>
{address.ticker}
</Link>
<code style={{ width: "128px", overflow: "hidden" }}>
{address.mint.toString()}
</code>
</div>
);
})}
</div>
</div>
</Popover> </Popover>
</div> </div>
) )
@ -158,3 +104,88 @@ function InfoPopover() {
</PopupState> </PopupState>
); );
} }
function InfoDetails() {
const { fromMint, toMint } = useSwapContext();
const { swapClient } = useDexContext();
const tokenList = useTokenList();
const fromMintTicker = tokenList
.filter((t) => t.address === fromMint.toString())
.map((t) => t.symbol)[0];
const toMintTicker = tokenList
.filter((t) => t.address === toMint.toString())
.map((t) => t.symbol)[0];
const addresses = [
{ ticker: fromMintTicker, mint: fromMint },
{ ticker: toMintTicker, mint: toMint },
];
return (
<div style={{ padding: "15px", width: "250px" }}>
<div>
<Typography
color="textSecondary"
style={{ fontWeight: "bold", marginBottom: "5px" }}
>
Trade Route
</Typography>
{swapClient.route(fromMint, toMint).map((market: PublicKey) => {
return <MarketRoute key={market.toString()} market={market} />;
})}
</div>
<div style={{ marginTop: "15px" }}>
<Typography
color="textSecondary"
style={{ fontWeight: "bold", marginBottom: "5px" }}
>
Tokens
</Typography>
{addresses.map((address) => {
return (
<div
key={address.mint.toString()}
style={{
marginTop: "5px",
display: "flex",
justifyContent: "space-between",
}}
>
<Link
href={`https://explorer.solana.com/address/${address.mint.toString()}`}
target="_blank"
rel="noopener"
>
{address.ticker}
</Link>
<code style={{ width: "128px", overflow: "hidden" }}>
{address.mint.toString()}
</code>
</div>
);
})}
</div>
</div>
);
}
function MarketRoute({ market }: { market: PublicKey }) {
const marketName = useMarketName(market);
const fair = useFair(market);
return (
<div
style={{
display: "flex",
justifyContent: "space-between",
marginTop: "5px",
}}
>
<Link
href={`https://dex.projectserum.com/#/market/${market.toString()}`}
target="_blank"
rel="noopener"
>
{marketName}
</Link>
<code style={{ marginLeft: "10px" }}>{fair ? fair.toFixed(6) : "-"}</code>
</div>
);
}

View File

@ -43,8 +43,6 @@ const useStyles = makeStyles(() => ({
export function SettingsButton() { export function SettingsButton() {
const styles = useStyles(); const styles = useStyles();
const { slippage, setSlippage } = useSwapContext();
const [showSettingsDialog, setShowSettingsDialog] = useState(false);
return ( return (
<PopupState variant="popover"> <PopupState variant="popover">
@ -70,47 +68,7 @@ export function SettingsButton() {
}} }}
PaperProps={{ style: { borderRadius: "10px" } }} PaperProps={{ style: { borderRadius: "10px" } }}
> >
<div style={{ padding: "15px", width: "305px" }}> <SettingsDetails />
<Typography
color="textSecondary"
style={{ fontWeight: "bold" }}
>
Settings
</Typography>
<div style={{ marginTop: "10px" }}>
<Typography>Slippage tolerance</Typography>
<TextField
type="number"
placeholder="Error tolerance percentage"
value={slippage}
onChange={(e) => setSlippage(parseFloat(e.target.value))}
style={{
display: "flex",
justifyContent: "center",
flexDirection: "column",
}}
InputProps={{
endAdornment: (
<InputAdornment position="end">%</InputAdornment>
),
}}
/>
<Button
style={{
width: "100%",
marginTop: "10px",
background: "#e0e0e0",
}}
onClick={() => setShowSettingsDialog(true)}
>
Manage Dex Accounts
</Button>
</div>
<SettingsDialog
open={showSettingsDialog}
onClose={() => setShowSettingsDialog(false)}
/>
</div>
</Popover> </Popover>
</div> </div>
) )
@ -119,6 +77,49 @@ export function SettingsButton() {
); );
} }
function SettingsDetails() {
const { slippage, setSlippage } = useSwapContext();
const [showSettingsDialog, setShowSettingsDialog] = useState(false);
return (
<div style={{ padding: "15px", width: "305px" }}>
<Typography color="textSecondary" style={{ fontWeight: "bold" }}>
Settings
</Typography>
<div style={{ marginTop: "10px" }}>
<Typography>Slippage tolerance</Typography>
<TextField
type="number"
placeholder="Error tolerance percentage"
value={slippage}
onChange={(e) => setSlippage(parseFloat(e.target.value))}
style={{
display: "flex",
justifyContent: "center",
flexDirection: "column",
}}
InputProps={{
endAdornment: <InputAdornment position="end">%</InputAdornment>,
}}
/>
<Button
style={{
width: "100%",
marginTop: "10px",
background: "#e0e0e0",
}}
onClick={() => setShowSettingsDialog(true)}
>
Manage Dex Accounts
</Button>
</div>
<SettingsDialog
open={showSettingsDialog}
onClose={() => setShowSettingsDialog(false)}
/>
</div>
);
}
export function SettingsDialog({ export function SettingsDialog({
open, open,
onClose, onClose,

View File

@ -63,8 +63,8 @@ export default function Swap({
<TokenListContextProvider tokenList={tokenList}> <TokenListContextProvider tokenList={tokenList}>
<MintContextProvider provider={provider}> <MintContextProvider provider={provider}>
<TokenContextProvider provider={provider}> <TokenContextProvider provider={provider}>
<DexContextProvider provider={provider}> <DexContextProvider swapClient={swapClient}>
<SwapContextProvider swapClient={swapClient}> <SwapContextProvider>
<SwapCard style={style} /> <SwapCard style={style} />
</SwapContextProvider> </SwapContextProvider>
</DexContextProvider> </DexContextProvider>

View File

@ -11,11 +11,11 @@ import {
Typography, Typography,
} from "@material-ui/core"; } from "@material-ui/core";
import { TokenIcon } from "./Swap"; import { TokenIcon } from "./Swap";
import { useSwapContext } from "./context/Swap"; import { useDexContext } from "./context/Dex";
import { useTokenList } from "./context/TokenList"; import { useTokenList } from "./context/TokenList";
import { USDC_MINT, USDT_MINT } from "../utils/pubkeys"; import { USDC_MINT, USDT_MINT } from "../utils/pubkeys";
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles(() => ({
dialogContent: { dialogContent: {
paddingTop: 0, paddingTop: 0,
}, },
@ -38,7 +38,7 @@ export default function TokenDialog({
}) { }) {
const [tokenFilter, setTokenFilter] = useState(""); const [tokenFilter, setTokenFilter] = useState("");
const styles = useStyles(); const styles = useStyles();
const { swapClient } = useSwapContext(); const { swapClient } = useDexContext();
return ( return (
<Dialog <Dialog
open={open} open={open}

View File

@ -1,7 +1,7 @@
import React, { useContext, useState, useEffect } from "react"; import React, { useContext, useState, useEffect, useMemo } from "react";
import { useAsync } from "react-async-hook"; import { useAsync } from "react-async-hook";
import * as anchor from "@project-serum/anchor"; import * as anchor from "@project-serum/anchor";
import { Provider } from "@project-serum/anchor"; import { Swap as SwapClient } from "@project-serum/swap";
import { import {
Market, Market,
OpenOrders, OpenOrders,
@ -9,6 +9,7 @@ import {
} from "@project-serum/serum"; } from "@project-serum/serum";
import { PublicKey } from "@solana/web3.js"; import { PublicKey } from "@solana/web3.js";
import { DEX_PID } from "../../utils/pubkeys"; import { DEX_PID } from "../../utils/pubkeys";
import { useTokenList } from "./TokenList";
type DexContext = { type DexContext = {
// Maps market address to open orders accounts. // Maps market address to open orders accounts.
@ -17,7 +18,7 @@ type DexContext = {
setMarketCache: (c: Map<string, Market>) => void; setMarketCache: (c: Map<string, Market>) => void;
orderbookCache: Map<string, Orderbook>; orderbookCache: Map<string, Orderbook>;
setOrderbookCache: (c: Map<string, Orderbook>) => void; setOrderbookCache: (c: Map<string, Orderbook>) => void;
provider: Provider; swapClient: SwapClient;
}; };
const _DexContext = React.createContext<DexContext | null>(null); const _DexContext = React.createContext<DexContext | null>(null);
@ -31,7 +32,7 @@ export function DexContextProvider(props: any) {
const [orderbookCache, setOrderbookCache] = useState<Map<string, Orderbook>>( const [orderbookCache, setOrderbookCache] = useState<Map<string, Orderbook>>(
new Map() new Map()
); );
const provider = props.provider; const swapClient = props.swapClient;
// Two operations: // Two operations:
// //
@ -40,8 +41,8 @@ export function DexContextProvider(props: any) {
// //
useEffect(() => { useEffect(() => {
OpenOrders.findForOwner( OpenOrders.findForOwner(
provider.connection, swapClient.program.provider.connection,
provider.wallet.publicKey, swapClient.program.provider.wallet.publicKey,
DEX_PID DEX_PID
).then(async (openOrders) => { ).then(async (openOrders) => {
const newOoAccounts = new Map(); const newOoAccounts = new Map();
@ -62,7 +63,7 @@ export function DexContextProvider(props: any) {
} }
const marketAccounts = ( const marketAccounts = (
await anchor.utils.getMultipleAccounts( await anchor.utils.getMultipleAccounts(
provider.connection, swapClient.program.provider.connection,
// @ts-ignore // @ts-ignore
[...markets].map((m) => new PublicKey(m)) [...markets].map((m) => new PublicKey(m))
) )
@ -73,7 +74,7 @@ export function DexContextProvider(props: any) {
Market.getLayout(DEX_PID).decode(programAccount?.account.data), Market.getLayout(DEX_PID).decode(programAccount?.account.data),
-1, // Not used so don't bother fetching. -1, // Not used so don't bother fetching.
-1, // Not used so don't bother fetching. -1, // Not used so don't bother fetching.
provider.opts, swapClient.program.provider.opts,
DEX_PID DEX_PID
), ),
}; };
@ -87,7 +88,11 @@ export function DexContextProvider(props: any) {
}); });
setOoAccounts(newOoAccounts); setOoAccounts(newOoAccounts);
}); });
}, [provider.connection, provider.wallet.publicKey, provider.opts]); }, [
swapClient.program.provider.connection,
swapClient.program.provider.wallet.publicKey,
swapClient.program.provider.opts,
]);
return ( return (
<_DexContext.Provider <_DexContext.Provider
value={{ value={{
@ -96,7 +101,7 @@ export function DexContextProvider(props: any) {
setMarketCache, setMarketCache,
orderbookCache, orderbookCache,
setOrderbookCache, setOrderbookCache,
provider, swapClient,
}} }}
> >
{props.children} {props.children}
@ -104,7 +109,7 @@ export function DexContextProvider(props: any) {
); );
} }
function useDexContext(): DexContext { export function useDexContext(): DexContext {
const ctx = useContext(_DexContext); const ctx = useContext(_DexContext);
if (ctx === null) { if (ctx === null) {
throw new Error("Context not available"); throw new Error("Context not available");
@ -118,15 +123,18 @@ export function useOpenOrders(): Map<string, Array<OpenOrders>> {
} }
// Lazy load a given market. // Lazy load a given market.
export function useMarket(market: PublicKey): Market | undefined { export function useMarket(market?: PublicKey): Market | undefined {
const ctx = useDexContext(); const ctx = useDexContext();
const asyncMarket = useAsync(async () => { const asyncMarket = useAsync(async () => {
if (!market) {
return undefined;
}
if (ctx.marketCache.get(market.toString())) { if (ctx.marketCache.get(market.toString())) {
return ctx.marketCache.get(market.toString()); return ctx.marketCache.get(market.toString());
} }
const marketClient = await Market.load( const marketClient = await Market.load(
ctx.provider.connection, ctx.swapClient.program.provider.connection,
market, market,
undefined, undefined,
DEX_PID DEX_PID
@ -137,7 +145,7 @@ export function useMarket(market: PublicKey): Market | undefined {
ctx.setMarketCache(cache); ctx.setMarketCache(cache);
return marketClient; return marketClient;
}, [ctx.provider.connection, market]); }, [ctx.swapClient.program.provider.connection, market]);
if (asyncMarket.result) { if (asyncMarket.result) {
return asyncMarket.result; return asyncMarket.result;
@ -147,21 +155,21 @@ export function useMarket(market: PublicKey): Market | undefined {
} }
// Lazy load the orderbook for a given market. // Lazy load the orderbook for a given market.
export function useOrderbook(market: PublicKey): Orderbook | undefined { export function useOrderbook(market?: PublicKey): Orderbook | undefined {
const ctx = useDexContext(); const { swapClient, orderbookCache, setOrderbookCache } = useDexContext();
const marketClient = useMarket(market); const marketClient = useMarket(market);
const asyncOrderbook = useAsync(async () => { const asyncOrderbook = useAsync(async () => {
if (!marketClient) { if (!market || !marketClient) {
return undefined; return undefined;
} }
if (ctx.orderbookCache.get(market.toString())) { if (orderbookCache.get(market.toString())) {
return ctx.orderbookCache.get(market.toString()); return orderbookCache.get(market.toString());
} }
const [bids, asks] = await Promise.all([ const [bids, asks] = await Promise.all([
marketClient.loadBids(ctx.provider.connection), marketClient.loadBids(swapClient.program.provider.connection),
marketClient.loadAsks(ctx.provider.connection), marketClient.loadAsks(swapClient.program.provider.connection),
]); ]);
const orderbook = { const orderbook = {
@ -169,12 +177,12 @@ export function useOrderbook(market: PublicKey): Orderbook | undefined {
asks, asks,
}; };
const cache = new Map(ctx.orderbookCache); const cache = new Map(orderbookCache);
cache.set(market.toString(), orderbook); cache.set(market.toString(), orderbook);
ctx.setOrderbookCache(cache); setOrderbookCache(cache);
return orderbook; return orderbook;
}, [ctx.provider.connection, market, marketClient]); }, [swapClient.program.provider.connection, market, marketClient]);
if (asyncOrderbook.result) { if (asyncOrderbook.result) {
return asyncOrderbook.result; return asyncOrderbook.result;
@ -183,33 +191,53 @@ export function useOrderbook(market: PublicKey): Orderbook | undefined {
return undefined; return undefined;
} }
export function useMarketRoute( export function useMarketName(market: PublicKey): string {
fromMint: PublicKey, const tokenList = useTokenList();
toMint: PublicKey const marketClient = useMarket(market);
): Array<{ address: PublicKey; name: string; fair: number }> { const baseTicker = tokenList
// todo .filter((t) => t.address === marketClient?.baseMintAddress.toString())
return [ .map((t) => t.symbol)[0];
{ const quoteTicker = tokenList
address: new PublicKey("ByRys5tuUWDgL73G8JBAEfkdFf8JWBzPBDHsBVQ5vbQA"), .filter((t) => t.address === marketClient?.quoteMintAddress.toString())
name: "SRM / USDC", .map((t) => t.symbol)[0];
fair: 0.5, const name = `${baseTicker} / ${quoteTicker}`;
}, return name;
{ }
address: new PublicKey("J7cPYBrXVy8Qeki2crZkZavcojf2sMRyQU7nx438Mf8t"),
name: "MATH / USDC", // Fair price for a given market, as defined by the mid.
fair: 1.23, export function useFair(market?: PublicKey): number | undefined {
}, const orderbook = useOrderbook(market);
]; if (orderbook === undefined) {
return undefined;
}
const bestBid = orderbook.bids.items(true).next().value;
const bestOffer = orderbook.asks.items(false).next().value;
const mid = (bestBid.price + bestOffer.price) / 2.0;
return mid;
} }
// Fair price for a theoretical toMint/fromMint market. I.e., the number // Fair price for a theoretical toMint/fromMint market. I.e., the number
// of `fromMint` tokens to purchase a single `toMint` token. // of `fromMint` tokens to purchase a single `toMint` token. Aggregates
export function useFair( // across a trade route, if needed.
export function useFairRoute(
fromMint: PublicKey, fromMint: PublicKey,
toMint: PublicKey toMint: PublicKey
): number | undefined { ): number | undefined {
// todo const { swapClient } = useDexContext();
return 0.5; const route = useMemo(
() => swapClient.route(fromMint, toMint),
[swapClient, fromMint, toMint]
);
const fromFair = useFair(route[0]);
const toFair = useFair(route[1]);
if (route.length === 1 && fromFair !== undefined) {
return 1.0 / fromFair;
}
if (fromFair === undefined || toFair === undefined) {
return undefined;
}
return toFair / fromFair;
} }
type Orderbook = { type Orderbook = {

View File

@ -1,12 +1,12 @@
import React, { useContext, useState } from "react"; import React, { useContext, useState } from "react";
import { Swap as SwapClient } from "@project-serum/swap";
import { PublicKey } from "@solana/web3.js"; import { PublicKey } from "@solana/web3.js";
import { MintInfo } from "@solana/spl-token"; import { MintInfo } from "@solana/spl-token";
import { SRM_MINT, USDC_MINT } from "../../utils/pubkeys"; import { SRM_MINT, USDC_MINT } from "../../utils/pubkeys";
import { useFair } from "./Dex"; import { useFairRoute } from "./Dex";
const DEFAULT_SLIPPAGE_PERCENT = 0.5;
export type SwapContext = { export type SwapContext = {
swapClient: SwapClient;
fromMint: PublicKey; fromMint: PublicKey;
setFromMint: (m: PublicKey) => void; setFromMint: (m: PublicKey) => void;
toMint: PublicKey; toMint: PublicKey;
@ -24,14 +24,13 @@ export type SwapContext = {
const _SwapContext = React.createContext<null | SwapContext>(null); const _SwapContext = React.createContext<null | SwapContext>(null);
export function SwapContextProvider(props: any) { export function SwapContextProvider(props: any) {
const swapClient = props.swapClient;
const [fromMint, setFromMint] = useState(SRM_MINT); const [fromMint, setFromMint] = useState(SRM_MINT);
const [toMint, setToMint] = useState(USDC_MINT); const [toMint, setToMint] = useState(USDC_MINT);
const [fromAmount, _setFromAmount] = useState(0); const [fromAmount, _setFromAmount] = useState(0);
const [toAmount, _setToAmount] = useState(0); const [toAmount, _setToAmount] = useState(0);
// Percent units. // Percent units.
const [slippage, setSlippage] = useState(0.5); const [slippage, setSlippage] = useState(DEFAULT_SLIPPAGE_PERCENT);
const fair = useFair(fromMint, toMint); const fair = useFairRoute(fromMint, toMint);
const swapToFromMints = () => { const swapToFromMints = () => {
const oldFrom = fromMint; const oldFrom = fromMint;
@ -63,7 +62,6 @@ export function SwapContextProvider(props: any) {
return ( return (
<_SwapContext.Provider <_SwapContext.Provider
value={{ value={{
swapClient,
fromMint, fromMint,
setFromMint, setFromMint,
toMint, toMint,

View File

@ -1577,15 +1577,15 @@
bs58 "^4.0.1" bs58 "^4.0.1"
eventemitter3 "^4.0.4" eventemitter3 "^4.0.4"
"@project-serum/swap@^0.1.0-alpha.2": "@project-serum/swap@^0.1.0-alpha.3":
version "0.1.0-alpha.2" version "0.1.0-alpha.3"
resolved "https://registry.yarnpkg.com/@project-serum/swap/-/swap-0.1.0-alpha.2.tgz#dc4bb2a182163e47deae8f67f433837d6a09a498" resolved "https://registry.yarnpkg.com/@project-serum/swap/-/swap-0.1.0-alpha.3.tgz#f400b646b2c40f41d34a4a273054be1051576296"
integrity sha512-p9kaae3WyOvL2Js1fskP59pzFm/tBNl8+mrD+obqvyWukUj8lnGIdn9083iyGdSD8GWMrP3dmYQqngfHOiIbVg== integrity sha512-pjk+uo2llyOhJnf7NCXkunm8dPlDOUbDWx97Xq/R7G/qDckBgbXuJxTE+5w0kxr6f2FwecglHDpfnfwXFJdFKQ==
dependencies: dependencies:
"@project-serum/anchor" "^0.5.1-beta.2" "@project-serum/anchor" "^0.5.1-beta.2"
"@project-serum/serum" "^0.13.34" "@project-serum/serum" "^0.13.34"
"@solana/spl-token" "^0.1.3" "@solana/spl-token" "^0.1.3"
"@solana/spl-token-registry" "^0.2.68" "@solana/spl-token-registry" "^0.2.86"
"@solana/web3.js" "^1.2.0" "@solana/web3.js" "^1.2.0"
base64-js "^1.5.1" base64-js "^1.5.1"
bn.js "^5.1.2" bn.js "^5.1.2"
@ -1632,7 +1632,7 @@
dependencies: dependencies:
"@sinonjs/commons" "^1.7.0" "@sinonjs/commons" "^1.7.0"
"@solana/spl-token-registry@^0.2.68", "@solana/spl-token-registry@^0.2.86": "@solana/spl-token-registry@^0.2.86":
version "0.2.86" version "0.2.86"
resolved "https://registry.yarnpkg.com/@solana/spl-token-registry/-/spl-token-registry-0.2.86.tgz#6ca8172d0f0c38ffc3dae174e3ba72674fd2ad66" resolved "https://registry.yarnpkg.com/@solana/spl-token-registry/-/spl-token-registry-0.2.86.tgz#6ca8172d0f0c38ffc3dae174e3ba72674fd2ad66"
integrity sha512-/ySaKRMRmCSHxiWonlFn+07Mj3wze6zpB6RvY169GQAiO+6RGDZPUP5kbdSHP9NXAInG9LyKjd6rEU5ymFfG3A== integrity sha512-/ySaKRMRmCSHxiWonlFn+07Mj3wze6zpB6RvY169GQAiO+6RGDZPUP5kbdSHP9NXAInG9LyKjd6rEU5ymFfG3A==