@whetstone-research/doppler-sdk 1.0.26 → 1.0.27
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 +13 -7
- package/dist/evm/index.cjs +198 -93
- package/dist/evm/index.cjs.map +1 -1
- package/dist/evm/index.d.cts +44 -5
- package/dist/evm/index.d.ts +44 -5
- package/dist/evm/index.js +197 -94
- package/dist/evm/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -444,9 +444,9 @@ console.log('Token address:', presetResult.tokenAddress);
|
|
|
444
444
|
|
|
445
445
|
The preset helper seeds three curated curve buckets sized for ~1B token supply targets:
|
|
446
446
|
|
|
447
|
-
- `low`:
|
|
448
|
-
- `medium`:
|
|
449
|
-
- `high`:
|
|
447
|
+
- `low`: 50% of the sale allocated to a $0-$3M market cap window.
|
|
448
|
+
- `medium`: 25% targeting roughly $1k-$40M market caps.
|
|
449
|
+
- `high`: 24% aimed at $100k-$1B market caps.
|
|
450
450
|
|
|
451
451
|
Pass `presets` to pick a subset (e.g. `['medium', 'high']`) or provide `overrides` to adjust ticks, positions, or shares for a specific tier. When the selected presets sum to less than 100%, the builder automatically appends a filler curve (using the highest selected tier's shape) so liquidity always covers the full sale. Shares must stay within 0-1e18 and the helper will throw if the total ever exceeds 100%.
|
|
452
452
|
|
|
@@ -914,6 +914,8 @@ import { Derc20 } from '@whetstone-research/doppler-sdk/evm';
|
|
|
914
914
|
const tokenDirect = new Derc20(publicClient, walletClient, tokenAddress);
|
|
915
915
|
```
|
|
916
916
|
|
|
917
|
+
For a runnable release-focused example covering legacy DERC20, DERC20 V2 schedules, and DopplerERC20V1 partial releases, see [examples/vesting-release.ts](./examples/vesting-release.ts).
|
|
918
|
+
|
|
917
919
|
### DopplerERC20V1 Tokens
|
|
918
920
|
|
|
919
921
|
Use the newer DopplerERC20V1 token template by either setting `type: 'dopplerERC20V1'` explicitly or by passing fields such as `maxBalanceLimit` with `balanceLimitEnd`, `controller`, or `excludedFromBalanceLimit`. When selected, the SDK uses the configured `dopplerERC20V1Factory` by default. `withTokenFactory(address)` is a generic factory override and takes precedence, but it must point to a factory compatible with the selected token path and token data ABI. `controller` is optional and defaults to the zero address, set it only if early balance-limit disable should be possible. Standard configs without the specific fields still use the legacy `standard` path, where cliff/allocation vesting routes to legacy DERC20 V2. Keep explicit `type: 'dopplerERC20V1'` when you want its behavior but have no specific fields to infer from.
|
|
@@ -1427,6 +1429,10 @@ for (const id of SUPPORTED_CHAIN_IDS) {
|
|
|
1427
1429
|
}
|
|
1428
1430
|
```
|
|
1429
1431
|
|
|
1432
|
+
Robinhood Chain is available as `CHAIN_IDS.ROBINHOOD` (`4663`). The SDK exposes
|
|
1433
|
+
addresses and support checks for it, but does not export a viem chain definition;
|
|
1434
|
+
use your application's chain/client setup when constructing clients.
|
|
1435
|
+
|
|
1430
1436
|
## Advanced Usage
|
|
1431
1437
|
|
|
1432
1438
|
### Custom Vesting Configuration
|
|
@@ -1782,7 +1788,7 @@ pnpm dev
|
|
|
1782
1788
|
|
|
1783
1789
|
The SDK includes comprehensive tests covering:
|
|
1784
1790
|
|
|
1785
|
-
- **Airlock Whitelisting**: Verifies that all modules are properly whitelisted on Ethereum Mainnet, Monad Mainnet, Base Mainnet, and
|
|
1791
|
+
- **Airlock Whitelisting**: Verifies that all modules are properly whitelisted on Ethereum Mainnet, Monad Mainnet, Base Mainnet, Base Sepolia, and Robinhood Chain
|
|
1786
1792
|
- **Multicurve Functionality**: Tests multicurve auction creation and quoting
|
|
1787
1793
|
- **Token Address Mining**: Tests for generating optimized token addresses
|
|
1788
1794
|
|
|
@@ -1796,10 +1802,10 @@ pnpm test:whitelisting
|
|
|
1796
1802
|
ALCHEMY_API_KEY=your_key_here pnpm test:whitelisting
|
|
1797
1803
|
|
|
1798
1804
|
# Limit to specific whitelist-audit chains when needed
|
|
1799
|
-
TEST_CHAINS=mainnet,base,base-sepolia,monad-mainnet pnpm test:whitelisting
|
|
1805
|
+
TEST_CHAINS=mainnet,base,base-sepolia,monad-mainnet,robinhood pnpm test:whitelisting
|
|
1800
1806
|
```
|
|
1801
1807
|
|
|
1802
|
-
The whitelisting suite is scoped to the release-audit chains: Ethereum Mainnet, Monad Mainnet, Base Mainnet, and
|
|
1808
|
+
The whitelisting suite is scoped to the release-audit chains: Ethereum Mainnet, Monad Mainnet, Base Mainnet, Base Sepolia, and Robinhood Chain.
|
|
1803
1809
|
|
|
1804
1810
|
Whitelisting test RPC priority is:
|
|
1805
1811
|
|
|
@@ -1833,7 +1839,7 @@ If you're migrating from `doppler-v3-sdk` or `doppler-v4-sdk`, see our [Migratio
|
|
|
1833
1839
|
|
|
1834
1840
|
## Contributing
|
|
1835
1841
|
|
|
1836
|
-
Contributions are welcome! Please see our [Contributing Guide](
|
|
1842
|
+
Contributions are welcome! Please see our [Contributing Guide](./CONTRIBUTING.md) for details.
|
|
1837
1843
|
|
|
1838
1844
|
## License
|
|
1839
1845
|
|
package/dist/evm/index.cjs
CHANGED
|
@@ -404,23 +404,23 @@ var DEFAULT_OPENING_DOPPLER_NUM_PD_SLUGS = DEFAULT_PD_SLUGS;
|
|
|
404
404
|
var DEFAULT_OPENING_DOPPLER_FEE = FEE_TIERS.HIGH;
|
|
405
405
|
var DEFAULT_OPENING_DOPPLER_TICK_SPACING = DOPPLER_MAX_TICK_SPACING;
|
|
406
406
|
var DEFAULT_MULTICURVE_LOWER_TICKS = [
|
|
407
|
-
-
|
|
408
|
-
-
|
|
409
|
-
-
|
|
407
|
+
-887200,
|
|
408
|
+
-222200,
|
|
409
|
+
-176200
|
|
410
410
|
];
|
|
411
411
|
var DEFAULT_MULTICURVE_UPPER_TICKS = [
|
|
412
|
-
-
|
|
413
|
-
-
|
|
414
|
-
-
|
|
412
|
+
-142200,
|
|
413
|
+
-116300,
|
|
414
|
+
-84100
|
|
415
415
|
];
|
|
416
416
|
var DEFAULT_MULTICURVE_NUM_POSITIONS = [11, 11, 11];
|
|
417
417
|
var DEFAULT_MULTICURVE_MAX_SUPPLY_SHARES = [
|
|
418
|
-
viem.parseEther("0.
|
|
419
|
-
//
|
|
420
|
-
viem.parseEther("0.
|
|
421
|
-
//
|
|
422
|
-
viem.parseEther("0.
|
|
423
|
-
//
|
|
418
|
+
viem.parseEther("0.5"),
|
|
419
|
+
// 50% for LOW tier
|
|
420
|
+
viem.parseEther("0.25"),
|
|
421
|
+
// 25% for MEDIUM tier
|
|
422
|
+
viem.parseEther("0.24")
|
|
423
|
+
// 24% for HIGH tier
|
|
424
424
|
];
|
|
425
425
|
var BASIS_POINTS = 1e4;
|
|
426
426
|
var FLAG_MASK = BigInt(16383);
|
|
@@ -464,7 +464,7 @@ var CHAIN_IDS = {
|
|
|
464
464
|
BASE: 8453,
|
|
465
465
|
BASE_SEPOLIA: 84532,
|
|
466
466
|
INK: 57073,
|
|
467
|
-
|
|
467
|
+
ROBINHOOD: 4663,
|
|
468
468
|
UNICHAIN: 130,
|
|
469
469
|
UNICHAIN_SEPOLIA: 1301,
|
|
470
470
|
MONAD_TESTNET: 10143,
|
|
@@ -736,48 +736,50 @@ var ADDRESSES = {
|
|
|
736
736
|
weth: "0x4200000000000000000000000000000000000006",
|
|
737
737
|
uniswapV4Quoter: "0x3972c00f7ed4885e145823eb7c655375d275a1c5"
|
|
738
738
|
},
|
|
739
|
-
[CHAIN_IDS.
|
|
740
|
-
airlock: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.
|
|
739
|
+
[CHAIN_IDS.ROBINHOOD]: {
|
|
740
|
+
airlock: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.ROBINHOOD].Airlock,
|
|
741
741
|
tokenFactory: ZERO_ADDRESS,
|
|
742
742
|
dopplerERC20V1Factory: getGeneratedAddress(
|
|
743
|
-
CHAIN_IDS.
|
|
743
|
+
CHAIN_IDS.ROBINHOOD,
|
|
744
744
|
"DopplerERC20V1Factory"
|
|
745
745
|
),
|
|
746
746
|
dopplerERC20V1Implementation: getGeneratedAddress(
|
|
747
|
-
CHAIN_IDS.
|
|
747
|
+
CHAIN_IDS.ROBINHOOD,
|
|
748
748
|
"DopplerERC20V1"
|
|
749
749
|
),
|
|
750
|
-
doppler404Factory: getGeneratedAddress(CHAIN_IDS.
|
|
750
|
+
doppler404Factory: getGeneratedAddress(CHAIN_IDS.ROBINHOOD, "DN404Factory"),
|
|
751
751
|
v3Initializer: ZERO_ADDRESS,
|
|
752
752
|
v3Quoter: "0x33e885ed0ec9bf04ecfb19341582aadcb4c8a9e7",
|
|
753
|
-
lockableV3Initializer: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.
|
|
754
|
-
v4Initializer: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.
|
|
755
|
-
dopplerHookInitializer: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.
|
|
753
|
+
lockableV3Initializer: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.ROBINHOOD].LockableUniswapV3Initializer,
|
|
754
|
+
v4Initializer: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.ROBINHOOD].UniswapV4Initializer,
|
|
755
|
+
dopplerHookInitializer: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.ROBINHOOD].DopplerHookInitializer,
|
|
756
756
|
rehypeDopplerHookInitializer: getRehypeDopplerHookInitializerAddress(
|
|
757
|
-
CHAIN_IDS.
|
|
757
|
+
CHAIN_IDS.ROBINHOOD
|
|
758
758
|
),
|
|
759
|
-
rehypeDopplerHook: getRehypeDopplerHookInitializerAddress(
|
|
760
|
-
|
|
761
|
-
|
|
759
|
+
rehypeDopplerHook: getRehypeDopplerHookInitializerAddress(
|
|
760
|
+
CHAIN_IDS.ROBINHOOD
|
|
761
|
+
),
|
|
762
|
+
dopplerLens: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.ROBINHOOD].DopplerLensQuoter,
|
|
763
|
+
dopplerDeployer: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.ROBINHOOD].DopplerDeployer,
|
|
762
764
|
poolManager: "0x8366a39cc670b4001a1121b8f6a443a643e40951",
|
|
763
765
|
v2Migrator: ZERO_ADDRESS,
|
|
764
|
-
v2MigratorSplit: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.
|
|
766
|
+
v2MigratorSplit: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.ROBINHOOD].UniswapV2MigratorSplit,
|
|
765
767
|
v4Migrator: ZERO_ADDRESS,
|
|
766
|
-
dopplerHookMigrator: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.
|
|
767
|
-
rehypeDopplerHookMigrator: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.
|
|
768
|
-
noOpMigrator: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.
|
|
769
|
-
governanceFactory: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.
|
|
770
|
-
noOpGovernanceFactory: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.
|
|
771
|
-
launchpadGovernanceFactory: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.
|
|
768
|
+
dopplerHookMigrator: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.ROBINHOOD].DopplerHookMigrator,
|
|
769
|
+
rehypeDopplerHookMigrator: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.ROBINHOOD].RehypeDopplerHookMigrator,
|
|
770
|
+
noOpMigrator: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.ROBINHOOD].NoOpMigrator,
|
|
771
|
+
governanceFactory: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.ROBINHOOD].GovernanceFactory,
|
|
772
|
+
noOpGovernanceFactory: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.ROBINHOOD].NoOpGovernanceFactory,
|
|
773
|
+
launchpadGovernanceFactory: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.ROBINHOOD].LaunchpadGovernanceFactory,
|
|
772
774
|
streamableFeesLocker: ZERO_ADDRESS,
|
|
773
775
|
streamableFeesLockerV2: getGeneratedAddress(
|
|
774
|
-
CHAIN_IDS.
|
|
776
|
+
CHAIN_IDS.ROBINHOOD,
|
|
775
777
|
"StreamableFeesLockerV2"
|
|
776
778
|
),
|
|
777
|
-
topUpDistributor: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.
|
|
779
|
+
topUpDistributor: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.ROBINHOOD].TopUpDistributor,
|
|
778
780
|
universalRouter: "0x8876789976decbfcbbbe364623c63652db8c0904",
|
|
779
781
|
permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
|
|
780
|
-
bundler: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.
|
|
782
|
+
bundler: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.ROBINHOOD].Bundler,
|
|
781
783
|
weth: "0x0bd7d308f8e1639fab988df18a8011f41eacad73",
|
|
782
784
|
uniswapV2Factory: "0x8bceaa40b9acdfaedf85adf4ff01f5ad6517937f",
|
|
783
785
|
uniswapV3Factory: "0x1f7d7550b1b028f7571e69a784071f0205fd2efa",
|
|
@@ -6675,6 +6677,92 @@ function getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, amount1) {
|
|
|
6675
6677
|
return amount1 * Q96 / diff;
|
|
6676
6678
|
}
|
|
6677
6679
|
|
|
6680
|
+
// src/evm/utils/multicurveLiquidity.ts
|
|
6681
|
+
var MAX_UINT128 = (1n << 128n) - 1n;
|
|
6682
|
+
function getMaxLiquiditySafeMulticurveTickUpper(params) {
|
|
6683
|
+
if (params.tickUpper <= params.tickLower) {
|
|
6684
|
+
throw new Error(
|
|
6685
|
+
`Unable to find a uint128-safe multicurve max tick below ${params.tickUpper}`
|
|
6686
|
+
);
|
|
6687
|
+
}
|
|
6688
|
+
if (isCanonicalCurveLiquiditySafe(params)) return params.tickUpper;
|
|
6689
|
+
for (let candidate = params.tickUpper - params.tickSpacing; candidate > params.tickLower; candidate -= params.tickSpacing) {
|
|
6690
|
+
if (isCanonicalCurveLiquiditySafe({ ...params, tickUpper: candidate })) {
|
|
6691
|
+
return candidate;
|
|
6692
|
+
}
|
|
6693
|
+
}
|
|
6694
|
+
throw new Error(
|
|
6695
|
+
`Unable to find a uint128-safe multicurve max tick below ${params.tickUpper}`
|
|
6696
|
+
);
|
|
6697
|
+
}
|
|
6698
|
+
function isCanonicalCurveLiquiditySafe(params) {
|
|
6699
|
+
return isAdjustedCurveLiquiditySafe({
|
|
6700
|
+
...params,
|
|
6701
|
+
isToken0: true
|
|
6702
|
+
}) && isAdjustedCurveLiquiditySafe({
|
|
6703
|
+
...params,
|
|
6704
|
+
tickLower: -params.tickUpper,
|
|
6705
|
+
tickUpper: -params.tickLower,
|
|
6706
|
+
isToken0: false
|
|
6707
|
+
});
|
|
6708
|
+
}
|
|
6709
|
+
function isAdjustedCurveLiquiditySafe(params) {
|
|
6710
|
+
if (params.numPositions <= 0 || params.tickSpacing <= 0) {
|
|
6711
|
+
throw new Error("Multicurve positions and tick spacing must be positive");
|
|
6712
|
+
}
|
|
6713
|
+
const amountPerPosition = params.curveSupply / BigInt(params.numPositions);
|
|
6714
|
+
if (amountPerPosition <= 1n) return true;
|
|
6715
|
+
const amount = amountPerPosition - 1n;
|
|
6716
|
+
const maxLiquidityPerTick = getMaxLiquidityPerTick(params.tickSpacing);
|
|
6717
|
+
const liquidityByTick = /* @__PURE__ */ new Map();
|
|
6718
|
+
const farTick = params.isToken0 ? params.tickUpper : params.tickLower;
|
|
6719
|
+
const closeTick = params.isToken0 ? params.tickLower : params.tickUpper;
|
|
6720
|
+
const spread = params.tickUpper - params.tickLower;
|
|
6721
|
+
const farSqrtPriceX96 = getSqrtRatioAtTick(farTick);
|
|
6722
|
+
for (let i = 0; i < params.numPositions; i++) {
|
|
6723
|
+
const tickDelta = Number(
|
|
6724
|
+
BigInt(i) * BigInt(spread) / BigInt(params.numPositions)
|
|
6725
|
+
);
|
|
6726
|
+
const unalignedTick = params.isToken0 ? closeTick + tickDelta : closeTick - tickDelta;
|
|
6727
|
+
const startingTick = alignMulticurveTick(
|
|
6728
|
+
params.isToken0,
|
|
6729
|
+
unalignedTick,
|
|
6730
|
+
params.tickSpacing
|
|
6731
|
+
);
|
|
6732
|
+
if (startingTick === farTick) continue;
|
|
6733
|
+
const startingSqrtPriceX96 = getSqrtRatioAtTick(startingTick);
|
|
6734
|
+
const liquidity = params.isToken0 ? getLiquidityForAmount0(startingSqrtPriceX96, farSqrtPriceX96, amount) : getLiquidityForAmount1(farSqrtPriceX96, startingSqrtPriceX96, amount);
|
|
6735
|
+
if (liquidity > maxLiquidityPerTick) return false;
|
|
6736
|
+
const tickA = Math.min(farTick, startingTick);
|
|
6737
|
+
const tickB = Math.max(farTick, startingTick);
|
|
6738
|
+
if (!addTickLiquidity(liquidityByTick, tickA, liquidity, maxLiquidityPerTick)) {
|
|
6739
|
+
return false;
|
|
6740
|
+
}
|
|
6741
|
+
if (!addTickLiquidity(liquidityByTick, tickB, liquidity, maxLiquidityPerTick)) {
|
|
6742
|
+
return false;
|
|
6743
|
+
}
|
|
6744
|
+
}
|
|
6745
|
+
return true;
|
|
6746
|
+
}
|
|
6747
|
+
function getMaxLiquidityPerTick(tickSpacing) {
|
|
6748
|
+
const minTick = Math.trunc(MIN_TICK / tickSpacing) * tickSpacing;
|
|
6749
|
+
const maxTick = Math.trunc(MAX_TICK / tickSpacing) * tickSpacing;
|
|
6750
|
+
const numTicks = BigInt((maxTick - minTick) / tickSpacing + 1);
|
|
6751
|
+
return MAX_UINT128 / numTicks;
|
|
6752
|
+
}
|
|
6753
|
+
function addTickLiquidity(liquidityByTick, tick, liquidity, maxLiquidityPerTick) {
|
|
6754
|
+
const updatedLiquidity = (liquidityByTick.get(tick) ?? 0n) + liquidity;
|
|
6755
|
+
if (updatedLiquidity > maxLiquidityPerTick) return false;
|
|
6756
|
+
liquidityByTick.set(tick, updatedLiquidity);
|
|
6757
|
+
return true;
|
|
6758
|
+
}
|
|
6759
|
+
function alignMulticurveTick(isToken0, tick, tickSpacing) {
|
|
6760
|
+
if (isToken0) {
|
|
6761
|
+
return tick < 0 ? Math.trunc((tick - tickSpacing + 1) / tickSpacing) * tickSpacing : Math.trunc(tick / tickSpacing) * tickSpacing;
|
|
6762
|
+
}
|
|
6763
|
+
return tick < 0 ? Math.trunc(tick / tickSpacing) * tickSpacing : Math.trunc((tick + tickSpacing - 1) / tickSpacing) * tickSpacing;
|
|
6764
|
+
}
|
|
6765
|
+
|
|
6678
6766
|
// src/evm/utils/computeOptimalGamma.ts
|
|
6679
6767
|
function computeOptimalGamma(startTick, endTick, duration, epochLength, tickSpacing) {
|
|
6680
6768
|
const totalEpochs = duration / epochLength;
|
|
@@ -6710,6 +6798,23 @@ function isToken0Expected(numeraire) {
|
|
|
6710
6798
|
}
|
|
6711
6799
|
}
|
|
6712
6800
|
|
|
6801
|
+
// src/evm/utils/beneficiaries.ts
|
|
6802
|
+
function sortBeneficiaries(beneficiaries) {
|
|
6803
|
+
const sorted = [...beneficiaries].sort((a, b) => {
|
|
6804
|
+
const aAddr = a.beneficiary.toLowerCase();
|
|
6805
|
+
const bAddr = b.beneficiary.toLowerCase();
|
|
6806
|
+
return aAddr < bAddr ? -1 : aAddr > bAddr ? 1 : 0;
|
|
6807
|
+
});
|
|
6808
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
6809
|
+
if (sorted[i].beneficiary.toLowerCase() === sorted[i - 1].beneficiary.toLowerCase()) {
|
|
6810
|
+
throw new Error(
|
|
6811
|
+
`Duplicate beneficiary address: ${sorted[i].beneficiary}. Each beneficiary address must be unique \u2014 the contract requires strictly ascending addresses and reverts with UnorderedBeneficiaries() otherwise. Merge the entries into a single beneficiary with the combined shares.`
|
|
6812
|
+
);
|
|
6813
|
+
}
|
|
6814
|
+
}
|
|
6815
|
+
return sorted;
|
|
6816
|
+
}
|
|
6817
|
+
|
|
6713
6818
|
// src/evm/types.ts
|
|
6714
6819
|
var NO_OP_ENABLED_CHAIN_IDS = [
|
|
6715
6820
|
CHAIN_IDS.MAINNET,
|
|
@@ -6718,7 +6823,7 @@ var NO_OP_ENABLED_CHAIN_IDS = [
|
|
|
6718
6823
|
CHAIN_IDS.BASE_SEPOLIA,
|
|
6719
6824
|
CHAIN_IDS.UNICHAIN,
|
|
6720
6825
|
CHAIN_IDS.UNICHAIN_SEPOLIA,
|
|
6721
|
-
CHAIN_IDS.
|
|
6826
|
+
CHAIN_IDS.ROBINHOOD,
|
|
6722
6827
|
CHAIN_IDS.MONAD_TESTNET,
|
|
6723
6828
|
CHAIN_IDS.MONAD_MAINNET
|
|
6724
6829
|
];
|
|
@@ -6729,7 +6834,7 @@ var LAUNCHPAD_ENABLED_CHAIN_IDS = [
|
|
|
6729
6834
|
CHAIN_IDS.MAINNET,
|
|
6730
6835
|
CHAIN_IDS.BASE,
|
|
6731
6836
|
CHAIN_IDS.BASE_SEPOLIA,
|
|
6732
|
-
CHAIN_IDS.
|
|
6837
|
+
CHAIN_IDS.ROBINHOOD,
|
|
6733
6838
|
CHAIN_IDS.MONAD_MAINNET
|
|
6734
6839
|
];
|
|
6735
6840
|
function isLaunchpadEnabledChain(chainId) {
|
|
@@ -7314,7 +7419,7 @@ function buildCurvesFromPresets(params) {
|
|
|
7314
7419
|
}
|
|
7315
7420
|
|
|
7316
7421
|
// src/evm/entities/DopplerFactory.ts
|
|
7317
|
-
var
|
|
7422
|
+
var MAX_UINT1282 = (1n << 128n) - 1n;
|
|
7318
7423
|
var MAX_PROCEEDS_SPLIT_SHARE = WAD / 2n;
|
|
7319
7424
|
var DERC20_V1_MAX_PREMINT_WAD = WAD * 8n / 10n;
|
|
7320
7425
|
var ONE_MILLION = 1000000n;
|
|
@@ -8010,11 +8115,7 @@ var DopplerFactory = class {
|
|
|
8010
8115
|
const hasBeneficiaries = params.pool.beneficiaries && params.pool.beneficiaries.length > 0;
|
|
8011
8116
|
let poolInitializerData;
|
|
8012
8117
|
if (hasBeneficiaries) {
|
|
8013
|
-
const sortedBeneficiaries = params.pool.beneficiaries
|
|
8014
|
-
const aAddr = a.beneficiary.toLowerCase();
|
|
8015
|
-
const bAddr = b.beneficiary.toLowerCase();
|
|
8016
|
-
return aAddr < bAddr ? -1 : aAddr > bAddr ? 1 : 0;
|
|
8017
|
-
});
|
|
8118
|
+
const sortedBeneficiaries = sortBeneficiaries(params.pool.beneficiaries);
|
|
8018
8119
|
poolInitializerData = viem.encodeAbiParameters(
|
|
8019
8120
|
[
|
|
8020
8121
|
{
|
|
@@ -8094,14 +8195,20 @@ var DopplerFactory = class {
|
|
|
8094
8195
|
const poolInitializerAddress = (() => {
|
|
8095
8196
|
if (hasBeneficiaries) {
|
|
8096
8197
|
const lockableInitializer = params.modules?.lockableV3Initializer ?? addresses.lockableV3Initializer;
|
|
8097
|
-
if (!lockableInitializer) {
|
|
8198
|
+
if (!lockableInitializer || lockableInitializer === ZERO_ADDRESS) {
|
|
8098
8199
|
throw new Error(
|
|
8099
8200
|
"Lockable V3 initializer address not configured on this chain. Required when using beneficiaries."
|
|
8100
8201
|
);
|
|
8101
8202
|
}
|
|
8102
8203
|
return lockableInitializer;
|
|
8103
8204
|
}
|
|
8104
|
-
|
|
8205
|
+
const standardInitializer = params.modules?.v3Initializer ?? addresses.v3Initializer;
|
|
8206
|
+
if (!standardInitializer || standardInitializer === ZERO_ADDRESS) {
|
|
8207
|
+
throw new Error(
|
|
8208
|
+
"UniswapV3Initializer address not configured on this chain. Use beneficiaries for lockable V3 support, provide an override via builder.withV3Initializer(...), or use a chain with standard V3 initializer support."
|
|
8209
|
+
);
|
|
8210
|
+
}
|
|
8211
|
+
return standardInitializer;
|
|
8105
8212
|
})();
|
|
8106
8213
|
const liquidityMigratorAddress = this.getMigratorAddress(
|
|
8107
8214
|
params.migration,
|
|
@@ -8516,6 +8623,11 @@ var DopplerFactory = class {
|
|
|
8516
8623
|
addresses
|
|
8517
8624
|
});
|
|
8518
8625
|
const poolInitializerAddress = params.modules?.v4Initializer ?? addresses.v4Initializer;
|
|
8626
|
+
if (!poolInitializerAddress || poolInitializerAddress === ZERO_ADDRESS) {
|
|
8627
|
+
throw new Error(
|
|
8628
|
+
"UniswapV4Initializer address not configured on this chain. Provide an override via builder.withV4Initializer(...) or use a chain with dynamic auction support."
|
|
8629
|
+
);
|
|
8630
|
+
}
|
|
8519
8631
|
const liquidityMigratorAddress = this.getMigratorAddress(
|
|
8520
8632
|
params.migration,
|
|
8521
8633
|
params.modules
|
|
@@ -9846,13 +9958,7 @@ var DopplerFactory = class {
|
|
|
9846
9958
|
if (!streamableFees) {
|
|
9847
9959
|
return "0x";
|
|
9848
9960
|
}
|
|
9849
|
-
const beneficiaryData =
|
|
9850
|
-
(a, b) => {
|
|
9851
|
-
const addrA = a.beneficiary.toLowerCase();
|
|
9852
|
-
const addrB = b.beneficiary.toLowerCase();
|
|
9853
|
-
return addrA < addrB ? -1 : addrA > addrB ? 1 : 0;
|
|
9854
|
-
}
|
|
9855
|
-
);
|
|
9961
|
+
const beneficiaryData = sortBeneficiaries(streamableFees.beneficiaries);
|
|
9856
9962
|
return viem.encodeAbiParameters(
|
|
9857
9963
|
[
|
|
9858
9964
|
{ type: "uint24" },
|
|
@@ -9877,12 +9983,8 @@ var DopplerFactory = class {
|
|
|
9877
9983
|
]
|
|
9878
9984
|
);
|
|
9879
9985
|
case "uniswapV4Split": {
|
|
9880
|
-
const beneficiaryData2 =
|
|
9881
|
-
|
|
9882
|
-
const addrA = a.beneficiary.toLowerCase();
|
|
9883
|
-
const addrB = b.beneficiary.toLowerCase();
|
|
9884
|
-
return addrA < addrB ? -1 : addrA > addrB ? 1 : 0;
|
|
9885
|
-
}
|
|
9986
|
+
const beneficiaryData2 = sortBeneficiaries(
|
|
9987
|
+
config.streamableFees.beneficiaries
|
|
9886
9988
|
);
|
|
9887
9989
|
const proceedsRecipient = config.proceedsSplit?.recipient ?? ZERO_ADDRESS;
|
|
9888
9990
|
const proceedsShare = config.proceedsSplit?.share ?? 0n;
|
|
@@ -9918,12 +10020,8 @@ var DopplerFactory = class {
|
|
|
9918
10020
|
"dopplerHook migration cannot set both hook and rehype config. Use exactly one hook mode."
|
|
9919
10021
|
);
|
|
9920
10022
|
}
|
|
9921
|
-
const beneficiaries =
|
|
9922
|
-
|
|
9923
|
-
const addrA = a.beneficiary.toLowerCase();
|
|
9924
|
-
const addrB = b.beneficiary.toLowerCase();
|
|
9925
|
-
return addrA < addrB ? -1 : addrA > addrB ? 1 : 0;
|
|
9926
|
-
}
|
|
10023
|
+
const beneficiaries = sortBeneficiaries(
|
|
10024
|
+
dopplerHookConfig.beneficiaries
|
|
9927
10025
|
);
|
|
9928
10026
|
let dopplerHookAddress = ZERO_ADDRESS;
|
|
9929
10027
|
let onInitializationCalldata = "0x";
|
|
@@ -10326,15 +10424,12 @@ var DopplerFactory = class {
|
|
|
10326
10424
|
}
|
|
10327
10425
|
const normalizedCurves = this.normalizeMulticurveCurves(
|
|
10328
10426
|
params.pool.curves,
|
|
10329
|
-
params.pool.tickSpacing
|
|
10427
|
+
params.pool.tickSpacing,
|
|
10428
|
+
params.sale.numTokensToSell
|
|
10330
10429
|
);
|
|
10331
10430
|
const addresses = getAddresses(this.chainId);
|
|
10332
|
-
const sortedBeneficiaries = (
|
|
10333
|
-
|
|
10334
|
-
const aAddr = a.beneficiary.toLowerCase();
|
|
10335
|
-
const bAddr = b.beneficiary.toLowerCase();
|
|
10336
|
-
return aAddr < bAddr ? -1 : aAddr > bAddr ? 1 : 0;
|
|
10337
|
-
}
|
|
10431
|
+
const sortedBeneficiaries = sortBeneficiaries(
|
|
10432
|
+
params.pool.beneficiaries ?? []
|
|
10338
10433
|
);
|
|
10339
10434
|
const initializerMode = this.resolveMulticurveInitializerMode(params);
|
|
10340
10435
|
const useScheduledInitializer = initializerMode.type === "scheduled";
|
|
@@ -10809,7 +10904,7 @@ var DopplerFactory = class {
|
|
|
10809
10904
|
/**
|
|
10810
10905
|
* Normalize user-provided multicurve positions and ensure they satisfy SDK constraints
|
|
10811
10906
|
*/
|
|
10812
|
-
normalizeMulticurveCurves(curves, tickSpacing) {
|
|
10907
|
+
normalizeMulticurveCurves(curves, tickSpacing, numTokensToSell) {
|
|
10813
10908
|
if (tickSpacing <= 0) {
|
|
10814
10909
|
throw new Error("Tick spacing must be positive");
|
|
10815
10910
|
}
|
|
@@ -10856,25 +10951,19 @@ var DopplerFactory = class {
|
|
|
10856
10951
|
if (fallbackTickLower === void 0) {
|
|
10857
10952
|
throw new Error("Unable to determine fallback multicurve tick range");
|
|
10858
10953
|
}
|
|
10859
|
-
const
|
|
10860
|
-
|
|
10861
|
-
|
|
10862
|
-
|
|
10863
|
-
|
|
10864
|
-
|
|
10865
|
-
|
|
10866
|
-
|
|
10867
|
-
tickUpper: fallbackTickUpper,
|
|
10868
|
-
numPositions: sanitizedCurves[sanitizedCurves.length - 1]?.numPositions ?? 1,
|
|
10869
|
-
shares: missingShare
|
|
10870
|
-
};
|
|
10871
|
-
return [...sanitizedCurves, fallbackCurve2];
|
|
10872
|
-
}
|
|
10954
|
+
const fallbackNumPositions = sanitizedCurves[sanitizedCurves.length - 1]?.numPositions ?? 1;
|
|
10955
|
+
const fallbackTickUpper = getMaxLiquiditySafeMulticurveTickUpper({
|
|
10956
|
+
tickLower: fallbackTickLower,
|
|
10957
|
+
tickUpper: this.roundMaxTickDown(tickSpacing),
|
|
10958
|
+
tickSpacing,
|
|
10959
|
+
numPositions: fallbackNumPositions,
|
|
10960
|
+
curveSupply: numTokensToSell * missingShare / WAD
|
|
10961
|
+
});
|
|
10873
10962
|
const fallbackCurve = {
|
|
10874
10963
|
// Extend from the most positive user tick out to the maximum supported tick bucket
|
|
10875
10964
|
tickLower: fallbackTickLower,
|
|
10876
10965
|
tickUpper: fallbackTickUpper,
|
|
10877
|
-
numPositions:
|
|
10966
|
+
numPositions: fallbackNumPositions,
|
|
10878
10967
|
shares: missingShare
|
|
10879
10968
|
};
|
|
10880
10969
|
return [...sanitizedCurves, fallbackCurve];
|
|
@@ -11394,8 +11483,15 @@ var DopplerFactory = class {
|
|
|
11394
11483
|
getMigratorAddress(config, overrides) {
|
|
11395
11484
|
const addresses = getAddresses(this.chainId);
|
|
11396
11485
|
switch (config.type) {
|
|
11397
|
-
case "uniswapV2":
|
|
11398
|
-
|
|
11486
|
+
case "uniswapV2": {
|
|
11487
|
+
const v2Address = overrides?.v2Migrator ?? addresses.v2Migrator;
|
|
11488
|
+
if (!v2Address || v2Address === ZERO_ADDRESS) {
|
|
11489
|
+
throw new Error(
|
|
11490
|
+
"UniswapV2Migrator not deployed on this chain. Use uniswapV2Split migration or provide override via modules.v2Migrator."
|
|
11491
|
+
);
|
|
11492
|
+
}
|
|
11493
|
+
return v2Address;
|
|
11494
|
+
}
|
|
11399
11495
|
case "uniswapV2Split": {
|
|
11400
11496
|
const v2SplitAddress = overrides?.v2MigratorSplit ?? addresses.v2MigratorSplit;
|
|
11401
11497
|
if (!v2SplitAddress || v2SplitAddress === ZERO_ADDRESS) {
|
|
@@ -11407,7 +11503,7 @@ var DopplerFactory = class {
|
|
|
11407
11503
|
}
|
|
11408
11504
|
case "uniswapV4": {
|
|
11409
11505
|
const v4Address = overrides?.v4Migrator ?? addresses.v4Migrator;
|
|
11410
|
-
if (v4Address ===
|
|
11506
|
+
if (!v4Address || v4Address === ZERO_ADDRESS) {
|
|
11411
11507
|
throw new Error(
|
|
11412
11508
|
"UniswapV4Migrator not deployed on this chain. Use uniswapV2 migration or provide override via modules.v4Migrator."
|
|
11413
11509
|
);
|
|
@@ -11573,7 +11669,7 @@ var DopplerFactory = class {
|
|
|
11573
11669
|
if (!allowZero && value === 0n) {
|
|
11574
11670
|
throw new Error(`${paramName} must be greater than zero`);
|
|
11575
11671
|
}
|
|
11576
|
-
if (value >
|
|
11672
|
+
if (value > MAX_UINT1282) {
|
|
11577
11673
|
throw new Error(`${paramName} exceeds uint128 range`);
|
|
11578
11674
|
}
|
|
11579
11675
|
}
|
|
@@ -18570,9 +18666,16 @@ var MulticurveBuilder = class _MulticurveBuilder {
|
|
|
18570
18666
|
tokenDecimals: config.tokenDecimals ?? 18,
|
|
18571
18667
|
numeraireDecimals: config.numeraireDecimals ?? 18
|
|
18572
18668
|
});
|
|
18669
|
+
const curveSupply = this.sale.numTokensToSell * curve.shares / WAD;
|
|
18670
|
+
const tickUpper = curve.marketCap.end === "max" ? getMaxLiquiditySafeMulticurveTickUpper({
|
|
18671
|
+
...curveTicks,
|
|
18672
|
+
tickSpacing,
|
|
18673
|
+
numPositions: curve.numPositions,
|
|
18674
|
+
curveSupply
|
|
18675
|
+
}) : curveTicks.tickUpper;
|
|
18573
18676
|
curves.push({
|
|
18574
18677
|
tickLower: curveTicks.tickLower,
|
|
18575
|
-
tickUpper
|
|
18678
|
+
tickUpper,
|
|
18576
18679
|
numPositions: curve.numPositions,
|
|
18577
18680
|
shares: curve.shares
|
|
18578
18681
|
});
|
|
@@ -18633,7 +18736,7 @@ var MulticurveBuilder = class _MulticurveBuilder {
|
|
|
18633
18736
|
}
|
|
18634
18737
|
dopplerHook = { ...dopplerHook, farTick };
|
|
18635
18738
|
}
|
|
18636
|
-
const initializer = this.initializer ?? (dopplerHook ? { type: "rehype", config: dopplerHook } : this.schedule ? { type: "scheduled", startTime: this.schedule.startTime } : { type: "standard" });
|
|
18739
|
+
const initializer = this.initializer?.type === "rehype" && dopplerHook ? { type: "rehype", config: dopplerHook } : this.initializer ?? (dopplerHook ? { type: "rehype", config: dopplerHook } : this.schedule ? { type: "scheduled", startTime: this.schedule.startTime } : { type: "standard" });
|
|
18637
18740
|
if (initializer.type === "scheduled" && dopplerHook) {
|
|
18638
18741
|
throw new Error(
|
|
18639
18742
|
"Cannot combine scheduled multicurve with rehype initializer. Use exactly one initializer mode."
|
|
@@ -19461,6 +19564,7 @@ exports.getAmount0ForLiquidity = getAmount0ForLiquidity;
|
|
|
19461
19564
|
exports.getAmount1ForLiquidity = getAmount1ForLiquidity;
|
|
19462
19565
|
exports.getLiquidityForAmount0 = getLiquidityForAmount0;
|
|
19463
19566
|
exports.getLiquidityForAmount1 = getLiquidityForAmount1;
|
|
19567
|
+
exports.getMaxLiquiditySafeMulticurveTickUpper = getMaxLiquiditySafeMulticurveTickUpper;
|
|
19464
19568
|
exports.getMaxTickRounded = getMaxTickRounded;
|
|
19465
19569
|
exports.getNearestUsableTick = getNearestUsableTick;
|
|
19466
19570
|
exports.getSqrtRatioAtTick = getSqrtRatioAtTick;
|
|
@@ -19489,6 +19593,7 @@ exports.ratioToTick = ratioToTick;
|
|
|
19489
19593
|
exports.rehypeDopplerHookAbi = rehypeDopplerHookAbi;
|
|
19490
19594
|
exports.rehypeDopplerHookMigratorAbi = rehypeDopplerHookMigratorAbi;
|
|
19491
19595
|
exports.resolveGasEstimate = resolveGasEstimate;
|
|
19596
|
+
exports.sortBeneficiaries = sortBeneficiaries;
|
|
19492
19597
|
exports.sqrtPriceX96ToPrice = sqrtPriceX96ToPrice;
|
|
19493
19598
|
exports.streamableFeesLockerAbi = streamableFeesLockerAbi;
|
|
19494
19599
|
exports.streamableFeesLockerV2Abi = streamableFeesLockerV2Abi;
|