diff --git a/apps/marginfi-v2-trading/src/components/common/trade-box-v2/components/amount-input/amount-input.tsx b/apps/marginfi-v2-trading/src/components/common/trade-box-v2/components/amount-input/amount-input.tsx index 55f145a583..a225b9a6e3 100644 --- a/apps/marginfi-v2-trading/src/components/common/trade-box-v2/components/amount-input/amount-input.tsx +++ b/apps/marginfi-v2-trading/src/components/common/trade-box-v2/components/amount-input/amount-input.tsx @@ -43,6 +43,7 @@ export const AmountInput = ({ inputMode="decimal" value={amount} onChange={(e) => handleAmountChange(e.target.value)} + disabled={maxAmount === 0} placeholder="0" className="bg-transparent shadow-none min-w-[130px] h-auto py-0 pr-0 text-right outline-none focus-visible:outline-none focus-visible:ring-0 border-none text-base font-medium" /> diff --git a/apps/marginfi-v2-trading/src/components/common/trade-box-v2/hooks/use-trade-simulation.ts b/apps/marginfi-v2-trading/src/components/common/trade-box-v2/hooks/use-trade-simulation.ts index fa6e76035b..55ab12718a 100644 --- a/apps/marginfi-v2-trading/src/components/common/trade-box-v2/hooks/use-trade-simulation.ts +++ b/apps/marginfi-v2-trading/src/components/common/trade-box-v2/hooks/use-trade-simulation.ts @@ -113,7 +113,7 @@ export function useTradeSimulation({ } else if (simulationResult.simulationResult) { return { simulationResult: simulationResult.simulationResult, actionMessage: null }; } else { - const errorMessage = DYNAMIC_SIMULATION_ERRORS.REPAY_COLLAT_FAILED_CHECK(props.bank.meta.tokenSymbol); // TODO: update + const errorMessage = DYNAMIC_SIMULATION_ERRORS.TRADE_FAILED_CHECK(); return { simulationResult: null, actionMessage: errorMessage }; } } else { @@ -125,20 +125,18 @@ export function useTradeSimulation({ props: CalculateLoopingProps ): Promise<{ actionTxns: TradeActionTxns | null; actionMessage: ActionMessageType | null }> => { try { - const loopingResult = await generateTradeTx({ + const tradingResult = await generateTradeTx({ ...props, }); - if (loopingResult && "actionQuote" in loopingResult) { - return { actionTxns: loopingResult, actionMessage: null }; + if (tradingResult && "actionQuote" in tradingResult) { + return { actionTxns: tradingResult, actionMessage: null }; } else { - const errorMessage = - loopingResult ?? DYNAMIC_SIMULATION_ERRORS.REPAY_COLLAT_FAILED_CHECK(props.borrowBank.meta.tokenSymbol); - // TODO: update + const errorMessage = tradingResult ?? DYNAMIC_SIMULATION_ERRORS.TRADE_FAILED_CHECK(); return { actionTxns: null, actionMessage: errorMessage }; } } catch (error) { - return { actionTxns: null, actionMessage: STATIC_SIMULATION_ERRORS.REPAY_COLLAT_FAILED }; // TODO: update + return { actionTxns: null, actionMessage: STATIC_SIMULATION_ERRORS.TRADE_FAILED }; } }; @@ -172,7 +170,7 @@ export function useTradeSimulation({ }); if (tradeActionTxns.actionMessage || tradeActionTxns.actionTxns === null) { - handleError(tradeActionTxns.actionMessage ?? STATIC_SIMULATION_ERRORS.REPAY_COLLAT_FAILED, { + handleError(tradeActionTxns.actionMessage ?? STATIC_SIMULATION_ERRORS.TRADE_FAILED, { // TODO: update error message setErrorMessage, setSimulationResult, @@ -198,7 +196,7 @@ export function useTradeSimulation({ }); if (simulationResult.actionMessage || simulationResult.simulationResult === null) { - handleError(simulationResult.actionMessage ?? STATIC_SIMULATION_ERRORS.REPAY_COLLAT_FAILED, { + handleError(simulationResult.actionMessage ?? STATIC_SIMULATION_ERRORS.TRADE_FAILED, { // TODO: update setErrorMessage, setSimulationResult, @@ -246,9 +244,7 @@ export function useTradeSimulation({ const { maxLeverage, ltv } = computeMaxLeverage(selectedBank.info.rawBank, selectedSecondaryBank.info.rawBank); if (!maxLeverage) { - const errorMessage = DYNAMIC_SIMULATION_ERRORS.REPAY_COLLAT_FAILED_CHECK( - selectedSecondaryBank.meta.tokenSymbol - ); + const errorMessage = DYNAMIC_SIMULATION_ERRORS.TRADE_FAILED_CHECK(); setErrorMessage(errorMessage); } else { setMaxLeverage(maxLeverage); diff --git a/apps/marginfi-v2-trading/src/context/TradeProvider.tsx b/apps/marginfi-v2-trading/src/context/TradeProvider.tsx index cb35947122..a7a948edc3 100644 --- a/apps/marginfi-v2-trading/src/context/TradeProvider.tsx +++ b/apps/marginfi-v2-trading/src/context/TradeProvider.tsx @@ -26,6 +26,8 @@ export const TradePovider: React.FC<{ state.initialized, state.hydrationComplete, ]); + + const [fetchPriorityFee] = useUiStore((state) => [state.fetchPriorityFee]); const [isLoggedIn, setIsLoggedIn] = React.useState(false); React.useEffect(() => { diff --git a/packages/marginfi-client-v2/src/models/account/wrapper.ts b/packages/marginfi-client-v2/src/models/account/wrapper.ts index 4d287a949a..54fb359231 100644 --- a/packages/marginfi-client-v2/src/models/account/wrapper.ts +++ b/packages/marginfi-client-v2/src/models/account/wrapper.ts @@ -15,6 +15,7 @@ import { ExtendedV0Transaction, getTxSize, getAccountKeys, + MRGN_TX_TYPES, } from "@mrgnlabs/mrgn-common"; import * as sb from "@switchboard-xyz/on-demand"; import { Address, BorshCoder, Idl, translateAddress } from "@coral-xyz/anchor"; @@ -727,7 +728,11 @@ class MarginfiAccountWrapper { instructions: setupIxs, }).compileToLegacyMessage(); - additionalTxs.push(new VersionedTransaction(message)); + additionalTxs.push( + addTransactionMetadata(new VersionedTransaction(message), { + type: "ATAS" as MRGN_TX_TYPES, + }) + ); } // if crank is needed, add it @@ -741,6 +746,7 @@ class MarginfiAccountWrapper { additionalTxs.push( addTransactionMetadata(new VersionedTransaction(message), { addressLookupTables: feedLuts, + type: "CRANK" as MRGN_TX_TYPES, }) ); } diff --git a/packages/mrgn-common/src/modules/transactions/transaction.types.ts b/packages/mrgn-common/src/modules/transactions/transaction.types.ts index 916e3bc7c7..f716cc4a0b 100644 --- a/packages/mrgn-common/src/modules/transactions/transaction.types.ts +++ b/packages/mrgn-common/src/modules/transactions/transaction.types.ts @@ -1,12 +1,13 @@ import { VersionedTransaction, Transaction, Signer, AddressLookupTableAccount } from "@solana/web3.js"; -export type MRGN_TX_TYPES = "CRANK" | "SETUP" | "BUNDLE_TIP" | "MRGN_ACCOUNT_CREATION"; +export type MRGN_TX_TYPES = "CRANK" | "SETUP" | "BUNDLE_TIP" | "MRGN_ACCOUNT_CREATION" | "ATAS"; export const MRGN_TX_TYPE_TOAST_MAP: Record = { CRANK: "Updating latest prices", SETUP: "Setting up token accounts", BUNDLE_TIP: "Sending bundle tip", MRGN_ACCOUNT_CREATION: "Creating marginfi account", + ATAS: "Creating associated token account", }; export type ExtendedTransaction = Transaction & { diff --git a/packages/mrgn-utils/src/actions/individualFlows.ts b/packages/mrgn-utils/src/actions/individualFlows.ts index 79a91102b4..2717908950 100644 --- a/packages/mrgn-utils/src/actions/individualFlows.ts +++ b/packages/mrgn-utils/src/actions/individualFlows.ts @@ -640,28 +640,9 @@ export async function trade({ try { let sigs: string[] = []; - if (actionTxns?.actionTxn) { - const txns: SolanaTransaction[] = [...actionTxns.additionalTxns, actionTxns.actionTxn]; - if (actionTxns.accountCreationTx) { - if (processOpts.broadcastType !== "RPC") { - await marginfiClient.processTransaction(actionTxns.accountCreationTx, { - ...processOpts, - callback: (index, success, sig, stepsToAdvance) => - success && - multiStepToast.setSuccessAndNext( - stepsToAdvance, - sig, - composeExplorerUrl(sig, processOpts?.broadcastType) - ), - }); // TODO: add sig saving & displaying - } else { - txns.push(actionTxns.accountCreationTx); - } - } - sigs = await marginfiClient.processTransactions( - txns, + [...actionTxns.additionalTxns, actionTxns.actionTxn], { ...processOpts, callback: (index, success, sig, stepsToAdvance) => diff --git a/packages/mrgn-utils/src/errors.ts b/packages/mrgn-utils/src/errors.ts index c6960884b3..c3ac58ad4a 100644 --- a/packages/mrgn-utils/src/errors.ts +++ b/packages/mrgn-utils/src/errors.ts @@ -162,6 +162,11 @@ export const STATIC_SIMULATION_ERRORS: { [key: string]: ActionMessageType } = { actionMethod: "WARNING", code: 124, }, + TRADE_FAILED: { + description: `Unable to execute trade, please try again.`, + isEnabled: false, + code: 142, + }, }; const createRepayCollatFailedCheck = (tokenSymbol?: string): ActionMessageType => ({ @@ -170,6 +175,12 @@ const createRepayCollatFailedCheck = (tokenSymbol?: string): ActionMessageType = code: 141, }); +const createTradeFailedCheck = (): ActionMessageType => ({ + description: `Unable to execute trade, please try again.`, + isEnabled: false, + code: 142, +}); + const createInsufficientBalanceCheck = (tokenSymbol?: string): ActionMessageType => ({ description: `Insufficient ${tokenSymbol} in wallet.`, isEnabled: false, @@ -326,6 +337,7 @@ export const DYNAMIC_SIMULATION_ERRORS = { EXISTING_ISO_BORROW_CHECK: createExistingIsolatedBorrowCheck, INSUFFICIENT_BALANCE_CHECK: createInsufficientBalanceCheck, REPAY_COLLAT_FAILED_CHECK: createRepayCollatFailedCheck, + TRADE_FAILED_CHECK: createTradeFailedCheck, }; const createCustomError = (description: string): ActionMessageType => ({ diff --git a/packages/mrgn-utils/src/toasts/toastUtils.tsx b/packages/mrgn-utils/src/toasts/toastUtils.tsx index 9baa215095..6ceb4f5b22 100644 --- a/packages/mrgn-utils/src/toasts/toastUtils.tsx +++ b/packages/mrgn-utils/src/toasts/toastUtils.tsx @@ -105,6 +105,12 @@ export class MultiStepToastHandle { this._stepsWithStatus[this._stepIndex].status = "error"; this._stepsWithStatus[this._stepIndex].message = message; + for (let i = 0; i < this._stepsWithStatus.length; i++) { + if (this._stepsWithStatus[i].status === "pending") { + this._stepsWithStatus[i].status = "error"; + } + } + for (let i = this._stepIndex + 1; i < this._stepsWithStatus.length; i++) { this._stepsWithStatus[i].status = "canceled"; }