UNPKG

@parifi/synthetix-sdk-ts

Version:

A Typescript SDK for interactions with the Synthetix protocol

739 lines (730 loc) 31.5 kB
// src/spot/index.ts import { encodeFunctionData as encodeFunctionData2, erc20Abi, getContract, maxUint256 } from "viem"; // src/constants/common.ts import { zeroAddress } from "viem"; var ZERO_ADDRESS = zeroAddress; var DISABLED_MARKETS = { 84532: [3, 6300], 8453: [6300] }; var CUSTOM_DECIMALS = { [421614 /* ARBITUM_SEPOLIA */]: { 2: 6, USDC: 6 }, [42161 /* ARBITRUM */]: { 2: 6, USDC: 6 }, [84532 /* BASE_SEPOLIA */]: { 1: 6, USDC: 6 }, [8453 /* BASE */]: { 1: 6, USDC: 6 } }; // src/utils/common.ts import { formatEther, maxUint128, parseEther } from "viem"; import { mainnet, base, optimism, arbitrum, baseSepolia, arbitrumSepolia } from "viem/chains"; // src/contracts/addreses/zap.ts import { zeroAddress as zeroAddress2 } from "viem"; var ZAP_BY_CHAIN = { [8453 /* BASE */]: "0x459Bbb4231f0a606DC514BacD5712A5922CBe6c8", [84532 /* BASE_SEPOLIA */]: zeroAddress2, [42161 /* ARBITRUM */]: "0x9ec181B2E69fB36C50031F0c87Bc0749b766A9f4", [421614 /* ARBITUM_SEPOLIA */]: "0xb569ed692206a1d73996088ae646333b1d59d9c5" }; var SYNTHETIX_ZAP = { [84532 /* BASE_SEPOLIA */]: "0xA6Fab50eB36F3eB2118eE2f4C12C968F8608bbc9", [8453 /* BASE */]: "0xA6Fab50eB36F3eB2118eE2f4C12C968F8608bbc9" }; // src/utils/common.ts function convertWeiToEther(amountInWei) { if (amountInWei == void 0) { throw new Error("Invalid amount received during conversion: undefined"); } if (typeof amountInWei == "bigint") { return Number(formatEther(amountInWei)); } else if (typeof amountInWei == "string") { return Number(formatEther(BigInt(amountInWei))); } else { throw new Error("Expected string or bigint for conversion"); } } function convertEtherToWei(amount) { if (amount == void 0) { throw new Error("Invalid amount received during conversion: undefined"); } if (typeof amount == "number") { return parseEther(amount.toString()); } else if (typeof amount == "string") { return parseEther(amount); } else { throw new Error("Expected string or bigint for conversion"); } } function sleep(seconds) { return new Promise((resolve) => setTimeout(resolve, seconds * 1e3)); } // src/utils/index.ts import { decodeAbiParameters, decodeErrorResult, decodeFunctionResult, encodeAbiParameters, encodeFunctionData, parseAbiParameters } from "viem"; // src/contracts/addreses/oracleProxy.ts var ORACLE_PROXY_BY_CHAIN = { [421614 /* ARBITUM_SEPOLIA */]: "0x59d6ec32e05900949d7fff679a4adc7f94f0208c", [42161 /* ARBITRUM */]: "0xe87ceB87b63267ef925E2897B629052eb815bB7d", [8453 /* BASE */]: "0xa03A0Be2f3B85B76765A442683d62E992972d816", [84532 /* BASE_SEPOLIA */]: "0x4Bc47c016EE6Ead253152CCfe6427D0bC06F544c" }; // src/utils/market.ts import { encodeAbiParameters as encodeAbiParameters2, parseUnits } from "viem"; var Market = class { constructor(synthetixSdk) { this.disabledMarkets = []; this.sdk = synthetixSdk; this.marketsById = /* @__PURE__ */ new Map(); this.marketsByName = /* @__PURE__ */ new Map(); this.marketsBySymbol = /* @__PURE__ */ new Map(); if (synthetixSdk.rpcConfig.chainId in DISABLED_MARKETS) { this.disabledMarkets = DISABLED_MARKETS[synthetixSdk.rpcConfig.chainId]; } } /** * Look up the market_id and market_name for a market. If only one is provided, * the other is resolved. If both are provided, they are checked for consistency. * @param marketIdOrName Id or name of the market to resolve */ async resolveMarket(marketIdOrName) { if (!this.sdk.resolveMarketNames && typeof marketIdOrName === "number") { console.log("Resolve markets set to false. Returning market id without validating..."); return { resolvedMarketName: "Unresolved Market", resolvedMarketId: Number(marketIdOrName) }; } const market = await this.getMarket(marketIdOrName); if (!market?.marketName || market?.marketId === void 0) throw new Error(`Market not found for ${marketIdOrName}`); return { resolvedMarketName: market.marketName, resolvedMarketId: market.marketId }; } /** * Format the size of a synth for an order. This is used for synths whose base asset * does not use 18 decimals. For example, USDC uses 6 decimals, so we need to handle size * differently from other assets. * @param size The size as an ether value (e.g. 100). * @param marketId The id of the market. * @returns The formatted size in wei. (e.g. 100 = 100000000000000000000) */ async formatSize(size, marketId) { return parseUnits(size.toString(), CUSTOM_DECIMALS[this.sdk.rpcConfig.chainId][marketId] || 18); } async prepareOracleCallsWithPriceId(priceFeedIds) { if (!priceFeedIds.length) { return []; } const stalenessTolerance = 30n; const updateData = await this.sdk.pyth.getPriceFeedsUpdateData(priceFeedIds); const signedRequiredData = encodeAbiParameters2( [ { type: "uint8", name: "updateType" }, { type: "uint64", name: "stalenessTolerance" }, { type: "bytes32[]", name: "priceIds" }, { type: "bytes[]", name: "updateData" } ], [1, stalenessTolerance, priceFeedIds, updateData] ); const pythWrapper = await this.sdk.contracts.getPythErc7412WrapperInstance(); const dataVerificationTx = this.sdk.utils.generateDataVerificationTx(pythWrapper.address, signedRequiredData); return [{ ...dataVerificationTx, value: 0n, requireSuccess: false }]; } /** * Prepare a call to the external node with oracle updates for the specified market names. * The result can be passed as the first argument to a multicall function to improve performance * of ERC-7412 calls. If no market names are provided, all markets are fetched. This is useful for * read functions since the user does not pay gas for those oracle calls, and reduces RPC calls and * runtime. * @param {number[]} marketIds An array of market ids to fetch prices for. If not provided, all markets are fetched * @returns {Promise<Call3Value[]>} objects representing the target contract, call data, value, requireSuccess flag and other necessary details for executing the function in the blockchain. */ async prepareOracleCall(marketIds = []) { let priceFeedIds = []; if (marketIds.length != 0) { const marketSymbols = []; marketIds.forEach((marketId) => { const marketSymbol = this.marketsById.get(marketId)?.symbol; if (!marketSymbol) return; marketSymbols.push(marketSymbol); }); marketSymbols.forEach((marketSymbol) => { const feedId = this.sdk.pyth.priceFeedIds.get(marketSymbol); if (!feedId) return; priceFeedIds.push(feedId); }); } else { priceFeedIds = Array.from(this.sdk.pyth.priceFeedIds.values()); } return this.prepareOracleCallsWithPriceId(priceFeedIds); } async getMarket(marketIdOrName) { throw new Error("Method not implemented. " + marketIdOrName); } }; // src/spot/index.ts var Spot = class extends Market { constructor(synthetixSdk) { super(synthetixSdk); this.asyncOrderEnabled = false; this.disabledMarkets = []; this.sdk = synthetixSdk; this.accountIds = []; if (synthetixSdk.rpcConfig.chainId == 42161 || synthetixSdk.rpcConfig.chainId == 421614) { this.asyncOrderEnabled = true; } } async initSpot() { await this.getMarkets(); } async getMarket(marketIdOrName) { const market = this.marketsById.get(Number(marketIdOrName)) ?? this.marketsByName.get(marketIdOrName); if (!market) { this.sdk.logger.warn(`Spot market ${marketIdOrName} not available. Available markets: ${this.marketsById}`); throw new Error(`Invalid market id or name: ${marketIdOrName}`); } return market; } /** * Fetches contracts and metadata about all spot markets on the network. This includes * the market id, synth name, contract address, and the underlying synth contract. Each * synth is an ERC20 token, so these contracts can be used for transfers and allowances. * The metadata is also used to simplify interactions in the SDK by mapping market ids * and names to their metadata * For example: * sdk.spot.wrap(100, market_name='sUSDC', submit=True) * This will look up the market id for the sUSDC market and use that to wrap 100 USDC into sUSDC. * The market metadata is returned from the method as a mapping object of two dictionaries/records. * The first is keyed by ``marketsById`` and the second is keyed by ``marketsByName`` * For example: sdk.spot.marketsByName * Response: { 'sUSD' => { marketId: 0, marketName: 'sUSD', contractAddress: '0x682f0d17feDC62b2a0B91f8992243Bf44cAfeaaE' }, * Example: sdk.spot.marketsById * Response: { 0 => { marketId: 0, marketName: 'sUSD', contractAddress: '0x682f0d17feDC62b2a0B91f8992243Bf44cAfeaaE' },... */ async getMarkets() { const usdProxy = await this.sdk.contracts.getUSDProxyInstance(); this.marketsById.set(0, { marketId: 0, marketName: "sUSD", symbol: "sUSD", contractAddress: usdProxy.address }); this.marketsByName.set("sUSD", { marketId: 0, marketName: "sUSD", symbol: "sUSD", contractAddress: usdProxy.address }); const spotProxy = await this.sdk.contracts.getSpotMarketProxyInstance(); const finalSynths = []; const MAX_MARKETS = 100; const ITEMS_PER_ITER = 5; for (let index = 0; index < MAX_MARKETS; index += ITEMS_PER_ITER) { const argsList = Array.from({ length: ITEMS_PER_ITER }, (_, i) => index + i); const synthAddresses = await this.sdk.utils.multicallErc7412({ contractAddress: spotProxy.address, abi: spotProxy.abi, functionName: "getSynth", args: argsList }); synthAddresses.forEach((synthAddress, idx) => { const isMarketDisabled = this.disabledMarkets.includes(argsList[idx]); if (synthAddress != ZERO_ADDRESS && !isMarketDisabled) { finalSynths.push({ marketId: argsList[idx], contractAddress: synthAddress }); } }); if (synthAddresses.at(-1) == ZERO_ADDRESS) { break; } } let settlementStrategies; if (this.asyncOrderEnabled) { } else { this.sdk.logger.info("Async orders not enabled on network ", this.sdk.rpcConfig.chainId); } const multicallInputs = []; finalSynths.forEach((synth) => { multicallInputs.push({ address: synth.contractAddress, abi: erc20Abi, functionName: "symbol" }); }); const synthSymbols = await this.sdk.publicClient.multicall({ contracts: multicallInputs }); finalSynths.forEach((synth, idx) => { if (synthSymbols.at(idx)?.status == "success") { const name = synthSymbols.at(idx)?.result; synth.marketName = name; synth.symbol = name.slice(1); } }); finalSynths.forEach((synth) => { if (settlementStrategies != void 0 && settlementStrategies.length > 0) { const strategy = settlementStrategies.find((strategy2) => strategy2.marketId == synth.marketId); synth.settlementStrategy = strategy; } this.marketsById.set(synth.marketId, synth); this.marketsByName.set(synth.marketName ?? "INVALID", synth); }); return { marketsById: this.marketsById, marketsByName: this.marketsByName }; } /** * @name getSynthContract * @description This function retrieves the Synth contract for a given market based on its ID or name. It returns the Synth contract instance. * @param {MarketIdOrName} marketIdOrName - The unique identifier or name of the market. * @returns {Contract<Synth>} - An instance of the Synth contract associated with the provided market. */ async getSynthContract(marketIdOrName) { const { resolvedMarketId } = await this.resolveMarket(marketIdOrName); const contractAddress = this.marketsById.get(resolvedMarketId)?.contractAddress; if (contractAddress == void 0) { throw new Error("Invalid market - contractAddress"); } const synthContract = getContract({ address: contractAddress, abi: erc20Abi, client: this.sdk.publicClient }); return synthContract; } /** * Get the balance of a spot synth. Provide either a ``marketId`` or ``marketName`` * to choose the synth. * @param {string} address The address to check the balance of. If not provided, the * current account will be used. * @param {MarketIdOrName} marketIdOrName - The unique identifier or name of the market. * @returns {number} The balance of the synth in ether. */ async getBalance(address = this.sdk.accountAddress, marketIdOrName) { const synthContract = await this.getSynthContract(marketIdOrName); const balance = await synthContract.read.balanceOf([address]); return convertWeiToEther(balance); } /** * Get the allowance for a ``target_address`` to transfer from ``address``. Provide either * a ``marketId`` or ``marketName`` to choose the synth. * @param {string} targetAddress The address for which to check allowance. * @param {string} address The owner address to check allowance for. * @param {MarketIdOrName} marketIdOrName - The unique identifier or name of the market. * @returns The allowance in ether. */ async getAllowance(targetAddress, address = this.sdk.accountAddress, marketIdOrName) { const synthContract = await this.getSynthContract(marketIdOrName); const allowance = await synthContract.read.allowance([address, targetAddress]); return convertWeiToEther(allowance); } /** * Get details about an async order by its ID. * Retrieves order details like owner, amount escrowed, settlement strategy, etc. * Can also fetch the full settlement strategy parameters if ``fetchSettlementStrategy`` * is ``true``. * Requires either a ``market_id`` or ``market_name`` to be provided to resolve the market. * @param {string} data.asyncOrderId The ID of the async order to retrieve. * @param {MarketIdOrName} data.marketIdOrName - The unique identifier or name of the market. * @param {boolean} data.fetchSettlementStrategy Whether to fetch the full settlement strategy parameters. Default is true. * @returns {SpotOrder} The order details. */ async getOrder({ asyncOrderId, marketIdOrName, fetchSettlementStrategy = true }) { const { resolvedMarketId } = await this.resolveMarket(marketIdOrName); const spotProxy = await this.sdk.contracts.getSpotMarketProxyInstance(); const order = await spotProxy.read.getAsyncOrderClaim([resolvedMarketId, asyncOrderId]); this.sdk.logger.info("order", order); if (fetchSettlementStrategy) { const settlementStrategy = await this.getSettlementStrategy({ settlementStrategyId: Number(order.settlementStrategyId) || 0, marketIdOrName: resolvedMarketId }); order.settlementStrategy = settlementStrategy; } return order; } /** * Fetch the settlement strategy for a spot market. * @param {GetSettlementStrategy} data The data for fetching the settlement strategy. * @param {number} data.settlementStrategyId The id of the settlement strategy to retrieve. * @param {MarketIdOrName} data.marketIdOrName - The unique identifier or name of the market. * @returns {SpotSettlementStrategy} The settlement strategy for the market. */ async getSettlementStrategy({ settlementStrategyId, marketIdOrName }) { const { resolvedMarketId, resolvedMarketName } = await this.resolveMarket(marketIdOrName); const spotProxy = await this.sdk.contracts.getSpotMarketProxyInstance(); const settlementStrategy = await this.sdk.utils.callErc7412({ contractAddress: spotProxy.address, abi: spotProxy.abi, functionName: "getSettlementStrategy", args: [resolvedMarketId, settlementStrategyId] }); return { marketId: resolvedMarketId, marketName: resolvedMarketName, strategyType: settlementStrategy.strategyType, settlementDelay: Number(settlementStrategy.settlementDelay), settlementWindowDuration: Number(settlementStrategy.settlementWindowDuration), priceVerificationContract: settlementStrategy.priceVerificationContract, feedId: settlementStrategy.feedId, url: settlementStrategy.url, settlementReward: convertWeiToEther(settlementStrategy.settlementReward), priceDeviationTolerance: convertWeiToEther(settlementStrategy.priceDeviationTolerance), minimumUsdExchangeAmount: convertWeiToEther(settlementStrategy.minimumUsdExchangeAmount), maxRoundingLoss: convertWeiToEther(settlementStrategy.maxRoundingLoss), disabled: settlementStrategy.disabled }; } /** * Fetch the settlement strategies for all spot markets. * @param {GetSettlementStrategies} data The data for fetching the settlement strategies. * @param {number} data.stragegyId The id of the settlement strategy to retrieve. * @param {number[]} data.marketIds Array of marketIds to fetch settlement strategy * @returns {SpotSettlementStrategy[]} The settlement strategies for the markets. */ async getSettlementStrategies({ settlementStrategyId: stragegyId, marketIds }) { const spotProxy = await this.sdk.contracts.getSpotMarketProxyInstance(); const settlementStrategies = []; let settlementStrategiesResponse; const argsList = marketIds.map((marketId) => [marketId, stragegyId]); const response = await this.sdk.utils.multicallErc7412({ contractAddress: spotProxy.address, abi: spotProxy.abi, functionName: "getSettlementStrategy", args: argsList }); if (response == void 0) { settlementStrategiesResponse = []; } else { settlementStrategiesResponse = response; } this.sdk.logger.info("settlementStrategiesResponse", settlementStrategiesResponse); settlementStrategiesResponse.forEach((strategy, index) => { settlementStrategies.push({ marketId: marketIds[index], strategyType: strategy.strategyType, settlementDelay: Number(strategy.settlementDelay), settlementWindowDuration: Number(strategy.settlementWindowDuration), priceVerificationContract: strategy.priceVerificationContract, feedId: strategy.feedId, url: strategy.url, settlementReward: convertWeiToEther(strategy.settlementReward), priceDeviationTolerance: convertWeiToEther(strategy.priceDeviationTolerance), minimumUsdExchangeAmount: convertWeiToEther(strategy.minimumUsdExchangeAmount), maxRoundingLoss: convertWeiToEther(strategy.maxRoundingLoss), disabled: strategy.disabled }); }); return settlementStrategies; } // === WRITE CALLS === async buildAtomicOrder({ side, size, slippageTolerance = 0, minAmountReceived, marketIdOrName }) { const { resolvedMarketId, resolvedMarketName } = await this.resolveMarket(marketIdOrName); const spotMarketProxy = await this.sdk.contracts.getSpotMarketProxyInstance(); if (this.sdk.rpcConfig.chainId in [8453, 84532] && resolvedMarketName in ["sUSDC"] && minAmountReceived == void 0) { minAmountReceived = size; } else if (minAmountReceived == void 0) { const tokenSymbol = this.marketsById.get(resolvedMarketId)?.symbol; if (tokenSymbol == void 0) { throw new Error(`Invalid token symbol for market id: ${resolvedMarketId}`); } const feedId = this.sdk.pyth.priceFeedIds.get(tokenSymbol) ?? "0xeaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a"; const price = await this.sdk.pyth.getFormattedPrice(feedId); this.sdk.logger.info("Formatted price:", price); let tradeSize; if (side == 0 /* BUY */) { tradeSize = size / price; } else { tradeSize = size * price; } minAmountReceived = tradeSize * (1 - slippageTolerance); } const minAmountReceivedInWei = convertEtherToWei(minAmountReceived); const sizeInWei = convertEtherToWei(size); const functionName = side == 0 /* BUY */ ? "buy" : "sell"; const args = [resolvedMarketId, sizeInWei, minAmountReceivedInWei, this.sdk.referrer]; return { target: spotMarketProxy.address, callData: encodeFunctionData2({ abi: spotMarketProxy.abi, functionName, args }), value: 0n, requireSuccess: true }; } /** * Execute an atomic order on the spot market. * Atomically executes a buy or sell order for the given size. * Amounts are transferred directly, no need to settle later. This function * is useful for swapping sUSDC with sUSD on Base Andromeda contracts. The default * slippage is set to zero, since sUSDC and sUSD can be swapped 1:1 * For example: * const tx = await atomicOrder(Side.BUY, 100, 0, undefined, undefined, "sUSDC"); * Requires either a ``market_id`` or ``market_name`` to be provided to resolve the market. * @param {AtomicOrder} data The data for the atomic order. * @param {Side} data.side The side of the order (buy/sell). * @param {number} data.size The order size in ether. * @param {number} data.slippageTolerance The slippage tolerance for the order as a percentage (0.01 = 1%). Default is 0. * @param {number} data.minAmountReceived The minimum amount to receive in ether units. This will override the slippage_tolerance. * @param {MarketIdOrName} data.marketIdOrName - The unique identifier or name of the market. * @param {OverrideParamsWrite} override - Override the default parameters for the transaction. * @returns {WriteReturnType} The transaction hash if ``submit`` is ``true``. */ async atomicOrder({ side, size, slippageTolerance = 0, minAmountReceived, marketIdOrName }, override = {}) { const atomicOrderTx = await this.buildAtomicOrder({ side, size, slippageTolerance, minAmountReceived, marketIdOrName }); const txs = [atomicOrderTx]; return this.sdk.utils.processTransactions(txs, { ...override }); } async buildWrap({ size, marketIdOrName }) { const { resolvedMarketId } = await this.resolveMarket(marketIdOrName); const spotMarketProxy = await this.sdk.contracts.getSpotMarketProxyInstance(); const tokenToWrap = resolvedMarketId; const sizeInWei = await this.formatSize(Math.abs(size), tokenToWrap); const functionName = size > 0 ? "wrap" : "unwrap"; const offset = sizeInWei * 100n / 1000n; const wrapTx = { target: spotMarketProxy.address, callData: encodeFunctionData2({ abi: spotMarketProxy.abi, functionName, args: [resolvedMarketId, sizeInWei, sizeInWei - offset] }), value: 0n, requireSuccess: true }; return wrapTx; } /** * Wrap an underlying asset into a synth or unwrap back to the asset. * Wraps an asset into a synth if size > 0, unwraps if size < 0. * The default slippage is set to zero, since the synth and asset can be swapped 1:1. * For example: * const tx = wrap(100, undefined, "sUSDC") # wrap 100 USDC into sUSDC * const tx = wrap(-100, undefined, "sUSDC") # unwrap 100 sUSDC into USDC * Requires either a ``market_id`` or ``market_name`` to be provided to resolve the market. * @param {Wrap} data The data for the wrap/unwrap transaction. * @param data.size The amount of the asset to wrap/unwrap. * @param {MarketIdOrName} data.marketIdOrName - The unique identifier or name of the market. * @param {OverrideParamsWrite} override - Override the default parameters for the transaction. * @returns {WriteReturnType} The transaction hash if ``submit`` is ``true``. */ async wrap({ size, marketIdOrName }, override = {}) { const wrapTx = await this.buildWrap({ size, marketIdOrName }); const txs = [wrapTx]; return this.sdk.utils.processTransactions(txs, { ...override }); } async buildCommitOrder({ side, size, slippageTolerance, minAmountReceived, settlementStrategyId = 0, marketIdOrName }) { const { resolvedMarketId } = await this.resolveMarket(marketIdOrName); const spotMarketProxy = await this.sdk.contracts.getSpotMarketProxyInstance(); if (!minAmountReceived) { const settlementReward = this.marketsById.get(resolvedMarketId)?.settlementStrategy?.settlementReward ?? 0; const feedId = this.marketsById.get(resolvedMarketId)?.settlementStrategy?.feedId ?? "0xeaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a"; const price = await this.sdk.pyth.getFormattedPrice(feedId); this.sdk.logger.info("Formatted price:", price); let tradeSize = size * price; if (side == 0 /* BUY */) { tradeSize = size / price; } minAmountReceived = tradeSize * (1 - slippageTolerance) - settlementReward; } const minAmountReceivedInWei = convertEtherToWei(minAmountReceived); const sizeInWei = convertEtherToWei(size); const orderType = side == 0 /* BUY */ ? 3 : 4; const args = [ resolvedMarketId, orderType, sizeInWei, settlementStrategyId, minAmountReceivedInWei, this.sdk.referrer ]; return { target: spotMarketProxy.address, callData: encodeFunctionData2({ abi: spotMarketProxy.abi, functionName: "commitOrder", args }), value: 0n, requireSuccess: true }; } /** * Commit an async order to the spot market. * Commits a buy or sell order of the given size. The order will be settled * according to the settlement strategy. * Requires either a ``marketId`` or ``marketName`` to be provided to resolve the market. * @param {CommitOrderSpot} data The data for the async order. * @param {Side} data.side The side of the order (buy/sell). * @param {number} data.size The order size in ether. If ``side`` is "buy", this is the amount * of the synth to buy. If ``side`` is "sell", this is the amount of the synth to sell. * @param {number} data.slippageTolerance The slippage tolerance for the order as a percentage (0.01 = 1%). Default is 0. * @param {number} data.minAmountReceived The minimum amount to receive in ether units. This will override the slippage_tolerance. * @param {number} data.settlementStrategyId The settlement strategy ID. Default 2. * @param {MarketIdOrName} data.marketIdOrName - The unique identifier or name of the market. * @param {OverrideParamsWrite} override - Override the default parameters for the transaction. */ async commitOrder({ side, size, slippageTolerance, minAmountReceived, settlementStrategyId = 0, marketIdOrName }, override = {}) { const commitTx = await this.buildCommitOrder({ side, size, slippageTolerance, minAmountReceived, settlementStrategyId, marketIdOrName }); const txs = [commitTx]; return this.sdk.utils.processTransactions(txs, { ...override }); } /** * Settle an async Pyth order after price data is available. * Fetches the price for the order from Pyth and settles the order. * Retries up to ``maxTxTries`` times on failure with a delay of ``txDelay`` seconds. * Requires either a ``marketId`` or ``marketName`` to be provided to resolve the market. * @param {SettleOrder} data The data for the async order. * @param {string} asyncOrderId The ID of the async order to settle. * @param {MarketIdOrName} marketIdOrName The unique identifier or name of the market. * @param {OverrideParamsWrite} override - Override the default parameters for the transaction. * @returns {WriteReturnType} The transaction hash if ``submit`` is ``true``. */ async settleOrder({ asyncOrderId, marketIdOrName }, override = {}) { const { resolvedMarketId } = await this.resolveMarket(marketIdOrName); const spotMarketProxy = await this.sdk.contracts.getSpotMarketProxyInstance(); const order = await this.getOrder({ asyncOrderId, marketIdOrName: resolvedMarketId }); if (order.settledAt == void 0 || order.commitmentTime == void 0) { throw new Error("Invalid fields for order: undefined"); } const settlementStrategy = order.settlementStrategy; const settlementTime = order.commitmentTime + (settlementStrategy?.settlementDelay ?? 0); const expirationTime = order.commitmentTime + (settlementStrategy?.settlementWindowDuration ?? 0); const currentTimestamp = Math.floor(Date.now() / 1e3); if (order.settledAt > 0) throw new Error(`Order ${asyncOrderId} on market ${resolvedMarketId} is already settled for account`); if (expirationTime < currentTimestamp) throw new Error(`Order ${asyncOrderId} on market ${resolvedMarketId} has expired`); if (settlementTime > currentTimestamp) { const duration = settlementTime - currentTimestamp; this.sdk.logger.info(`Waiting ${duration} seconds to settle order`); await sleep(duration); } this.sdk.logger.info(`Order ${asyncOrderId} on market ${resolvedMarketId} is ready to be settled`); const settleTx = { target: spotMarketProxy.address, callData: encodeFunctionData2({ abi: spotMarketProxy.abi, functionName: "settleOrder", args: [resolvedMarketId, asyncOrderId] }), value: 0n, requireSuccess: true }; const txs = [settleTx]; return this.sdk.utils.processTransactions(txs, { ...override }); } async buildApprove({ spender, amount, token }) { const amountInWei = convertEtherToWei(amount); const tx = { target: token, callData: encodeFunctionData2({ abi: erc20Abi, functionName: "approve", args: [spender, amountInWei] }), value: 0n, requireSuccess: true }; return tx; } /** * Approve an address to transfer a specified synth from the connected address. * Approves the ``targetAddress`` to transfer up to the ``amount`` from your account. * If ``amount`` is ``undefined``, approves the maximum possible amount. * Requires either a ``marketId`` or ``marketName`` to be provided to resolve the market. * @param {string} data.targetAddress The address to approve. * @param {number} data.amount The amount in ether to approve. Default is max uint256. * @param {MarketIdOrName} dart.marketIdOrName - The unique identifier or name of the market. * @param {OverrideParamsWrite} override - Override the default parameters for the transaction. * @returns {WriteReturnType} The transaction hash if ``submit`` is ``true``. */ async approve({ targetAddress, amount = 0, marketIdOrName }, override = {}) { let amountInWei = maxUint256; if (amount) { amountInWei = convertEtherToWei(amount); } const synthContract = await this.getSynthContract(marketIdOrName); const txs = [ { target: synthContract.address, callData: encodeFunctionData2({ abi: synthContract.abi, functionName: "approve", args: [targetAddress, amountInWei] }), value: 0n, requireSuccess: true } ]; return this.sdk.utils.processTransactions(txs, { ...override, useOracleCalls: false }); } }; export { Spot }; //# sourceMappingURL=index.mjs.map