diff --git a/.github/workflows/lighthouse.yml b/.github/workflows/lighthouse.yml index 6f1283687..b40caf9a6 100644 --- a/.github/workflows/lighthouse.yml +++ b/.github/workflows/lighthouse.yml @@ -29,7 +29,7 @@ jobs: continue-on-error: true - name: Archive lighthouse artifacts - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # pin@v2 + uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # pin@v2 # run on lighthouse fail if: always() with: diff --git a/packages/app/src/assets/png/currencies/s1INCH.png b/packages/app/src/assets/png/currencies/s1INCH.png new file mode 100644 index 000000000..f1c7bc0ab Binary files /dev/null and b/packages/app/src/assets/png/currencies/s1INCH.png differ diff --git a/packages/app/src/assets/png/currencies/sALGO.png b/packages/app/src/assets/png/currencies/sALGO.png new file mode 100644 index 000000000..2c1051bb5 Binary files /dev/null and b/packages/app/src/assets/png/currencies/sALGO.png differ diff --git a/packages/app/src/assets/png/currencies/sCELO.png b/packages/app/src/assets/png/currencies/sCELO.png new file mode 100644 index 000000000..8c28fcfb3 Binary files /dev/null and b/packages/app/src/assets/png/currencies/sCELO.png differ diff --git a/packages/app/src/assets/png/currencies/sENJ.png b/packages/app/src/assets/png/currencies/sENJ.png new file mode 100644 index 000000000..b824d9373 Binary files /dev/null and b/packages/app/src/assets/png/currencies/sENJ.png differ diff --git a/packages/app/src/assets/png/currencies/sEOS.png b/packages/app/src/assets/png/currencies/sEOS.png new file mode 100644 index 000000000..45a1f8ba8 Binary files /dev/null and b/packages/app/src/assets/png/currencies/sEOS.png differ diff --git a/packages/app/src/assets/png/currencies/sICP.png b/packages/app/src/assets/png/currencies/sICP.png new file mode 100644 index 000000000..68cc08967 Binary files /dev/null and b/packages/app/src/assets/png/currencies/sICP.png differ diff --git a/packages/app/src/assets/png/currencies/sRUNE.png b/packages/app/src/assets/png/currencies/sRUNE.png new file mode 100644 index 000000000..220288d31 Binary files /dev/null and b/packages/app/src/assets/png/currencies/sRUNE.png differ diff --git a/packages/app/src/assets/png/currencies/sSEI.png b/packages/app/src/assets/png/currencies/sSEI.png new file mode 100644 index 000000000..fb0e16d8c Binary files /dev/null and b/packages/app/src/assets/png/currencies/sSEI.png differ diff --git a/packages/app/src/assets/png/currencies/sUMA.png b/packages/app/src/assets/png/currencies/sUMA.png new file mode 100644 index 000000000..66068a25b Binary files /dev/null and b/packages/app/src/assets/png/currencies/sUMA.png differ diff --git a/packages/app/src/assets/png/currencies/sXLM.png b/packages/app/src/assets/png/currencies/sXLM.png new file mode 100644 index 000000000..ad841b5c8 Binary files /dev/null and b/packages/app/src/assets/png/currencies/sXLM.png differ diff --git a/packages/app/src/assets/png/currencies/sXTZ.png b/packages/app/src/assets/png/currencies/sXTZ.png new file mode 100644 index 000000000..e1f09add3 Binary files /dev/null and b/packages/app/src/assets/png/currencies/sXTZ.png differ diff --git a/packages/app/src/assets/png/currencies/sZEC.png b/packages/app/src/assets/png/currencies/sZEC.png new file mode 100644 index 000000000..a9b3a5d45 Binary files /dev/null and b/packages/app/src/assets/png/currencies/sZEC.png differ diff --git a/packages/app/src/assets/png/currencies/sZRX.png b/packages/app/src/assets/png/currencies/sZRX.png new file mode 100644 index 000000000..364a4d08f Binary files /dev/null and b/packages/app/src/assets/png/currencies/sZRX.png differ diff --git a/packages/app/src/assets/png/currencies/ssthETH.png b/packages/app/src/assets/png/currencies/ssthETH.png new file mode 100644 index 000000000..fc46776d0 Binary files /dev/null and b/packages/app/src/assets/png/currencies/ssthETH.png differ diff --git a/packages/app/src/state/futures/actions.ts b/packages/app/src/state/futures/actions.ts index 1ea6ea470..0902ad404 100644 --- a/packages/app/src/state/futures/actions.ts +++ b/packages/app/src/state/futures/actions.ts @@ -138,7 +138,12 @@ export const cancelDelayedOrder = createAsyncThunk( hash: null, }) ) - const tx = await sdk.futures.cancelDelayedOrder(marketAddress, account, true) + + const tx = await sdk.futures.cancelDelayedOrder({ + marketAddress, + account, + isOffchain: true, + }) await monitorAndAwaitTransaction(dispatch, tx) dispatch(fetchSmartMarginOpenOrders()) } catch (err) { diff --git a/packages/app/src/state/futures/smartMargin/actions.ts b/packages/app/src/state/futures/smartMargin/actions.ts index 38ff437c6..c51af9168 100644 --- a/packages/app/src/state/futures/smartMargin/actions.ts +++ b/packages/app/src/state/futures/smartMargin/actions.ts @@ -376,12 +376,14 @@ export const fetchSmartMarginTradePreview = createAsyncThunk< try { const leverageSide = selectSmartMarginLeverageSide(getState()) - const preview = await sdk.futures.getSmartMarginTradePreview( - account || ZERO_ADDRESS, - params.market.key, - params.market.address, - { ...params, leverageSide, marginDelta } - ) + const preview = await sdk.futures.getSmartMarginTradePreview({ + account: account || ZERO_ADDRESS, + market: { + marketAddress: params.market.address, + marketKey: params.market.key, + }, + tradeParams: { ...params, leverageSide, marginDelta }, + }) // Check the preview hasn't been cleared before query resolves const count = selectSmartMarginPreviewCount(getState()) @@ -958,8 +960,8 @@ export const withdrawSmartMargin = createAsyncThunk( export const approveSmartMargin = createAsyncThunk( 'futures/approveSmartMargin', async (_, { getState, dispatch, extra: { sdk } }) => { - const account = selectSmartMarginAccount(getState()) - if (!account) throw new Error('No smart margin account') + const address = selectSmartMarginAccount(getState()) + if (!address) throw new Error('No smart margin account') try { dispatch( setTransaction({ @@ -968,7 +970,7 @@ export const approveSmartMargin = createAsyncThunk( hash: null, }) ) - const tx = await sdk.futures.approveSmartMarginDeposit(account) + const tx = await sdk.futures.approveSmartMarginDeposit({ address }) await monitorAndAwaitTransaction(dispatch, tx) dispatch(fetchSmartMarginBalanceInfo()) } catch (err) { @@ -1072,13 +1074,13 @@ export const submitSmartMarginOrder = createAsyncThunk o.isStale && o.market.marketKey === marketInfo.marketKey ) - const tx = await sdk.futures.submitSmartMarginOrder( - { address: marketInfo.marketAddress, key: marketInfo.marketKey }, - wallet, - account, - orderInputs, - { cancelPendingReduceOrders: isClosing, cancelExpiredDelayedOrders: !!staleOrder } - ) + const tx = await sdk.futures.submitSmartMarginOrder({ + market: marketInfo, + walletAddress: wallet, + smAddress: account, + order: orderInputs, + options: { cancelPendingReduceOrders: isClosing, cancelExpiredDelayedOrders: !!staleOrder }, + }) await monitorAndAwaitTransaction(dispatch, tx) dispatch(fetchSmartMarginOpenOrders()) dispatch(setOpenModal(null)) @@ -1111,11 +1113,11 @@ export const submitSmartMarginAdjustMargin = createAsyncThunk( 'futures/cancelConditionalOrder', - async (contractOrderId, { getState, dispatch, extra: { sdk } }) => { - const crossMarginAccount = selectSmartMarginAccount(getState()) + async (orderId, { getState, dispatch, extra: { sdk } }) => { + const account = selectSmartMarginAccount(getState()) try { - if (!crossMarginAccount) throw new Error('No smart margin account') + if (!account) throw new Error('No smart margin account') dispatch( setTransaction({ status: TransactionStatus.AwaitingExecution, @@ -1272,8 +1271,11 @@ export const cancelConditionalOrder = createAsyncThunk( 'futures/withdrawAccountKeeperBalance', async (amount, { getState, dispatch, extra: { sdk } }) => { - const crossMarginAccount = selectSmartMarginAccount(getState()) + const address = selectSmartMarginAccount(getState()) try { - if (!crossMarginAccount) throw new Error('No smart margin account') + if (!address) throw new Error('No smart margin account') dispatch( setTransaction({ status: TransactionStatus.AwaitingExecution, @@ -1300,7 +1302,10 @@ export const withdrawAccountKeeperBalance = createAsyncThunk { dispatch( @@ -1353,10 +1362,11 @@ const submitSMTransferTransaction = async ( ) try { + const isPrepareOnly = false const tx = type === 'deposit_smart_margin' - ? await sdk.futures.depositSmartMarginAccount(account, amount) - : await sdk.futures.withdrawSmartMarginAccount(account, amount) + ? await sdk.futures.depositSmartMarginAccount({ address, amount, isPrepareOnly }) + : await sdk.futures.withdrawSmartMarginAccount({ address, amount, isPrepareOnly }) await monitorAndAwaitTransaction(dispatch, tx) dispatch(fetchSmartMarginBalanceInfo()) dispatch(setOpenModal(null)) @@ -1446,7 +1456,11 @@ export const updateStopLossAndTakeProfit = createAsyncThunk { + return { + ...state, + stats: STATS_INITIAL_STATE, + } + }, } export default migrations diff --git a/packages/app/src/state/store.ts b/packages/app/src/state/store.ts index ed5fc2649..e09cecf46 100644 --- a/packages/app/src/state/store.ts +++ b/packages/app/src/state/store.ts @@ -36,7 +36,7 @@ const LOG_REDUX = false const persistConfig = { key: 'root1', storage, - version: 36, + version: 37, blacklist: ['app', 'wallet'], migrate: createMigrate(migrations, { debug: true }), } diff --git a/packages/sdk/src/services/futures.ts b/packages/sdk/src/services/futures.ts index e606ce650..e0debf4ed 100644 --- a/packages/sdk/src/services/futures.ts +++ b/packages/sdk/src/services/futures.ts @@ -15,39 +15,52 @@ import { getContractsByNetwork, getPerpsV2MarketMulticall } from '../contracts' import PerpsMarketABI from '../contracts/abis/PerpsV2Market.json' import SmartMarginAccountABI from '../contracts/abis/SmartMarginAccount.json' import PerpsV2MarketInternal from '../contracts/PerpsV2MarketInternalV2' -import { SmartMarginAccount__factory, PerpsV2Market__factory } from '../contracts/types' +import { PerpsV2Market__factory, SmartMarginAccount__factory } from '../contracts/types' import { IPerpsV2MarketConsolidated } from '../contracts/types/PerpsV2Market' import { IPerpsV2MarketSettings, PerpsV2MarketData } from '../contracts/types/PerpsV2MarketData' import { - querySmartMarginAccounts, + queryFundingRateHistory, queryFuturesTrades, queryIsolatedMarginTransfers, queryPositionHistory, - queryTrades, - queryFundingRateHistory, + querySmartMarginAccounts, querySmartMarginAccountTransfers, + queryTrades, } from '../queries/futures' -import { NetworkId, NetworkOverrideOptions } from '../types/common' +import { NetworkId, NetworkOverrideOptions, TxReturn } from '../types/common' import { + AccountExecuteFunctions, + ApproveSmartMarginDepositParams, + CancelConditionalOrderParams, + CancelDelayedOrderParams, + ChangeMarketBalanceParams, + CloseIsolatedPositionParams, + CloseSmartMarginPositionParams, + ConditionalOrder, + ConditionalOrderTypeEnum, + ExecuteDelayedOffchainOrderParams, + ExecuteDelayedOrderParams, FundingRateInput, FundingRateResponse, FundingRateUpdate, + FuturesMarginType, FuturesMarketAsset, FuturesMarketKey, FuturesVolumes, - MarketClosureReason, - ContractOrderType, - PositionDetail, - PositionSide, - AccountExecuteFunctions, + GetIsolatedMarginTradePreviewParams, + GetSkewAdjustedPriceParams, + GetSmartMarginTradePreviewParams, MarginTransfer, + Market, + MarketClosureReason, MarketWithIdleMargin, - SmartMarginOrderInputs, - ConditionalOrderTypeEnum, - SLTPOrderInputs, - FuturesMarginType, - ConditionalOrder, + ModifyMarketMarginParams, + ModifySmartMarginPositionParams, PerpsMarketV2, + PositionDetail, + SubmitIsolatedMarginOrdersParams, + SubmitSmartMarginOrderParams, + UpdateConditionalOrderParams, } from '../types/futures' import { PricesMap } from '../types/prices' import { calculateTimestampForPeriod } from '../utils/date' @@ -55,21 +68,21 @@ import { calculateFundingRate, calculateVolumes, ConditionalOrderResult, + encodeCloseOffchainOrderParams, encodeConditionalOrderParams, encodeModidyMarketMarginParams, encodeSubmitOffchainOrderParams, - formatV2DelayedOrder, + formatPerpsV2Market, formatPotentialTrade, + formatV2DelayedOrder, getFuturesEndpoint, mapConditionalOrderFromContract, mapFuturesPosition, mapFuturesPositions, mapTrades, - marketsForNetwork, - MarketKeyByAsset, - encodeCloseOffchainOrderParams, marginTypeToSubgraphType, - formatPerpsV2Market, + MarketKeyByAsset, + marketsForNetwork, } from '../utils/futures' import { getFuturesAggregateStats } from '../utils/subgraph' import { getReasonFromCode } from '../utils/synths' @@ -612,36 +625,35 @@ export default class FuturesService { * console.log(preview) * ``` */ - public async getIsolatedMarginTradePreview( - marketAddress: string, - marketKey: FuturesMarketKey, - orderType: ContractOrderType, - inputs: { - sizeDelta: Wei - price: Wei - leverageSide: PositionSide - } - ) { - const market = PerpsV2Market__factory.connect(marketAddress, this.sdk.context.provider) - const details = await market.postTradeDetails( - inputs.sizeDelta.toBN(), - inputs.price.toBN(), + public async getIsolatedMarginTradePreview({ + market, + orderType, + sizeDelta, + leverageSide, + price, + }: GetIsolatedMarginTradePreviewParams) { + const marketContract = PerpsV2Market__factory.connect( + market.marketAddress, + this.sdk.context.provider + ) + const details = await marketContract.postTradeDetails( + sizeDelta.toBN(), + price.toBN(), orderType, this.sdk.context.walletAddress ) - const skewAdjustedPrice = await this.getSkewAdjustedPrice( - inputs.price, - marketAddress, - marketKey - ) + const skewAdjustedPrice = await this.getSkewAdjustedPrice({ + price, + ...market, + }) - return formatPotentialTrade(details, skewAdjustedPrice, inputs.sizeDelta, inputs.leverageSide) + return formatPotentialTrade(details, skewAdjustedPrice, sizeDelta, leverageSide) } /** * @desc Generate a trade preview for a potential trade with a smart margin account. - * @param smartMarginAccount Smart margin account address + * @param account Smart margin account address * @param marketKey Futures market key * @param marketAddress Futures market address * @param tradeParams Object containing size delta, margin delta, order price, and leverage side @@ -663,31 +675,24 @@ export default class FuturesService { * console.log(preview) * ``` */ - public async getSmartMarginTradePreview( - smartMarginAccount: string, - marketKey: FuturesMarketKey, - marketAddress: string, - tradeParams: { - sizeDelta: Wei - marginDelta: Wei - orderPrice: Wei - leverageSide: PositionSide - } - ) { - const marketInternal = this.getInternalFuturesMarket(marketAddress, marketKey) + public async getSmartMarginTradePreview({ + account, + market, + tradeParams, + }: GetSmartMarginTradePreviewParams) { + const marketInternal = this.getInternalFuturesMarket(market) const preview = await marketInternal.getTradePreview( - smartMarginAccount, + account, tradeParams.sizeDelta.toBN(), tradeParams.marginDelta.toBN(), tradeParams.orderPrice.toBN() ) - const skewAdjustedPrice = await this.getSkewAdjustedPrice( - tradeParams.orderPrice, - marketAddress, - marketKey - ) + const skewAdjustedPrice = await this.getSkewAdjustedPrice({ + price: tradeParams.orderPrice, + ...market, + }) return formatPotentialTrade( preview, @@ -815,8 +820,7 @@ export default class FuturesService { if (market) { acc.marketsWithIdleMargin.push({ - marketAddress: market.marketAddress, - marketKey: market.marketKey, + ...market, position: p, }) } @@ -896,15 +900,22 @@ export default class FuturesService { * @param amount Amount to approve * @returns ethers.js TransactionResponse object */ - public async approveSmartMarginDeposit( - smartMarginAddress: string, - amount: BigNumber = BigNumber.from(ethers.constants.MaxUint256) - ) { + public async approveSmartMarginDeposit({ + address, + amount = BigNumber.from(ethers.constants.MaxUint256), + isPrepareOnly, + }: ApproveSmartMarginDepositParams): TxReturn { if (!this.sdk.context.contracts.SUSD) throw new Error(UNSUPPORTED_NETWORK) - return this.sdk.transactions.createContractTxn(this.sdk.context.contracts.SUSD, 'approve', [ - smartMarginAddress, - amount, - ]) + const txn = this.sdk.transactions.prepareContractTxn( + this.sdk.context.contracts.SUSD, + 'approve', + [address, amount] + ) + if (isPrepareOnly) { + return txn as TxReturn + } else { + return this.sdk.transactions.createEVMTxn(txn) as TxReturn + } } /** @@ -913,16 +924,26 @@ export default class FuturesService { * @param amount Amount to deposit * @returns ethers.js TransactionResponse object */ - public async depositSmartMarginAccount(smartMarginAddress: string, amount: Wei) { + public async depositSmartMarginAccount({ + address, + amount, + isPrepareOnly, + }: ChangeMarketBalanceParams): TxReturn { const smartMarginAccountContract = SmartMarginAccount__factory.connect( - smartMarginAddress, + address, this.sdk.context.signer ) - return this.sdk.transactions.createContractTxn(smartMarginAccountContract, 'execute', [ + const txn = this.sdk.transactions.prepareContractTxn(smartMarginAccountContract, 'execute', [ [AccountExecuteFunctions.ACCOUNT_MODIFY_MARGIN], [defaultAbiCoder.encode(['int256'], [amount.toBN()])], ]) + + if (isPrepareOnly) { + return txn as TxReturn + } else { + return this.sdk.transactions.createEVMTxn(txn) as TxReturn + } } /** @@ -931,35 +952,45 @@ export default class FuturesService { * @param amount Amount to withdraw * @returns ethers.js TransactionResponse object */ - public async withdrawSmartMarginAccount(smartMarginAddress: string, amount: Wei) { + public async withdrawSmartMarginAccount({ + address, + amount, + isPrepareOnly, + }: ChangeMarketBalanceParams): TxReturn { const smartMarginAccountContract = SmartMarginAccount__factory.connect( - smartMarginAddress, + address, this.sdk.context.signer ) - const { commands, inputs } = await this.batchIdleMarketMarginSweeps(smartMarginAddress) + const { commands, inputs } = await this.batchIdleMarketMarginSweeps(address) commands.push(AccountExecuteFunctions.ACCOUNT_MODIFY_MARGIN) inputs.push(defaultAbiCoder.encode(['int256'], [amount.neg().toBN()])) - return this.sdk.transactions.createContractTxn(smartMarginAccountContract, 'execute', [ + const txn = this.sdk.transactions.prepareContractTxn(smartMarginAccountContract, 'execute', [ commands, inputs, ]) + + if (isPrepareOnly) { + return txn as TxReturn + } else { + return this.sdk.transactions.createEVMTxn(txn) as TxReturn + } } /** * @desc Modify the margin for a specific market in a smart margin account - * @param smartMarginAddress Smart margin account address - * @param marketAddress Market address + * @param address Smart margin account address + * @param market Market address * @param marginDelta Amount to modify the margin by (can be positive or negative) + * @param isPrepareOnly Boolean describing if the transaction should be prepared only without execute (default: false) * @returns ethers.js TransactionResponse object */ - public async modifySmartMarginMarketMargin( - smartMarginAddress: string, - marketAddress: string, - marginDelta: Wei - ) { + public async modifySmartMarginMarketMargin( + params: ModifyMarketMarginParams + ): TxReturn { + const { address, market, marginDelta, isPrepareOnly } = params const smartMarginAccountContract = SmartMarginAccount__factory.connect( - smartMarginAddress, + address, this.sdk.context.signer ) @@ -967,7 +998,7 @@ export default class FuturesService { const inputs = [] if (marginDelta.gt(0)) { - const freeMargin = await this.getSmartMarginAccountBalance(smartMarginAddress) + const freeMargin = await this.getSmartMarginAccountBalance(address) if (marginDelta.gt(freeMargin)) { // Margin delta bigger than account balance, // need to pull some from the users wallet or idle margin @@ -975,7 +1006,7 @@ export default class FuturesService { commands: sweepCommands, inputs: sweepInputs, idleMargin, - } = await this.batchIdleMarketMarginSweeps(smartMarginAddress) + } = await this.batchIdleMarketMarginSweeps(address) commands.push(...sweepCommands) inputs.push(...sweepInputs) @@ -993,21 +1024,28 @@ export default class FuturesService { } commands.push(AccountExecuteFunctions.PERPS_V2_MODIFY_MARGIN) - inputs.push(encodeModidyMarketMarginParams(marketAddress, marginDelta)) + inputs.push(encodeModidyMarketMarginParams(market, marginDelta)) - return this.sdk.transactions.createContractTxn(smartMarginAccountContract, 'execute', [ + const tx = this.sdk.transactions.prepareContractTxn(smartMarginAccountContract, 'execute', [ commands, inputs, ]) + + if (isPrepareOnly) { + return tx as TxReturn + } else { + return this.sdk.transactions.createEVMTxn(tx) as TxReturn + } } /** * @desc Modify the position size for a specific market in a smart margin account - * @param smartMarginAddress Smart margin account address + * @param address Smart margin account address * @param market Object containing the market key and address * @param sizeDelta Intended size change (positive or negative) * @param desiredFillPrice Desired fill price * @param cancelPendingReduceOrders Boolean describing if pending reduce orders should be cancelled + * @param isPrepareOnly Boolean describing if the transaction should be prepared only without execute (default: false) * @returns ethers.js TransactionResponse object * @example * ```ts @@ -1022,22 +1060,23 @@ export default class FuturesService { * console.log(txn) * ``` */ - public async modifySmartMarginPositionSize( - smartMarginAddress: string, - market: { key: FuturesMarketKey; address: string }, - sizeDelta: Wei, - desiredFillPrice: Wei, - cancelPendingReduceOrders?: boolean - ) { + public async modifySmartMarginPositionSize({ + address, + market, + sizeDelta, + desiredFillPrice, + cancelPendingReduceOrders, + isPrepareOnly, + }: ModifySmartMarginPositionParams): TxReturn { const commands = [] const inputs = [] if (cancelPendingReduceOrders) { - const existingOrders = await this.getConditionalOrders(smartMarginAddress) + const existingOrders = await this.getConditionalOrders(address) existingOrders.forEach((o) => { // Remove all pending reduce only orders if instructed - if (o.marketKey === market.key && o.reduceOnly) { + if (o.marketKey === market.marketKey && o.reduceOnly) { commands.push(AccountExecuteFunctions.GELATO_CANCEL_CONDITIONAL_ORDER) inputs.push(defaultAbiCoder.encode(['uint256'], [o.id])) } @@ -1045,23 +1084,30 @@ export default class FuturesService { } const smartMarginAccountContract = SmartMarginAccount__factory.connect( - smartMarginAddress, + address, this.sdk.context.signer ) commands.push(AccountExecuteFunctions.PERPS_V2_SUBMIT_OFFCHAIN_DELAYED_ORDER) - inputs.push(encodeSubmitOffchainOrderParams(market.address, sizeDelta, desiredFillPrice)) + inputs.push(encodeSubmitOffchainOrderParams(market.marketAddress, sizeDelta, desiredFillPrice)) - return this.sdk.transactions.createContractTxn(smartMarginAccountContract, 'execute', [ + const tx = this.sdk.transactions.prepareContractTxn(smartMarginAccountContract, 'execute', [ commands, inputs, ]) + + if (isPrepareOnly) { + return tx as TxReturn + } else { + return this.sdk.transactions.createEVMTxn(tx) as TxReturn + } } /** * @desc Deposit margin for use in an isolated margin market - * @param marketAddress Market address + * @param address Market address * @param amount Amount to deposit + * @param isPrepareOnly Boolean describing if the transaction should be prepared only without execute (default: false) * @returns ethers.js TransactionResponse object * @example * ```ts @@ -1070,16 +1116,26 @@ export default class FuturesService { * console.log(txn) * ``` */ - public async depositIsolatedMargin(marketAddress: string, amount: Wei) { - const market = PerpsV2Market__factory.connect(marketAddress, this.sdk.context.signer) - const txn = this.sdk.transactions.createContractTxn(market, 'transferMargin', [amount.toBN()]) - return txn + public async depositIsolatedMargin({ + address, + amount, + isPrepareOnly, + }: ChangeMarketBalanceParams): TxReturn { + const market = PerpsV2Market__factory.connect(address, this.sdk.context.signer) + const txn = this.sdk.transactions.prepareContractTxn(market, 'transferMargin', [amount.toBN()]) + + if (isPrepareOnly) { + return txn as TxReturn + } else { + return this.sdk.transactions.createEVMTxn(txn) as TxReturn + } } /** * @desc Withdraw margin from an isolated margin market - * @param marketAddress Market address + * @param address Market address * @param amount Amount to withdraw + * @param isPrepareOnly Boolean describing if the transaction should be prepared only without execute (default: false) * @returns ethers.js TransactionResponse object * @example * ```ts @@ -1088,18 +1144,28 @@ export default class FuturesService { * console.log(txn) * ``` */ - public async withdrawIsolatedMargin(marketAddress: string, amount: Wei) { - const market = PerpsV2Market__factory.connect(marketAddress, this.sdk.context.signer) - const txn = this.sdk.transactions.createContractTxn(market, 'transferMargin', [ + public async withdrawIsolatedMargin({ + address, + amount, + isPrepareOnly, + }: ChangeMarketBalanceParams): TxReturn { + const market = PerpsV2Market__factory.connect(address, this.sdk.context.signer) + const txn = this.sdk.transactions.prepareContractTxn(market, 'transferMargin', [ amount.neg().toBN(), ]) - return txn + + if (isPrepareOnly) { + return txn as TxReturn + } else { + return this.sdk.transactions.createEVMTxn(txn) as TxReturn + } } /** * @desc Close an open position in an isolated margin market - * @param marketAddress Market address + * @param market Market address * @param priceImpactDelta Price impact delta + * @param isPrepareOnly Boolean describing if the transaction should be prepared only without execute (default: false) * @returns ethers.js ContractTransaction object * @example * ```ts @@ -1108,15 +1174,30 @@ export default class FuturesService { * console.log(txn) * ``` */ - public async closeIsolatedPosition(marketAddress: string, priceImpactDelta: Wei) { + public async closeIsolatedPosition({ + marketAddress, + priceImpactDelta, + isPrepareOnly, + }: CloseIsolatedPositionParams): TxReturn { const market = PerpsV2Market__factory.connect(marketAddress, this.sdk.context.signer) - return market.closePositionWithTracking(priceImpactDelta.toBN(), KWENTA_TRACKING_CODE) + + const txn = this.sdk.transactions.prepareContractTxn(market, 'closePositionWithTracking', [ + priceImpactDelta.toBN(), + KWENTA_TRACKING_CODE, + ]) + + if (isPrepareOnly) { + return txn as TxReturn + } else { + return this.sdk.transactions.createEVMTxn(txn) as TxReturn + } } /** * @desc Get idle margin for given wallet address or smart margin account address * @param eoa Wallet address * @param account Smart margin account address + * @param isPrepareOnly Boolean describing if the transaction should be prepared only without execute (default: false) * @returns Total idle margin, idle margin in markets, total wallet balance and the markets with idle margin for the given address(es). * @example * ```ts @@ -1125,18 +1206,25 @@ export default class FuturesService { * console.log(idleMargin) * ``` */ - public async submitIsolatedMarginOrder( - marketAddress: string, - sizeDelta: Wei, - priceImpactDelta: Wei - ) { + public async submitIsolatedMarginOrder({ + marketAddress, + sizeDelta, + priceImpactDelta, + isPrepareOnly, + }: SubmitIsolatedMarginOrdersParams): TxReturn { const market = PerpsV2Market__factory.connect(marketAddress, this.sdk.context.signer) - return this.sdk.transactions.createContractTxn( + const txn = this.sdk.transactions.prepareContractTxn( market, 'submitOffchainDelayedOrderWithTracking', [sizeDelta.toBN(), priceImpactDelta.toBN(), KWENTA_TRACKING_CODE] ) + + if (isPrepareOnly) { + return txn as TxReturn + } else { + return this.sdk.transactions.createEVMTxn(txn) as TxReturn + } } /** @@ -1144,6 +1232,7 @@ export default class FuturesService { * @param marketAddress Market address * @param account Wallet address * @param isOffchain Boolean describing if the order is offchain or not + * @param isPrepareOnly Boolean describing if the transaction should be prepared only without execute (default: false) * @returns ethers.js ContractTransaction object * @example * ```ts @@ -1152,11 +1241,25 @@ export default class FuturesService { * console.log(txn) * ``` */ - public async cancelDelayedOrder(marketAddress: string, account: string, isOffchain: boolean) { + public async cancelDelayedOrder({ + marketAddress, + account, + isOffchain, + isPrepareOnly, + }: CancelDelayedOrderParams): TxReturn { const market = PerpsV2Market__factory.connect(marketAddress, this.sdk.context.signer) - return isOffchain - ? market.cancelOffchainDelayedOrder(account) - : market.cancelDelayedOrder(account) + + const txn = this.sdk.transactions.prepareContractTxn( + market, + isOffchain ? 'cancelOffchainDelayedOrder' : 'cancelDelayedOrder', + [account] + ) + + if (isPrepareOnly) { + return txn as TxReturn + } else { + return this.sdk.transactions.createEVMTxn(txn) as TxReturn + } } /** @@ -1171,15 +1274,26 @@ export default class FuturesService { * console.log(txn) * ``` */ - public async executeDelayedOrder(marketAddress: string, account: string) { + public async executeDelayedOrder({ + marketAddress, + account, + isPrepareOnly, + }: ExecuteDelayedOrderParams): TxReturn { const market = PerpsV2Market__factory.connect(marketAddress, this.sdk.context.signer) - return market.executeDelayedOrder(account) + + const txn = this.sdk.transactions.prepareContractTxn(market, 'executeDelayedOrder', [account]) + + if (isPrepareOnly) { + return txn as TxReturn + } else { + return this.sdk.transactions.createEVMTxn(txn) as TxReturn + } } /** * @desc Executes a pending delayed order, for the given market and account - * @param marketKey Futures market key - * @param marketAddress Market address + * @param key Futures market key + * @param address Market address * @param account Wallet address * @returns ethers.js ContractTransaction object * @example @@ -1189,20 +1303,32 @@ export default class FuturesService { * console.log(txn) * ``` */ - public async executeDelayedOffchainOrder( - marketKey: FuturesMarketKey, - marketAddress: string, - account: string - ) { + public async executeDelayedOffchainOrder({ + marketKey: key, + marketAddress: address, + account, + isPrepareOnly, + }: ExecuteDelayedOffchainOrderParams): TxReturn { const { Pyth } = this.sdk.context.contracts - const market = PerpsV2Market__factory.connect(marketAddress, this.sdk.context.signer) + const market = PerpsV2Market__factory.connect(address, this.sdk.context.signer) if (!Pyth) throw new Error(UNSUPPORTED_NETWORK) // get price update data - const priceUpdateData = await this.sdk.prices.getPythPriceUpdateData(marketKey) + const priceUpdateData = await this.sdk.prices.getPythPriceUpdateData(key) const updateFee = await Pyth.getUpdateFee(priceUpdateData) - return market.executeOffchainDelayedOrder(account, priceUpdateData, { value: updateFee }) + const txn = this.sdk.transactions.prepareContractTxn( + market, + 'executeOffchainDelayedOrder', + [account, priceUpdateData], + { value: updateFee } + ) + + if (isPrepareOnly) { + return txn as TxReturn + } else { + return this.sdk.transactions.createEVMTxn(txn) as TxReturn + } } /** @@ -1236,31 +1362,31 @@ export default class FuturesService { * console.log(idleMargin) * ``` */ - public async submitSmartMarginOrder( - market: { key: FuturesMarketKey; address: string }, - walletAddress: string, - smartMarginAddress: string, - order: SmartMarginOrderInputs, - options?: { - cancelPendingReduceOrders?: boolean - cancelExpiredDelayedOrders?: boolean - } - ) { + public async submitSmartMarginOrder({ + market, + walletAddress, + smAddress, + order, + options = {}, + isPrepareOnly, + }: SubmitSmartMarginOrderParams): TxReturn { + const { cancelExpiredDelayedOrders, cancelPendingReduceOrders } = options + const smartMarginAccountContract = SmartMarginAccount__factory.connect( - smartMarginAddress, + smAddress, this.sdk.context.signer ) const commands = [] const inputs = [] - if (options?.cancelExpiredDelayedOrders) { + if (cancelExpiredDelayedOrders) { commands.push(AccountExecuteFunctions.PERPS_V2_CANCEL_OFFCHAIN_DELAYED_ORDER) - inputs.push(defaultAbiCoder.encode(['address'], [market.address])) + inputs.push(defaultAbiCoder.encode(['address'], [market.marketAddress])) } const [idleMargin, freeMargin] = await Promise.all([ - this.getIdleMargin(walletAddress, smartMarginAddress), - this.getSmartMarginAccountBalance(smartMarginAddress), + this.getIdleMargin(walletAddress, smAddress), + this.getSmartMarginAccountBalance(smAddress), ]) // Sweep idle margin from other markets to account @@ -1286,15 +1412,19 @@ export default class FuturesService { if (order.sizeDelta.abs().gt(0)) { if (!order.conditionalOrderInputs) { commands.push(AccountExecuteFunctions.PERPS_V2_MODIFY_MARGIN) - inputs.push(encodeModidyMarketMarginParams(market.address, order.marginDelta)) + inputs.push(encodeModidyMarketMarginParams(market.marketAddress, order.marginDelta)) commands.push(AccountExecuteFunctions.PERPS_V2_SUBMIT_OFFCHAIN_DELAYED_ORDER) inputs.push( - encodeSubmitOffchainOrderParams(market.address, order.sizeDelta, order.desiredFillPrice) + encodeSubmitOffchainOrderParams( + market.marketAddress, + order.sizeDelta, + order.desiredFillPrice + ) ) } else { commands.push(AccountExecuteFunctions.GELATO_PLACE_CONDITIONAL_ORDER) const params = encodeConditionalOrderParams( - market.key, + market.marketKey, { marginDelta: order.marginDelta, sizeDelta: order.sizeDelta, @@ -1312,7 +1442,7 @@ export default class FuturesService { if (order.takeProfit) { commands.push(AccountExecuteFunctions.GELATO_PLACE_CONDITIONAL_ORDER) const encodedParams = encodeConditionalOrderParams( - market.key, + market.marketKey, { marginDelta: wei(0), sizeDelta: order.takeProfit.sizeDelta, @@ -1328,7 +1458,7 @@ export default class FuturesService { if (order.stopLoss) { commands.push(AccountExecuteFunctions.GELATO_PLACE_CONDITIONAL_ORDER) const encodedParams = encodeConditionalOrderParams( - market.key, + market.marketKey, { marginDelta: wei(0), sizeDelta: order.stopLoss.sizeDelta, @@ -1342,12 +1472,12 @@ export default class FuturesService { } } - const existingOrders = await this.getConditionalOrders(smartMarginAddress) + const existingOrders = await this.getConditionalOrders(smAddress) const existingOrdersForMarket = existingOrders.filter( - (o) => o.marketKey === market.key && o.reduceOnly + (o) => o.marketKey === market.marketKey && o.reduceOnly ) - if (options?.cancelPendingReduceOrders) { + if (cancelPendingReduceOrders) { // Remove all pending reduce only orders if instructed existingOrdersForMarket.forEach((o) => { commands.push(AccountExecuteFunctions.GELATO_CANCEL_CONDITIONAL_ORDER) @@ -1380,18 +1510,24 @@ export default class FuturesService { } } - return this.sdk.transactions.createContractTxn( + const txn = this.sdk.transactions.prepareContractTxn( smartMarginAccountContract, 'execute', [commands, inputs], { value: order.keeperEthDeposit?.toBN() ?? '0' } ) + + if (isPrepareOnly) { + return txn as TxReturn + } else { + return this.sdk.transactions.createEVMTxn(txn) as TxReturn + } } /** * @desc Closes a smart margin position * @param market Object containing market address and key - * @param smartMarginAddress Smart margin account address + * @param address Smart margin account address * @param desiredFillPrice Desired fill price * @returns ethers.js TransactionResponse object * @example @@ -1405,40 +1541,47 @@ export default class FuturesService { * console.log(txn) * ``` */ - public async closeSmartMarginPosition( - market: { address: string; key: FuturesMarketKey }, - smartMarginAddress: string, - desiredFillPrice: Wei - ) { + public async closeSmartMarginPosition({ + market, + address, + desiredFillPrice, + isPrepareOnly, + }: CloseSmartMarginPositionParams): TxReturn { const smartMarginAccountContract = SmartMarginAccount__factory.connect( - smartMarginAddress, + address, this.sdk.context.signer ) const commands = [] const inputs = [] - const existingOrders = await this.getConditionalOrders(smartMarginAddress) + const existingOrders = await this.getConditionalOrders(address) existingOrders.forEach((o) => { - if (o.marketKey === market.key && o.reduceOnly) { + if (o.marketKey === market.marketKey && o.reduceOnly) { commands.push(AccountExecuteFunctions.GELATO_CANCEL_CONDITIONAL_ORDER) inputs.push(defaultAbiCoder.encode(['uint256'], [o.id])) } }) commands.push(AccountExecuteFunctions.PERPS_V2_SUBMIT_CLOSE_OFFCHAIN_DELAYED_ORDER) - inputs.push(encodeCloseOffchainOrderParams(market.address, desiredFillPrice)) + inputs.push(encodeCloseOffchainOrderParams(market.marketAddress, desiredFillPrice)) - return this.sdk.transactions.createContractTxn(smartMarginAccountContract, 'execute', [ + const txn = this.sdk.transactions.prepareContractTxn(smartMarginAccountContract, 'execute', [ commands, inputs, ]) + + if (isPrepareOnly) { + return txn as TxReturn + } else { + return this.sdk.transactions.createEVMTxn(txn) as TxReturn + } } /** * @desc Cancels a conditional order - * @param smartMarginAddress Smart margin account address + * @param account Smart margin account address * @param orderId Conditional order id * @returns ethers.js TransactionResponse object * @example @@ -1448,21 +1591,31 @@ export default class FuturesService { * console.log(txn) * ``` */ - public async cancelConditionalOrder(smartMarginAddress: string, orderId: number) { + public async cancelConditionalOrder({ + account, + orderId, + isPrepareOnly, + }: CancelConditionalOrderParams): TxReturn { const smartMarginAccountContract = SmartMarginAccount__factory.connect( - smartMarginAddress, + account, this.sdk.context.signer ) - return this.sdk.transactions.createContractTxn(smartMarginAccountContract, 'execute', [ + const txn = this.sdk.transactions.prepareContractTxn(smartMarginAccountContract, 'execute', [ [AccountExecuteFunctions.GELATO_CANCEL_CONDITIONAL_ORDER], [defaultAbiCoder.encode(['uint256'], [orderId])], ]) + + if (isPrepareOnly) { + return txn as TxReturn + } else { + return this.sdk.transactions.createEVMTxn(txn) as TxReturn + } } /** * @desc Withdraws given smarkt margin account's keeper balance - * @param smartMarginAddress Smart margin account address + * @param account Smart margin account address * @param amount Amount to withdraw * @returns ethers.js TransactionResponse object * @example @@ -1472,22 +1625,32 @@ export default class FuturesService { * console.log(txn) * ``` */ - public async withdrawAccountKeeperBalance(smartMarginAddress: string, amount: Wei) { + public async withdrawAccountKeeperBalance({ + address, + amount, + isPrepareOnly, + }: ChangeMarketBalanceParams): TxReturn { const smartMarginAccountContract = SmartMarginAccount__factory.connect( - smartMarginAddress, + address, this.sdk.context.signer ) - return this.sdk.transactions.createContractTxn(smartMarginAccountContract, 'execute', [ + const txn = this.sdk.transactions.prepareContractTxn(smartMarginAccountContract, 'execute', [ [AccountExecuteFunctions.ACCOUNT_WITHDRAW_ETH], [defaultAbiCoder.encode(['uint256'], [amount.toBN()])], ]) + + if (isPrepareOnly) { + return txn as TxReturn + } else { + return this.sdk.transactions.createEVMTxn(txn) as TxReturn + } } /** * @desc Updates the stop loss and take profit values for a given smart margin account, based on the specified market. * @param marketKey Market key - * @param smartMarginAddress Smart margin account address + * @param account Smart margin account address * @param params Object containing the stop loss and take profit values * @returns ethers.js TransactionResponse object * @example @@ -1515,20 +1678,21 @@ export default class FuturesService { * console.log(txn) * ``` */ - public async updateStopLossAndTakeProfit( - marketKey: FuturesMarketKey, - smartMarginAddress: string, - params: SLTPOrderInputs - ) { + public async updateStopLossAndTakeProfit({ + marketKey, + account, + params, + isPrepareOnly, + }: UpdateConditionalOrderParams): TxReturn { const smartMarginAccountContract = SmartMarginAccount__factory.connect( - smartMarginAddress, + account, this.sdk.context.signer ) const commands = [] const inputs = [] if (params.takeProfit || params.stopLoss) { - const existingOrders = await this.getConditionalOrders(smartMarginAddress) + const existingOrders = await this.getConditionalOrders(account) const existingStopLosses: ConditionalOrder[] = [] const existingTakeProfits: ConditionalOrder[] = [] @@ -1591,19 +1755,25 @@ export default class FuturesService { } } - return this.sdk.transactions.createContractTxn( + const txn = this.sdk.transactions.prepareContractTxn( smartMarginAccountContract, 'execute', [commands, inputs], { value: params.keeperEthDeposit?.toBN() ?? '0' } ) + + if (isPrepareOnly) { + return txn as TxReturn + } else { + return this.sdk.transactions.createEVMTxn(txn) as TxReturn + } } /** * @desc Adjusts the given price, based on the current market skew. * @param price Price to adjust - * @param marketAddress Market address - * @param marketKey Market key + * @param address Market address + * @param key Market key * @returns Adjusted price, based on the given market's skew. * @example * ```ts @@ -1612,14 +1782,18 @@ export default class FuturesService { * console.log(adjustedPrice) * ``` */ - public async getSkewAdjustedPrice(price: Wei, marketAddress: string, marketKey: string) { - const marketContract = new EthCallContract(marketAddress, PerpsMarketABI) + public async getSkewAdjustedPrice({ + price, + marketAddress: address, + marketKey: key, + }: GetSkewAdjustedPriceParams) { + const marketContract = new EthCallContract(address, PerpsMarketABI) const { PerpsV2MarketSettings } = this.sdk.context.multicallContracts if (!PerpsV2MarketSettings) throw new Error(UNSUPPORTED_NETWORK) const [marketSkew, skewScale] = await this.sdk.context.multicallProvider.all([ marketContract.marketSkew(), - PerpsV2MarketSettings.skewScale(formatBytes32String(marketKey)), + PerpsV2MarketSettings.skewScale(formatBytes32String(key)), ]) const skewWei = wei(marketSkew) @@ -1630,19 +1804,14 @@ export default class FuturesService { // Private methods - private getInternalFuturesMarket(marketAddress: string, marketKey: FuturesMarketKey) { - let market = this.internalFuturesMarkets[this.sdk.context.networkId]?.[marketAddress] + private getInternalFuturesMarket({ marketKey: key, marketAddress: address }: Market) { + let market = this.internalFuturesMarkets[this.sdk.context.networkId]?.[address] if (market) return market - market = new PerpsV2MarketInternal( - this.sdk, - this.sdk.context.provider, - marketKey, - marketAddress - ) + market = new PerpsV2MarketInternal(this.sdk, this.sdk.context.provider, key, address) this.internalFuturesMarkets = { [this.sdk.context.networkId]: { ...this.internalFuturesMarkets[this.sdk.context.networkId], - [marketAddress]: market, + [address]: market, }, } diff --git a/packages/sdk/src/services/transactions.ts b/packages/sdk/src/services/transactions.ts index 752b1a2d6..9eca8f800 100644 --- a/packages/sdk/src/services/transactions.ts +++ b/packages/sdk/src/services/transactions.ts @@ -12,6 +12,7 @@ import { ContractName } from '../contracts' import { NetworkIdByName } from '../types/common' import { Emitter } from '../types/transactions' import { createEmitter, getRevertReason } from '../utils/transactions' +import { TransactionRequest } from '@ethersproject/providers' const OVMGasPriceOracle = getContractFactory('OVM_GasPriceOracle').attach( predeploys.OVM_GasPriceOracle @@ -92,6 +93,20 @@ export default class TransactionsService { return this.createEVMTxn(txn, options) } + public prepareContractTxn( + contract: ethers.Contract, + method: string, + args: any[], + txnOptions: Partial = {} + ): TransactionRequest { + return { + to: contract.address, + data: contract.interface.encodeFunctionData(method, args), + value: BigNumber.from(0), + ...txnOptions, + } + } + public async createEVMTxn(txn: ethers.providers.TransactionRequest, options?: any) { const execTxn = clone(txn) diff --git a/packages/sdk/src/types/common.ts b/packages/sdk/src/types/common.ts index b3ef84fd6..e08e4d20d 100644 --- a/packages/sdk/src/types/common.ts +++ b/packages/sdk/src/types/common.ts @@ -1,3 +1,4 @@ +import { TransactionRequest, TransactionResponse } from '@ethersproject/providers' import { ethers } from 'ethers' export type PriceServer = 'KWENTA' | 'PYTH' @@ -37,3 +38,7 @@ export const NetworkNameById = { } as const export type CurrencyKey = string + +export type TxReturn = Promise< + PrepareOnly extends true ? TransactionRequest : TransactionResponse +> diff --git a/packages/sdk/src/types/futures.ts b/packages/sdk/src/types/futures.ts index 795bd60bc..8550c8c10 100644 --- a/packages/sdk/src/types/futures.ts +++ b/packages/sdk/src/types/futures.ts @@ -518,9 +518,12 @@ export type MarginTransfer = { asset?: FuturesMarketAsset } -export type MarketWithIdleMargin = { +export type Market = { marketAddress: string marketKey: FuturesMarketKey +} + +export type MarketWithIdleMargin = Market & { position: PerpsV2Position } @@ -582,3 +585,109 @@ export type PerpsV3SubgraphMarket = { makerFee: string takerFee: string } + +export type PrepareTxParams = { + isPrepareOnly?: T +} + +export type ApproveSmartMarginDepositParams = PrepareTxParams & { + address: string + amount?: BigNumber +} + +export type ChangeMarketBalanceParams = PrepareTxParams & { + address: string + amount: Wei +} + +export type ModifyMarketMarginParams = PrepareTxParams & { + address: string + market: string + marginDelta: Wei +} + +export type ModifySmartMarginPositionParams = PrepareTxParams & { + address: string + market: Market + sizeDelta: Wei + desiredFillPrice: Wei + cancelPendingReduceOrders?: boolean +} + +export type CloseIsolatedPositionParams = PrepareTxParams & { + marketAddress: string + priceImpactDelta: Wei +} + +export type SubmitIsolatedMarginOrdersParams = PrepareTxParams & { + marketAddress: string + sizeDelta: Wei + priceImpactDelta: Wei +} + +export type CancelDelayedOrderParams = PrepareTxParams & { + marketAddress: string + account: string + isOffchain: boolean +} + +export type ExecuteDelayedOrderParams = PrepareTxParams & { + marketAddress: string + account: string +} + +export type ExecuteDelayedOffchainOrderParams = PrepareTxParams & + Market & { + account: string + } + +export type SubmitSmartMarginOrderParams = PrepareTxParams & { + market: Market + walletAddress: string + smAddress: string + order: SmartMarginOrderInputs + options?: { + cancelPendingReduceOrders?: boolean + cancelExpiredDelayedOrders?: boolean + } +} + +export type CloseSmartMarginPositionParams = PrepareTxParams & { + market: Market + address: string + desiredFillPrice: Wei +} + +export type CancelConditionalOrderParams = PrepareTxParams & { + account: string + orderId: number +} + +export type UpdateConditionalOrderParams = PrepareTxParams & { + marketKey: FuturesMarketKey + account: string + params: SLTPOrderInputs +} + +export type GetSkewAdjustedPriceParams = Market & { + price: Wei +} + +export type GetIsolatedMarginTradePreviewParams = { + market: Market + orderType: ContractOrderType + sizeDelta: Wei + price: Wei + leverageSide: PositionSide +} + +export type GetSmartMarginTradePreviewParams = { + market: Market + account: string + tradeParams: { + sizeDelta: Wei + marginDelta: Wei + orderPrice: Wei + leverageSide: PositionSide + } +}