Add SOL markets
This commit is contained in:
parent
ddd3116096
commit
ea6a32983e
|
@ -6,7 +6,7 @@
|
|||
"dependencies": {
|
||||
"@ant-design/icons": "^4.2.1",
|
||||
"@craco/craco": "^5.6.4",
|
||||
"@project-serum/serum": "^0.9.2",
|
||||
"@project-serum/serum": "^0.11.1",
|
||||
"@project-serum/sol-wallet-adapter": "^0.1.0",
|
||||
"@solana/web3.js": "^0.71.9",
|
||||
"@testing-library/jest-dom": "^4.2.4",
|
||||
|
|
|
@ -45,8 +45,8 @@ const sliderMarks = {
|
|||
export default function TradeForm({ style, setChangeOrderRef }) {
|
||||
const [side, setSide] = useState('buy');
|
||||
const { baseCurrency, quoteCurrency, market } = useMarket();
|
||||
const [baseCurrencyBalances] = useBaseCurrencyBalances();
|
||||
const [quoteCurrencyBalances] = useQuoteCurrencyBalances();
|
||||
const baseCurrencyBalances = useBaseCurrencyBalances();
|
||||
const quoteCurrencyBalances = useQuoteCurrencyBalances();
|
||||
const baseCurrencyAccount = useSelectedBaseCurrencyAccount();
|
||||
const quoteCurrencyAccount = useSelectedQuoteCurrencyAccount();
|
||||
const openOrdersAccount = useSelectedOpenOrdersAccount(true);
|
||||
|
@ -130,7 +130,7 @@ export default function TradeForm({ style, setChangeOrderRef }) {
|
|||
|
||||
setSubmitting(true);
|
||||
try {
|
||||
!(await placeOrder({
|
||||
await placeOrder({
|
||||
side,
|
||||
price: parsedPrice,
|
||||
size: parsedSize,
|
||||
|
@ -138,14 +138,13 @@ export default function TradeForm({ style, setChangeOrderRef }) {
|
|||
market,
|
||||
connection: sendConnection,
|
||||
wallet,
|
||||
baseCurrencyAccount: baseCurrencyAccount?.pubkey?.toBase58(),
|
||||
quoteCurrencyAccount: quoteCurrencyAccount?.pubkey?.toBase58(),
|
||||
openOrdersAccount: openOrdersAccount?.pubkey?.toBase58(),
|
||||
onBeforeSendCallBack: () => setSubmitting(true),
|
||||
onConfirmCallBack: () => setSubmitting(false),
|
||||
})) && setSubmitting(false);
|
||||
baseCurrencyAccount: baseCurrencyAccount?.pubkey,
|
||||
quoteCurrencyAccount: quoteCurrencyAccount?.pubkey,
|
||||
});
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
notify({ message: 'Error placing order: ' + e.message, type: 'error' });
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,14 +2,9 @@ import { HashRouter, Route } from 'react-router-dom';
|
|||
import TradePage from './pages/TradePage';
|
||||
import OpenOrdersPage from './pages/OpenOrdersPage';
|
||||
import React from 'react';
|
||||
import { Layout } from 'antd';
|
||||
import TopBar from './components/TopBar';
|
||||
import { CustomFooter } from './components/Footer';
|
||||
import BalancesPage from './pages/BalancesPage';
|
||||
import BasicLayout from './components/BasicLayout';
|
||||
|
||||
const { Header, Content } = Layout;
|
||||
|
||||
export function Routes() {
|
||||
return (
|
||||
<HashRouter basename={'/'}>
|
||||
|
|
|
@ -80,7 +80,7 @@ export function useAccountInfo(publicKey) {
|
|||
let id = publicKey?.toBase58();
|
||||
useEffect(() => {
|
||||
if (!publicKey) {
|
||||
return () => {};
|
||||
return;
|
||||
}
|
||||
if (accountListenerCount.has(cacheKey)) {
|
||||
let currentItem = accountListenerCount.get(cacheKey);
|
||||
|
|
|
@ -3,15 +3,17 @@ import {
|
|||
Orderbook,
|
||||
decodeEventQueue,
|
||||
DEX_PROGRAM_ID,
|
||||
TokenInstructions,
|
||||
} from '@project-serum/serum';
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import { PublicKey } from '@solana/web3.js';
|
||||
import { useLocalStorageState } from './utils';
|
||||
import { useAsyncData } from './fetch-loop';
|
||||
import { useAccountData, useConnection } from './connection';
|
||||
import { useAccountData, useAccountInfo, useConnection } from './connection';
|
||||
import { useWallet } from './wallet';
|
||||
import tuple from 'immutable-tuple';
|
||||
import { notify } from './notifications';
|
||||
import { BN } from 'bn.js';
|
||||
|
||||
const DEFAULT_MARKET_NAME = 'SRM/USDT';
|
||||
|
||||
|
@ -26,17 +28,10 @@ export const COIN_MINTS = {
|
|||
BXXkv6z8ykpG1yuvUDPgh732wzVHB69RnB9YgSYh3itW: 'USDC',
|
||||
MSRMcoVyrFxnSgo5uXwone5SKcGhT1KEJMFEkMEWf9L: 'MSRM',
|
||||
SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt: 'SRM',
|
||||
[TokenInstructions.WRAPPED_SOL_MINT]: 'SOL',
|
||||
};
|
||||
|
||||
export const MARKET_INFO_BY_NAME = {
|
||||
'MSRM/USDT': {
|
||||
address: 'H4snTKK9adiU15gP22ErfZYtro3aqR9BTMXiH3AwiUTQ',
|
||||
name: 'MSRM/USDT',
|
||||
},
|
||||
'MSRM/USDC': {
|
||||
address: '7kgkDyW7dmyMeP8KFXzbcUZz1R2WHsovDZ7n3ihZuNDS',
|
||||
name: 'MSRM/USDC',
|
||||
},
|
||||
'BTC/USDT': {
|
||||
address: '8AcVjMG2LTbpkjNoyq8RwysokqZunkjy3d5JDzxC6BJa',
|
||||
name: 'BTC/USDT',
|
||||
|
@ -53,6 +48,16 @@ export const MARKET_INFO_BY_NAME = {
|
|||
address: 'ASKiV944nKg1W9vsf7hf3fTsjawK6DwLwrnB2LH9n61c',
|
||||
name: 'ETH/USDC',
|
||||
},
|
||||
'SOL/USDT': {
|
||||
address: '8mDuvJJSgoodovMRYArtVVYBbixWYdGzR47GPrRT65YJ',
|
||||
name: 'SOL/USDT',
|
||||
programId: 'BJ3jrUzddfuSrZHXSCxMUUQsjKEyLmuuyZebkcaFp2fg',
|
||||
},
|
||||
'SOL/USDC': {
|
||||
address: 'Cdp72gDcYMCLLk3aDkPxjeiirKoFqK38ECm8Ywvk94Wi',
|
||||
name: 'SOL/USDC',
|
||||
programId: 'BJ3jrUzddfuSrZHXSCxMUUQsjKEyLmuuyZebkcaFp2fg',
|
||||
},
|
||||
'SRM/USDT': {
|
||||
address: 'HARFLhSq8nECZk4DVFKvzqXMNMA9a3hjvridGMFizeLa',
|
||||
name: 'SRM/USDT',
|
||||
|
@ -61,6 +66,14 @@ export const MARKET_INFO_BY_NAME = {
|
|||
address: '68J6nkWToik6oM9rTatKSR5ibVSykAtzftBUEAvpRsys',
|
||||
name: 'SRM/USDC',
|
||||
},
|
||||
'MSRM/USDT': {
|
||||
address: 'H4snTKK9adiU15gP22ErfZYtro3aqR9BTMXiH3AwiUTQ',
|
||||
name: 'MSRM/USDT',
|
||||
},
|
||||
'MSRM/USDC': {
|
||||
address: '7kgkDyW7dmyMeP8KFXzbcUZz1R2WHsovDZ7n3ihZuNDS',
|
||||
name: 'MSRM/USDC',
|
||||
},
|
||||
'FTT/USDT': {
|
||||
address: 'DHDdghmkBhEpReno3tbzBPtsxCt6P3KrMzZvxavTktJt',
|
||||
name: 'FTT/USDT',
|
||||
|
@ -329,6 +342,7 @@ export function useBaseCurrencyAccounts() {
|
|||
return await market.findBaseTokenAccountsForOwner(
|
||||
connection,
|
||||
wallet.publicKey,
|
||||
true,
|
||||
);
|
||||
}
|
||||
return useAsyncData(
|
||||
|
@ -353,6 +367,7 @@ export function useQuoteCurrencyAccounts() {
|
|||
return await market.findQuoteTokenAccountsForOwner(
|
||||
connection,
|
||||
wallet.publicKey,
|
||||
true,
|
||||
);
|
||||
}
|
||||
return useAsyncData(
|
||||
|
@ -380,50 +395,30 @@ export function useSelectedBaseCurrencyAccount() {
|
|||
|
||||
// TODO: Update to use websocket
|
||||
export function useQuoteCurrencyBalances() {
|
||||
const connection = useConnection();
|
||||
const quoteCurrencyAccount = useSelectedQuoteCurrencyAccount();
|
||||
async function getBalance() {
|
||||
if (!quoteCurrencyAccount) {
|
||||
return null;
|
||||
}
|
||||
const balances = await connection.getTokenAccountBalance(
|
||||
quoteCurrencyAccount.pubkey,
|
||||
);
|
||||
return balances && balances.value && balances.value.uiAmount;
|
||||
const { market } = useMarket();
|
||||
const [accountInfo, loaded] = useAccountInfo(quoteCurrencyAccount?.pubkey);
|
||||
if (!market || !quoteCurrencyAccount || !loaded) {
|
||||
return null;
|
||||
}
|
||||
return useAsyncData(
|
||||
getBalance,
|
||||
tuple(
|
||||
'useQuoteCurrencyBalances',
|
||||
connection,
|
||||
quoteCurrencyAccount && quoteCurrencyAccount.pubkey.toBase58(),
|
||||
),
|
||||
{ refreshInterval: _FAST_REFRESH_INTERVAL },
|
||||
);
|
||||
if (market.quoteMintAddress.equals(TokenInstructions.WRAPPED_SOL_MINT)) {
|
||||
return accountInfo?.lamports / 1e9 ?? 0;
|
||||
}
|
||||
return market.quoteSplSizeToNumber(new BN(accountInfo.data.slice(64, 72)));
|
||||
}
|
||||
|
||||
// TODO: Update to use websocket
|
||||
export function useBaseCurrencyBalances() {
|
||||
const connection = useConnection();
|
||||
const baseCurrencyAccount = useSelectedBaseCurrencyAccount();
|
||||
async function getBalance() {
|
||||
if (!baseCurrencyAccount) {
|
||||
return null;
|
||||
}
|
||||
const balances = await connection.getTokenAccountBalance(
|
||||
baseCurrencyAccount.pubkey,
|
||||
);
|
||||
return balances && balances.value && balances.value.uiAmount;
|
||||
const { market } = useMarket();
|
||||
const [accountInfo, loaded] = useAccountInfo(baseCurrencyAccount?.pubkey);
|
||||
if (!market || !baseCurrencyAccount || !loaded) {
|
||||
return null;
|
||||
}
|
||||
return useAsyncData(
|
||||
getBalance,
|
||||
tuple(
|
||||
'useBaseCurrencyBalances',
|
||||
connection,
|
||||
baseCurrencyAccount && baseCurrencyAccount.pubkey.toBase58(),
|
||||
),
|
||||
{ refreshInterval: _FAST_REFRESH_INTERVAL },
|
||||
);
|
||||
if (market.baseMintAddress.equals(TokenInstructions.WRAPPED_SOL_MINT)) {
|
||||
return accountInfo?.lamports / 1e9 ?? 0;
|
||||
}
|
||||
return market.baseSplSizeToNumber(new BN(accountInfo.data.slice(64, 72)));
|
||||
}
|
||||
|
||||
export function useOpenOrders() {
|
||||
|
@ -583,8 +578,8 @@ export function useOpenOrdersForAllMarkets() {
|
|||
}
|
||||
|
||||
export function useBalances() {
|
||||
const [baseCurrencyBalances] = useBaseCurrencyBalances();
|
||||
const [quoteCurrencyBalances] = useQuoteCurrencyBalances();
|
||||
const baseCurrencyBalances = useBaseCurrencyBalances();
|
||||
const quoteCurrencyBalances = useQuoteCurrencyBalances();
|
||||
const openOrdersAccount = useSelectedOpenOrdersAccount(true);
|
||||
const { baseCurrency, quoteCurrency, market } = useMarket();
|
||||
const baseExists =
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
import { notify } from './notifications';
|
||||
import nacl from 'tweetnacl';
|
||||
import { sleep, getDecimalCount } from './utils';
|
||||
import { Transaction, PublicKey } from '@solana/web3.js';
|
||||
import { Buffer } from 'buffer';
|
||||
import { getDecimalCount, sleep } from './utils';
|
||||
|
||||
export async function settleFunds({
|
||||
market,
|
||||
|
@ -34,25 +31,12 @@ export async function settleFunds({
|
|||
return;
|
||||
}
|
||||
|
||||
// This is a workaround for this issue: https://github.com/solana-labs/solana-web3.js/issues/985
|
||||
const transaction = new Transaction();
|
||||
const vaultSigner =
|
||||
market.address.toBase58() === 'H4snTKK9adiU15gP22ErfZYtro3aqR9BTMXiH3AwiUTQ'
|
||||
? new PublicKey('12rqwuEgBYiGhBrDJStCiqEtzQpTTiZbh7teNVLuYcFA')
|
||||
: await PublicKey.createProgramAddress(
|
||||
[
|
||||
market.address.toBuffer(),
|
||||
market._decoded.vaultSignerNonce.toArrayLike(Buffer, 'le', 8),
|
||||
],
|
||||
market._programId,
|
||||
);
|
||||
const settleInstruction = market.makeSettleInstruction(
|
||||
const { transaction, signers } = await market.makeSettleFundsTransaction(
|
||||
connection,
|
||||
openOrders,
|
||||
baseCurrencyAccount.pubkey,
|
||||
quoteCurrencyAccount.pubkey,
|
||||
vaultSigner,
|
||||
);
|
||||
transaction.add(settleInstruction);
|
||||
|
||||
const onConfirm = (result) => {
|
||||
if (result.timeout) {
|
||||
|
@ -73,6 +57,7 @@ export async function settleFunds({
|
|||
notify({ message: 'Funds settled', type: 'success' });
|
||||
return await sendTransaction({
|
||||
transaction,
|
||||
signers,
|
||||
wallet,
|
||||
connection,
|
||||
onBeforeSend,
|
||||
|
@ -94,14 +79,13 @@ export async function cancelOrders({
|
|||
onAfterSendCallBack,
|
||||
onConfirmCallBack,
|
||||
}) {
|
||||
const transaction = new Transaction();
|
||||
transaction.add(market.makeMatchOrdersInstruction(5));
|
||||
const transaction = market.makeMatchOrdersTransaction(5);
|
||||
orders.forEach((order) => {
|
||||
transaction.add(
|
||||
market.makeCancelOrderInstruction(connection, wallet.publicKey, order),
|
||||
);
|
||||
});
|
||||
transaction.add(market.makeMatchOrdersInstruction(5));
|
||||
transaction.add(market.makeMatchOrdersTransaction(5));
|
||||
const onConfirm = (result) => {
|
||||
if (result.timeout) {
|
||||
notify({
|
||||
|
@ -161,7 +145,6 @@ export async function placeOrder({
|
|||
wallet,
|
||||
baseCurrencyAccount,
|
||||
quoteCurrencyAccount,
|
||||
openOrdersAccount,
|
||||
onBeforeSendCallBack,
|
||||
onAfterSendCallBack,
|
||||
onConfirmCallBack,
|
||||
|
@ -231,26 +214,16 @@ export async function placeOrder({
|
|||
size,
|
||||
orderType,
|
||||
};
|
||||
let transaction, signers;
|
||||
let extraSigners = [];
|
||||
console.log(params);
|
||||
|
||||
// If the user does not has an open orders account, use serum-js to create one
|
||||
if (!openOrdersAccount) {
|
||||
let result = await market.makePlaceOrderTransaction(connection, params);
|
||||
transaction = result.transaction;
|
||||
signers = result.signers;
|
||||
if (signers.length > 1) {
|
||||
extraSigners = [signers[1]];
|
||||
}
|
||||
} else {
|
||||
transaction = new Transaction();
|
||||
transaction.add(market.makeMatchOrdersInstruction(5));
|
||||
transaction.add(
|
||||
market.makePlaceOrderInstruction(connection, params, openOrdersAccount),
|
||||
);
|
||||
}
|
||||
const transaction = market.makeMatchOrdersTransaction(5);
|
||||
let {
|
||||
transaction: placeOrderTx,
|
||||
signers,
|
||||
} = await market.makePlaceOrderTransaction(connection, params);
|
||||
transaction.add(placeOrderTx);
|
||||
transaction.add(market.makeMatchOrdersTransaction(5));
|
||||
|
||||
transaction.add(market.makeMatchOrdersInstruction(5));
|
||||
const onConfirm = (result) => {
|
||||
if (result.timeout) {
|
||||
notify({
|
||||
|
@ -282,34 +255,26 @@ export async function placeOrder({
|
|||
onBeforeSend,
|
||||
onAfterSend,
|
||||
onConfirm,
|
||||
extraSigners,
|
||||
signers,
|
||||
});
|
||||
}
|
||||
|
||||
async function sendTransaction({
|
||||
transaction,
|
||||
wallet,
|
||||
signers = [wallet.publicKey],
|
||||
connection,
|
||||
onBeforeSend,
|
||||
onAfterSend,
|
||||
onConfirm,
|
||||
extraSigners = [],
|
||||
}) {
|
||||
transaction.recentBlockhash = (
|
||||
await connection.getRecentBlockhash('max')
|
||||
).blockhash;
|
||||
transaction.signPartial(...signers);
|
||||
const signed = await wallet.signTransaction(transaction);
|
||||
const signedAt = new Date().getTime();
|
||||
|
||||
// Don't rely on the open orders account being the 2nd element in the list
|
||||
// Sign with any accounts with a pubkey different from that of the wallet
|
||||
extraSigners.forEach((extraSigner) => {
|
||||
const extraSignature = nacl.sign.detached(
|
||||
signed.serializeMessage(),
|
||||
extraSigner.secretKey,
|
||||
);
|
||||
signed.addSignature(extraSigner.publicKey, extraSignature);
|
||||
});
|
||||
onBeforeSend();
|
||||
|
||||
const txid = await connection.sendRawTransaction(signed.serialize(), {
|
||||
|
|
|
@ -1467,10 +1467,10 @@
|
|||
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
|
||||
integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==
|
||||
|
||||
"@project-serum/serum@^0.9.2":
|
||||
version "0.9.2"
|
||||
resolved "https://registry.yarnpkg.com/@project-serum/serum/-/serum-0.9.2.tgz#72fa9855d9bdef169e20d01f838d74361ce11c81"
|
||||
integrity sha512-EcDQUTaMigREhalhvzRVwIjN/54QuHhDFq81d3cML90T/Ac71kh5b7PdUNG9eyE9CsdvD1vLuW9cXrEUj5YnEw==
|
||||
"@project-serum/serum@^0.11.1":
|
||||
version "0.11.1"
|
||||
resolved "https://registry.yarnpkg.com/@project-serum/serum/-/serum-0.11.1.tgz#4d41bdc49e30d82168af5b4d4c8773a1b670ac81"
|
||||
integrity sha512-/bYJEwlZ3dFINg5YsaD5rK619YA+Qgbx7tR54vJ6X3AJun9GZCNCubfgD3blOCyy5PnhxBB/pchv/oYT5cXgMg==
|
||||
dependencies:
|
||||
"@solana/web3.js" "^0.71.9"
|
||||
bn.js "^5.1.2"
|
||||
|
|
Loading…
Reference in New Issue