@whetstone-research/doppler-sdk 1.0.2 → 1.0.5

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/evm/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import '../chunk-PZ5AY32C.js';
2
- import { parseEther, formatEther, getAddress, encodeAbiParameters, keccak256, decodeEventLog, toHex, decodeAbiParameters, encodePacked, zeroAddress, zeroHash } from 'viem';
2
+ import { parseEther, formatEther, getAddress, encodeAbiParameters, keccak256, encodePacked, decodeEventLog, toHex, decodeAbiParameters, zeroAddress, zeroHash } from 'viem';
3
3
 
4
4
  // src/evm/deployments.generated.ts
5
5
  var GENERATED_DOPPLER_DEPLOYMENTS = {
@@ -297,6 +297,14 @@ var ADDRESSES = {
297
297
  [CHAIN_IDS.MAINNET]: {
298
298
  airlock: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.MAINNET].Airlock,
299
299
  tokenFactory: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.MAINNET].CloneERC20Factory,
300
+ derc20V2Factory: getGeneratedAddress(
301
+ CHAIN_IDS.MAINNET,
302
+ "CloneDERC20VotesV2Factory"
303
+ ),
304
+ derc20V2Implementation: getGeneratedAddress(
305
+ CHAIN_IDS.MAINNET,
306
+ "CloneDERC20VotesV2"
307
+ ),
300
308
  v3Initializer: ZERO_ADDRESS,
301
309
  v3Quoter: ZERO_ADDRESS,
302
310
  v4Initializer: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.MAINNET].UniswapV4Initializer,
@@ -329,6 +337,14 @@ var ADDRESSES = {
329
337
  [CHAIN_IDS.ETH_SEPOLIA]: {
330
338
  airlock: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.ETH_SEPOLIA].Airlock,
331
339
  tokenFactory: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.ETH_SEPOLIA].CloneERC20Factory,
340
+ derc20V2Factory: getGeneratedAddress(
341
+ CHAIN_IDS.ETH_SEPOLIA,
342
+ "CloneDERC20VotesV2Factory"
343
+ ),
344
+ derc20V2Implementation: getGeneratedAddress(
345
+ CHAIN_IDS.ETH_SEPOLIA,
346
+ "CloneDERC20VotesV2"
347
+ ),
332
348
  v3Initializer: ZERO_ADDRESS,
333
349
  v3Quoter: ZERO_ADDRESS,
334
350
  v4Initializer: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.ETH_SEPOLIA].UniswapV4Initializer,
@@ -359,6 +375,14 @@ var ADDRESSES = {
359
375
  [CHAIN_IDS.BASE]: {
360
376
  airlock: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.BASE].Airlock,
361
377
  tokenFactory: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.BASE].TokenFactory80,
378
+ derc20V2Factory: getGeneratedAddress(
379
+ CHAIN_IDS.BASE,
380
+ "CloneDERC20VotesV2Factory"
381
+ ),
382
+ derc20V2Implementation: getGeneratedAddress(
383
+ CHAIN_IDS.BASE,
384
+ "CloneDERC20VotesV2"
385
+ ),
362
386
  v3Initializer: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.BASE].UniswapV3Initializer,
363
387
  v3Quoter: "0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a",
364
388
  lockableV3Initializer: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.BASE].LockableUniswapV3Initializer,
@@ -397,6 +421,14 @@ var ADDRESSES = {
397
421
  [CHAIN_IDS.BASE_SEPOLIA]: {
398
422
  airlock: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.BASE_SEPOLIA].Airlock,
399
423
  tokenFactory: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.BASE_SEPOLIA].TokenFactory80,
424
+ derc20V2Factory: getGeneratedAddress(
425
+ CHAIN_IDS.BASE_SEPOLIA,
426
+ "CloneDERC20VotesV2Factory"
427
+ ),
428
+ derc20V2Implementation: getGeneratedAddress(
429
+ CHAIN_IDS.BASE_SEPOLIA,
430
+ "CloneDERC20VotesV2"
431
+ ),
400
432
  doppler404Factory: "0xdd8cea2890f1b3498436f19ec8da8fecc2cb7af7",
401
433
  v3Initializer: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.BASE_SEPOLIA].UniswapV3Initializer,
402
434
  v3Quoter: "0xC5290058841028F1614F3A6F0F5816cAd0df5E27",
@@ -439,6 +471,14 @@ var ADDRESSES = {
439
471
  [CHAIN_IDS.INK]: {
440
472
  airlock: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.INK].Airlock,
441
473
  tokenFactory: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.INK].TokenFactory,
474
+ derc20V2Factory: getGeneratedAddress(
475
+ CHAIN_IDS.INK,
476
+ "CloneDERC20VotesV2Factory"
477
+ ),
478
+ derc20V2Implementation: getGeneratedAddress(
479
+ CHAIN_IDS.INK,
480
+ "CloneDERC20VotesV2"
481
+ ),
442
482
  v3Initializer: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.INK].UniswapV3Initializer,
443
483
  v3Quoter: "0x96b572D2d880cf2Fa2563651BD23ADE6f5516652",
444
484
  v4Initializer: "0xC99b485499f78995C6F1640dbB1413c57f8BA684",
@@ -462,6 +502,14 @@ var ADDRESSES = {
462
502
  [CHAIN_IDS.UNICHAIN]: {
463
503
  airlock: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.UNICHAIN].Airlock,
464
504
  tokenFactory: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.UNICHAIN].TokenFactory,
505
+ derc20V2Factory: getGeneratedAddress(
506
+ CHAIN_IDS.UNICHAIN,
507
+ "CloneDERC20VotesV2Factory"
508
+ ),
509
+ derc20V2Implementation: getGeneratedAddress(
510
+ CHAIN_IDS.UNICHAIN,
511
+ "CloneDERC20VotesV2"
512
+ ),
465
513
  v3Initializer: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.UNICHAIN].UniswapV3Initializer,
466
514
  v3Quoter: "0x385A5cf5F83e99f7BB2852b6A19C3538b9FA7658",
467
515
  v4Initializer: "0x2F2BAcd46d3F5c9EE052Ab392b73711dB89129DB",
@@ -485,6 +533,14 @@ var ADDRESSES = {
485
533
  [CHAIN_IDS.UNICHAIN_SEPOLIA]: {
486
534
  airlock: "0x651ab94B4777e2e4cdf96082d90C65bd947b73A4",
487
535
  tokenFactory: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.UNICHAIN_SEPOLIA].TokenFactory,
536
+ derc20V2Factory: getGeneratedAddress(
537
+ CHAIN_IDS.UNICHAIN_SEPOLIA,
538
+ "CloneDERC20VotesV2Factory"
539
+ ),
540
+ derc20V2Implementation: getGeneratedAddress(
541
+ CHAIN_IDS.UNICHAIN_SEPOLIA,
542
+ "CloneDERC20VotesV2"
543
+ ),
488
544
  v3Initializer: "0x7Fb9a622186B4660A5988C223ebb9d3690dD5007",
489
545
  v3Quoter: "0x6Dd37329A1A225a6Fca658265D460423DCafBF89",
490
546
  v4Initializer: "0x992375478626E67F4e639d3298EbCAaE51C3dF0b",
@@ -508,6 +564,14 @@ var ADDRESSES = {
508
564
  [CHAIN_IDS.MONAD_TESTNET]: {
509
565
  airlock: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.MONAD_TESTNET].Airlock,
510
566
  tokenFactory: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.MONAD_TESTNET].TokenFactory80,
567
+ derc20V2Factory: getGeneratedAddress(
568
+ CHAIN_IDS.MONAD_TESTNET,
569
+ "CloneDERC20VotesV2Factory"
570
+ ),
571
+ derc20V2Implementation: getGeneratedAddress(
572
+ CHAIN_IDS.MONAD_TESTNET,
573
+ "CloneDERC20VotesV2"
574
+ ),
511
575
  v3Initializer: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.MONAD_TESTNET].UniswapV3Initializer,
512
576
  v3Quoter: ZERO_ADDRESS,
513
577
  v4Initializer: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.MONAD_TESTNET].UniswapV4Initializer,
@@ -532,6 +596,14 @@ var ADDRESSES = {
532
596
  [CHAIN_IDS.MONAD_MAINNET]: {
533
597
  airlock: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.MONAD_MAINNET].Airlock,
534
598
  tokenFactory: GENERATED_DOPPLER_DEPLOYMENTS[CHAIN_IDS.MONAD_MAINNET].TokenFactory80,
599
+ derc20V2Factory: getGeneratedAddress(
600
+ CHAIN_IDS.MONAD_MAINNET,
601
+ "CloneDERC20VotesV2Factory"
602
+ ),
603
+ derc20V2Implementation: getGeneratedAddress(
604
+ CHAIN_IDS.MONAD_MAINNET,
605
+ "CloneDERC20VotesV2"
606
+ ),
535
607
  v3Initializer: ZERO_ADDRESS,
536
608
  v3Quoter: "0x66266174564170519409d8853898f065c719536b",
537
609
  v4Initializer: ZERO_ADDRESS,
@@ -1772,6 +1844,87 @@ var derc20Abi = [
1772
1844
  ]
1773
1845
  }
