UNPKG

@uniswap/v4-sdk

Version:

⚒️ An SDK for building applications on top of Uniswap V4

266 lines 13.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.V4Planner = exports.V4_SWAP_ACTIONS_V2_1_1 = exports.V4_BASE_ACTIONS_ABI_DEFINITION = exports.Subparser = exports.Actions = exports.isAtLeastV2_1_1 = exports.URVersion = void 0; const tslib_1 = require("tslib"); const tiny_invariant_1 = tslib_1.__importDefault(require("tiny-invariant")); const utils_1 = require("ethers/lib/utils"); const sdk_core_1 = require("@uniswap/sdk-core"); const internalConstants_1 = require("../internalConstants"); const encodeRouteToPath_1 = require("./encodeRouteToPath"); /** * Actions * @description Constants that define what action to perform * Not all actions are supported yet. * @enum {number} */ /** * UniversalRouter version * @description Version of the UniversalRouter contract * @enum {string} */ var URVersion; (function (URVersion) { URVersion["V2_0"] = "2.0"; URVersion["V2_1_1"] = "2.1.1"; URVersion["V2_2_0"] = "2.2.0"; })(URVersion = exports.URVersion || (exports.URVersion = {})); function isAtLeastV2_1_1(version) { return !!version && version.localeCompare(URVersion.V2_1_1, undefined, { numeric: true }) >= 0; } exports.isAtLeastV2_1_1 = isAtLeastV2_1_1; var Actions; (function (Actions) { // pool actions // liquidity actions Actions[Actions["INCREASE_LIQUIDITY"] = 0] = "INCREASE_LIQUIDITY"; Actions[Actions["DECREASE_LIQUIDITY"] = 1] = "DECREASE_LIQUIDITY"; Actions[Actions["MINT_POSITION"] = 2] = "MINT_POSITION"; Actions[Actions["BURN_POSITION"] = 3] = "BURN_POSITION"; // for fee on transfer tokens // INCREASE_LIQUIDITY_FROM_DELTAS = 0x04, // MINT_POSITION_FROM_DELTAS = 0x05, // swapping Actions[Actions["SWAP_EXACT_IN_SINGLE"] = 6] = "SWAP_EXACT_IN_SINGLE"; Actions[Actions["SWAP_EXACT_IN"] = 7] = "SWAP_EXACT_IN"; Actions[Actions["SWAP_EXACT_OUT_SINGLE"] = 8] = "SWAP_EXACT_OUT_SINGLE"; Actions[Actions["SWAP_EXACT_OUT"] = 9] = "SWAP_EXACT_OUT"; // closing deltas on the pool manager // settling Actions[Actions["SETTLE"] = 11] = "SETTLE"; Actions[Actions["SETTLE_ALL"] = 12] = "SETTLE_ALL"; Actions[Actions["SETTLE_PAIR"] = 13] = "SETTLE_PAIR"; // taking Actions[Actions["TAKE"] = 14] = "TAKE"; Actions[Actions["TAKE_ALL"] = 15] = "TAKE_ALL"; Actions[Actions["TAKE_PORTION"] = 16] = "TAKE_PORTION"; Actions[Actions["TAKE_PAIR"] = 17] = "TAKE_PAIR"; Actions[Actions["CLOSE_CURRENCY"] = 18] = "CLOSE_CURRENCY"; // CLEAR_OR_TAKE = 0x13, Actions[Actions["SWEEP"] = 20] = "SWEEP"; // for wrapping/unwrapping native // WRAP = 0x15, Actions[Actions["UNWRAP"] = 22] = "UNWRAP"; })(Actions = exports.Actions || (exports.Actions = {})); var Subparser; (function (Subparser) { Subparser[Subparser["V4SwapExactInSingle"] = 0] = "V4SwapExactInSingle"; Subparser[Subparser["V4SwapExactIn"] = 1] = "V4SwapExactIn"; Subparser[Subparser["V4SwapExactOutSingle"] = 2] = "V4SwapExactOutSingle"; Subparser[Subparser["V4SwapExactOut"] = 3] = "V4SwapExactOut"; Subparser[Subparser["PoolKey"] = 4] = "PoolKey"; })(Subparser = exports.Subparser || (exports.Subparser = {})); const POOL_KEY_STRUCT = '(address currency0,address currency1,uint24 fee,int24 tickSpacing,address hooks)'; const PATH_KEY_STRUCT = '(address intermediateCurrency,uint256 fee,int24 tickSpacing,address hooks,bytes hookData)'; // UR 2.0 swap structs (without minHopPriceX36) const SWAP_EXACT_IN_SINGLE_STRUCT_V2_0 = '(' + POOL_KEY_STRUCT + ' poolKey,bool zeroForOne,uint128 amountIn,uint128 amountOutMinimum,bytes hookData)'; const SWAP_EXACT_IN_STRUCT_V2_0 = '(address currencyIn,' + PATH_KEY_STRUCT + '[] path,uint128 amountIn,uint128 amountOutMinimum)'; const SWAP_EXACT_OUT_SINGLE_STRUCT_V2_0 = '(' + POOL_KEY_STRUCT + ' poolKey,bool zeroForOne,uint128 amountOut,uint128 amountInMaximum,bytes hookData)'; const SWAP_EXACT_OUT_STRUCT_V2_0 = '(address currencyOut,' + PATH_KEY_STRUCT + '[] path,uint128 amountOut,uint128 amountInMaximum)'; // UR 2.1.1 swap structs (with minHopPriceX36) const SWAP_EXACT_IN_SINGLE_STRUCT_V2_1_1 = '(' + POOL_KEY_STRUCT + ' poolKey,bool zeroForOne,uint128 amountIn,uint128 amountOutMinimum,uint256 minHopPriceX36,bytes hookData)'; const SWAP_EXACT_IN_STRUCT_V2_1_1 = '(address currencyIn,' + PATH_KEY_STRUCT + '[] path,uint256[] minHopPriceX36,uint128 amountIn,uint128 amountOutMinimum)'; const SWAP_EXACT_OUT_SINGLE_STRUCT_V2_1_1 = '(' + POOL_KEY_STRUCT + ' poolKey,bool zeroForOne,uint128 amountOut,uint128 amountInMaximum,uint256 minHopPriceX36,bytes hookData)'; const SWAP_EXACT_OUT_STRUCT_V2_1_1 = '(address currencyOut,' + PATH_KEY_STRUCT + '[] path,uint256[] minHopPriceX36,uint128 amountOut,uint128 amountInMaximum)'; // V4_BASE_ACTIONS_ABI_DEFINITION uses V2.0 structs (default, without minHopPriceX36) const SWAP_EXACT_IN_SINGLE_STRUCT = SWAP_EXACT_IN_SINGLE_STRUCT_V2_0; const SWAP_EXACT_IN_STRUCT = SWAP_EXACT_IN_STRUCT_V2_0; const SWAP_EXACT_OUT_SINGLE_STRUCT = SWAP_EXACT_OUT_SINGLE_STRUCT_V2_0; const SWAP_EXACT_OUT_STRUCT = SWAP_EXACT_OUT_STRUCT_V2_0; // eslint-disable-next-line @typescript-eslint/no-unused-vars exports.V4_BASE_ACTIONS_ABI_DEFINITION = { // Liquidity commands [Actions.INCREASE_LIQUIDITY]: [ { name: 'tokenId', type: 'uint256' }, { name: 'liquidity', type: 'uint256' }, { name: 'amount0Max', type: 'uint128' }, { name: 'amount1Max', type: 'uint128' }, { name: 'hookData', type: 'bytes' }, ], [Actions.DECREASE_LIQUIDITY]: [ { name: 'tokenId', type: 'uint256' }, { name: 'liquidity', type: 'uint256' }, { name: 'amount0Min', type: 'uint128' }, { name: 'amount1Min', type: 'uint128' }, { name: 'hookData', type: 'bytes' }, ], [Actions.MINT_POSITION]: [ { name: 'poolKey', type: POOL_KEY_STRUCT, subparser: Subparser.PoolKey }, { name: 'tickLower', type: 'int24' }, { name: 'tickUpper', type: 'int24' }, { name: 'liquidity', type: 'uint256' }, { name: 'amount0Max', type: 'uint128' }, { name: 'amount1Max', type: 'uint128' }, { name: 'owner', type: 'address' }, { name: 'hookData', type: 'bytes' }, ], [Actions.BURN_POSITION]: [ { name: 'tokenId', type: 'uint256' }, { name: 'amount0Min', type: 'uint128' }, { name: 'amount1Min', type: 'uint128' }, { name: 'hookData', type: 'bytes' }, ], // Swapping commands [Actions.SWAP_EXACT_IN_SINGLE]: [ { name: 'swap', type: SWAP_EXACT_IN_SINGLE_STRUCT, subparser: Subparser.V4SwapExactInSingle }, ], [Actions.SWAP_EXACT_IN]: [{ name: 'swap', type: SWAP_EXACT_IN_STRUCT, subparser: Subparser.V4SwapExactIn }], [Actions.SWAP_EXACT_OUT_SINGLE]: [ { name: 'swap', type: SWAP_EXACT_OUT_SINGLE_STRUCT, subparser: Subparser.V4SwapExactOutSingle }, ], [Actions.SWAP_EXACT_OUT]: [{ name: 'swap', type: SWAP_EXACT_OUT_STRUCT, subparser: Subparser.V4SwapExactOut }], // Payments commands [Actions.SETTLE]: [ { name: 'currency', type: 'address' }, { name: 'amount', type: 'uint256' }, { name: 'payerIsUser', type: 'bool' }, ], [Actions.SETTLE_ALL]: [ { name: 'currency', type: 'address' }, { name: 'maxAmount', type: 'uint256' }, ], [Actions.SETTLE_PAIR]: [ { name: 'currency0', type: 'address' }, { name: 'currency1', type: 'address' }, ], [Actions.TAKE]: [ { name: 'currency', type: 'address' }, { name: 'recipient', type: 'address' }, { name: 'amount', type: 'uint256' }, ], [Actions.TAKE_ALL]: [ { name: 'currency', type: 'address' }, { name: 'minAmount', type: 'uint256' }, ], [Actions.TAKE_PORTION]: [ { name: 'currency', type: 'address' }, { name: 'recipient', type: 'address' }, { name: 'bips', type: 'uint256' }, ], [Actions.TAKE_PAIR]: [ { name: 'currency0', type: 'address' }, { name: 'currency1', type: 'address' }, { name: 'recipient', type: 'address' }, ], [Actions.CLOSE_CURRENCY]: [{ name: 'currency', type: 'address' }], [Actions.SWEEP]: [ { name: 'currency', type: 'address' }, { name: 'recipient', type: 'address' }, ], [Actions.UNWRAP]: [{ name: 'amount', type: 'uint256' }], }; // UR 2.1.1 specific ABI definitions for swap actions (with minHopPriceX36) exports.V4_SWAP_ACTIONS_V2_1_1 = { [Actions.SWAP_EXACT_IN_SINGLE]: [ { name: 'swap', type: SWAP_EXACT_IN_SINGLE_STRUCT_V2_1_1, subparser: Subparser.V4SwapExactInSingle }, ], [Actions.SWAP_EXACT_IN]: [{ name: 'swap', type: SWAP_EXACT_IN_STRUCT_V2_1_1, subparser: Subparser.V4SwapExactIn }], [Actions.SWAP_EXACT_OUT_SINGLE]: [ { name: 'swap', type: SWAP_EXACT_OUT_SINGLE_STRUCT_V2_1_1, subparser: Subparser.V4SwapExactOutSingle }, ], [Actions.SWAP_EXACT_OUT]: [{ name: 'swap', type: SWAP_EXACT_OUT_STRUCT_V2_1_1, subparser: Subparser.V4SwapExactOut }], }; const FULL_DELTA_AMOUNT = 0; class V4Planner { constructor() { this.actions = internalConstants_1.EMPTY_BYTES; this.params = []; } addAction(type, parameters, urVersion = URVersion.V2_0) { let command = createAction(type, parameters, urVersion); this.params.push(command.encodedInput); this.actions = this.actions.concat(command.action.toString(16).padStart(2, '0')); return this; } addTrade(trade, slippageTolerance, minHopPriceX36, urVersion = URVersion.V2_0) { const exactOutput = trade.tradeType === sdk_core_1.TradeType.EXACT_OUTPUT; // exactInput we sometimes perform aggregated slippage checks, but not with exactOutput if (exactOutput) (0, tiny_invariant_1.default)(!!slippageTolerance, 'ExactOut requires slippageTolerance'); (0, tiny_invariant_1.default)(trade.swaps.length === 1, 'Only accepts Trades with 1 swap (must break swaps into individual trades)'); (0, tiny_invariant_1.default)(urVersion === URVersion.V2_0 || !(minHopPriceX36 === null || minHopPriceX36 === void 0 ? void 0 : minHopPriceX36.length) || minHopPriceX36.length === trade.route.pools.length, `minHopPriceX36 length (${minHopPriceX36 === null || minHopPriceX36 === void 0 ? void 0 : minHopPriceX36.length}) must equal route.pools.length (${trade.route.pools.length})`); const actionType = exactOutput ? Actions.SWAP_EXACT_OUT : Actions.SWAP_EXACT_IN; const currencyIn = currencyAddress(trade.route.pathInput); const currencyOut = currencyAddress(trade.route.pathOutput); const swapStruct = exactOutput ? { currencyOut, path: (0, encodeRouteToPath_1.encodeRouteToPath)(trade.route, exactOutput), ...(isAtLeastV2_1_1(urVersion) && { minHopPriceX36: minHopPriceX36 !== null && minHopPriceX36 !== void 0 ? minHopPriceX36 : [] }), amountOut: trade.outputAmount.quotient.toString(), amountInMaximum: trade.maximumAmountIn(slippageTolerance !== null && slippageTolerance !== void 0 ? slippageTolerance : new sdk_core_1.Percent(0)).quotient.toString(), } : { currencyIn, path: (0, encodeRouteToPath_1.encodeRouteToPath)(trade.route, exactOutput), ...(isAtLeastV2_1_1(urVersion) && { minHopPriceX36: minHopPriceX36 !== null && minHopPriceX36 !== void 0 ? minHopPriceX36 : [] }), amountIn: trade.inputAmount.quotient.toString(), amountOutMinimum: slippageTolerance ? trade.minimumAmountOut(slippageTolerance).quotient.toString() : 0, }; this.addSwapAction(actionType, [swapStruct], urVersion); return this; } addSettle(currency, payerIsUser, amount) { this.addAction(Actions.SETTLE, [currencyAddress(currency), amount !== null && amount !== void 0 ? amount : FULL_DELTA_AMOUNT, payerIsUser]); return this; } addTake(currency, recipient, amount) { const takeAmount = amount !== null && amount !== void 0 ? amount : FULL_DELTA_AMOUNT; this.addAction(Actions.TAKE, [currencyAddress(currency), recipient, takeAmount]); return this; } addUnwrap(amount) { this.addAction(Actions.UNWRAP, [amount]); return this; } finalize() { return utils_1.defaultAbiCoder.encode(['bytes', 'bytes[]'], [this.actions, this.params]); } addSwapAction(type, parameters, urVersion) { // Use V2.1.1 ABI (with minHopPriceX36) for V2.1.1, otherwise default to V2.0 ABI (without minHopPriceX36) const abiDef = isAtLeastV2_1_1(urVersion) ? exports.V4_SWAP_ACTIONS_V2_1_1[type] : exports.V4_BASE_ACTIONS_ABI_DEFINITION[type]; const encodedInput = utils_1.defaultAbiCoder.encode(abiDef.map((v) => v.type), parameters); this.params.push(encodedInput); this.actions = this.actions.concat(type.toString(16).padStart(2, '0')); return this; } } exports.V4Planner = V4Planner; function currencyAddress(currency) { return currency.isNative ? internalConstants_1.ADDRESS_ZERO : currency.wrapped.address; } function createAction(action, parameters, urVersion = URVersion.V2_0) { const abiDef = isAtLeastV2_1_1(urVersion) && action in exports.V4_SWAP_ACTIONS_V2_1_1 ? exports.V4_SWAP_ACTIONS_V2_1_1[action] : exports.V4_BASE_ACTIONS_ABI_DEFINITION[action]; const encodedInput = utils_1.defaultAbiCoder.encode(abiDef.map((v) => v.type), parameters); return { action, encodedInput }; } //# sourceMappingURL=v4Planner.js.map