Skip to content

Commit

Permalink
include fee if creating a token account during swap (#3244)
Browse files Browse the repository at this point in the history
  • Loading branch information
wentokay authored Mar 10, 2023
1 parent 23e7223 commit 9810c50
Show file tree
Hide file tree
Showing 4 changed files with 226 additions and 119 deletions.
125 changes: 95 additions & 30 deletions packages/app-extension/src/components/Unlocked/Swap.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useEffect, useState } from "react";
import {
Blockchain,
SOL_NATIVE_MINT,
Expand All @@ -14,7 +15,11 @@ import {
SecondaryButton,
TextFieldLabel,
} from "@coral-xyz/react-common";
import type { TokenData, TokenDataWithPrice } from "@coral-xyz/recoil";
import type {
SwapContext,
TokenData,
TokenDataWithPrice,
} from "@coral-xyz/recoil";
import {
useActiveWallet,
useDarkMode,
Expand All @@ -31,8 +36,8 @@ import {
Tooltip,
Typography,
} from "@mui/material";
import type { BigNumberish } from "ethers";
import { ethers, FixedNumber } from "ethers";
import { useEffect, useState } from "react";

import { Button as XnftButton } from "../../plugin/Component";
import { TextField } from "../common";
Expand Down Expand Up @@ -205,6 +210,17 @@ const useStyles = styles((theme) => ({
fontSize: "14px",
fontWeight: 500,
},
feesTooltipTable: {
tableCollapse: "collapse",
},
feesTooltipTableHeading: {
fontWeight: 500,
textAlign: "left",
paddingRight: 10,
},
feesTooltipTableValue: {
textAlign: "right",
},
}));

enum SwapState {
Expand Down Expand Up @@ -631,7 +647,7 @@ function SwapInfo({ compact = true }: { compact?: boolean }) {
priceImpactPct,
isLoadingRoutes,
isLoadingTransactions,
transactionFee,
transactionFees,
swapFee,
} = useSwapContext();

Expand Down Expand Up @@ -694,7 +710,7 @@ function SwapInfo({ compact = true }: { compact?: boolean }) {
youPay: `${toDisplayBalance(fromAmount, fromToken.decimals)} ${
fromToken.ticker
}`,
rate: `1 ${fromToken.ticker} = ${rate.substring(0, 10)} ${
rate: `1 ${fromToken.ticker} ${rate.substring(0, 10)} ${
toToken.ticker
}`,
priceImpact: `${
Expand All @@ -704,38 +720,43 @@ function SwapInfo({ compact = true }: { compact?: boolean }) {
? priceImpactPct.toFixed(2)
: "< 0.1"
}%`,
networkFee: transactionFee
? `${ethers.utils.formatUnits(transactionFee, 9)} SOL`
networkFee: transactionFees
? `~ ${approximateAmount(transactionFees.total)} SOL`
: "-",
swapFee,
transactionFees,
}}
/>
);
}

type SwapInfoRowProps = {
label: string;
value: string | React.ReactElement;
tooltip?: string;
};

function SwapInfoRows({
youPay,
rate,
networkFee,
priceImpact,
compact,
swapFee,
transactionFees,
}: {
youPay: any;
rate: any;
priceImpact: any;
networkFee: any;
swapFee?: any;
compact?: boolean;
swapFee?: SwapContext["swapFee"];
transactionFees?: SwapContext["transactionFees"];
}) {
const classes = useStyles();
const wallet = useActiveWallet();

const rows: Array<{
label: string;
value: string | React.ReactElement;
tooltip?: string;
}> = [
const rows: Array<SwapInfoRowProps> = [
{
label: "Wallet",
value: <WalletDrawerButton wallet={wallet} style={{ height: "20px" }} />,
Expand All @@ -748,35 +769,71 @@ function SwapInfoRows({

rows.push({ label: "Rate", value: rate });
rows.push({
label: "Network Fee",
label: "Estimated Fees",
value: networkFee,
tooltip: swapFee?.pct
? `Quote includes a ${swapFee?.pct}% Backpack fee`
: undefined,
// @ts-ignore - tooltip's supposed to be a string, can be a component for now
tooltip:
transactionFees && swapFee ? (
<table className={classes.feesTooltipTable}>
<tbody>
{Object.entries(transactionFees?.fees ?? {}).map(
([description, value]) => (
<tr key={description}>
<th className={classes.feesTooltipTableHeading}>
{description}
</th>
<td className={classes.feesTooltipTableValue}>
{approximateAmount(value)} SOL
</td>
</tr>
)
)}
{swapFee.pct > 0 ? (
<tr>
<td colSpan={2} style={{ opacity: 0.5 }}>
Quote includes a {swapFee.pct}% Backpack fee
</td>
</tr>
) : null}
</tbody>
</table>
) : null,
});
rows.push({ label: "Price Impact", value: priceImpact });

return (
<>
{rows.map(({ label, value, tooltip }) => (
<div className={classes.swapInfoRow} key={label}>
<Typography className={classes.swapInfoTitleLeft}>
{label}
{tooltip ? (
<Tooltip title={tooltip}>
<Info className={classes.tooltipIcon} />
</Tooltip>
) : null}
</Typography>
<Typography className={classes.swapInfoTitleRight}>
{value}
</Typography>
</div>
{rows.map((row) => (
<SwapInfoRow key={row.label} {...row} />
))}
</>
);
}

const SwapInfoRow = ({ label, value, tooltip }: SwapInfoRowProps) => {
const classes = useStyles();
// show tooltip when user hovers on the label text, not just the icon
const [tooltipVisible, setTooltipVisible] = useState(false);
return (
<div className={classes.swapInfoRow}>
<div
onMouseOver={() => setTooltipVisible(true)}
onMouseOut={() => setTooltipVisible(false)}
>
<Typography className={classes.swapInfoTitleLeft}>
{label}
{tooltip ? (
<Tooltip title={tooltip} arrow open={tooltipVisible}>
<Info className={classes.tooltipIcon} />
</Tooltip>
) : null}
</Typography>
</div>
<Typography className={classes.swapInfoTitleRight}>{value}</Typography>
</div>
);
};

function SwapTokensButton({
onClick,
style,
Expand Down Expand Up @@ -893,3 +950,11 @@ export function SwapSelectToken({
/>
);
}

/**
* Hides miniscule amounts of SOL
* @example approximateAmount(0.00203928) = "0.002"
* @param value BigNumberish amount of Solana Lamports
*/
const approximateAmount = (value: BigNumberish) =>
ethers.utils.formatUnits(value, 9).replace(/(0.0{2,}[1-9])(\d+)/, "$1");
102 changes: 51 additions & 51 deletions packages/common/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -565,8 +565,8 @@ export const QUERY_ADD_USER_ACCOUNT = "add-user-account=true";

export const SIMULATOR_PORT = 9933;

export const NATIVE_ACCOUNT_RENT_EXEMPTION_LAMPORTS = 890880;
export const TOKEN_ACCOUNT_RENT_EXEMPTION_LAMPORTS = 2039280;
export const NATIVE_ACCOUNT_RENT_EXEMPTION_LAMPORTS = 890880 as const;
export const TOKEN_ACCOUNT_RENT_EXEMPTION_LAMPORTS = 2039280 as const;

export const DISCORD_INVITE_LINK = "https://discord.gg/RhKxgS8SaD";
export const TWITTER_LINK = "https://twitter.com/xNFT_Backpack";
Expand Down Expand Up @@ -595,13 +595,13 @@ export const DEFAULT_GROUP_CHATS: {
name: string;
image: string;
}[] = [
{
id: "backpack-chat",
name: "Backpack",
image:
"https://user-images.githubusercontent.com/321395/206757416-a80e662a-0ccc-41cc-a20f-ff397755d47f.png",
},
];
{
id: "backpack-chat",
name: "Backpack",
image:
"https://user-images.githubusercontent.com/321395/206757416-a80e662a-0ccc-41cc-a20f-ff397755d47f.png",
},
];

export const WHITELISTED_CHAT_COLLECTIONS: {
id: string;
Expand All @@ -610,49 +610,49 @@ export const WHITELISTED_CHAT_COLLECTIONS: {
collectionId: string;
attributeMapping?: { [key: string]: string };
}[] = [
{
id: "nouns",
name: "Y00ts + Nouns",
image: "https://metadata.y00ts.com/y/12189.png",
collectionId: "4mKSoDDqApmF1DqXvVTSL6tu2zixrSSNjqMxUnwvVzy2",
attributeMapping: {
Eyewear: "Nouns",
},
},
{
id: "nokiamon",
name: "Nokiamon",
image:
"https://madlist-images.s3.us-west-2.amazonaws.com/nokiamon_pfp_1675332500467.png",
collectionId: "3YysdoK6ZcJFEL5QJxccY3q8AcTUFpahgbp4HFgBtjNF",
},
{
id: "backpack-chat-internal",
name: "Backpack Team",
image: "https://one.xnfts.dev/BackpackTeamNFT.gif",

collectionId: "BjN9u6zneFrjzuC7LH3eLaGC9FgYLnwQJMGA1xzVBKsj",
{
id: "nouns",
name: "Y00ts + Nouns",
image: "https://metadata.y00ts.com/y/12189.png",
collectionId: "4mKSoDDqApmF1DqXvVTSL6tu2zixrSSNjqMxUnwvVzy2",
attributeMapping: {
Eyewear: "Nouns",
},
{
id: "bonkz",
name: "BONKz",
image:
"https://bafybeiecuemcqxzuv4ti4sgffjlwvrqedr7golppwrbbu2u5yttglath3m.ipfs.nftstorage.link/0.png",
collectionId: "ajM4QBHtZBBRcMqqq9gawdHK28GXcb2yeRs6WBnqhay",
},
{
id: "3PMczHyeW2ds7ZWDZbDSF3d21HBqG6yR4tG7vP6qczfj",
name: "The Madlist",
image: "https://www.madlads.com/mad_lads_logo.svg",
collectionId: "3PMczHyeW2ds7ZWDZbDSF3d21HBqG6yR4tG7vP6qczfj",
},
{
id: "FCk24cq1pYhQo5MQYKHf5N9VnY8tdrToF7u6gvvsnGrn",
name: "The Madlist",
image: "https://www.madlads.com/mad_lads_logo.svg",
collectionId: "FCk24cq1pYhQo5MQYKHf5N9VnY8tdrToF7u6gvvsnGrn",
},
];
},
{
id: "nokiamon",
name: "Nokiamon",
image:
"https://madlist-images.s3.us-west-2.amazonaws.com/nokiamon_pfp_1675332500467.png",
collectionId: "3YysdoK6ZcJFEL5QJxccY3q8AcTUFpahgbp4HFgBtjNF",
},
{
id: "backpack-chat-internal",
name: "Backpack Team",
image: "https://one.xnfts.dev/BackpackTeamNFT.gif",

collectionId: "BjN9u6zneFrjzuC7LH3eLaGC9FgYLnwQJMGA1xzVBKsj",
},
{
id: "bonkz",
name: "BONKz",
image:
"https://bafybeiecuemcqxzuv4ti4sgffjlwvrqedr7golppwrbbu2u5yttglath3m.ipfs.nftstorage.link/0.png",
collectionId: "ajM4QBHtZBBRcMqqq9gawdHK28GXcb2yeRs6WBnqhay",
},
{
id: "3PMczHyeW2ds7ZWDZbDSF3d21HBqG6yR4tG7vP6qczfj",
name: "The Madlist",
image: "https://www.madlads.com/mad_lads_logo.svg",
collectionId: "3PMczHyeW2ds7ZWDZbDSF3d21HBqG6yR4tG7vP6qczfj",
},
{
id: "FCk24cq1pYhQo5MQYKHf5N9VnY8tdrToF7u6gvvsnGrn",
name: "The Madlist",
image: "https://www.madlads.com/mad_lads_logo.svg",
collectionId: "FCk24cq1pYhQo5MQYKHf5N9VnY8tdrToF7u6gvvsnGrn",
},
];

// Load a fixed amount of public keys for various actions, e.g. import list,
// searching mnemonics
Expand Down
9 changes: 5 additions & 4 deletions packages/common/src/solana/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ import {
} from "@magiceden-oss/open_creator_protocol";
import type {
TransferInstructionAccounts,
TransferInstructionArgs} from "@metaplex-foundation/mpl-token-metadata";
TransferInstructionArgs,
} from "@metaplex-foundation/mpl-token-metadata";
import {
createTransferInstruction as createTokenMetadataTransferInstruction,
Metadata,
TokenRecord,
TokenState
TokenState,
} from "@metaplex-foundation/mpl-token-metadata";
import type { Program, SplToken } from "@project-serum/anchor";
import * as anchor from "@project-serum/anchor";
Expand Down Expand Up @@ -50,6 +51,7 @@ import {
import BN from "bn.js";

import type { BackgroundClient } from "../";
import { TOKEN_ACCOUNT_RENT_EXEMPTION_LAMPORTS } from "../constants";

import * as assertOwner from "./programs/assert-owner";
import {
Expand Down Expand Up @@ -678,13 +680,12 @@ export const generateUnwrapSolTx = async (
);
} else {
const newAccount = Keypair.generate();
const rentExemptionLamports = 2039280;
// Create a new account to transfer wSOL into and then close
tx.instructions.push(
SystemProgram.createAccount({
fromPubkey: walletPublicKey,
newAccountPubkey: newAccount.publicKey,
lamports: rentExemptionLamports,
lamports: TOKEN_ACCOUNT_RENT_EXEMPTION_LAMPORTS,
space: 165,
programId: TOKEN_PROGRAM_ID,
})
Expand Down
Loading

1 comment on commit 9810c50

@vercel
Copy link

@vercel vercel bot commented on 9810c50 Mar 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.