Allow SPL WUSDC -> SPL USDC swaps

This commit is contained in:
Gary Wang 2020-10-21 10:53:11 -07:00
parent 896a36bb2e
commit eac4ae3c8d
4 changed files with 99 additions and 26 deletions

View File

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

View File

@ -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}`} />
{mint?.equals(WUSDC_MINT)
? [
<Tab label="SPL WUSDC" key="spl" value="spl" />,
<Tab
label={`${swapCoinInfo.erc20Contract ? 'ERC20' : 'Native'} ${
swapCoinInfo.ticker
}`}
/>
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.

View File

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

View File

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