Add SOL markets

This commit is contained in:
Gary Wang 2020-09-01 10:04:13 -07:00
parent ddd3116096
commit ea6a32983e
7 changed files with 73 additions and 119 deletions

View File

@ -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",

View File

@ -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);
}
}

View File

@ -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={'/'}>

View File

@ -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);

View File

@ -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 =

View File

@ -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(), {

View File

@ -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"