1774
1846
  ];
1847
+ var derc20V2Abi = [
1848
+ ...derc20Abi,
1849
+ {
1850
+ type: "function",
1851
+ name: "computeAvailableVestedAmount",
1852
+ inputs: [
1853
+ { name: "beneficiary", type: "address", internalType: "address" },
1854
+ { name: "scheduleId", type: "uint256", internalType: "uint256" }
1855
+ ],
1856
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
1857
+ stateMutability: "view"
1858
+ },
1859
+ {
1860
+ type: "function",
1861
+ name: "getScheduleIdsOf",
1862
+ inputs: [{ name: "beneficiary", type: "address", internalType: "address" }],
1863
+ outputs: [{ name: "", type: "uint256[]", internalType: "uint256[]" }],
1864
+ stateMutability: "view"
1865
+ },
1866
+ {
1867
+ type: "function",
1868
+ name: "release",
1869
+ inputs: [{ name: "scheduleId", type: "uint256", internalType: "uint256" }],
1870
+ outputs: [],
1871
+ stateMutability: "nonpayable"
1872
+ },
1873
+ {
1874
+ type: "function",
1875
+ name: "releaseFor",
1876
+ inputs: [
1877
+ { name: "beneficiary", type: "address", internalType: "address" },
1878
+ { name: "scheduleId", type: "uint256", internalType: "uint256" }
1879
+ ],
1880
+ outputs: [],
1881
+ stateMutability: "nonpayable"
1882
+ },
1883
+ {
1884
+ type: "function",
1885
+ name: "releaseFor",
1886
+ inputs: [{ name: "beneficiary", type: "address", internalType: "address" }],
1887
+ outputs: [],
1888
+ stateMutability: "nonpayable"
1889
+ },
1890
+ {
1891
+ type: "function",
1892
+ name: "totalAllocatedOf",
1893
+ inputs: [{ name: "beneficiary", type: "address", internalType: "address" }],
1894
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
1895
+ stateMutability: "view"
1896
+ },
1897
+ {
1898
+ type: "function",
1899
+ name: "vestingOf",
1900
+ inputs: [
1901
+ { name: "beneficiary", type: "address", internalType: "address" },
1902
+ { name: "scheduleId", type: "uint256", internalType: "uint256" }
1903
+ ],
1904
+ outputs: [
1905
+ { name: "totalAmount", type: "uint256", internalType: "uint256" },
1906
+ { name: "releasedAmount", type: "uint256", internalType: "uint256" }
1907
+ ],
1908
+ stateMutability: "view"
1909
+ },
1910
+ {
1911
+ type: "function",
1912
+ name: "vestingScheduleCount",
1913
+ inputs: [],
1914
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
1915
+ stateMutability: "view"
1916
+ },
1917
+ {
1918
+ type: "function",
1919
+ name: "vestingSchedules",
1920
+ inputs: [{ name: "", type: "uint256", internalType: "uint256" }],
1921
+ outputs: [
1922
+ { name: "cliff", type: "uint64", internalType: "uint64" },
1923
+ { name: "duration", type: "uint64", internalType: "uint64" }
1924
+ ],
1925
+ stateMutability: "view"
1926
+ }
1927
+ ];
1775
1928
  var uniswapV4InitializerAbi = [
1776
1929
  {
1777
1930
  type: "function",
@@ -4317,6 +4470,22 @@ var STANDARD_TOKEN_DATA_ABI = [
4317
4470
  { type: "uint256[]" },
4318
4471
  { type: "string" }
4319
4472
  ];
4473
+ var STANDARD_TOKEN_V2_DATA_ABI = [
4474
+ { type: "string" },
4475
+ { type: "string" },
4476
+ { type: "uint256" },
4477
+ {
4478
+ type: "tuple[]",
4479
+ components: [
4480
+ { type: "uint64", name: "cliff" },
4481
+ { type: "uint64", name: "duration" }
4482
+ ]
4483
+ },
4484
+ { type: "address[]" },
4485
+ { type: "uint256[]" },
4486
+ { type: "uint256[]" },
4487
+ { type: "string" }
4488
+ ];
4320
4489
  var DOPPLER404_TOKEN_DATA_ABI = [
4321
4490
  { type: "string" },
4322
4491
  { type: "string" },
@@ -4374,6 +4543,13 @@ function computeCreate2AddressFast(buffer) {
4374
4543
  const hash = keccak256(bytesToHex(buffer));
4375
4544
  return "0x" + hash.slice(-40).toLowerCase();
4376
4545
  }
4546
+ function computeSoladyCloneInitCodeHash(implementation) {
4547
+ return keccak256(
4548
+ `0x602c3d8160093d39f33d3d3d3d363d3d37363d73${implementation.slice(
4549
+ 2
4550
+ )}5af43d3d93803e602a57fd5bf3`
4551
+ );
4552
+ }
4377
4553
  function buildTokenInitHash(params) {
4378
4554
  const {
4379
4555
  variant,
@@ -4382,7 +4558,8 @@ function buildTokenInitHash(params) {
4382
4558
  initialSupply,
4383
4559
  recipient,
4384
4560
  owner,
4385
- customBytecode
4561
+ customBytecode,
4562
+ v2Implementation
4386
4563
  } = params;
4387
4564
  if (variant === "doppler404") {
4388
4565
  const [name2, symbol2, baseURI] = decodeAbiParameters(
@@ -4407,6 +4584,15 @@ function buildTokenInitHash(params) {
4407
4584
  )
4408
4585
  );
4409
4586
  }
4587
+ if (variant === "standard-v2") {
4588
+ decodeAbiParameters(STANDARD_TOKEN_V2_DATA_ABI, tokenData);
4589
+ if (!v2Implementation) {
4590
+ throw new Error(
4591
+ "TokenAddressMiner: v2Implementation is required for standard-v2 tokens"
4592
+ );
4593
+ }
4594
+ return computeSoladyCloneInitCodeHash(v2Implementation);
4595
+ }
4410
4596
  const [
4411
4597
  name,
4412
4598
  symbol,
@@ -4487,7 +4673,8 @@ function mineTokenAddress(params) {
4487
4673
  initialSupply,
4488
4674
  recipient,
4489
4675
  owner,
4490
- customBytecode
4676
+ customBytecode,
4677
+ v2Implementation: params.v2Implementation
4491
4678
  });
4492
4679
  const hookConfig = hook ? {
4493
4680
  deployer: hook.deployer,
@@ -5092,6 +5279,7 @@ var erc20BalanceOfAbi = [
5092
5279
  }
5093
5280
  ];
5094
5281
  var TOKEN_FACTORY_80_ADDRESS2 = "0xf0b5141dd9096254b2ca624dff26024f46087229";
5282
+ var DERC20_V2_MIN_VESTING_DURATION = 24 * 60 * 60;
5095
5283
  var DopplerFactory = class {
5096
5284
  publicClient;
5097
5285
  walletClient;
@@ -5103,6 +5291,204 @@ var DopplerFactory = class {
5103
5291
  this.walletClient = walletClient;
5104
5292
  this.chainId = chainId;
5105
5293
  }
5294
+ usesDerc20V2Vesting(vesting) {
5295
+ return (vesting?.cliffDuration ?? 0) > 0;
5296
+ }
5297
+ resolveVestingAllocations(args) {
5298
+ if (!args.vesting) {
5299
+ return { recipients: [], amounts: [] };
5300
+ }
5301
+ if (args.vesting.recipients && args.vesting.amounts) {
5302
+ return {
5303
+ recipients: args.vesting.recipients,
5304
+ amounts: args.vesting.amounts
5305
+ };
5306
+ }
5307
+ return {
5308
+ recipients: [args.userAddress],
5309
+ amounts: [args.sale.initialSupply - args.sale.numTokensToSell]
5310
+ };
5311
+ }
5312
+ resolveStandardTokenFactoryMode(args) {
5313
+ if (this.usesDerc20V2Vesting(args.vesting)) {
5314
+ return "v2";
5315
+ }
5316
+ const v2Factory = args.addresses.derc20V2Factory;
5317
+ if (v2Factory && args.tokenFactory.toLowerCase() === v2Factory.toLowerCase()) {
5318
+ return "v2";
5319
+ }
5320
+ return "legacy";
5321
+ }
5322
+ assertStandardTokenFactoryCompatibility(args) {
5323
+ if (this.isDoppler404Token(args.token) || !this.usesDerc20V2Vesting(args.vesting)) {
5324
+ return;
5325
+ }
5326
+ const v2Factory = args.addresses.derc20V2Factory;
5327
+ if (!v2Factory || v2Factory === ZERO_ADDRESS2) {
5328
+ throw new Error(
5329
+ "Cliff vesting requires the DERC20 V2 factory, but no V2 factory is configured for this chain."
5330
+ );
5331
+ }
5332
+ if (args.tokenFactory.toLowerCase() !== v2Factory.toLowerCase()) {
5333
+ throw new Error(
5334
+ "Cliff vesting requires the DERC20 V2 factory. Remove the tokenFactory override or point it at the chain DERC20 V2 factory."
5335
+ );
5336
+ }
5337
+ }
5338
+ buildStandardTokenFactoryData(args) {
5339
+ const { recipients, amounts } = this.resolveVestingAllocations(args);
5340
+ const yearlyMintRate = args.token.yearlyMintRate ?? DEFAULT_V4_YEARLY_MINT_RATE;
5341
+ const mode = this.resolveStandardTokenFactoryMode({
5342
+ vesting: args.vesting,
5343
+ tokenFactory: args.tokenFactory,
5344
+ addresses: args.addresses
5345
+ });
5346
+ if (mode === "v2") {
5347
+ const implementation = args.addresses.derc20V2Implementation;
5348
+ if (!implementation || implementation === ZERO_ADDRESS2) {
5349
+ throw new Error(
5350
+ "DERC20 V2 implementation address not configured for this chain."
5351
+ );
5352
+ }
5353
+ const schedules = args.vesting === void 0 ? [] : [
5354
+ {
5355
+ cliff: BigInt(args.vesting.cliffDuration ?? 0),
5356
+ duration: BigInt(args.vesting.duration ?? 0)
5357
+ }
5358
+ ];
5359
+ return {
5360
+ kind: "v2",
5361
+ name: args.token.name,
5362
+ symbol: args.token.symbol,
5363
+ initialSupply: args.sale.initialSupply,
5364
+ airlock: args.airlock,
5365
+ yearlyMintRate,
5366
+ schedules,
5367
+ beneficiaries: recipients,
5368
+ scheduleIds: recipients.map(() => 0n),
5369
+ amounts,
5370
+ tokenURI: args.token.tokenURI,
5371
+ implementation
5372
+ };
5373
+ }
5374
+ return {
5375
+ kind: "legacy",
5376
+ name: args.token.name,
5377
+ symbol: args.token.symbol,
5378
+ initialSupply: args.sale.initialSupply,
5379
+ airlock: args.airlock,
5380
+ yearlyMintRate,
5381
+ vestingDuration: BigInt(args.vesting?.duration ?? 0),
5382
+ recipients,
5383
+ amounts,
5384
+ tokenURI: args.token.tokenURI
5385
+ };
5386
+ }
5387
+ encodeStandardTokenFactoryData(tokenFactoryData) {
5388
+ if (tokenFactoryData.kind === "v2") {
5389
+ return encodeAbiParameters(
5390
+ [
5391
+ { type: "string" },
5392
+ { type: "string" },
5393
+ { type: "uint256" },
5394
+ {
5395
+ type: "tuple[]",
5396
+ components: [
5397
+ { type: "uint64", name: "cliff" },
5398
+ { type: "uint64", name: "duration" }
5399
+ ]
5400
+ },
5401
+ { type: "address[]" },
5402
+ { type: "uint256[]" },
5403
+ { type: "uint256[]" },
5404
+ { type: "string" }
5405
+ ],
5406
+ [
5407
+ tokenFactoryData.name,
5408
+ tokenFactoryData.symbol,
5409
+ tokenFactoryData.yearlyMintRate,
5410
+ tokenFactoryData.schedules.map((schedule) => ({
5411
+ cliff: schedule.cliff,
5412
+ duration: schedule.duration
5413
+ })),
5414
+ tokenFactoryData.beneficiaries,
5415
+ tokenFactoryData.scheduleIds,
5416
+ tokenFactoryData.amounts,
5417
+ tokenFactoryData.tokenURI
5418
+ ]
5419
+ );
5420
+ }
5421
+ return encodeAbiParameters(
5422
+ [
5423
+ { type: "string" },
5424
+ { type: "string" },
5425
+ { type: "uint256" },
5426
+ { type: "uint256" },
5427
+ { type: "address[]" },
5428
+ { type: "uint256[]" },
5429
+ { type: "string" }
5430
+ ],
5431
+ [
5432
+ tokenFactoryData.name,
5433
+ tokenFactoryData.symbol,
5434
+ tokenFactoryData.yearlyMintRate,
5435
+ tokenFactoryData.vestingDuration,
5436
+ tokenFactoryData.recipients,
5437
+ tokenFactoryData.amounts,
5438
+ tokenFactoryData.tokenURI
5439
+ ]
5440
+ );
5441
+ }
5442
+ computeSoladyCloneInitCodeHash(implementation) {
5443
+ return keccak256(
5444
+ `0x602c3d8160093d39f33d3d3d3d363d3d37363d73${implementation.slice(
5445
+ 2
5446
+ )}5af43d3d93803e602a57fd5bf3`
5447
+ );
5448
+ }
5449
+ computeStandardTokenInitHash(tokenFactoryData, tokenFactory) {
5450
+ if (tokenFactoryData.kind === "v2") {
5451
+ return this.computeSoladyCloneInitCodeHash(
5452
+ tokenFactoryData.implementation
5453
+ );
5454
+ }
5455
+ const initData = encodeAbiParameters(
5456
+ [
5457
+ { type: "string" },
5458
+ { type: "string" },
5459
+ { type: "uint256" },
5460
+ { type: "address" },
5461
+ { type: "address" },
5462
+ { type: "uint256" },
5463
+ { type: "uint256" },
5464
+ { type: "address[]" },
5465
+ { type: "uint256[]" },
5466
+ { type: "string" }
5467
+ ],
5468
+ [
5469
+ tokenFactoryData.name,
5470
+ tokenFactoryData.symbol,
5471
+ tokenFactoryData.initialSupply,
5472
+ tokenFactoryData.airlock,
5473
+ tokenFactoryData.airlock,
5474
+ tokenFactoryData.yearlyMintRate,
5475
+ tokenFactoryData.vestingDuration,
5476
+ tokenFactoryData.recipients,
5477
+ tokenFactoryData.amounts,
5478
+ tokenFactoryData.tokenURI
5479
+ ]
5480
+ );
5481
+ const isTokenFactory802 = tokenFactory.toLowerCase() === TOKEN_FACTORY_80_ADDRESS2;
5482
+ return keccak256(
5483
+ encodePacked(
5484
+ ["bytes", "bytes"],
5485
+ [
5486
+ isTokenFactory802 ? derc2080_default : derc20_default,
5487
+ initData
5488
+ ]
5489
+ )
5490
+ );
5491
+ }
5106
5492
  /**
5107
5493
  * Set a custom migration data encoder function
5108
5494
  * @param encoder Custom function to encode migration data
@@ -5187,6 +5573,18 @@ var DopplerFactory = class {
5187
5573
  numeraire: params.sale.numeraire,
5188
5574
  overrides: params.modules
5189
5575
  });
5576
+ const resolvedTokenFactory = params.modules?.tokenFactory ?? (this.isDoppler404Token(params.token) ? addresses.doppler404Factory : this.usesDerc20V2Vesting(params.vesting) ? addresses.derc20V2Factory : addresses.tokenFactory);
5577
+ if (!resolvedTokenFactory || resolvedTokenFactory === ZERO_ADDRESS2) {
5578
+ throw new Error(
5579
+ "Token factory address not configured. Provide an explicit address via builder.withTokenFactory(...) or ensure chain config includes a valid factory."
5580
+ );
5581
+ }
5582
+ this.assertStandardTokenFactoryCompatibility({
5583
+ token: params.token,
5584
+ vesting: params.vesting,
5585
+ tokenFactory: resolvedTokenFactory,
5586
+ addresses
5587
+ });
5190
5588
  let tokenFactoryData;
5191
5589
  if (this.isDoppler404Token(params.token)) {
5192
5590
  const token404 = params.token;
@@ -5202,41 +5600,17 @@ var DopplerFactory = class {
5202
5600
  [params.token.name, params.token.symbol, baseURI, unit]
5203
5601
  );
5204
5602
  } else {
5205
- const tokenStd = params.token;
5206
- const vestingDuration = params.vesting?.duration ?? BigInt(0);
5207
- const yearlyMintRate = tokenStd.yearlyMintRate ?? DEFAULT_V4_YEARLY_MINT_RATE;
5208
- let vestingRecipients = [];
5209
- let vestingAmounts = [];
5210
- if (params.vesting) {
5211
- if (params.vesting.recipients && params.vesting.amounts) {
5212
- vestingRecipients = params.vesting.recipients;
5213
- vestingAmounts = params.vesting.amounts;
5214
- } else {
5215
- vestingRecipients = [params.userAddress];
5216
- vestingAmounts = [
5217
- params.sale.initialSupply - params.sale.numTokensToSell
5218
- ];
5219
- }
5220
- }
5221
- tokenFactoryData = encodeAbiParameters(
5222
- [
5223
- { type: "string" },
5224
- { type: "string" },
5225
- { type: "uint256" },
5226
- { type: "uint256" },
5227
- { type: "address[]" },
5228
- { type: "uint256[]" },
5229
- { type: "string" }
5230
- ],
5231
- [
5232
- tokenStd.name,
5233
- tokenStd.symbol,
5234
- yearlyMintRate,
5235
- BigInt(vestingDuration),
5236
- vestingRecipients,
5237
- vestingAmounts,
5238
- tokenStd.tokenURI
5239
- ]
5603
+ const standardTokenFactoryData = this.buildStandardTokenFactoryData({
5604
+ token: params.token,
5605
+ sale: params.sale,
5606
+ vesting: params.vesting,
5607
+ userAddress: params.userAddress,
5608
+ airlock: params.modules?.airlock ?? addresses.airlock,
5609
+ tokenFactory: resolvedTokenFactory,
5610
+ addresses
5611
+ });
5612
+ tokenFactoryData = this.encodeStandardTokenFactoryData(
5613
+ standardTokenFactoryData
5240
5614
  );
5241
5615
  }
5242
5616
  const governanceFactoryData = (() => {
@@ -5291,12 +5665,6 @@ var DopplerFactory = class {
5291
5665
  }
5292
5666
  return resolved;
5293
5667
  })();
5294
- const resolvedTokenFactory = params.modules?.tokenFactory ?? (this.isDoppler404Token(params.token) ? addresses.doppler404Factory : addresses.tokenFactory);
5295
- if (!resolvedTokenFactory || resolvedTokenFactory === ZERO_ADDRESS2) {
5296
- throw new Error(
5297
- "Token factory address not configured. Provide an explicit address via builder.withTokenFactory(...) or ensure chain config includes a valid factory."
5298
- );
5299
- }
5300
5668
  const baseCreateParams = {
5301
5669
  initialSupply: params.sale.initialSupply,
5302
5670
  numTokensToSell: params.sale.numTokensToSell,
@@ -5582,7 +5950,18 @@ var DopplerFactory = class {
5582
5950
  );
5583
5951
  }
5584
5952
  }
5585
- const vestingDuration = params.vesting?.duration ?? BigInt(0);
5953
+ const resolvedTokenFactoryDyn = params.modules?.tokenFactory ?? (this.isDoppler404Token(params.token) ? addresses.doppler404Factory : this.usesDerc20V2Vesting(params.vesting) ? addresses.derc20V2Factory : addresses.tokenFactory);
5954
+ if (!resolvedTokenFactoryDyn || resolvedTokenFactoryDyn === ZERO_ADDRESS2) {
5955
+ throw new Error(
5956
+ "Token factory address not configured. Provide an explicit address via builder.withTokenFactory(...) or ensure chain config includes a valid factory."
5957
+ );
5958
+ }
5959
+ this.assertStandardTokenFactoryCompatibility({
5960
+ token: params.token,
5961
+ vesting: params.vesting,
5962
+ tokenFactory: resolvedTokenFactoryDyn,
5963
+ addresses
5964
+ });
5586
5965
  const tokenFactoryData = this.isDoppler404Token(params.token) ? (() => {
5587
5966
  const t = params.token;
5588
5967
  return {
@@ -5591,39 +5970,15 @@ var DopplerFactory = class {
5591
5970
  baseURI: t.baseURI,
5592
5971
  unit: t.unit !== void 0 ? BigInt(t.unit) : 1000n
5593
5972
  };
5594
- })() : (() => {
5595
- const t = params.token;
5596
- let vestingRecipients = [];
5597
- let vestingAmounts = [];
5598
- if (params.vesting) {
5599
- if (params.vesting.recipients && params.vesting.amounts) {
5600
- vestingRecipients = params.vesting.recipients;
5601
- vestingAmounts = params.vesting.amounts;
5602
- } else {
5603
- vestingRecipients = [params.userAddress];
5604
- vestingAmounts = [
5605
- params.sale.initialSupply - params.sale.numTokensToSell
5606
- ];
5607
- }
5608
- }
5609
- return {
5610
- name: t.name,
5611
- symbol: t.symbol,
5612
- initialSupply: params.sale.initialSupply,
5613
- airlock: addresses.airlock,
5614
- yearlyMintRate: t.yearlyMintRate ?? DEFAULT_V4_YEARLY_MINT_RATE,
5615
- vestingDuration: BigInt(vestingDuration),
5616
- recipients: vestingRecipients,
5617
- amounts: vestingAmounts,
5618
- tokenURI: t.tokenURI
5619
- };
5620
- })();
5621
- const resolvedTokenFactoryDyn = params.modules?.tokenFactory ?? (this.isDoppler404Token(params.token) ? addresses.doppler404Factory : addresses.tokenFactory);
5622
- if (!resolvedTokenFactoryDyn || resolvedTokenFactoryDyn === ZERO_ADDRESS2) {
5623
- throw new Error(
5624
- "Token factory address not configured. Provide an explicit address via builder.withTokenFactory(...) or ensure chain config includes a valid factory."
5625
- );
5626
- }
5973
+ })() : this.buildStandardTokenFactoryData({
5974
+ token: params.token,
5975
+ sale: params.sale,
5976
+ vesting: params.vesting,
5977
+ userAddress: params.userAddress,
5978
+ airlock: params.modules?.airlock ?? addresses.airlock,
5979
+ tokenFactory: resolvedTokenFactoryDyn,
5980
+ addresses
5981
+ });
5627
5982
  const [
5628
5983
  salt,
5629
5984
  hookAddress,
@@ -5950,7 +6305,18 @@ var DopplerFactory = class {
5950
6305
  );
5951
6306
  }
5952
6307
  }
5953
- const vestingDuration = params.vesting?.duration ?? BigInt(0);
6308
+ const resolvedTokenFactory = params.modules?.tokenFactory ?? (this.isDoppler404Token(params.token) ? addresses.doppler404Factory : this.usesDerc20V2Vesting(params.vesting) ? addresses.derc20V2Factory : addresses.tokenFactory);
6309
+ if (!resolvedTokenFactory || resolvedTokenFactory === ZERO_ADDRESS2) {
6310
+ throw new Error(
6311
+ "Token factory address not configured. Provide an explicit address via builder.withTokenFactory(...) or ensure chain config includes a valid factory."
6312
+ );
6313
+ }
6314
+ this.assertStandardTokenFactoryCompatibility({
6315
+ token: params.token,
6316
+ vesting: params.vesting,
6317
+ tokenFactory: resolvedTokenFactory,
6318
+ addresses
6319
+ });
5954
6320
  const tokenFactoryData = this.isDoppler404Token(params.token) ? (() => {
5955
6321
  const t = params.token;
5956
6322
  return {
@@ -5959,39 +6325,15 @@ var DopplerFactory = class {
5959
6325
  baseURI: t.baseURI,
5960
6326
  unit: t.unit !== void 0 ? BigInt(t.unit) : 1000n
5961
6327
  };
5962
- })() : (() => {
5963
- const t = params.token;
5964
- let vestingRecipients = [];
5965
- let vestingAmounts = [];
5966
- if (params.vesting) {
5967
- if (params.vesting.recipients && params.vesting.amounts) {
5968
- vestingRecipients = params.vesting.recipients;
5969
- vestingAmounts = params.vesting.amounts;
5970
- } else {
5971
- vestingRecipients = [params.userAddress];
5972
- vestingAmounts = [
5973
- params.sale.initialSupply - params.sale.numTokensToSell
5974
- ];
5975
- }
5976
- }
5977
- return {
5978
- name: t.name,
5979
- symbol: t.symbol,
5980
- initialSupply: params.sale.initialSupply,
5981
- airlock: params.modules?.airlock ?? addresses.airlock,
5982
- yearlyMintRate: t.yearlyMintRate ?? DEFAULT_V4_YEARLY_MINT_RATE,
5983
- vestingDuration: BigInt(vestingDuration),
5984
- recipients: vestingRecipients,
5985
- amounts: vestingAmounts,
5986
- tokenURI: t.tokenURI
5987
- };
5988
- })();
5989
- const resolvedTokenFactory = params.modules?.tokenFactory ?? (this.isDoppler404Token(params.token) ? addresses.doppler404Factory : addresses.tokenFactory);
5990
- if (!resolvedTokenFactory || resolvedTokenFactory === ZERO_ADDRESS2) {
5991
- throw new Error(
5992
- "Token factory address not configured. Provide an explicit address via builder.withTokenFactory(...) or ensure chain config includes a valid factory."
5993
- );
5994
- }
6328
+ })() : this.buildStandardTokenFactoryData({
6329
+ token: params.token,
6330
+ sale: params.sale,
6331
+ vesting: params.vesting,
6332
+ userAddress: params.userAddress,
6333
+ airlock: params.modules?.airlock ?? addresses.airlock,
6334
+ tokenFactory: resolvedTokenFactory,
6335
+ addresses
6336
+ });
5995
6337
  const auctionTokens = params.sale.numTokensToSell * BigInt(params.openingAuction.shareToAuctionBps) / 10000n;
5996
6338
  if (auctionTokens <= 0n) {
5997
6339
  throw new Error("Opening auction token allocation rounds to zero");
@@ -6777,29 +7119,9 @@ var DopplerFactory = class {
6777
7119
  ],
6778
7120
  [t.name, t.symbol, t.baseURI, t.unit ?? 1000n]
6779
7121
  );
6780
- })() : (() => {
6781
- const t = params.tokenFactoryData;
6782
- return encodeAbiParameters(
6783
- [
6784
- { type: "string" },
6785
- { type: "string" },
6786
- { type: "uint256" },
6787
- { type: "uint256" },
6788
- { type: "address[]" },
6789
- { type: "uint256[]" },
6790
- { type: "string" }
6791
- ],
6792
- [
6793
- t.name,
6794
- t.symbol,
6795
- t.yearlyMintRate,
6796
- t.vestingDuration,
6797
- t.recipients,
6798
- t.amounts,
6799
- t.tokenURI
6800
- ]
6801
- );
6802
- })();
7122
+ })() : this.encodeStandardTokenFactoryData(
7123
+ params.tokenFactoryData
7124
+ );
6803
7125
  let tokenInitHash;
6804
7126
  if (params.tokenVariant === "doppler404") {
6805
7127
  const t = params.tokenFactoryData;
@@ -6828,42 +7150,9 @@ var DopplerFactory = class {
6828
7150
  )
6829
7151
  );
6830
7152
  } else {
6831
- const t = params.tokenFactoryData;
6832
- const initData = encodeAbiParameters(
6833
- [
6834
- { type: "string" },
6835
- { type: "string" },
6836
- { type: "uint256" },
6837
- { type: "address" },
6838
- { type: "address" },
6839
- { type: "uint256" },
6840
- { type: "uint256" },
6841
- { type: "address[]" },
6842
- { type: "uint256[]" },
6843
- { type: "string" }
6844
- ],
6845
- [
6846
- t.name,
6847
- t.symbol,
6848
- params.initialSupply,
6849
- params.airlock,
6850
- params.airlock,
6851
- t.yearlyMintRate,
6852
- t.vestingDuration,
6853
- t.recipients,
6854
- t.amounts,
6855
- t.tokenURI
6856
- ]
6857
- );
6858
- const isTokenFactory802 = params.tokenFactory.toLowerCase() === TOKEN_FACTORY_80_ADDRESS2;
6859
- tokenInitHash = keccak256(
6860
- encodePacked(
6861
- ["bytes", "bytes"],
6862
- [
6863
- isTokenFactory802 ? derc2080_default : derc20_default,
6864
- initData
6865
- ]
6866
- )
7153
+ tokenInitHash = this.computeStandardTokenInitHash(
7154
+ params.tokenFactoryData,
7155
+ params.tokenFactory
6867
7156
  );
6868
7157
  }
6869
7158
  const isToken0 = isToken0Expected(params.numeraire);
@@ -7540,6 +7829,18 @@ var DopplerFactory = class {
7540
7829
  ]
7541
7830
  );
7542
7831
  }
7832
+ const resolvedTokenFactory = params.modules?.tokenFactory ?? (this.isDoppler404Token(params.token) ? addresses.doppler404Factory : this.usesDerc20V2Vesting(params.vesting) ? addresses.derc20V2Factory : addresses.tokenFactory);
7833
+ if (!resolvedTokenFactory || resolvedTokenFactory === ZERO_ADDRESS2) {
7834
+ throw new Error(
7835
+ "Token factory address not configured. Provide an explicit address or ensure chain config includes a valid factory."
7836
+ );
7837
+ }
7838
+ this.assertStandardTokenFactoryCompatibility({
7839
+ token: params.token,
7840
+ vesting: params.vesting,
7841
+ tokenFactory: resolvedTokenFactory,
7842
+ addresses
7843
+ });
7543
7844
  let tokenFactoryData;
7544
7845
  if (this.isDoppler404Token(params.token)) {
7545
7846
  const token404 = params.token;
@@ -7554,41 +7855,17 @@ var DopplerFactory = class {
7554
7855
  [token404.name, token404.symbol, token404.baseURI, unit]
7555
7856
  );
7556
7857
  } else {
7557
- const tokenStd = params.token;
7558
- const vestingDuration = params.vesting?.duration ?? BigInt(0);
7559
- const yearlyMintRate = tokenStd.yearlyMintRate ?? DEFAULT_V4_YEARLY_MINT_RATE;
7560
- let vestingRecipients = [];
7561
- let vestingAmounts = [];
7562
- if (params.vesting) {
7563
- if (params.vesting.recipients && params.vesting.amounts) {
7564
- vestingRecipients = params.vesting.recipients;
7565
- vestingAmounts = params.vesting.amounts;
7566
- } else {
7567
- vestingRecipients = [params.userAddress];
7568
- vestingAmounts = [
7569
- params.sale.initialSupply - params.sale.numTokensToSell
7570
- ];
7571
- }
7572
- }
7573
- tokenFactoryData = encodeAbiParameters(
7574
- [
7575
- { type: "string" },
7576
- { type: "string" },
7577
- { type: "uint256" },
7578
- { type: "uint256" },
7579
- { type: "address[]" },
7580
- { type: "uint256[]" },
7581
- { type: "string" }
7582
- ],
7583
- [
7584
- tokenStd.name,
7585
- tokenStd.symbol,
7586
- yearlyMintRate,
7587
- BigInt(vestingDuration),
7588
- vestingRecipients,
7589
- vestingAmounts,
7590
- tokenStd.tokenURI
7591
- ]
7858
+ const standardTokenFactoryData = this.buildStandardTokenFactoryData({
7859
+ token: params.token,
7860
+ sale: params.sale,
7861
+ vesting: params.vesting,
7862
+ userAddress: params.userAddress,
7863
+ airlock: params.modules?.airlock ?? addresses.airlock,
7864
+ tokenFactory: resolvedTokenFactory,
7865
+ addresses
7866
+ });
7867
+ tokenFactoryData = this.encodeStandardTokenFactoryData(
7868
+ standardTokenFactoryData
7592
7869
  );
7593
7870
  }
7594
7871
  const governanceFactoryData = (() => {
@@ -7617,12 +7894,6 @@ var DopplerFactory = class {
7617
7894
  );
7618
7895
  })();
7619
7896
  const salt = this.generateRandomSalt(params.userAddress);
7620
- const resolvedTokenFactory = params.modules?.tokenFactory ?? (this.isDoppler404Token(params.token) ? addresses.doppler404Factory : addresses.tokenFactory);
7621
- if (!resolvedTokenFactory || resolvedTokenFactory === ZERO_ADDRESS2) {
7622
- throw new Error(
7623
- "Token factory address not configured. Provide an explicit address or ensure chain config includes a valid factory."
7624
- );
7625
- }
7626
7897
  const resolvedInitializer = (() => {
7627
7898
  if (useDopplerHookInitializer) {
7628
7899
  return params.modules?.dopplerHookInitializer ?? addresses.dopplerHookInitializer;
@@ -7875,6 +8146,49 @@ var DopplerFactory = class {
7875
8146
  const rounded = Math.floor(MAX_TICK / tickSpacing) * tickSpacing;
7876
8147
  return rounded;
7877
8148
  }
8149
+ validateVestingConfig(sale, vesting) {
8150
+ if (!vesting) {
8151
+ return;
8152
+ }
8153
+ const cliffDuration = vesting.cliffDuration ?? 0;
8154
+ const duration = vesting.duration ?? 0;
8155
+ if (cliffDuration < 0) {
8156
+ throw new Error("Vesting cliff duration cannot be negative");
8157
+ }
8158
+ if (duration < 0) {
8159
+ throw new Error("Vesting duration cannot be negative");
8160
+ }
8161
+ if (cliffDuration > duration) {
8162
+ throw new Error("Vesting cliff duration cannot exceed vesting duration");
8163
+ }
8164
+ if (cliffDuration > 0 && duration > 0 && duration < DERC20_V2_MIN_VESTING_DURATION) {
8165
+ throw new Error(
8166
+ `Vesting duration must be 0 or at least ${DERC20_V2_MIN_VESTING_DURATION} seconds when using cliffs`
8167
+ );
8168
+ }
8169
+ if (vesting.recipients && vesting.amounts) {
8170
+ if (vesting.recipients.length !== vesting.amounts.length) {
8171
+ throw new Error(
8172
+ "Vesting recipients and amounts arrays must have the same length"
8173
+ );
8174
+ }
8175
+ if (vesting.recipients.length === 0) {
8176
+ throw new Error("Vesting recipients array cannot be empty");
8177
+ }
8178
+ const totalVested = vesting.amounts.reduce((sum, amt) => sum + amt, 0n);
8179
+ const availableForVesting = sale.initialSupply - sale.numTokensToSell;
8180
+ if (totalVested > availableForVesting) {
8181
+ throw new Error(
8182
+ `Total vesting amount (${totalVested}) exceeds available tokens (${availableForVesting})`
8183
+ );
8184
+ }
8185
+ return;
8186
+ }
8187
+ const vestedAmount = sale.initialSupply - sale.numTokensToSell;
8188
+ if (vestedAmount <= 0n) {
8189
+ throw new Error("No tokens available for vesting");
8190
+ }
8191
+ }
7878
8192
  validateStaticAuctionParams(params) {
7879
8193
  if (!params.token.name || params.token.name.trim().length === 0) {
7880
8194
  throw new Error("Token name is required");
@@ -7912,33 +8226,8 @@ var DopplerFactory = class {
7912
8226
  if (params.sale.numTokensToSell > params.sale.initialSupply) {
7913
8227
  throw new Error("Cannot sell more tokens than initial supply");
7914
8228
  }
7915
- if (params.vesting) {
7916
- if (params.vesting.recipients && params.vesting.amounts) {
7917
- if (params.vesting.recipients.length !== params.vesting.amounts.length) {
7918
- throw new Error(
7919
- "Vesting recipients and amounts arrays must have the same length"
7920
- );
7921
- }
7922
- if (params.vesting.recipients.length === 0) {
7923
- throw new Error("Vesting recipients array cannot be empty");
7924
- }
7925
- const totalVested = params.vesting.amounts.reduce(
7926
- (sum, amt) => sum + amt,
7927
- BigInt(0)
7928
- );
7929
- const availableForVesting = params.sale.initialSupply - params.sale.numTokensToSell;
7930
- if (totalVested > availableForVesting) {
7931
- throw new Error(
7932
- `Total vesting amount (${totalVested}) exceeds available tokens (${availableForVesting})`
7933
- );
7934
- }
7935
- } else {
7936
- const vestedAmount = params.sale.initialSupply - params.sale.numTokensToSell;
7937
- if (vestedAmount <= BigInt(0)) {
7938
- throw new Error("No tokens available for vesting");
7939
- }
7940
- }
7941
- }
8229
+ this.validateVestingConfig(params.sale, params.vesting);
8230
+ this.validateVestingConfig(params.sale, params.vesting);
7942
8231
  if (params.migration.type === "dopplerHook") {
7943
8232
  throw new Error(
7944
8233
  "dopplerHook migration is only supported for dynamic auctions"
@@ -8003,6 +8292,7 @@ var DopplerFactory = class {
8003
8292
  if (params.sale.numTokensToSell > params.sale.initialSupply) {
8004
8293
  throw new Error("Cannot sell more tokens than initial supply");
8005
8294
  }
8295
+ this.validateVestingConfig(params.sale, params.vesting);
8006
8296
  if (params.auction.duration <= 0) {
8007
8297
  throw new Error("Auction duration must be positive");
8008
8298
  }
@@ -8231,28 +8521,7 @@ var DopplerFactory = class {
8231
8521
  throw new Error("Cannot sell more tokens than initial supply");
8232
8522
  }
8233
8523
  this.resolveMulticurveInitializerMode(params);
8234
- if (params.vesting) {
8235
- if (params.vesting.recipients && params.vesting.amounts) {
8236
- if (params.vesting.recipients.length !== params.vesting.amounts.length) {
8237
- throw new Error(
8238
- "Vesting recipients and amounts arrays must have the same length"
8239
- );
8240
- }
8241
- if (params.vesting.recipients.length === 0) {
8242
- throw new Error("Vesting recipients array cannot be empty");
8243
- }
8244
- const totalVested = params.vesting.amounts.reduce(
8245
- (sum, amt) => sum + amt,
8246
- BigInt(0)
8247
- );
8248
- const availableForVesting = params.sale.initialSupply - params.sale.numTokensToSell;
8249
- if (totalVested > availableForVesting) {
8250
- throw new Error(
8251
- `Total vesting amount (${totalVested}) exceeds available tokens (${availableForVesting})`
8252
- );
8253
- }
8254
- }
8255
- }
8524
+ this.validateVestingConfig(params.sale, params.vesting);
8256
8525
  if (params.pool.beneficiaries && params.pool.beneficiaries.length > 0) {
8257
8526
  const beneficiaries = params.pool.beneficiaries;
8258
8527
  const totalShares = beneficiaries.reduce((sum, b) => sum + b.shares, 0n);
@@ -8652,37 +8921,9 @@ var DopplerFactory = class {
8652
8921
  ],
8653
8922
  [t.name, t.symbol, t.baseURI, t.unit ?? 1000n]
8654
8923
  );
8655
- })() : (() => {
8656
- const {
8657
- name,
8658
- symbol,
8659
- yearlyMintRate,
8660
- vestingDuration,
8661
- recipients,
8662
- amounts,
8663
- tokenURI
8664
- } = params.tokenFactoryData;
8665
- return encodeAbiParameters(
8666
- [
8667
- { type: "string" },
8668
- { type: "string" },
8669
- { type: "uint256" },
8670
- { type: "uint256" },
8671
- { type: "address[]" },
8672
- { type: "uint256[]" },
8673
- { type: "string" }
8674
- ],
8675
- [
8676
- name,
8677
- symbol,
8678
- yearlyMintRate,
8679
- vestingDuration,
8680
- recipients,
8681
- amounts,
8682
- tokenURI
8683
- ]
8684
- );
8685
- })();
8924
+ })() : this.encodeStandardTokenFactoryData(
8925
+ params.tokenFactoryData
8926
+ );
8686
8927
  let tokenInitHash;
8687
8928
  if (params.tokenVariant === "doppler404") {
8688
8929
  const { name, symbol, baseURI } = params.tokenFactoryData;
@@ -8705,47 +8946,45 @@ var DopplerFactory = class {
8705
8946
  )
8706
8947
  );
8707
8948
  } else {
8708
- const {
8709
- name,
8710
- symbol,
8711
- yearlyMintRate,
8712
- vestingDuration,
8713
- recipients,
8714
- amounts,
8715
- tokenURI
8716
- } = params.tokenFactoryData;
8717
- const { airlock, initialSupply } = params;
8718
- const initHashData = encodeAbiParameters(
8719
- [
8720
- { type: "string" },
8721
- { type: "string" },
8722
- { type: "uint256" },
8723
- { type: "address" },
8724
- { type: "address" },
8725
- { type: "uint256" },
8726
- { type: "uint256" },
8727
- { type: "address[]" },
8728
- { type: "uint256[]" },
8729
- { type: "string" }
8730
- ],
8731
- [
8732
- name,
8733
- symbol,
8734
- initialSupply,
8735
- airlock,
8736
- airlock,
8737
- yearlyMintRate,
8738
- vestingDuration,
8739
- recipients,
8740
- amounts,
8741
- tokenURI
8742
- ]
8743
- );
8744
- const isTokenFactory802 = params.tokenFactory.toLowerCase() === TOKEN_FACTORY_80_ADDRESS2;
8745
- const bytecode = isTokenFactory802 ? derc2080_default : params.customDerc20Bytecode ?? derc20_default;
8746
- tokenInitHash = keccak256(
8747
- encodePacked(["bytes", "bytes"], [bytecode, initHashData])
8748
- );
8949
+ const standardTokenFactoryData = params.tokenFactoryData;
8950
+ if (standardTokenFactoryData.kind === "v2") {
8951
+ tokenInitHash = this.computeStandardTokenInitHash(
8952
+ standardTokenFactoryData,
8953
+ params.tokenFactory
8954
+ );
8955
+ } else {
8956
+ const initHashData = encodeAbiParameters(
8957
+ [
8958
+ { type: "string" },
8959
+ { type: "string" },
8960
+ { type: "uint256" },
8961
+ { type: "address" },
8962
+ { type: "address" },
8963
+ { type: "uint256" },
8964
+ { type: "uint256" },
8965
+ { type: "address[]" },
8966
+ { type: "uint256[]" },
8967
+ { type: "string" }
8968
+ ],
8969
+ [
8970
+ standardTokenFactoryData.name,
8971
+ standardTokenFactoryData.symbol,
8972
+ standardTokenFactoryData.initialSupply,
8973
+ standardTokenFactoryData.airlock,
8974
+ standardTokenFactoryData.airlock,
8975
+ standardTokenFactoryData.yearlyMintRate,
8976
+ standardTokenFactoryData.vestingDuration,
8977
+ standardTokenFactoryData.recipients,
8978
+ standardTokenFactoryData.amounts,
8979
+ standardTokenFactoryData.tokenURI
8980
+ ]
8981
+ );
8982
+ const isTokenFactory802 = params.tokenFactory.toLowerCase() === TOKEN_FACTORY_80_ADDRESS2;
8983
+ const bytecode = isTokenFactory802 ? derc2080_default : params.customDerc20Bytecode ?? derc20_default;
8984
+ tokenInitHash = keccak256(
8985
+ encodePacked(["bytes", "bytes"], [bytecode, initHashData])
8986
+ );
8987
+ }
8749
8988
  }
8750
8989
  const flags = BigInt(
8751
8990
  1 << 13 | // BEFORE_INITIALIZE_FLAG
@@ -13026,6 +13265,108 @@ var Derc20 = class _Derc20 {
13026
13265
  );
13027
13266
  }
13028
13267
  };
13268
+
13269
+ // src/evm/entities/token/derc20/Derc20V2.ts
13270
+ var Derc20V2 = class extends Derc20 {
13271
+ async getVestingScheduleCount() {
13272
+ return await this.rpc.readContract({
13273
+ address: this.address,
13274
+ abi: derc20V2Abi,
13275
+ functionName: "vestingScheduleCount"
13276
+ });
13277
+ }
13278
+ async getVestingSchedule(scheduleId) {
13279
+ const result = await this.rpc.readContract({
13280
+ address: this.address,
13281
+ abi: derc20V2Abi,
13282
+ functionName: "vestingSchedules",
13283
+ args: [scheduleId]
13284
+ });
13285
+ return {
13286
+ cliffDuration: BigInt(result[0]),
13287
+ duration: BigInt(result[1])
13288
+ };
13289
+ }
13290
+ async getScheduleIdsOf(beneficiary) {
13291
+ const result = await this.rpc.readContract({
13292
+ address: this.address,
13293
+ abi: derc20V2Abi,
13294
+ functionName: "getScheduleIdsOf",
13295
+ args: [beneficiary]
13296
+ });
13297
+ return Array.from(result);
13298
+ }
13299
+ async getTotalAllocatedOf(beneficiary) {
13300
+ return await this.rpc.readContract({
13301
+ address: this.address,
13302
+ abi: derc20V2Abi,
13303
+ functionName: "totalAllocatedOf",
13304
+ args: [beneficiary]
13305
+ });
13306
+ }
13307
+ async getAvailableVestedAmountForSchedule(beneficiary, scheduleId) {
13308
+ return await this.rpc.readContract({
13309
+ address: this.address,
13310
+ abi: derc20V2Abi,
13311
+ functionName: "computeAvailableVestedAmount",
13312
+ args: [beneficiary, scheduleId]
13313
+ });
13314
+ }
13315
+ async getVestingDataForSchedule(beneficiary, scheduleId) {
13316
+ const result = await this.rpc.readContract({
13317
+ address: this.address,
13318
+ abi: derc20V2Abi,
13319
+ functionName: "vestingOf",
13320
+ args: [beneficiary, scheduleId]
13321
+ });
13322
+ return {
13323
+ totalAmount: result[0],
13324
+ releasedAmount: result[1]
13325
+ };
13326
+ }
13327
+ async releaseSchedule(scheduleId, options) {
13328
+ if (!this.walletClient) {
13329
+ throw new Error("Wallet client required for write operations");
13330
+ }
13331
+ const { request } = await this.rpc.simulateContract({
13332
+ address: this.address,
13333
+ abi: derc20V2Abi,
13334
+ functionName: "release",
13335
+ args: [scheduleId],
13336
+ account: this.walletClient.account
13337
+ });
13338
+ return await this.walletClient.writeContract(
13339
+ options?.gas ? { ...request, gas: options.gas } : request
13340
+ );
13341
+ }
13342
+ async releaseFor(beneficiary, scheduleId, options) {
13343
+ if (!this.walletClient) {
13344
+ throw new Error("Wallet client required for write operations");
13345
+ }
13346
+ if (scheduleId === void 0) {
13347
+ const { request: request2 } = await this.rpc.simulateContract({
13348
+ address: this.address,
13349
+ abi: derc20V2Abi,
13350
+ functionName: "releaseFor",
13351
+ args: [beneficiary],
13352
+ account: this.walletClient.account
13353
+ });
13354
+ return await this.walletClient.writeContract(
13355
+ options?.gas ? { ...request2, gas: options.gas } : request2
13356
+ );
13357
+ }
13358
+ const { request } = await this.rpc.simulateContract({
13359
+ address: this.address,
13360
+ abi: derc20V2Abi,
13361
+ functionName: "releaseFor",
13362
+ args: [beneficiary, scheduleId],
13363
+ account: this.walletClient.account
13364
+ });
13365
+ return await this.walletClient.writeContract(
13366
+ options?.gas ? { ...request, gas: options.gas } : request
13367
+ );
13368
+ }
13369
+ };
13029
13370
  var Eth = class {
13030
13371
  publicClient;
13031
13372
  get rpc() {
@@ -15153,6 +15494,13 @@ var DopplerSDK = class {
15153
15494
  getDerc20(tokenAddress) {
15154
15495
  return new Derc20(this.publicClient, this.walletClient, tokenAddress);
15155
15496
  }
15497
+ /**
15498
+ * Get a DERC20 V2 token instance for interacting with cliffed / multi-schedule vesting tokens
15499
+ * @param tokenAddress The address of the DERC20 V2 token
15500
+ */
15501
+ getDerc20V2(tokenAddress) {
15502
+ return new Derc20V2(this.publicClient, this.walletClient, tokenAddress);
15503
+ }
15156
15504
  /**
15157
15505
  * Get information about a static auction pool
15158
15506
  * @param poolAddress The address of the pool
@@ -15225,6 +15573,6 @@ var DopplerSDK = class {
15225
15573
  // src/evm/index.ts
15226
15574
  var VERSION = "1.0.0";
15227
15575
 
15228
- export { ADDRESSES, BASIS_POINTS, CHAIN_IDS, DAY_SECONDS, DEAD_ADDRESS, DECAY_MAX_START_FEE, DEFAULT_AIRLOCK_BENEFICIARY_SHARES, DEFAULT_AUCTION_DURATION, DEFAULT_EPOCH_LENGTH, DEFAULT_LOCK_DURATION, DEFAULT_MULTICURVE_LOWER_TICKS, DEFAULT_MULTICURVE_MAX_SUPPLY_SHARES, DEFAULT_MULTICURVE_NUM_POSITIONS, DEFAULT_MULTICURVE_UPPER_TICKS, DEFAULT_OPENING_AUCTION_DURATION, DEFAULT_OPENING_AUCTION_FEE, DEFAULT_OPENING_AUCTION_INCENTIVE_SHARE_BPS, DEFAULT_OPENING_AUCTION_MIN_ACCEPTABLE_TICK_TOKEN0, DEFAULT_OPENING_AUCTION_MIN_ACCEPTABLE_TICK_TOKEN1, DEFAULT_OPENING_AUCTION_MIN_LIQUIDITY, DEFAULT_OPENING_AUCTION_SHARE_TO_AUCTION_BPS, DEFAULT_OPENING_DOPPLER_DURATION, DEFAULT_OPENING_DOPPLER_EPOCH_LENGTH, DEFAULT_OPENING_DOPPLER_FEE, DEFAULT_OPENING_DOPPLER_NUM_PD_SLUGS, DEFAULT_OPENING_DOPPLER_TICK_SPACING, DEFAULT_PD_SLUGS, DEFAULT_V3_END_TICK, DEFAULT_V3_FEE, DEFAULT_V3_INITIAL_PROPOSAL_THRESHOLD, DEFAULT_V3_INITIAL_SUPPLY, DEFAULT_V3_INITIAL_VOTING_DELAY, DEFAULT_V3_INITIAL_VOTING_PERIOD, DEFAULT_V3_MAX_SHARE_TO_BE_SOLD, DEFAULT_V3_NUM_POSITIONS, DEFAULT_V3_NUM_TOKENS_TO_SELL, DEFAULT_V3_PRE_MINT, DEFAULT_V3_START_TICK, DEFAULT_V3_VESTING_DURATION, DEFAULT_V3_YEARLY_MINT_RATE, DEFAULT_V4_INITIAL_PROPOSAL_THRESHOLD, DEFAULT_V4_INITIAL_VOTING_DELAY, DEFAULT_V4_INITIAL_VOTING_PERIOD, DEFAULT_V4_YEARLY_MINT_RATE, derc2080_default as DERC2080Bytecode, derc20_default as DERC20Bytecode, DOPPLER_FLAGS, DOPPLER_MAX_TICK_SPACING, DYNAMIC_FEE_FLAG, Derc20, doppler_default as DopplerBytecode, dopplerDN404_default as DopplerDN404Bytecode, DopplerFactory, DopplerSDK, DynamicAuction, DynamicAuctionBuilder, Eth, FEE_AMOUNT_MASK, FEE_TIERS, FLAG_MASK, INT24_MAX, INT24_MIN, LAUNCHPAD_ENABLED_CHAIN_IDS, LockablePoolStatus, MAX_SQRT_RATIO, MAX_TICK, MIN_SQRT_RATIO, MIN_TICK, MulticurveBuilder, MulticurvePool, NO_OP_ENABLED_CHAIN_IDS, OPENING_AUCTION_FLAGS, OPENING_AUCTION_PHASE_ACTIVE, OPENING_AUCTION_PHASE_CLOSED, OPENING_AUCTION_PHASE_NOT_STARTED, OPENING_AUCTION_PHASE_SETTLED, OPENING_AUCTION_STATUS_ACTIVE, OPENING_AUCTION_STATUS_DOPPLER_ACTIVE, OPENING_AUCTION_STATUS_EXITED, OPENING_AUCTION_STATUS_UNINITIALIZED, OpeningAuction, OpeningAuctionBidManager, OpeningAuctionBuilder, openingAuction_default as OpeningAuctionBytecode, OpeningAuctionLifecycle, OpeningAuctionPhase, OpeningAuctionPositionManager, OpeningAuctionStatus, Q96, Quoter, RehypeDopplerHook, RehypeDopplerHookMigrator, RehypeFeeRoutingMode, SECONDS_PER_DAY, SECONDS_PER_YEAR, SUPPORTED_CHAIN_IDS, stateView_default as StateViewBytecode, StaticAuction, StaticAuctionBuilder, TICK_SPACINGS, V3_FEE_TIERS, V4_MAX_FEE, VALID_FEE_TIERS, VERSION, WAD, ZERO_ADDRESS2 as ZERO_ADDRESS, airlockAbi, applyTickOffsets, bundlerAbi, calculateFDV, calculateGamma, calculateMarketCap, calculateTickRange, calculateTokensToSell, computeOptimalGamma, computePoolId, createAirlockBeneficiary, decayMulticurveInitializerHookAbi, decodeBalanceDelta, derc20Abi, dopplerHookAbi, dopplerHookInitializerAbi, dopplerLensAbi, encodeRehypeDopplerHookMigratorCalldata, estimatePriceAtEpoch, estimateSlippage, formatTickAsPrice, getAddresses, getAirlockBeneficiary, getAirlockOwner, getAmount0ForLiquidity, getAmount1ForLiquidity, getLiquidityForAmount0, getLiquidityForAmount1, getMaxTickRounded, getNearestUsableTick, getSqrtRatioAtTick, getTickAtSqrtRatio, isLaunchpadEnabledChain, isNoOpEnabledChain, isSupportedChainId, isToken0Expected, isToken1, lockableUniswapV3InitializerAbi, marketCapToTickForMulticurve, marketCapToTicksForDynamicAuction, marketCapToTicksForMulticurve, marketCapToTicksForStaticAuction, marketCapToTokenPrice, mineTokenAddress, normalizePoolKey, openingAuctionAbi, openingAuctionInitializerAbi, openingAuctionPositionManagerAbi, poolManagerAbi, priceToSqrtPriceX96, priceToTick, quoterV2Abi, ratioToTick, rehypeDopplerHookAbi, rehypeDopplerHookMigratorAbi, resolveGasEstimate, sqrtPriceX96ToPrice, streamableFeesLockerAbi, tickToMarketCap, tickToPrice, tokenPriceToRatio, uniswapV2Router02Abi, uniswapV3InitializerAbi, uniswapV3PoolAbi, uniswapV4InitializerAbi, v2MigratorAbi, v3MigratorAbi, v4MigratorAbi, v4MulticurveInitializerAbi, v4MulticurveMigratorAbi, v4QuoterAbi, validateMarketCapParameters, weth9Abi };
15576
+ export { ADDRESSES, BASIS_POINTS, CHAIN_IDS, DAY_SECONDS, DEAD_ADDRESS, DECAY_MAX_START_FEE, DEFAULT_AIRLOCK_BENEFICIARY_SHARES, DEFAULT_AUCTION_DURATION, DEFAULT_EPOCH_LENGTH, DEFAULT_LOCK_DURATION, DEFAULT_MULTICURVE_LOWER_TICKS, DEFAULT_MULTICURVE_MAX_SUPPLY_SHARES, DEFAULT_MULTICURVE_NUM_POSITIONS, DEFAULT_MULTICURVE_UPPER_TICKS, DEFAULT_OPENING_AUCTION_DURATION, DEFAULT_OPENING_AUCTION_FEE, DEFAULT_OPENING_AUCTION_INCENTIVE_SHARE_BPS, DEFAULT_OPENING_AUCTION_MIN_ACCEPTABLE_TICK_TOKEN0, DEFAULT_OPENING_AUCTION_MIN_ACCEPTABLE_TICK_TOKEN1, DEFAULT_OPENING_AUCTION_MIN_LIQUIDITY, DEFAULT_OPENING_AUCTION_SHARE_TO_AUCTION_BPS, DEFAULT_OPENING_DOPPLER_DURATION, DEFAULT_OPENING_DOPPLER_EPOCH_LENGTH, DEFAULT_OPENING_DOPPLER_FEE, DEFAULT_OPENING_DOPPLER_NUM_PD_SLUGS, DEFAULT_OPENING_DOPPLER_TICK_SPACING, DEFAULT_PD_SLUGS, DEFAULT_V3_END_TICK, DEFAULT_V3_FEE, DEFAULT_V3_INITIAL_PROPOSAL_THRESHOLD, DEFAULT_V3_INITIAL_SUPPLY, DEFAULT_V3_INITIAL_VOTING_DELAY, DEFAULT_V3_INITIAL_VOTING_PERIOD, DEFAULT_V3_MAX_SHARE_TO_BE_SOLD, DEFAULT_V3_NUM_POSITIONS, DEFAULT_V3_NUM_TOKENS_TO_SELL, DEFAULT_V3_PRE_MINT, DEFAULT_V3_START_TICK, DEFAULT_V3_VESTING_DURATION, DEFAULT_V3_YEARLY_MINT_RATE, DEFAULT_V4_INITIAL_PROPOSAL_THRESHOLD, DEFAULT_V4_INITIAL_VOTING_DELAY, DEFAULT_V4_INITIAL_VOTING_PERIOD, DEFAULT_V4_YEARLY_MINT_RATE, derc2080_default as DERC2080Bytecode, derc20_default as DERC20Bytecode, DOPPLER_FLAGS, DOPPLER_MAX_TICK_SPACING, DYNAMIC_FEE_FLAG, Derc20, Derc20V2, doppler_default as DopplerBytecode, dopplerDN404_default as DopplerDN404Bytecode, DopplerFactory, DopplerSDK, DynamicAuction, DynamicAuctionBuilder, Eth, FEE_AMOUNT_MASK, FEE_TIERS, FLAG_MASK, INT24_MAX, INT24_MIN, LAUNCHPAD_ENABLED_CHAIN_IDS, LockablePoolStatus, MAX_SQRT_RATIO, MAX_TICK, MIN_SQRT_RATIO, MIN_TICK, MulticurveBuilder, MulticurvePool, NO_OP_ENABLED_CHAIN_IDS, OPENING_AUCTION_FLAGS, OPENING_AUCTION_PHASE_ACTIVE, OPENING_AUCTION_PHASE_CLOSED, OPENING_AUCTION_PHASE_NOT_STARTED, OPENING_AUCTION_PHASE_SETTLED, OPENING_AUCTION_STATUS_ACTIVE, OPENING_AUCTION_STATUS_DOPPLER_ACTIVE, OPENING_AUCTION_STATUS_EXITED, OPENING_AUCTION_STATUS_UNINITIALIZED, OpeningAuction, OpeningAuctionBidManager, OpeningAuctionBuilder, openingAuction_default as OpeningAuctionBytecode, OpeningAuctionLifecycle, OpeningAuctionPhase, OpeningAuctionPositionManager, OpeningAuctionStatus, Q96, Quoter, RehypeDopplerHook, RehypeDopplerHookMigrator, RehypeFeeRoutingMode, SECONDS_PER_DAY, SECONDS_PER_YEAR, SUPPORTED_CHAIN_IDS, stateView_default as StateViewBytecode, StaticAuction, StaticAuctionBuilder, TICK_SPACINGS, V3_FEE_TIERS, V4_MAX_FEE, VALID_FEE_TIERS, VERSION, WAD, ZERO_ADDRESS2 as ZERO_ADDRESS, airlockAbi, applyTickOffsets, bundlerAbi, calculateFDV, calculateGamma, calculateMarketCap, calculateTickRange, calculateTokensToSell, computeOptimalGamma, computePoolId, createAirlockBeneficiary, decayMulticurveInitializerHookAbi, decodeBalanceDelta, derc20Abi, derc20V2Abi, dopplerHookAbi, dopplerHookInitializerAbi, dopplerLensAbi, encodeRehypeDopplerHookMigratorCalldata, estimatePriceAtEpoch, estimateSlippage, formatTickAsPrice, getAddresses, getAirlockBeneficiary, getAirlockOwner, getAmount0ForLiquidity, getAmount1ForLiquidity, getLiquidityForAmount0, getLiquidityForAmount1, getMaxTickRounded, getNearestUsableTick, getSqrtRatioAtTick, getTickAtSqrtRatio, isLaunchpadEnabledChain, isNoOpEnabledChain, isSupportedChainId, isToken0Expected, isToken1, lockableUniswapV3InitializerAbi, marketCapToTickForMulticurve, marketCapToTicksForDynamicAuction, marketCapToTicksForMulticurve, marketCapToTicksForStaticAuction, marketCapToTokenPrice, mineTokenAddress, normalizePoolKey, openingAuctionAbi, openingAuctionInitializerAbi, openingAuctionPositionManagerAbi, poolManagerAbi, priceToSqrtPriceX96, priceToTick, quoterV2Abi, ratioToTick, rehypeDopplerHookAbi, rehypeDopplerHookMigratorAbi, resolveGasEstimate, sqrtPriceX96ToPrice, streamableFeesLockerAbi, tickToMarketCap, tickToPrice, tokenPriceToRatio, uniswapV2Router02Abi, uniswapV3InitializerAbi, uniswapV3PoolAbi, uniswapV4InitializerAbi, v2MigratorAbi, v3MigratorAbi, v4MigratorAbi, v4MulticurveInitializerAbi, v4MulticurveMigratorAbi, v4QuoterAbi, validateMarketCapParameters, weth9Abi };
15229
15577
  //# sourceMappingURL=index.js.map
15230
15578
  //# sourceMappingURL=index.js.map