Allow SPL WUSDC -> SPL USDC swaps
This commit is contained in:
parent
896a36bb2e
commit
eac4ae3c8d
|
@ -5,7 +5,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@material-ui/core": "^4.11.0",
|
"@material-ui/core": "^4.11.0",
|
||||||
"@material-ui/icons": "^4.9.1",
|
"@material-ui/icons": "^4.9.1",
|
||||||
"@project-serum/serum": "^0.13.5",
|
"@project-serum/serum": "^0.13.6",
|
||||||
"@solana/web3.js": "^0.78.2",
|
"@solana/web3.js": "^0.78.2",
|
||||||
"@testing-library/jest-dom": "^4.2.4",
|
"@testing-library/jest-dom": "^4.2.4",
|
||||||
"@testing-library/react": "^9.3.2",
|
"@testing-library/react": "^9.3.2",
|
||||||
|
|
|
@ -5,7 +5,7 @@ import DialogTitle from '@material-ui/core/DialogTitle';
|
||||||
import DialogContent from '@material-ui/core/DialogContent';
|
import DialogContent from '@material-ui/core/DialogContent';
|
||||||
import TextField from '@material-ui/core/TextField';
|
import TextField from '@material-ui/core/TextField';
|
||||||
import DialogForm from './DialogForm';
|
import DialogForm from './DialogForm';
|
||||||
import { useWallet } from '../utils/wallet';
|
import { useWallet, useWalletAddressForMint } from '../utils/wallet';
|
||||||
import { PublicKey } from '@solana/web3.js';
|
import { PublicKey } from '@solana/web3.js';
|
||||||
import { abbreviateAddress } from '../utils/utils';
|
import { abbreviateAddress } from '../utils/utils';
|
||||||
import InputAdornment from '@material-ui/core/InputAdornment';
|
import InputAdornment from '@material-ui/core/InputAdornment';
|
||||||
|
@ -29,9 +29,14 @@ import Typography from '@material-ui/core/Typography';
|
||||||
import { useAsyncData } from '../utils/fetch-loop';
|
import { useAsyncData } from '../utils/fetch-loop';
|
||||||
import CircularProgress from '@material-ui/core/CircularProgress';
|
import CircularProgress from '@material-ui/core/CircularProgress';
|
||||||
|
|
||||||
|
const WUSDC_MINT = new PublicKey(
|
||||||
|
'BXXkv6z8ykpG1yuvUDPgh732wzVHB69RnB9YgSYh3itW',
|
||||||
|
);
|
||||||
|
const USDC_MINT = new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v');
|
||||||
|
|
||||||
export default function SendDialog({ open, onClose, publicKey, balanceInfo }) {
|
export default function SendDialog({ open, onClose, publicKey, balanceInfo }) {
|
||||||
const isProdNetwork = useIsProdNetwork();
|
const isProdNetwork = useIsProdNetwork();
|
||||||
const [tab, setTab] = useState(0);
|
const [tab, setTab] = useState('spl');
|
||||||
const onSubmitRef = useRef();
|
const onSubmitRef = useRef();
|
||||||
|
|
||||||
const [swapCoinInfo] = useSwapApiGet(
|
const [swapCoinInfo] = useSwapApiGet(
|
||||||
|
@ -62,23 +67,52 @@ export default function SendDialog({ open, onClose, publicKey, balanceInfo }) {
|
||||||
textColor="primary"
|
textColor="primary"
|
||||||
indicatorColor="primary"
|
indicatorColor="primary"
|
||||||
>
|
>
|
||||||
<Tab label={`SPL ${swapCoinInfo.ticker}`} />
|
{mint?.equals(WUSDC_MINT)
|
||||||
<Tab
|
? [
|
||||||
label={`${swapCoinInfo.erc20Contract ? 'ERC20' : 'Native'} ${
|
<Tab label="SPL WUSDC" key="spl" value="spl" />,
|
||||||
swapCoinInfo.ticker
|
<Tab
|
||||||
}`}
|
label="SPL USDC"
|
||||||
/>
|
key="wusdcToSplUsdc"
|
||||||
|
value="wusdcToSplUsdc"
|
||||||
|
/>,
|
||||||
|
<Tab label="ERC20 USDC" key="swap" value="swap" />,
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
<Tab
|
||||||
|
label={`SPL ${swapCoinInfo.ticker}`}
|
||||||
|
key="spl"
|
||||||
|
value="spl"
|
||||||
|
/>,
|
||||||
|
<Tab
|
||||||
|
label={`${
|
||||||
|
swapCoinInfo.erc20Contract ? 'ERC20' : 'Native'
|
||||||
|
} ${swapCoinInfo.ticker}`}
|
||||||
|
key="swap"
|
||||||
|
value="swap"
|
||||||
|
/>,
|
||||||
|
]}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
) : null}
|
) : null}
|
||||||
{tab === 0 ? (
|
{tab === 'spl' ? (
|
||||||
<SendSplDialog
|
<SendSplDialog
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
publicKey={publicKey}
|
publicKey={publicKey}
|
||||||
balanceInfo={balanceInfo}
|
balanceInfo={balanceInfo}
|
||||||
onSubmitRef={onSubmitRef}
|
onSubmitRef={onSubmitRef}
|
||||||
/>
|
/>
|
||||||
|
) : tab === 'wusdcToSplUsdc' ? (
|
||||||
|
<SendSwapDialog
|
||||||
|
key={tab}
|
||||||
|
onClose={onClose}
|
||||||
|
publicKey={publicKey}
|
||||||
|
balanceInfo={balanceInfo}
|
||||||
|
swapCoinInfo={swapCoinInfo}
|
||||||
|
onSubmitRef={onSubmitRef}
|
||||||
|
wusdcToSplUsdc
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<SendSwapDialog
|
<SendSwapDialog
|
||||||
|
key={tab}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
publicKey={publicKey}
|
publicKey={publicKey}
|
||||||
balanceInfo={balanceInfo}
|
balanceInfo={balanceInfo}
|
||||||
|
@ -146,6 +180,7 @@ function SendSwapDialog({
|
||||||
balanceInfo,
|
balanceInfo,
|
||||||
swapCoinInfo,
|
swapCoinInfo,
|
||||||
ethAccount,
|
ethAccount,
|
||||||
|
wusdcToSplUsdc = false,
|
||||||
onSubmitRef,
|
onSubmitRef,
|
||||||
}) {
|
}) {
|
||||||
const wallet = useWallet();
|
const wallet = useWallet();
|
||||||
|
@ -160,8 +195,11 @@ function SendSwapDialog({
|
||||||
} = useForm(balanceInfo);
|
} = useForm(balanceInfo);
|
||||||
|
|
||||||
const { tokenName, decimals, mint } = balanceInfo;
|
const { tokenName, decimals, mint } = balanceInfo;
|
||||||
const blockchain =
|
const blockchain = wusdcToSplUsdc
|
||||||
swapCoinInfo.blockchain === 'sol' ? 'eth' : swapCoinInfo.blockchain;
|
? 'sol'
|
||||||
|
: swapCoinInfo.blockchain === 'sol'
|
||||||
|
? 'eth'
|
||||||
|
: swapCoinInfo.blockchain;
|
||||||
const needMetamask = blockchain === 'eth';
|
const needMetamask = blockchain === 'eth';
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -170,19 +208,34 @@ function SendSwapDialog({
|
||||||
}
|
}
|
||||||
}, [blockchain, ethAccount, setDestinationAddress]);
|
}, [blockchain, ethAccount, setDestinationAddress]);
|
||||||
|
|
||||||
|
let splUsdcWalletAddress = useWalletAddressForMint(
|
||||||
|
wusdcToSplUsdc ? USDC_MINT : null,
|
||||||
|
);
|
||||||
|
useEffect(() => {
|
||||||
|
if (wusdcToSplUsdc && splUsdcWalletAddress) {
|
||||||
|
setDestinationAddress(splUsdcWalletAddress);
|
||||||
|
}
|
||||||
|
}, [setDestinationAddress, wusdcToSplUsdc, splUsdcWalletAddress]);
|
||||||
|
|
||||||
async function makeTransaction() {
|
async function makeTransaction() {
|
||||||
let amount = Math.round(parseFloat(transferAmountString) * 10 ** decimals);
|
let amount = Math.round(parseFloat(transferAmountString) * 10 ** decimals);
|
||||||
if (!amount || amount <= 0) {
|
if (!amount || amount <= 0) {
|
||||||
throw new Error('Invalid amount');
|
throw new Error('Invalid amount');
|
||||||
}
|
}
|
||||||
const swapInfo = await swapApiRequest('POST', 'swap_to', {
|
const params = {
|
||||||
blockchain,
|
blockchain,
|
||||||
coin: swapCoinInfo.erc20Contract,
|
|
||||||
address: destinationAddress,
|
address: destinationAddress,
|
||||||
size: amount / 10 ** decimals,
|
size: amount / 10 ** decimals,
|
||||||
wusdcToUsdc:
|
};
|
||||||
mint?.toBase58() === 'BXXkv6z8ykpG1yuvUDPgh732wzVHB69RnB9YgSYh3itW',
|
if (blockchain === 'sol') {
|
||||||
});
|
params.coin = swapCoinInfo.splMint;
|
||||||
|
} else if (blockchain === 'eth') {
|
||||||
|
params.coin = swapCoinInfo.erc20Contract;
|
||||||
|
}
|
||||||
|
if (mint?.equals(WUSDC_MINT)) {
|
||||||
|
params.wusdcToUsdc = true;
|
||||||
|
}
|
||||||
|
const swapInfo = await swapApiRequest('POST', 'swap_to', params);
|
||||||
if (swapInfo.blockchain !== 'sol') {
|
if (swapInfo.blockchain !== 'sol') {
|
||||||
throw new Error('Unexpected blockchain');
|
throw new Error('Unexpected blockchain');
|
||||||
}
|
}
|
||||||
|
@ -205,6 +258,7 @@ function SendSwapDialog({
|
||||||
key={signature}
|
key={signature}
|
||||||
publicKey={publicKey}
|
publicKey={publicKey}
|
||||||
signature={signature}
|
signature={signature}
|
||||||
|
blockchain={blockchain}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -215,7 +269,11 @@ function SendSwapDialog({
|
||||||
<DialogContent style={{ paddingTop: 16 }}>
|
<DialogContent style={{ paddingTop: 16 }}>
|
||||||
<DialogContentText>
|
<DialogContentText>
|
||||||
SPL {tokenName} can be converted to{' '}
|
SPL {tokenName} can be converted to{' '}
|
||||||
{swapCoinInfo.erc20Contract ? 'ERC20' : 'native'}{' '}
|
{blockchain === 'eth' && swapCoinInfo.erc20Contract
|
||||||
|
? 'ERC20'
|
||||||
|
: blockchain === 'sol' && swapCoinInfo.splMint
|
||||||
|
? 'SPL'
|
||||||
|
: 'native'}{' '}
|
||||||
{swapCoinInfo.ticker}
|
{swapCoinInfo.ticker}
|
||||||
{needMetamask ? ' via MetaMask' : null}.
|
{needMetamask ? ' via MetaMask' : null}.
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
|
@ -235,7 +293,7 @@ function SendSwapDialog({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SendSwapProgress({ publicKey, signature, onClose }) {
|
function SendSwapProgress({ publicKey, signature, onClose, blockchain }) {
|
||||||
const connection = useConnection();
|
const connection = useConnection();
|
||||||
const [swaps] = useSwapApiGet(`swaps_from/sol/${publicKey.toBase58()}`, {
|
const [swaps] = useSwapApiGet(`swaps_from/sol/${publicKey.toBase58()}`, {
|
||||||
refreshInterval: 1000,
|
refreshInterval: 1000,
|
||||||
|
@ -257,6 +315,8 @@ function SendSwapProgress({ publicKey, signature, onClose }) {
|
||||||
if (withdrawal.txid?.startsWith('0x')) {
|
if (withdrawal.txid?.startsWith('0x')) {
|
||||||
step = 3;
|
step = 3;
|
||||||
ethTxid = withdrawal.txid;
|
ethTxid = withdrawal.txid;
|
||||||
|
} else if (withdrawal.txid && blockchain !== 'eth') {
|
||||||
|
step = 3;
|
||||||
} else {
|
} else {
|
||||||
step = 2;
|
step = 2;
|
||||||
}
|
}
|
||||||
|
@ -287,7 +347,7 @@ function SendSwapProgress({ publicKey, signature, onClose }) {
|
||||||
View on Etherscan
|
View on Etherscan
|
||||||
</Link>
|
</Link>
|
||||||
</Typography>
|
</Typography>
|
||||||
) : (
|
) : step < 3 ? (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
@ -304,8 +364,8 @@ function SendSwapProgress({ publicKey, signature, onClose }) {
|
||||||
<Typography>Transaction Pending</Typography>
|
<Typography>Transaction Pending</Typography>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
) : null}
|
||||||
{!ethTxid ? (
|
{!ethTxid && blockchain === 'eth' ? (
|
||||||
<DialogContentText style={{ marginTop: 16, marginBottom: 0 }}>
|
<DialogContentText style={{ marginTop: 16, marginBottom: 0 }}>
|
||||||
Please keep this window open. You will need to approve the request
|
Please keep this window open. You will need to approve the request
|
||||||
on MetaMask to complete the transaction.
|
on MetaMask to complete the transaction.
|
||||||
|
|
|
@ -165,6 +165,19 @@ export function refreshWalletPublicKeys(wallet) {
|
||||||
refreshCache(wallet.getTokenAccountInfo);
|
refreshCache(wallet.getTokenAccountInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useWalletAddressForMint(mint) {
|
||||||
|
const [walletAccounts] = useWalletTokenAccounts();
|
||||||
|
return useMemo(
|
||||||
|
() =>
|
||||||
|
mint
|
||||||
|
? walletAccounts
|
||||||
|
?.find((account) => account.parsed?.mint?.equals(mint))
|
||||||
|
?.publicKey.toBase58()
|
||||||
|
: null,
|
||||||
|
[walletAccounts, mint],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function useBalanceInfo(publicKey) {
|
export function useBalanceInfo(publicKey) {
|
||||||
let [accountInfo, accountInfoLoaded] = useAccountInfo(publicKey);
|
let [accountInfo, accountInfoLoaded] = useAccountInfo(publicKey);
|
||||||
let { mint, owner, amount } = accountInfo?.owner.equals(TOKEN_PROGRAM_ID)
|
let { mint, owner, amount } = accountInfo?.owner.equals(TOKEN_PROGRAM_ID)
|
||||||
|
|
|
@ -1578,10 +1578,10 @@
|
||||||
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
|
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
|
||||||
integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==
|
integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==
|
||||||
|
|
||||||
"@project-serum/serum@^0.13.5":
|
"@project-serum/serum@^0.13.6":
|
||||||
version "0.13.5"
|
version "0.13.6"
|
||||||
resolved "https://registry.yarnpkg.com/@project-serum/serum/-/serum-0.13.5.tgz#9e8591886b3fc7f2486a94c242e5728d97da0938"
|
resolved "https://registry.yarnpkg.com/@project-serum/serum/-/serum-0.13.6.tgz#d45fa52a31d2820d19030964fd3a418e87b8a1f9"
|
||||||
integrity sha512-qMnxYKR/z8pqN+LFUIPRFwdSsJ1bGD39Jy6nooQl+aFp+ZpS8+hjIsJQGjpJA4kf+H+U8v6kcMhgMJ6diAWUHw==
|
integrity sha512-DoiqJABmGKWvrOLI0/ZctnXlzsPxIiKVHeIsFua3ODXqFWSDojUQDs8y1Rd26wFPEqB6Vsq1Xq8sqsku1leziQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@solana/web3.js" "^0.71.10"
|
"@solana/web3.js" "^0.71.10"
|
||||||
bn.js "^5.1.2"
|
bn.js "^5.1.2"
|
||||||
|
|
Loading…
Reference in New Issue