UNPKG

@oyl/sdk

Version:
305 lines 11.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.swap = exports.swapPsbt = exports.removeLiquidity = exports.removeLiquidityPsbt = exports.previewRemoveLiquidity = exports.addLiquidity = exports.addLiquidityPsbt = exports.AlkanesAMMPoolDecoder = void 0; const bytes_1 = require("alkanes/lib/bytes"); const proto_runestone_upgrade_1 = require("alkanes/lib/protorune/proto_runestone_upgrade"); const protostone_1 = require("alkanes/lib/protorune/protostone"); const __1 = require(".."); const alkanes_1 = require("../alkanes"); const integer_1 = require("@magiceden-oss/runestone-lib/dist/src/integer"); const protoruneruneid_1 = require("alkanes/lib/protorune/protoruneruneid"); const factory_1 = require("./factory"); const utils_1 = require("./utils"); class AlkanesAMMPoolDecoder { decodeSwap(data) { if (data === '0x') return undefined; // Convert hex to BigInt (little-endian) const bytes = Buffer.from(data.slice(2), 'hex'); const reversed = Buffer.from([...bytes].reverse()); return { amountOut: BigInt('0x' + reversed.toString('hex')), }; } decodePoolDetails(data) { if (data === '0x') return undefined; const bytes = Buffer.from(data.slice(2), 'hex'); const token0 = { block: bytes.readBigUInt64LE(0).toString(), tx: bytes.readBigUInt64LE(16).toString(), }; const token1 = { block: bytes.readBigUInt64LE(32).toString(), tx: bytes.readBigUInt64LE(48).toString(), }; const token0Amount = bytes.readBigUInt64LE(64).toString(); const token1Amount = bytes.readBigUInt64LE(80).toString(); const tokenSupply = bytes.readBigUInt64LE(96).toString(); const poolName = Buffer.from(bytes.subarray(116)).toString('utf8'); return { token0, token1, token0Amount, token1Amount, tokenSupply, poolName }; } decodeName(data) { if (data === '0x') return undefined; const bytes = Buffer.from(data.slice(2), 'hex'); return bytes.toString('utf8'); } static decodeSimulation(result, opcode) { const decoder = new AlkanesAMMPoolDecoder(); let decoded; switch (opcode) { case utils_1.PoolOpcodes.INIT_POOL: case utils_1.PoolOpcodes.ADD_LIQUIDITY: case utils_1.PoolOpcodes.REMOVE_LIQUIDITY: throw new Error('Opcode not supported in simulation mode; see previewRemoveLiquidity'); case utils_1.PoolOpcodes.SIMULATE_SWAP: decoded = decoder.decodeSwap(result.execution.data); break; case utils_1.PoolOpcodes.NAME: decoded = decoder.decodeName(result.execution.data); break; case utils_1.PoolOpcodes.POOL_DETAILS: decoded = decoder.decodePoolDetails(result.execution.data); break; default: decoded = undefined; } if (result.status !== 0 || result.execution.error) { throw new Error(result.execution.error || 'Unknown error'); } return decoded; } } exports.AlkanesAMMPoolDecoder = AlkanesAMMPoolDecoder; const addLiquidityPsbt = async ({ calldata, token0, token0Amount, token1, token1Amount, gatheredUtxos, feeRate, account, provider, }) => { const tokens = [ { alkaneId: token0, amount: token0Amount }, { alkaneId: token1, amount: token1Amount }, ]; const { edicts, alkaneUtxos, totalSatoshis } = await (0, factory_1.splitAlkaneUtxos)(tokens, account, provider); const protostone = (0, proto_runestone_upgrade_1.encodeRunestoneProtostone)({ protostones: [ protostone_1.ProtoStone.message({ edicts, protocolTag: 1n, pointer: 0, refundPointer: 0, calldata: (0, bytes_1.encipher)([]), }), protostone_1.ProtoStone.message({ protocolTag: 1n, pointer: 0, refundPointer: 0, calldata: (0, bytes_1.encipher)(calldata), }), ], }).encodedRunestone; const { psbt, fee } = await __1.alkanes.executePsbt({ alkaneUtxos: { alkaneUtxos, totalSatoshis }, protostone, gatheredUtxos, feeRate, account, provider, }); return { psbt, fee }; }; exports.addLiquidityPsbt = addLiquidityPsbt; const addLiquidity = async ({ calldata, token0, token0Amount, token1, token1Amount, gatheredUtxos, feeRate, account, signer, provider, }) => { const { psbt } = await (0, exports.addLiquidityPsbt)({ calldata, token0, token0Amount, token1, token1Amount, gatheredUtxos, feeRate, account, provider, }); const { signedPsbt } = await signer.signAllInputs({ rawPsbt: psbt, finalize: true, }); const pushResult = await provider.pushPsbt({ psbtBase64: signedPsbt, }); return pushResult; }; exports.addLiquidity = addLiquidity; /** * Estimates the tokens that would be received when removing liquidity from a pool * @param token The LP token ID * @param tokenAmount The amount of LP tokens to remove * @param provider The provider instance * @returns A promise that resolves to the preview result containing token amounts */ const previewRemoveLiquidity = async ({ token, tokenAmount, provider, }) => { const poolDetailsRequest = { target: token, inputs: [utils_1.PoolOpcodes.POOL_DETAILS.toString()], }; const detailsResult = await provider.alkanes.simulate(poolDetailsRequest); const decoder = new AlkanesAMMPoolDecoder(); const poolDetails = decoder.decodePoolDetails(detailsResult.execution.data); if (!poolDetails) { throw new Error('Failed to get pool details'); } return (0, utils_1.estimateRemoveLiquidityAmounts)(poolDetails, tokenAmount); }; exports.previewRemoveLiquidity = previewRemoveLiquidity; const removeLiquidityPsbt = async ({ calldata, token, tokenAmount, gatheredUtxos, feeRate, account, provider, }) => { if (tokenAmount <= 0n) { throw new Error('Cannot process zero tokens'); } let alkaneTokenUtxos; const tokenUtxos = await Promise.all([ (0, alkanes_1.findAlkaneUtxos)({ address: account.taproot.address, greatestToLeast: false, provider, targetNumberOfAlkanes: Number(tokenAmount), alkaneId: token, }), ]); alkaneTokenUtxos = { alkaneUtxos: tokenUtxos[0].alkaneUtxos, totalSatoshis: tokenUtxos[0].totalSatoshis, }; const edicts = [ { id: new protoruneruneid_1.ProtoruneRuneId((0, integer_1.u128)(BigInt(token.block)), (0, integer_1.u128)(BigInt(token.tx))), amount: (0, integer_1.u128)(tokenAmount), output: (0, integer_1.u32)(5), }, ]; const protostone = (0, proto_runestone_upgrade_1.encodeRunestoneProtostone)({ protostones: [ protostone_1.ProtoStone.message({ protocolTag: 1n, edicts, pointer: 0, refundPointer: 0, calldata: (0, bytes_1.encipher)([]), }), protostone_1.ProtoStone.message({ protocolTag: 1n, pointer: 0, refundPointer: 0, calldata: (0, bytes_1.encipher)(calldata), }), ], }).encodedRunestone; const { psbt, fee } = await __1.alkanes.executePsbt({ alkaneUtxos: alkaneTokenUtxos, protostone, gatheredUtxos, feeRate, account, provider, }); return { psbt, fee }; }; exports.removeLiquidityPsbt = removeLiquidityPsbt; const removeLiquidity = async ({ calldata, token, tokenAmount, gatheredUtxos, feeRate, account, signer, provider, }) => { const { psbt } = await (0, exports.removeLiquidityPsbt)({ calldata, token, tokenAmount, gatheredUtxos, feeRate, account, provider, }); const { signedPsbt } = await signer.signAllInputs({ rawPsbt: psbt, finalize: true, }); const pushResult = await provider.pushPsbt({ psbtBase64: signedPsbt, }); return pushResult; }; exports.removeLiquidity = removeLiquidity; const swapPsbt = async ({ calldata, token, tokenAmount, gatheredUtxos, feeRate, account, provider, frontendFee, feeAddress, }) => { if (tokenAmount <= 0n) { throw new Error('Cannot process zero tokens'); } let alkaneTokenUtxos; const tokenUtxos = await Promise.all([ (0, alkanes_1.findAlkaneUtxos)({ address: account.taproot.address, greatestToLeast: false, provider, targetNumberOfAlkanes: Number(tokenAmount), alkaneId: token, }), ]); alkaneTokenUtxos = { alkaneUtxos: tokenUtxos[0].alkaneUtxos, totalSatoshis: tokenUtxos[0].totalSatoshis, }; const edicts = [ { id: new protoruneruneid_1.ProtoruneRuneId((0, integer_1.u128)(BigInt(token.block)), (0, integer_1.u128)(BigInt(token.tx))), amount: (0, integer_1.u128)(tokenAmount), output: (0, integer_1.u32)(5), }, ]; const protostone = (0, proto_runestone_upgrade_1.encodeRunestoneProtostone)({ protostones: [ protostone_1.ProtoStone.message({ protocolTag: 1n, edicts, pointer: 0, refundPointer: 0, calldata: (0, bytes_1.encipher)([]), }), protostone_1.ProtoStone.message({ protocolTag: 1n, pointer: 0, refundPointer: 0, calldata: (0, bytes_1.encipher)(calldata), }), ], }).encodedRunestone; let psbtOptions = { alkaneUtxos: alkaneTokenUtxos, protostone, gatheredUtxos, feeRate, account, provider, }; if (frontendFee && feeAddress) { psbtOptions.frontendFee = frontendFee; psbtOptions.feeAddress = feeAddress; } const { psbt, fee } = await __1.alkanes.executePsbt(psbtOptions); return { psbt, fee }; }; exports.swapPsbt = swapPsbt; const swap = async ({ calldata, token, tokenAmount, gatheredUtxos, feeRate, account, signer, provider, frontendFee, feeAddress, }) => { const { psbt } = await (0, exports.swapPsbt)({ calldata, token, tokenAmount, gatheredUtxos, feeRate, account, provider, frontendFee, feeAddress, }); const { signedPsbt } = await signer.signAllInputs({ rawPsbt: psbt, finalize: true, }); const pushResult = await provider.pushPsbt({ psbtBase64: signedPsbt, }); return pushResult; }; exports.swap = swap; //# sourceMappingURL=pool.js.map