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