liquid-sdk 1.0.0 → 1.1.0
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/README.md +71 -31
- package/dist/index.d.mts +324 -7
- package/dist/index.d.ts +324 -7
- package/dist/index.js +412 -27
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +391 -22
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// src/client.ts
|
|
2
2
|
import {
|
|
3
3
|
decodeEventLog,
|
|
4
|
-
encodeAbiParameters,
|
|
4
|
+
encodeAbiParameters as encodeAbiParameters2,
|
|
5
5
|
encodePacked,
|
|
6
6
|
keccak256,
|
|
7
7
|
getAddress,
|
|
8
|
-
zeroAddress
|
|
8
|
+
zeroAddress as zeroAddress2
|
|
9
9
|
} from "viem";
|
|
10
10
|
import { base as base2 } from "viem/chains";
|
|
11
11
|
|
|
@@ -52,8 +52,154 @@ var TOKEN = {
|
|
|
52
52
|
MAX_EXTENSIONS: 10,
|
|
53
53
|
MAX_EXTENSION_BPS: 9e3
|
|
54
54
|
};
|
|
55
|
+
var POOL_POSITIONS = {
|
|
56
|
+
/** Single position, 100% of liquidity in one range */
|
|
57
|
+
Standard: [
|
|
58
|
+
{
|
|
59
|
+
tickLower: -230400,
|
|
60
|
+
// ~10 ETH / ~$20K
|
|
61
|
+
tickUpper: -12e4,
|
|
62
|
+
// ~$1.5B
|
|
63
|
+
positionBps: 1e4
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
/** 3-tranche Liquid default (hardcoded for ~10 ETH start, ~$2070/ETH) */
|
|
67
|
+
Liquid: [
|
|
68
|
+
{
|
|
69
|
+
tickLower: -230400,
|
|
70
|
+
// ~$20K starting
|
|
71
|
+
tickUpper: -198600,
|
|
72
|
+
// ~$500K
|
|
73
|
+
positionBps: 4e3
|
|
74
|
+
// 40%
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
tickLower: -198600,
|
|
78
|
+
// ~$500K
|
|
79
|
+
tickUpper: -168600,
|
|
80
|
+
// ~$10M
|
|
81
|
+
positionBps: 5e3
|
|
82
|
+
// 50%
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
tickLower: -168600,
|
|
86
|
+
// ~$10M
|
|
87
|
+
tickUpper: -122600,
|
|
88
|
+
// ~$1B
|
|
89
|
+
positionBps: 1e3
|
|
90
|
+
// 10%
|
|
91
|
+
}
|
|
92
|
+
]
|
|
93
|
+
};
|
|
94
|
+
var DEFAULTS = {
|
|
95
|
+
HOOK: ADDRESSES.HOOK_STATIC_FEE_V2,
|
|
96
|
+
TICK_SPACING: 200,
|
|
97
|
+
TICK_IF_TOKEN0_IS_LIQUID: -230400,
|
|
98
|
+
/** Static fee on buys (ETH → token): 1% (100 bps). Fees collected in ETH. */
|
|
99
|
+
PAIRED_FEE_BPS: 100,
|
|
100
|
+
/** Static fee on sells (token → ETH): 0%. No fees in liquid token. */
|
|
101
|
+
LIQUID_FEE_BPS: 0,
|
|
102
|
+
/** MEV module: Sniper Auction V2 */
|
|
103
|
+
MEV_MODULE: ADDRESSES.SNIPER_AUCTION_V2,
|
|
104
|
+
/** Sniper auction starting fee: 80% (800,000 uniBps) */
|
|
105
|
+
SNIPER_STARTING_FEE: 8e5,
|
|
106
|
+
/** Sniper auction ending fee: 40% (400,000 uniBps) */
|
|
107
|
+
SNIPER_ENDING_FEE: 4e5,
|
|
108
|
+
/** Sniper auction decay period: 32 seconds */
|
|
109
|
+
SNIPER_SECONDS_TO_DECAY: 32
|
|
110
|
+
};
|
|
55
111
|
var DEFAULT_CHAIN = base;
|
|
56
112
|
var DEFAULT_CHAIN_ID = 8453;
|
|
113
|
+
var DEFAULT_RPC_URL = "https://base.drpc.org";
|
|
114
|
+
|
|
115
|
+
// src/utils/encoding.ts
|
|
116
|
+
import { encodeAbiParameters, zeroAddress } from "viem";
|
|
117
|
+
var PoolInitializationDataAbi = [
|
|
118
|
+
{
|
|
119
|
+
type: "tuple",
|
|
120
|
+
components: [
|
|
121
|
+
{ name: "extension", type: "address" },
|
|
122
|
+
{ name: "extensionData", type: "bytes" },
|
|
123
|
+
{ name: "feeData", type: "bytes" }
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
];
|
|
127
|
+
var StaticFeeInitAbi = [
|
|
128
|
+
{ type: "uint24" },
|
|
129
|
+
{ type: "uint24" }
|
|
130
|
+
];
|
|
131
|
+
var SniperAuctionInitAbi = [
|
|
132
|
+
{
|
|
133
|
+
type: "tuple",
|
|
134
|
+
components: [
|
|
135
|
+
{ name: "startingFee", type: "uint24" },
|
|
136
|
+
{ name: "endingFee", type: "uint24" },
|
|
137
|
+
{ name: "secondsToDecay", type: "uint256" }
|
|
138
|
+
]
|
|
139
|
+
}
|
|
140
|
+
];
|
|
141
|
+
function encodeStaticFeePoolData(liquidFeeBps, pairedFeeBps, extension = zeroAddress, extensionData = "0x") {
|
|
142
|
+
const feeData = encodeAbiParameters(StaticFeeInitAbi, [
|
|
143
|
+
liquidFeeBps * 100,
|
|
144
|
+
pairedFeeBps * 100
|
|
145
|
+
]);
|
|
146
|
+
return encodeAbiParameters(PoolInitializationDataAbi, [
|
|
147
|
+
{
|
|
148
|
+
extension,
|
|
149
|
+
extensionData,
|
|
150
|
+
feeData
|
|
151
|
+
}
|
|
152
|
+
]);
|
|
153
|
+
}
|
|
154
|
+
var DynamicFeeInitAbi = [
|
|
155
|
+
{ type: "uint24" },
|
|
156
|
+
// baseFee (uniBps)
|
|
157
|
+
{ type: "uint24" },
|
|
158
|
+
// maxFee (uniBps)
|
|
159
|
+
{ type: "uint256" },
|
|
160
|
+
// referenceTickFilterPeriod
|
|
161
|
+
{ type: "uint256" },
|
|
162
|
+
// resetPeriod
|
|
163
|
+
{ type: "int24" },
|
|
164
|
+
// resetTickFilter
|
|
165
|
+
{ type: "uint256" },
|
|
166
|
+
// feeControlNumerator
|
|
167
|
+
{ type: "uint24" }
|
|
168
|
+
// decayFilterBps
|
|
169
|
+
];
|
|
170
|
+
function encodeDynamicFeePoolData(config, extension = zeroAddress, extensionData = "0x") {
|
|
171
|
+
const feeData = encodeAbiParameters(DynamicFeeInitAbi, [
|
|
172
|
+
config.baseFeeBps * 100,
|
|
173
|
+
config.maxFeeBps * 100,
|
|
174
|
+
BigInt(config.referenceTickFilterPeriod),
|
|
175
|
+
BigInt(config.resetPeriod),
|
|
176
|
+
config.resetTickFilter,
|
|
177
|
+
config.feeControlNumerator,
|
|
178
|
+
config.decayFilterBps
|
|
179
|
+
]);
|
|
180
|
+
return encodeAbiParameters(PoolInitializationDataAbi, [
|
|
181
|
+
{
|
|
182
|
+
extension,
|
|
183
|
+
extensionData,
|
|
184
|
+
feeData
|
|
185
|
+
}
|
|
186
|
+
]);
|
|
187
|
+
}
|
|
188
|
+
function encodeSniperAuctionData(config) {
|
|
189
|
+
if (config.startingFee <= config.endingFee) {
|
|
190
|
+
throw new Error("startingFee must be greater than endingFee");
|
|
191
|
+
}
|
|
192
|
+
if (config.secondsToDecay <= 0) {
|
|
193
|
+
throw new Error("secondsToDecay must be positive");
|
|
194
|
+
}
|
|
195
|
+
return encodeAbiParameters(SniperAuctionInitAbi, [
|
|
196
|
+
{
|
|
197
|
+
startingFee: config.startingFee,
|
|
198
|
+
endingFee: config.endingFee,
|
|
199
|
+
secondsToDecay: BigInt(config.secondsToDecay)
|
|
200
|
+
}
|
|
201
|
+
]);
|
|
202
|
+
}
|
|
57
203
|
|
|
58
204
|
// src/abis/LiquidFactory.ts
|
|
59
205
|
var LiquidFactoryAbi = [
|
|
@@ -756,7 +902,7 @@ var LiquidSDK = class {
|
|
|
756
902
|
* The paired token must be WETH for simple dev buys.
|
|
757
903
|
*/
|
|
758
904
|
buildDevBuyExtension(devBuy) {
|
|
759
|
-
const extensionData =
|
|
905
|
+
const extensionData = encodeAbiParameters2(
|
|
760
906
|
[
|
|
761
907
|
{
|
|
762
908
|
type: "tuple",
|
|
@@ -780,11 +926,11 @@ var LiquidSDK = class {
|
|
|
780
926
|
[
|
|
781
927
|
{
|
|
782
928
|
pairedTokenPoolKey: {
|
|
783
|
-
currency0:
|
|
784
|
-
currency1:
|
|
929
|
+
currency0: zeroAddress2,
|
|
930
|
+
currency1: zeroAddress2,
|
|
785
931
|
fee: 0,
|
|
786
932
|
tickSpacing: 0,
|
|
787
|
-
hooks:
|
|
933
|
+
hooks: zeroAddress2
|
|
788
934
|
},
|
|
789
935
|
pairedTokenAmountOutMinimum: 0n,
|
|
790
936
|
recipient: devBuy.recipient
|
|
@@ -798,6 +944,97 @@ var LiquidSDK = class {
|
|
|
798
944
|
extensionData
|
|
799
945
|
};
|
|
800
946
|
}
|
|
947
|
+
// ── Validation ─────────────────────────────────────────────────
|
|
948
|
+
/**
|
|
949
|
+
* Validate a DeploymentConfig before sending to the contract.
|
|
950
|
+
* Catches common mistakes client-side with clear error messages.
|
|
951
|
+
*/
|
|
952
|
+
validateDeploymentConfig(config) {
|
|
953
|
+
const { lockerConfig, extensionConfigs } = config;
|
|
954
|
+
const { tickSpacing } = config.poolConfig;
|
|
955
|
+
const posLen = lockerConfig.tickLower.length;
|
|
956
|
+
if (lockerConfig.tickUpper.length !== posLen || lockerConfig.positionBps.length !== posLen) {
|
|
957
|
+
throw new Error(
|
|
958
|
+
`tickLower (${posLen}), tickUpper (${lockerConfig.tickUpper.length}), and positionBps (${lockerConfig.positionBps.length}) arrays must be the same length`
|
|
959
|
+
);
|
|
960
|
+
}
|
|
961
|
+
if (posLen === 0) {
|
|
962
|
+
throw new Error("At least one position is required");
|
|
963
|
+
}
|
|
964
|
+
if (posLen > 7) {
|
|
965
|
+
throw new Error(`Maximum 7 positions allowed, got ${posLen}`);
|
|
966
|
+
}
|
|
967
|
+
const posBpsSum = lockerConfig.positionBps.reduce((s, b) => s + b, 0);
|
|
968
|
+
if (posBpsSum !== FEE.BPS) {
|
|
969
|
+
throw new Error(
|
|
970
|
+
`positionBps must sum to ${FEE.BPS} (100%), got ${posBpsSum}`
|
|
971
|
+
);
|
|
972
|
+
}
|
|
973
|
+
for (let i = 0; i < posLen; i++) {
|
|
974
|
+
if (lockerConfig.tickLower[i] >= lockerConfig.tickUpper[i]) {
|
|
975
|
+
throw new Error(
|
|
976
|
+
`Position ${i}: tickLower (${lockerConfig.tickLower[i]}) must be less than tickUpper (${lockerConfig.tickUpper[i]})`
|
|
977
|
+
);
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
for (let i = 0; i < posLen; i++) {
|
|
981
|
+
if (lockerConfig.tickLower[i] % tickSpacing !== 0) {
|
|
982
|
+
throw new Error(
|
|
983
|
+
`Position ${i}: tickLower (${lockerConfig.tickLower[i]}) is not a multiple of tickSpacing (${tickSpacing})`
|
|
984
|
+
);
|
|
985
|
+
}
|
|
986
|
+
if (lockerConfig.tickUpper[i] % tickSpacing !== 0) {
|
|
987
|
+
throw new Error(
|
|
988
|
+
`Position ${i}: tickUpper (${lockerConfig.tickUpper[i]}) is not a multiple of tickSpacing (${tickSpacing})`
|
|
989
|
+
);
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
const startingTick = config.poolConfig.tickIfToken0IsLiquid;
|
|
993
|
+
for (let i = 0; i < posLen; i++) {
|
|
994
|
+
if (lockerConfig.tickLower[i] < startingTick) {
|
|
995
|
+
throw new Error(
|
|
996
|
+
`Position ${i}: tickLower (${lockerConfig.tickLower[i]}) is below the starting tick (${startingTick})`
|
|
997
|
+
);
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
const touchesStart = lockerConfig.tickLower.some(
|
|
1001
|
+
(t) => t === startingTick
|
|
1002
|
+
);
|
|
1003
|
+
if (!touchesStart) {
|
|
1004
|
+
throw new Error(
|
|
1005
|
+
`At least one position's tickLower must equal tickIfToken0IsLiquid (${startingTick})`
|
|
1006
|
+
);
|
|
1007
|
+
}
|
|
1008
|
+
const rwdLen = lockerConfig.rewardAdmins.length;
|
|
1009
|
+
if (lockerConfig.rewardRecipients.length !== rwdLen || lockerConfig.rewardBps.length !== rwdLen) {
|
|
1010
|
+
throw new Error(
|
|
1011
|
+
`rewardAdmins (${rwdLen}), rewardRecipients (${lockerConfig.rewardRecipients.length}), and rewardBps (${lockerConfig.rewardBps.length}) arrays must be the same length`
|
|
1012
|
+
);
|
|
1013
|
+
}
|
|
1014
|
+
if (rwdLen === 0) {
|
|
1015
|
+
throw new Error("At least one reward recipient is required");
|
|
1016
|
+
}
|
|
1017
|
+
const rwdBpsSum = lockerConfig.rewardBps.reduce((s, b) => s + b, 0);
|
|
1018
|
+
if (rwdBpsSum !== FEE.BPS) {
|
|
1019
|
+
throw new Error(
|
|
1020
|
+
`rewardBps must sum to ${FEE.BPS} (100%), got ${rwdBpsSum}`
|
|
1021
|
+
);
|
|
1022
|
+
}
|
|
1023
|
+
if (extensionConfigs.length > TOKEN.MAX_EXTENSIONS) {
|
|
1024
|
+
throw new Error(
|
|
1025
|
+
`Maximum ${TOKEN.MAX_EXTENSIONS} extensions allowed, got ${extensionConfigs.length}`
|
|
1026
|
+
);
|
|
1027
|
+
}
|
|
1028
|
+
const extBpsSum = extensionConfigs.reduce(
|
|
1029
|
+
(s, e) => s + e.extensionBps,
|
|
1030
|
+
0
|
|
1031
|
+
);
|
|
1032
|
+
if (extBpsSum > TOKEN.MAX_EXTENSION_BPS) {
|
|
1033
|
+
throw new Error(
|
|
1034
|
+
`Total extensionBps (${extBpsSum}) exceeds maximum (${TOKEN.MAX_EXTENSION_BPS})`
|
|
1035
|
+
);
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
801
1038
|
// ── Token Deployment ─────────────────────────────────────────────
|
|
802
1039
|
async deployToken(params) {
|
|
803
1040
|
if (!this.walletClient?.account) {
|
|
@@ -821,25 +1058,32 @@ var LiquidSDK = class {
|
|
|
821
1058
|
originatingChainId: BigInt(DEFAULT_CHAIN_ID)
|
|
822
1059
|
},
|
|
823
1060
|
poolConfig: {
|
|
824
|
-
hook: params.hook ??
|
|
1061
|
+
hook: params.hook ?? DEFAULTS.HOOK,
|
|
825
1062
|
pairedToken: params.pairedToken ?? EXTERNAL.WETH,
|
|
826
|
-
tickIfToken0IsLiquid: params.tickIfToken0IsLiquid ??
|
|
827
|
-
tickSpacing: params.tickSpacing ??
|
|
828
|
-
poolData: params.poolData ??
|
|
1063
|
+
tickIfToken0IsLiquid: params.tickIfToken0IsLiquid ?? DEFAULTS.TICK_IF_TOKEN0_IS_LIQUID,
|
|
1064
|
+
tickSpacing: params.tickSpacing ?? DEFAULTS.TICK_SPACING,
|
|
1065
|
+
poolData: params.poolData ?? encodeStaticFeePoolData(
|
|
1066
|
+
DEFAULTS.LIQUID_FEE_BPS,
|
|
1067
|
+
DEFAULTS.PAIRED_FEE_BPS
|
|
1068
|
+
)
|
|
829
1069
|
},
|
|
830
1070
|
lockerConfig: {
|
|
831
1071
|
locker: params.locker ?? ADDRESSES.LP_LOCKER,
|
|
832
1072
|
rewardAdmins: params.rewardAdmins ?? [account],
|
|
833
1073
|
rewardRecipients: params.rewardRecipients ?? [account],
|
|
834
1074
|
rewardBps: params.rewardBps ?? [1e4],
|
|
835
|
-
tickLower: params.tickLower ??
|
|
836
|
-
tickUpper: params.tickUpper ??
|
|
837
|
-
positionBps: params.positionBps ??
|
|
1075
|
+
tickLower: params.tickLower ?? POOL_POSITIONS.Liquid.map((p) => p.tickLower),
|
|
1076
|
+
tickUpper: params.tickUpper ?? POOL_POSITIONS.Liquid.map((p) => p.tickUpper),
|
|
1077
|
+
positionBps: params.positionBps ?? POOL_POSITIONS.Liquid.map((p) => p.positionBps),
|
|
838
1078
|
lockerData: params.lockerData ?? "0x"
|
|
839
1079
|
},
|
|
840
1080
|
mevModuleConfig: {
|
|
841
|
-
mevModule: params.mevModule ??
|
|
842
|
-
mevModuleData: params.mevModuleData ??
|
|
1081
|
+
mevModule: params.mevModule ?? DEFAULTS.MEV_MODULE,
|
|
1082
|
+
mevModuleData: params.mevModuleData ?? encodeSniperAuctionData({
|
|
1083
|
+
startingFee: DEFAULTS.SNIPER_STARTING_FEE,
|
|
1084
|
+
endingFee: DEFAULTS.SNIPER_ENDING_FEE,
|
|
1085
|
+
secondsToDecay: DEFAULTS.SNIPER_SECONDS_TO_DECAY
|
|
1086
|
+
})
|
|
843
1087
|
},
|
|
844
1088
|
extensionConfigs: [...params.extensions ?? []]
|
|
845
1089
|
};
|
|
@@ -848,6 +1092,7 @@ var LiquidSDK = class {
|
|
|
848
1092
|
this.buildDevBuyExtension(params.devBuy)
|
|
849
1093
|
);
|
|
850
1094
|
}
|
|
1095
|
+
this.validateDeploymentConfig(deploymentConfig);
|
|
851
1096
|
const msgValue = deploymentConfig.extensionConfigs.reduce(
|
|
852
1097
|
(sum, ext) => sum + ext.msgValue,
|
|
853
1098
|
0n
|
|
@@ -1034,7 +1279,7 @@ var LiquidSDK = class {
|
|
|
1034
1279
|
if (!this.walletClient?.account) {
|
|
1035
1280
|
throw new Error("walletClient with account required for claimFees");
|
|
1036
1281
|
}
|
|
1037
|
-
return this.walletClient.writeContract({
|
|
1282
|
+
return await this.walletClient.writeContract({
|
|
1038
1283
|
address: ADDRESSES.FEE_LOCKER,
|
|
1039
1284
|
abi: LiquidFeeLockerAbi,
|
|
1040
1285
|
functionName: "claim",
|
|
@@ -1073,7 +1318,7 @@ var LiquidSDK = class {
|
|
|
1073
1318
|
if (!this.walletClient?.account) {
|
|
1074
1319
|
throw new Error("walletClient with account required for claimVault");
|
|
1075
1320
|
}
|
|
1076
|
-
return this.walletClient.writeContract({
|
|
1321
|
+
return await this.walletClient.writeContract({
|
|
1077
1322
|
address: ADDRESSES.VAULT,
|
|
1078
1323
|
abi: LiquidVaultAbi,
|
|
1079
1324
|
functionName: "claim",
|
|
@@ -1202,7 +1447,7 @@ var LiquidSDK = class {
|
|
|
1202
1447
|
if (!this.walletClient?.account) {
|
|
1203
1448
|
throw new Error("walletClient with account required for claimAirdrop");
|
|
1204
1449
|
}
|
|
1205
|
-
return this.walletClient.writeContract({
|
|
1450
|
+
return await this.walletClient.writeContract({
|
|
1206
1451
|
address: ADDRESSES.AIRDROP_V2,
|
|
1207
1452
|
abi: LiquidAirdropV2Abi,
|
|
1208
1453
|
functionName: "claim",
|
|
@@ -1236,7 +1481,7 @@ var LiquidSDK = class {
|
|
|
1236
1481
|
throw new Error("walletClient with account required for collectRewards");
|
|
1237
1482
|
}
|
|
1238
1483
|
const locker = lockerAddress ?? ADDRESSES.LP_LOCKER;
|
|
1239
|
-
return this.walletClient.writeContract({
|
|
1484
|
+
return await this.walletClient.writeContract({
|
|
1240
1485
|
address: locker,
|
|
1241
1486
|
abi: LiquidLpLockerAbi,
|
|
1242
1487
|
functionName: "collectRewards",
|
|
@@ -1252,7 +1497,7 @@ var LiquidSDK = class {
|
|
|
1252
1497
|
);
|
|
1253
1498
|
}
|
|
1254
1499
|
const locker = lockerAddress ?? ADDRESSES.LP_LOCKER;
|
|
1255
|
-
return this.walletClient.writeContract({
|
|
1500
|
+
return await this.walletClient.writeContract({
|
|
1256
1501
|
address: locker,
|
|
1257
1502
|
abi: LiquidLpLockerAbi,
|
|
1258
1503
|
functionName: "collectRewardsWithoutUnlock",
|
|
@@ -1268,7 +1513,7 @@ var LiquidSDK = class {
|
|
|
1268
1513
|
);
|
|
1269
1514
|
}
|
|
1270
1515
|
const locker = lockerAddress ?? ADDRESSES.LP_LOCKER;
|
|
1271
|
-
return this.walletClient.writeContract({
|
|
1516
|
+
return await this.walletClient.writeContract({
|
|
1272
1517
|
address: locker,
|
|
1273
1518
|
abi: LiquidLpLockerAbi,
|
|
1274
1519
|
functionName: "updateRewardRecipient",
|
|
@@ -1303,10 +1548,121 @@ var LiquidSDK = class {
|
|
|
1303
1548
|
});
|
|
1304
1549
|
}
|
|
1305
1550
|
};
|
|
1551
|
+
|
|
1552
|
+
// src/utils/tick-math.ts
|
|
1553
|
+
var LOG_BASE = Math.log(1.0001);
|
|
1554
|
+
var DEFAULT_TICK_SPACING = 200;
|
|
1555
|
+
var TOTAL_SUPPLY = 1e11;
|
|
1556
|
+
function getTickFromMarketCapETH(marketCapETH, tickSpacing = DEFAULT_TICK_SPACING) {
|
|
1557
|
+
if (marketCapETH <= 0) throw new Error("marketCapETH must be positive");
|
|
1558
|
+
const price = marketCapETH / TOTAL_SUPPLY;
|
|
1559
|
+
const rawTick = Math.log(price) / LOG_BASE;
|
|
1560
|
+
return Math.floor(rawTick / tickSpacing) * tickSpacing;
|
|
1561
|
+
}
|
|
1562
|
+
function getTickFromMarketCapUSD(marketCapUSD, ethPriceUSD, tickSpacing = DEFAULT_TICK_SPACING) {
|
|
1563
|
+
if (ethPriceUSD <= 0) throw new Error("ethPriceUSD must be positive");
|
|
1564
|
+
return getTickFromMarketCapETH(marketCapUSD / ethPriceUSD, tickSpacing);
|
|
1565
|
+
}
|
|
1566
|
+
function marketCapFromTickETH(tick) {
|
|
1567
|
+
const price = Math.pow(1.0001, tick);
|
|
1568
|
+
return price * TOTAL_SUPPLY;
|
|
1569
|
+
}
|
|
1570
|
+
function marketCapFromTickUSD(tick, ethPriceUSD) {
|
|
1571
|
+
return marketCapFromTickETH(tick) * ethPriceUSD;
|
|
1572
|
+
}
|
|
1573
|
+
function getTickFromMarketCapStable(marketCap, stableDecimals, tickSpacing = DEFAULT_TICK_SPACING) {
|
|
1574
|
+
if (marketCap <= 0) throw new Error("marketCap must be positive");
|
|
1575
|
+
const price = marketCap / Math.pow(10, 29 - stableDecimals);
|
|
1576
|
+
const rawTick = Math.log(price) / LOG_BASE;
|
|
1577
|
+
return Math.floor(rawTick / tickSpacing) * tickSpacing;
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
// src/utils/positions.ts
|
|
1581
|
+
var DEFAULT_TRANCHES_USD = [
|
|
1582
|
+
{ upperMarketCapUSD: 5e5, supplyPct: 40 },
|
|
1583
|
+
{ upperMarketCapUSD: 1e7, supplyPct: 50 },
|
|
1584
|
+
{ upperMarketCapUSD: 1e9, supplyPct: 10 }
|
|
1585
|
+
];
|
|
1586
|
+
function createPositions(startingMarketCapETH, tranches, tickSpacing = 200) {
|
|
1587
|
+
if (tranches.length === 0) throw new Error("At least one tranche is required");
|
|
1588
|
+
if (tranches.length > 7) throw new Error("Maximum 7 positions allowed");
|
|
1589
|
+
const totalPct = tranches.reduce((sum, t) => sum + t.supplyPct, 0);
|
|
1590
|
+
if (Math.abs(totalPct - 100) > 0.01) {
|
|
1591
|
+
throw new Error(`Tranche percentages must sum to 100, got ${totalPct}`);
|
|
1592
|
+
}
|
|
1593
|
+
for (let i = 1; i < tranches.length; i++) {
|
|
1594
|
+
if (tranches[i].upperMarketCapETH <= tranches[i - 1].upperMarketCapETH) {
|
|
1595
|
+
throw new Error("Tranches must be ordered by ascending upperMarketCapETH");
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
const startingTick = getTickFromMarketCapETH(startingMarketCapETH, tickSpacing);
|
|
1599
|
+
const tickLower = [];
|
|
1600
|
+
const tickUpper = [];
|
|
1601
|
+
const positionBps = [];
|
|
1602
|
+
let prevTick = startingTick;
|
|
1603
|
+
for (const tranche of tranches) {
|
|
1604
|
+
const upperTick = getTickFromMarketCapETH(tranche.upperMarketCapETH, tickSpacing);
|
|
1605
|
+
if (upperTick <= prevTick) {
|
|
1606
|
+
throw new Error(
|
|
1607
|
+
`Tranche upper market cap ${tranche.upperMarketCapETH} ETH resolves to tick ${upperTick}, which is not above previous tick ${prevTick}. Increase the market cap or reduce tick spacing.`
|
|
1608
|
+
);
|
|
1609
|
+
}
|
|
1610
|
+
tickLower.push(prevTick);
|
|
1611
|
+
tickUpper.push(upperTick);
|
|
1612
|
+
positionBps.push(Math.round(tranche.supplyPct * 100));
|
|
1613
|
+
prevTick = upperTick;
|
|
1614
|
+
}
|
|
1615
|
+
return { tickLower, tickUpper, positionBps };
|
|
1616
|
+
}
|
|
1617
|
+
function createPositionsUSD(startingMarketCapUSD, ethPriceUSD, tranches, tickSpacing = 200) {
|
|
1618
|
+
if (ethPriceUSD <= 0) throw new Error("ethPriceUSD must be positive");
|
|
1619
|
+
const ethTranches = tranches.map((t) => ({
|
|
1620
|
+
upperMarketCapETH: t.upperMarketCapUSD / ethPriceUSD,
|
|
1621
|
+
supplyPct: t.supplyPct
|
|
1622
|
+
}));
|
|
1623
|
+
return createPositions(
|
|
1624
|
+
startingMarketCapUSD / ethPriceUSD,
|
|
1625
|
+
ethTranches,
|
|
1626
|
+
tickSpacing
|
|
1627
|
+
);
|
|
1628
|
+
}
|
|
1629
|
+
function createDefaultPositions(startingMarketCapUSD, ethPriceUSD, tickSpacing = 200) {
|
|
1630
|
+
const positions = createPositionsUSD(
|
|
1631
|
+
startingMarketCapUSD,
|
|
1632
|
+
ethPriceUSD,
|
|
1633
|
+
DEFAULT_TRANCHES_USD,
|
|
1634
|
+
tickSpacing
|
|
1635
|
+
);
|
|
1636
|
+
return {
|
|
1637
|
+
...positions,
|
|
1638
|
+
tickIfToken0IsLiquid: positions.tickLower[0]
|
|
1639
|
+
};
|
|
1640
|
+
}
|
|
1641
|
+
function describePositions(positions, ethPriceUSD) {
|
|
1642
|
+
return positions.tickLower.map((_, i) => {
|
|
1643
|
+
const lowerETH = Math.pow(1.0001, positions.tickLower[i]) * 1e11;
|
|
1644
|
+
const upperETH = Math.pow(1.0001, positions.tickUpper[i]) * 1e11;
|
|
1645
|
+
return {
|
|
1646
|
+
index: i,
|
|
1647
|
+
tickLower: positions.tickLower[i],
|
|
1648
|
+
tickUpper: positions.tickUpper[i],
|
|
1649
|
+
supplyPct: positions.positionBps[i] / 100,
|
|
1650
|
+
marketCapLowerETH: lowerETH,
|
|
1651
|
+
marketCapUpperETH: upperETH,
|
|
1652
|
+
...ethPriceUSD != null && {
|
|
1653
|
+
marketCapLowerUSD: lowerETH * ethPriceUSD,
|
|
1654
|
+
marketCapUpperUSD: upperETH * ethPriceUSD
|
|
1655
|
+
}
|
|
1656
|
+
};
|
|
1657
|
+
});
|
|
1658
|
+
}
|
|
1306
1659
|
export {
|
|
1307
1660
|
ADDRESSES,
|
|
1661
|
+
DEFAULTS,
|
|
1308
1662
|
DEFAULT_CHAIN,
|
|
1309
1663
|
DEFAULT_CHAIN_ID,
|
|
1664
|
+
DEFAULT_RPC_URL,
|
|
1665
|
+
DEFAULT_TRANCHES_USD,
|
|
1310
1666
|
ERC20Abi,
|
|
1311
1667
|
EXTERNAL,
|
|
1312
1668
|
FEE,
|
|
@@ -1321,6 +1677,19 @@ export {
|
|
|
1321
1677
|
LiquidSniperAuctionV2Abi,
|
|
1322
1678
|
LiquidSniperUtilV2Abi,
|
|
1323
1679
|
LiquidVaultAbi,
|
|
1324
|
-
|
|
1680
|
+
POOL_POSITIONS,
|
|
1681
|
+
TOKEN,
|
|
1682
|
+
createDefaultPositions,
|
|
1683
|
+
createPositions,
|
|
1684
|
+
createPositionsUSD,
|
|
1685
|
+
describePositions,
|
|
1686
|
+
encodeDynamicFeePoolData,
|
|
1687
|
+
encodeSniperAuctionData,
|
|
1688
|
+
encodeStaticFeePoolData,
|
|
1689
|
+
getTickFromMarketCapETH,
|
|
1690
|
+
getTickFromMarketCapStable,
|
|
1691
|
+
getTickFromMarketCapUSD,
|
|
1692
|
+
marketCapFromTickETH,
|
|
1693
|
+
marketCapFromTickUSD
|
|
1325
1694
|
};
|
|
1326
1695
|
//# sourceMappingURL=index.mjs.map
|