@strobelabs/perpcity-sdk 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +17 -3
- package/dist/index.d.ts +17 -3
- package/dist/index.js +133 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +127 -20
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2375,6 +2375,10 @@ async function approveUsdc(context, amount, confirmations = DEFAULT_CONFIRMATION
|
|
|
2375
2375
|
var NUMBER_1E6 = 1e6;
|
|
2376
2376
|
var BIGINT_1E6 = 1000000n;
|
|
2377
2377
|
var Q96 = 79228162514264337593543950336n;
|
|
2378
|
+
var MIN_TICK = -887272;
|
|
2379
|
+
var MAX_TICK = 887272;
|
|
2380
|
+
var MIN_PRICE = 1e-6;
|
|
2381
|
+
var MAX_PRICE = 1e6;
|
|
2378
2382
|
|
|
2379
2383
|
// src/utils/conversions.ts
|
|
2380
2384
|
function priceToSqrtPriceX96(price) {
|
|
@@ -2407,6 +2411,11 @@ function priceToTick(price, roundDown) {
|
|
|
2407
2411
|
if (price <= 0) {
|
|
2408
2412
|
throw new Error("Price must be positive");
|
|
2409
2413
|
}
|
|
2414
|
+
if (price < MIN_PRICE || price > MAX_PRICE) {
|
|
2415
|
+
throw new Error(
|
|
2416
|
+
`Price ${price} is outside the representable range [${MIN_PRICE}, ${MAX_PRICE}]`
|
|
2417
|
+
);
|
|
2418
|
+
}
|
|
2410
2419
|
const logPrice = Math.log(price) / Math.log(1.0001);
|
|
2411
2420
|
return roundDown ? Math.floor(logPrice) : Math.ceil(logPrice);
|
|
2412
2421
|
}
|
|
@@ -3468,7 +3477,9 @@ async function createPerp(context, params) {
|
|
|
3468
3477
|
account: context.walletClient.account
|
|
3469
3478
|
});
|
|
3470
3479
|
const txHash = await context.walletClient.writeContract(request);
|
|
3471
|
-
const receipt = await context.publicClient.waitForTransactionReceipt({
|
|
3480
|
+
const receipt = await context.publicClient.waitForTransactionReceipt({
|
|
3481
|
+
hash: txHash
|
|
3482
|
+
});
|
|
3472
3483
|
if (receipt.status === "reverted") {
|
|
3473
3484
|
throw new Error(`Transaction reverted. Hash: ${txHash}`);
|
|
3474
3485
|
}
|
|
@@ -3535,7 +3546,9 @@ async function openTakerPosition(context, perpId, params) {
|
|
|
3535
3546
|
account: context.walletClient.account
|
|
3536
3547
|
});
|
|
3537
3548
|
const txHash = await context.walletClient.writeContract(request);
|
|
3538
|
-
const receipt = await context.publicClient.waitForTransactionReceipt({
|
|
3549
|
+
const receipt = await context.publicClient.waitForTransactionReceipt({
|
|
3550
|
+
hash: txHash
|
|
3551
|
+
});
|
|
3539
3552
|
if (receipt.status === "reverted") {
|
|
3540
3553
|
throw new Error(`Transaction reverted. Hash: ${txHash}`);
|
|
3541
3554
|
}
|
|
@@ -3560,6 +3573,82 @@ async function openTakerPosition(context, perpId, params) {
|
|
|
3560
3573
|
return new OpenPosition(context, perpId, takerPosId, params.isLong, false, txHash);
|
|
3561
3574
|
}, "openTakerPosition");
|
|
3562
3575
|
}
|
|
3576
|
+
function buildMakerContractParams(context, marginScaled, params, alignedTickLower, alignedTickUpper, maxAmt0In, maxAmt1In) {
|
|
3577
|
+
return {
|
|
3578
|
+
holder: context.walletClient.account.address,
|
|
3579
|
+
margin: marginScaled,
|
|
3580
|
+
liquidity: params.liquidity,
|
|
3581
|
+
tickLower: alignedTickLower,
|
|
3582
|
+
tickUpper: alignedTickUpper,
|
|
3583
|
+
maxAmt0In,
|
|
3584
|
+
maxAmt1In
|
|
3585
|
+
};
|
|
3586
|
+
}
|
|
3587
|
+
function calculateAlignedTicks(priceLower, priceUpper, tickSpacing) {
|
|
3588
|
+
const tickLower = priceToTick(priceLower, true);
|
|
3589
|
+
const tickUpper = priceToTick(priceUpper, false);
|
|
3590
|
+
const alignedTickLower = Math.floor(tickLower / tickSpacing) * tickSpacing;
|
|
3591
|
+
const alignedTickUpper = Math.ceil(tickUpper / tickSpacing) * tickSpacing;
|
|
3592
|
+
if (alignedTickLower < MIN_TICK) {
|
|
3593
|
+
throw new Error(
|
|
3594
|
+
`Lower tick ${alignedTickLower} is below MIN_TICK (${MIN_TICK}). Increase priceLower.`
|
|
3595
|
+
);
|
|
3596
|
+
}
|
|
3597
|
+
if (alignedTickUpper > MAX_TICK) {
|
|
3598
|
+
throw new Error(
|
|
3599
|
+
`Upper tick ${alignedTickUpper} exceeds MAX_TICK (${MAX_TICK}). Decrease priceUpper.`
|
|
3600
|
+
);
|
|
3601
|
+
}
|
|
3602
|
+
if (alignedTickLower === alignedTickUpper) {
|
|
3603
|
+
throw new Error(
|
|
3604
|
+
"Price range too narrow: lower and upper ticks are equal after alignment. Widen the range."
|
|
3605
|
+
);
|
|
3606
|
+
}
|
|
3607
|
+
return { alignedTickLower, alignedTickUpper };
|
|
3608
|
+
}
|
|
3609
|
+
function alignMakerTicks(params, tickSpacing) {
|
|
3610
|
+
return calculateAlignedTicks(params.priceLower, params.priceUpper, tickSpacing);
|
|
3611
|
+
}
|
|
3612
|
+
var DEFAULT_MAKER_SLIPPAGE_TOLERANCE = 0.01;
|
|
3613
|
+
var MAX_UINT128 = 2n ** 128n - 1n;
|
|
3614
|
+
async function quoteOpenMakerPosition(context, perpId, params) {
|
|
3615
|
+
return withErrorHandling(async () => {
|
|
3616
|
+
if (params.margin <= 0) {
|
|
3617
|
+
throw new Error("Margin must be greater than 0");
|
|
3618
|
+
}
|
|
3619
|
+
if (params.priceLower >= params.priceUpper) {
|
|
3620
|
+
throw new Error("priceLower must be less than priceUpper");
|
|
3621
|
+
}
|
|
3622
|
+
const marginScaled = scale6Decimals(params.margin);
|
|
3623
|
+
const perpData = await context.getPerpData(perpId);
|
|
3624
|
+
const { alignedTickLower, alignedTickUpper } = alignMakerTicks(params, perpData.tickSpacing);
|
|
3625
|
+
const contractParams = buildMakerContractParams(
|
|
3626
|
+
context,
|
|
3627
|
+
marginScaled,
|
|
3628
|
+
params,
|
|
3629
|
+
alignedTickLower,
|
|
3630
|
+
alignedTickUpper,
|
|
3631
|
+
MAX_UINT128,
|
|
3632
|
+
MAX_UINT128
|
|
3633
|
+
);
|
|
3634
|
+
const [unexpectedReason, perpDelta, usdDelta] = await context.publicClient.readContract({
|
|
3635
|
+
address: context.deployments().perpManager,
|
|
3636
|
+
abi: PERP_MANAGER_ABI,
|
|
3637
|
+
functionName: "quoteOpenMakerPosition",
|
|
3638
|
+
args: [perpId, contractParams]
|
|
3639
|
+
});
|
|
3640
|
+
if (unexpectedReason !== "0x") {
|
|
3641
|
+
throw new Error(`Quote failed: ${unexpectedReason}`);
|
|
3642
|
+
}
|
|
3643
|
+
return { perpDelta, usdDelta };
|
|
3644
|
+
}, "quoteOpenMakerPosition");
|
|
3645
|
+
}
|
|
3646
|
+
function applySlippage(delta, slippageTolerance) {
|
|
3647
|
+
if (delta >= 0n) return 0n;
|
|
3648
|
+
const absDelta = -delta;
|
|
3649
|
+
const slippageBps = BigInt(Math.ceil(slippageTolerance * 1e4));
|
|
3650
|
+
return absDelta + absDelta * slippageBps / 10000n;
|
|
3651
|
+
}
|
|
3563
3652
|
async function openMakerPosition(context, perpId, params) {
|
|
3564
3653
|
return withErrorHandling(async () => {
|
|
3565
3654
|
if (params.margin <= 0) {
|
|
@@ -3569,8 +3658,24 @@ async function openMakerPosition(context, perpId, params) {
|
|
|
3569
3658
|
throw new Error("priceLower must be less than priceUpper");
|
|
3570
3659
|
}
|
|
3571
3660
|
const marginScaled = scale6Decimals(params.margin);
|
|
3572
|
-
const
|
|
3573
|
-
const
|
|
3661
|
+
const perpData = await context.getPerpData(perpId);
|
|
3662
|
+
const { alignedTickLower, alignedTickUpper } = alignMakerTicks(params, perpData.tickSpacing);
|
|
3663
|
+
let maxAmt0In;
|
|
3664
|
+
let maxAmt1In;
|
|
3665
|
+
if (params.maxAmt0In === void 0 !== (params.maxAmt1In === void 0)) {
|
|
3666
|
+
throw new Error(
|
|
3667
|
+
"Both maxAmt0In and maxAmt1In must be provided together or neither. Omit both to use automatic quote-based slippage calculation."
|
|
3668
|
+
);
|
|
3669
|
+
}
|
|
3670
|
+
if (params.maxAmt0In !== void 0 && params.maxAmt1In !== void 0) {
|
|
3671
|
+
maxAmt0In = typeof params.maxAmt0In === "bigint" ? params.maxAmt0In : scale6Decimals(params.maxAmt0In);
|
|
3672
|
+
maxAmt1In = typeof params.maxAmt1In === "bigint" ? params.maxAmt1In : scale6Decimals(params.maxAmt1In);
|
|
3673
|
+
} else {
|
|
3674
|
+
const quote = await quoteOpenMakerPosition(context, perpId, params);
|
|
3675
|
+
const slippage = params.slippageTolerance ?? DEFAULT_MAKER_SLIPPAGE_TOLERANCE;
|
|
3676
|
+
maxAmt0In = applySlippage(quote.perpDelta, slippage);
|
|
3677
|
+
maxAmt1In = applySlippage(quote.usdDelta, slippage);
|
|
3678
|
+
}
|
|
3574
3679
|
const currentAllowance = await context.publicClient.readContract({
|
|
3575
3680
|
address: context.deployments().usdc,
|
|
3576
3681
|
abi: erc20Abi3,
|
|
@@ -3581,21 +3686,15 @@ async function openMakerPosition(context, perpId, params) {
|
|
|
3581
3686
|
if (currentAllowance < marginScaled) {
|
|
3582
3687
|
await approveUsdc(context, marginScaled);
|
|
3583
3688
|
}
|
|
3584
|
-
const
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
liquidity: params.liquidity,
|
|
3594
|
-
tickLower: alignedTickLower,
|
|
3595
|
-
tickUpper: alignedTickUpper,
|
|
3596
|
-
maxAmt0In: maxAmt0InScaled,
|
|
3597
|
-
maxAmt1In: maxAmt1InScaled
|
|
3598
|
-
};
|
|
3689
|
+
const contractParams = buildMakerContractParams(
|
|
3690
|
+
context,
|
|
3691
|
+
marginScaled,
|
|
3692
|
+
params,
|
|
3693
|
+
alignedTickLower,
|
|
3694
|
+
alignedTickUpper,
|
|
3695
|
+
maxAmt0In,
|
|
3696
|
+
maxAmt1In
|
|
3697
|
+
);
|
|
3599
3698
|
const { request } = await context.publicClient.simulateContract({
|
|
3600
3699
|
address: context.deployments().perpManager,
|
|
3601
3700
|
abi: PERP_MANAGER_ABI,
|
|
@@ -3604,7 +3703,9 @@ async function openMakerPosition(context, perpId, params) {
|
|
|
3604
3703
|
account: context.walletClient.account
|
|
3605
3704
|
});
|
|
3606
3705
|
const txHash = await context.walletClient.writeContract(request);
|
|
3607
|
-
const receipt = await context.publicClient.waitForTransactionReceipt({
|
|
3706
|
+
const receipt = await context.publicClient.waitForTransactionReceipt({
|
|
3707
|
+
hash: txHash
|
|
3708
|
+
});
|
|
3608
3709
|
if (receipt.status === "reverted") {
|
|
3609
3710
|
throw new Error(`Transaction reverted. Hash: ${txHash}`);
|
|
3610
3711
|
}
|
|
@@ -3791,6 +3892,10 @@ export {
|
|
|
3791
3892
|
ErrorCategory,
|
|
3792
3893
|
ErrorSource,
|
|
3793
3894
|
InsufficientFundsError,
|
|
3895
|
+
MAX_PRICE,
|
|
3896
|
+
MAX_TICK,
|
|
3897
|
+
MIN_PRICE,
|
|
3898
|
+
MIN_TICK,
|
|
3794
3899
|
NUMBER_1E6,
|
|
3795
3900
|
OpenPosition,
|
|
3796
3901
|
PERP_MANAGER_ABI,
|
|
@@ -3801,6 +3906,7 @@ export {
|
|
|
3801
3906
|
TransactionRejectedError,
|
|
3802
3907
|
ValidationError,
|
|
3803
3908
|
approveUsdc,
|
|
3909
|
+
calculateAlignedTicks,
|
|
3804
3910
|
calculateEntryPrice,
|
|
3805
3911
|
calculateLeverage,
|
|
3806
3912
|
calculateLiquidationPrice,
|
|
@@ -3835,6 +3941,7 @@ export {
|
|
|
3835
3941
|
parseContractError,
|
|
3836
3942
|
priceToSqrtPriceX96,
|
|
3837
3943
|
priceToTick,
|
|
3944
|
+
quoteOpenMakerPosition,
|
|
3838
3945
|
scale6Decimals,
|
|
3839
3946
|
scaleFrom6Decimals,
|
|
3840
3947
|
scaleFromX96,
|