From d368648476abe5750455a366c1dd9c0ae9dfeb07 Mon Sep 17 00:00:00 2001 From: Armani Ferrante Date: Fri, 16 Apr 2021 00:38:46 +0800 Subject: [PATCH 1/6] Use transfer checked instruction (#191) --- src/components/MergeAccountsDialog.js | 4 ++- src/components/SendDialog.js | 1 + src/utils/tokens/index.js | 46 +++++++++++---------------- src/utils/tokens/instructions.js | 15 +++++---- src/utils/wallet.js | 13 ++------ 5 files changed, 33 insertions(+), 46 deletions(-) diff --git a/src/components/MergeAccountsDialog.js b/src/components/MergeAccountsDialog.js index 9a52ee3..7c8cacf 100644 --- a/src/components/MergeAccountsDialog.js +++ b/src/components/MergeAccountsDialog.js @@ -115,6 +115,7 @@ export default function MergeAccountsDialog({ open, onClose }) { assocTokAddr, mintGroup, mint, + tokenInfo.decimals, wallet, connection, enqueueSnackbar, @@ -242,11 +243,11 @@ async function mergeMint( assocTokAddr, mintAccountSet, mint, + decimals, wallet, connection, enqueueSnackbar, ) { - console.log('mint', mint, mint.toString()); if (mintAccountSet.length === 0) { return; } @@ -292,6 +293,7 @@ async function mergeMint( associatedTokenAccount, tokenAccount.account.amount, mint, + decimals, ); } } diff --git a/src/components/SendDialog.js b/src/components/SendDialog.js index 237e50a..767de84 100644 --- a/src/components/SendDialog.js +++ b/src/components/SendDialog.js @@ -259,6 +259,7 @@ function SendSplDialog({ onClose, publicKey, balanceInfo, onSubmitRef }) { new PublicKey(destinationAddress), amount, balanceInfo.mint, + decimals, null, overrideDestinationCheck, ); diff --git a/src/utils/tokens/index.js b/src/utils/tokens/index.js index 7d8d9fc..e2b05ea 100644 --- a/src/utils/tokens/index.js +++ b/src/utils/tokens/index.js @@ -14,7 +14,7 @@ import { memoInstruction, mintTo, TOKEN_PROGRAM_ID, - transfer, + transferChecked, } from './instructions'; import { ACCOUNT_LAYOUT, @@ -300,6 +300,7 @@ export async function transferTokens({ amount, memo, mint, + decimals, overrideDestinationCheck, }) { const destinationAccountInfo = await connection.getAccountInfo( @@ -312,6 +313,8 @@ export async function transferTokens({ return await transferBetweenSplTokenAccounts({ connection, owner, + mint, + decimals, sourcePublicKey, destinationPublicKey, amount, @@ -339,6 +342,8 @@ export async function transferTokens({ return await transferBetweenSplTokenAccounts({ connection, owner, + mint, + decimals, sourcePublicKey, destinationPublicKey: destinationSplTokenAccount.publicKey, amount, @@ -353,44 +358,24 @@ export async function transferTokens({ amount, memo, mint, + decimals, }); } -// SPL tokens only. -export async function transferAndClose({ - connection, - owner, - sourcePublicKey, - destinationPublicKey, - amount, -}) { - const tx = createTransferBetweenSplTokenAccountsInstruction({ - ownerPublicKey: owner.publicKey, - sourcePublicKey, - destinationPublicKey, - amount, - }); - tx.add( - closeAccount({ - source: sourcePublicKey, - destination: owner.publicKey, - owner: owner.publicKey, - }), - ); - let signers = []; - return await signAndSendTransaction(connection, tx, owner, signers); -} - function createTransferBetweenSplTokenAccountsInstruction({ ownerPublicKey, + mint, + decimals, sourcePublicKey, destinationPublicKey, amount, memo, }) { let transaction = new Transaction().add( - transfer({ + transferChecked({ source: sourcePublicKey, + mint, + decimals, destination: destinationPublicKey, owner: ownerPublicKey, amount, @@ -405,6 +390,8 @@ function createTransferBetweenSplTokenAccountsInstruction({ async function transferBetweenSplTokenAccounts({ connection, owner, + mint, + decimals, sourcePublicKey, destinationPublicKey, amount, @@ -412,6 +399,8 @@ async function transferBetweenSplTokenAccounts({ }) { const transaction = createTransferBetweenSplTokenAccountsInstruction({ ownerPublicKey: owner.publicKey, + mint, + decimals, sourcePublicKey, destinationPublicKey, amount, @@ -429,6 +418,7 @@ async function createAndTransferToAccount({ amount, memo, mint, + decimals, }) { const [ createAccountInstruction, @@ -449,6 +439,8 @@ async function createAndTransferToAccount({ const transferBetweenAccountsTxn = createTransferBetweenSplTokenAccountsInstruction( { ownerPublicKey: owner.publicKey, + mint, + decimals, sourcePublicKey, destinationPublicKey: newAddress, amount, diff --git a/src/utils/tokens/instructions.js b/src/utils/tokens/instructions.js index cde72f0..abc86e8 100644 --- a/src/utils/tokens/instructions.js +++ b/src/utils/tokens/instructions.js @@ -29,11 +29,6 @@ LAYOUT.addVariant( 'initializeMint', ); LAYOUT.addVariant(1, BufferLayout.struct([]), 'initializeAccount'); -LAYOUT.addVariant( - 3, - BufferLayout.struct([BufferLayout.nu64('amount')]), - 'transfer', -); LAYOUT.addVariant( 7, BufferLayout.struct([BufferLayout.nu64('amount')]), @@ -45,6 +40,11 @@ LAYOUT.addVariant( 'burn', ); LAYOUT.addVariant(9, BufferLayout.struct([]), 'closeAccount'); +LAYOUT.addVariant( + 12, + BufferLayout.struct([BufferLayout.nu64('amount'), BufferLayout.u8('decimals')]), + 'transferChecked', +); const instructionMaxSpan = Math.max( ...Object.values(LAYOUT.registry).map((r) => r.span), @@ -96,16 +96,17 @@ export function initializeAccount({ account, mint, owner }) { }); } -export function transfer({ source, destination, amount, owner }) { +export function transferChecked({ source, mint, destination, amount, decimals, owner }) { let keys = [ { pubkey: source, isSigner: false, isWritable: true }, + { pubkey: mint, isSigner: false, isWritable: false }, { pubkey: destination, isSigner: false, isWritable: true }, { pubkey: owner, isSigner: true, isWritable: false }, ]; return new TransactionInstruction({ keys, data: encodeTokenInstructionData({ - transfer: { amount }, + transferChecked: { amount, decimals }, }), programId: TOKEN_PROGRAM_ID, }); diff --git a/src/utils/wallet.js b/src/utils/wallet.js index 18667e4..47c9af8 100644 --- a/src/utils/wallet.js +++ b/src/utils/wallet.js @@ -14,7 +14,6 @@ import { getOwnedTokenAccounts, nativeTransfer, transferTokens, - transferAndClose, } from './tokens'; import { TOKEN_PROGRAM_ID } from './tokens/instructions'; import { @@ -99,6 +98,7 @@ export class Wallet { destination, amount, mint, + decimals, memo = null, overrideDestinationCheck = false, ) => { @@ -116,6 +116,7 @@ export class Wallet { amount, memo, mint, + decimals, overrideDestinationCheck, }); }; @@ -133,16 +134,6 @@ export class Wallet { }); }; - transferAndClose = async (source, destination, amount) => { - return await transferAndClose({ - connection: this.connection, - owner: this, - sourcePublicKey: source, - destinationPublicKey: destination, - amount, - }); - }; - signTransaction = async (transaction) => { return this.provider.signTransaction(transaction); }; From 401789f3497df47154d43f72ea39d5af31e61599 Mon Sep 17 00:00:00 2001 From: armaniferrante Date: Fri, 16 Apr 2021 10:24:17 -0700 Subject: [PATCH 2/6] Fix add token dialog --- src/components/AddTokenDialog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/AddTokenDialog.js b/src/components/AddTokenDialog.js index f976eee..d035929 100644 --- a/src/components/AddTokenDialog.js +++ b/src/components/AddTokenDialog.js @@ -167,7 +167,7 @@ export default function AddTokenDialog({ open, onClose }) { ) : tab === 'popular' ? ( - {popularTokens.map((tokenInfo) => ( + {popularTokens.filter(tokenInfo => tokenInfo.address).map((tokenInfo) => ( Date: Tue, 20 Apr 2021 12:11:02 +0800 Subject: [PATCH 3/6] WUSDC flow (#197) --- src/components/SendDialog.js | 87 +++++++++++++++++++++++------------- src/utils/swap/api.js | 1 + 2 files changed, 56 insertions(+), 32 deletions(-) diff --git a/src/components/SendDialog.js b/src/components/SendDialog.js index 767de84..e0bc089 100644 --- a/src/components/SendDialog.js +++ b/src/components/SendDialog.js @@ -43,12 +43,10 @@ const WUSDC_MINT = new PublicKey( const USDC_MINT = new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'); const WUSDT_MINT = new PublicKey( - 'BQcdHdAQW1hczDbBi9hiegXAR7A98Q9jx3X3iBBBDiq4' + 'BQcdHdAQW1hczDbBi9hiegXAR7A98Q9jx3X3iBBBDiq4', ); -const USDT_MINT = new PublicKey( - 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB' -); +const USDT_MINT = new PublicKey('Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB'); export default function SendDialog({ open, onClose, publicKey, balanceInfo }) { const isProdNetwork = useIsProdNetwork(); @@ -68,40 +66,34 @@ export default function SendDialog({ open, onClose, publicKey, balanceInfo }) { if (mint?.equals(WUSDC_MINT)) { return [ , - , + , , - ] + ]; } else if (mint?.equals(WUSDT_MINT)) { return [ , - , + , , - ] + ]; + } else if (localStorage.getItem('sollet-private') && mint?.equals(USDC_MINT)) { + return [ + , + , + , + ]; } else { return [ + , , - , - ] + ]; } - } + }; return ( <> @@ -160,6 +152,16 @@ export default function SendDialog({ open, onClose, publicKey, balanceInfo }) { onSubmitRef={onSubmitRef} wusdtToSplUsdt /> + ) : tab === 'usdcToSplWUsdc' ? ( + ) : ( { if (wusdcToSplUsdc && splUsdcWalletAddress) { setDestinationAddress(splUsdcWalletAddress); } else if (wusdtToSplUsdt && splUsdtWalletAddress) { setDestinationAddress(splUsdtWalletAddress); + } else if (usdcToSplWUsdc && splWUsdcWalletAddress) { + setDestinationAddress(splWUsdcWalletAddress); } - }, [setDestinationAddress, wusdcToSplUsdc, splUsdcWalletAddress, wusdtToSplUsdt, splUsdtWalletAddress]); + }, [ + setDestinationAddress, + wusdcToSplUsdc, + splUsdcWalletAddress, + wusdtToSplUsdt, + splUsdtWalletAddress, + usdcToSplWUsdc, + splWUsdcWalletAddress, + ]); async function makeTransaction() { let amount = Math.round(parseFloat(transferAmountString) * 10 ** decimals); @@ -387,6 +404,11 @@ function SendSwapDialog({ } if (mint?.equals(WUSDC_MINT)) { params.wusdcToUsdc = true; + } else if (mint?.equals(USDC_MINT)) { + if (usdcToSplWUsdc) { + params.usdcToWUsdc = true; + params.coin = WUSDC_MINT.toString(); + } } else if (mint?.equals(WUSDT_MINT)) { params.wusdtToUsdt = true; } @@ -399,6 +421,7 @@ function SendSwapDialog({ new PublicKey(swapInfo.address), amount, balanceInfo.mint, + decimals, swapInfo.memo, ); } diff --git a/src/utils/swap/api.js b/src/utils/swap/api.js index 37c985b..022f0ee 100644 --- a/src/utils/swap/api.js +++ b/src/utils/swap/api.js @@ -22,6 +22,7 @@ export async function swapApiRequest( headers['Content-Type'] = 'application/json'; params.body = JSON.stringify(body); } + let resp = await fetch(`https://swap.sollet.io/api/${path}`, params); return await handleSwapApiResponse(resp, ignoreUserErrors); } From 275801931e306e187346fdad19dcaa46240b88d0 Mon Sep 17 00:00:00 2001 From: armaniferrante Date: Wed, 21 Apr 2021 11:13:34 -0700 Subject: [PATCH 4/6] Fix wallet selection --- src/components/NavigationFrame.js | 3 ++- src/utils/wallet.js | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/components/NavigationFrame.js b/src/components/NavigationFrame.js index 1fe9662..3f20336 100644 --- a/src/components/NavigationFrame.js +++ b/src/components/NavigationFrame.js @@ -241,6 +241,7 @@ function NetworkSelector() { function WalletSelector() { const { accounts, + derivedAccounts, hardwareWalletAccount, setHardwareWalletAccount, setWalletSelector, @@ -290,7 +291,7 @@ function WalletSelector() { onAdd={({ name, importedAccount }) => { addAccount({ name, importedAccount }); setWalletSelector({ - walletIndex: importedAccount ? undefined : accounts.length, + walletIndex: importedAccount ? undefined : derivedAccounts.length, importedPubkey: importedAccount ? importedAccount.publicKey.toString() : undefined, diff --git a/src/utils/wallet.js b/src/utils/wallet.js index 47c9af8..ad926a2 100644 --- a/src/utils/wallet.js +++ b/src/utils/wallet.js @@ -280,7 +280,7 @@ export function WalletProvider({ children }) { } } - const accounts = useMemo(() => { + const [accounts, derivedAccounts] = useMemo(() => { if (!seed) { return []; } @@ -316,7 +316,8 @@ export function WalletProvider({ children }) { }; }); - return derivedAccounts.concat(importedAccounts); + const accounts = derivedAccounts.concat(importedAccounts); + return [accounts, derivedAccounts]; // eslint-disable-next-line react-hooks/exhaustive-deps }, [seed, walletCount, walletSelector, privateKeyImports, walletNames]); @@ -349,6 +350,7 @@ export function WalletProvider({ children }) { privateKeyImports, setPrivateKeyImports, accounts, + derivedAccounts, addAccount, setAccountName, derivationPath, @@ -466,6 +468,7 @@ export function useBalanceInfo(publicKey) { export function useWalletSelector() { const { accounts, + derivedAccounts, addAccount, setWalletSelector, setAccountName, @@ -475,6 +478,7 @@ export function useWalletSelector() { return { accounts, + derivedAccounts, setWalletSelector, addAccount, setAccountName, From fd4bc93f4fd7f1d37d0f60ec0dc6145a5924372d Mon Sep 17 00:00:00 2001 From: armaniferrante Date: Wed, 21 Apr 2021 11:52:34 -0700 Subject: [PATCH 5/6] Return correct type for new wallets --- src/utils/wallet.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/wallet.js b/src/utils/wallet.js index ad926a2..76781e0 100644 --- a/src/utils/wallet.js +++ b/src/utils/wallet.js @@ -282,7 +282,7 @@ export function WalletProvider({ children }) { const [accounts, derivedAccounts] = useMemo(() => { if (!seed) { - return []; + return [[], []]; } const seedBuffer = Buffer.from(seed, 'hex'); From ce8e8cc71bd0a5f48606cc25bc88683ad5421b28 Mon Sep 17 00:00:00 2001 From: jhl <77697590+jhlx@users.noreply.github.com> Date: Thu, 22 Apr 2021 15:33:29 +0800 Subject: [PATCH 6/6] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8013e92..e764035 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Example Solana wallet with support for [SPL tokens](https://spl.solana.com/token) and Serum integration. -See [sollet.io](https://www.sollet.io) for a demo. +See [sollet.io](https://www.sollet.io) or the [Sollet Chrome Extension](https://chrome.google.com/webstore/detail/sollet/fhmfendgdocmcbmfikdcogofphimnkno) for a demo. Wallet keys are stored in `localStorage`, optionally encrypted by a password.