@whetstone-research/doppler-sdk 1.0.6 → 1.0.7

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 CHANGED
@@ -88,13 +88,19 @@ const params = new StaticAuctionBuilder()
88
88
  // Optional: specify multiple recipients and amounts
89
89
  // recipients: ['0xTeam...', '0xAdvisor...'],
90
90
  // amounts: [parseEther('50000000'), parseEther('50000000')]
91
- // Optional: define per-beneficiary schedules on the DERC20 V2 path
92
- // schedules: [
93
- // { duration: BigInt(180 * 24 * 60 * 60), cliffDuration: 30 * 24 * 60 * 60 },
94
- // { duration: BigInt(365 * 24 * 60 * 60), cliffDuration: 90 * 24 * 60 * 60 },
95
- // ],
96
- // Optional: if omitted, one schedule is assigned per recipient in order
97
- // scheduleIds: [0, 1]
91
+ // Optional: define per-beneficiary vesting allocations on the DERC20 V2 path
92
+ // allocations: [
93
+ // {
94
+ // recipient: '0xTeam...',
95
+ // amount: parseEther('50000000'),
96
+ // schedule: { duration: BigInt(180 * 24 * 60 * 60), cliffDuration: 30 * 24 * 60 * 60 },
97
+ // },
98
+ // {
99
+ // recipient: '0xAdvisor...',
100
+ // amount: parseEther('50000000'),
101
+ // schedule: { duration: BigInt(365 * 24 * 60 * 60), cliffDuration: 90 * 24 * 60 * 60 },
102
+ // },
103
+ // ]
98
104
  })
99
105
  .withMigration({ type: 'uniswapV2' })
100
106
  .withUserAddress('0x...')
@@ -105,7 +111,7 @@ console.log('Pool address:', result.poolAddress);
105
111
  console.log('Token address:', result.tokenAddress);
106
112
  ```
107
113
 
108
- If you set `cliffDuration > 0` or provide `schedules`, the SDK automatically uses the DERC20 V2 factory and exposes schedule-aware token reads via `sdk.getDerc20V2(tokenAddress)`. When `schedules` is provided, omit `scheduleIds` to assign one schedule per recipient in order, or provide `scheduleIds` to reuse schedules across beneficiaries.
114
+ If you set `cliffDuration > 0` or provide `allocations`, the SDK automatically uses the DERC20 V2 factory and exposes schedule-aware token reads via `sdk.getDerc20V2(tokenAddress)`. When `allocations` is provided, the SDK dedupes identical schedules internally and maps each recipient to the correct on-chain schedule.
109
115
 
110
116
  For a runnable example, see [examples/multicurve-per-beneficiary-vesting.ts](./examples/multicurve-per-beneficiary-vesting.ts).
111
117
 
@@ -5295,7 +5295,7 @@ var DopplerFactory = class {
5295
5295
  this.chainId = chainId;
5296
5296
  }
5297
5297
  hasCustomV2Schedules(vesting) {
5298
- return (vesting?.schedules?.length ?? 0) > 0 || (vesting?.scheduleIds?.length ?? 0) > 0;
5298
+ return (vesting?.allocations?.length ?? 0) > 0;
5299
5299
  }
5300
5300
  usesDerc20V2Vesting(vesting) {
5301
5301
  if (!vesting) {
@@ -5307,6 +5307,16 @@ var DopplerFactory = class {
5307
5307
  if (!args.vesting) {
5308
5308
  return { recipients: [], amounts: [] };
5309
5309
  }
5310
+ if (args.vesting.allocations) {
5311
+ return {
5312
+ recipients: args.vesting.allocations.map(
5313
+ (allocation) => allocation.recipient
5314
+ ),
5315
+ amounts: args.vesting.allocations.map(
5316
+ (allocation) => allocation.amount
5317
+ )
5318
+ };
5319
+ }
5310
5320
  if (args.vesting.recipients && args.vesting.amounts) {
5311
5321
  return {
5312
5322
  recipients: args.vesting.recipients,
@@ -5318,18 +5328,6 @@ var DopplerFactory = class {
5318
5328
  amounts: [args.sale.initialSupply - args.sale.numTokensToSell]
5319
5329
  };
5320
5330
  }
5321
- normalizeV2ScheduleId(scheduleId, label) {
5322
- if (!Number.isFinite(scheduleId) || !Number.isInteger(scheduleId)) {
5323
- throw new Error(`${label} must be an integer`);
5324
- }
5325
- if (!Number.isSafeInteger(scheduleId)) {
5326
- throw new Error(`${label} must be a safe integer`);
5327
- }
5328
- if (scheduleId < 0) {
5329
- throw new Error(`${label} cannot be negative`);
5330
- }
5331
- return BigInt(scheduleId);
5332
- }
5333
5331
  validateUint64LikeNumber(value, fieldPath, options = {}) {
5334
5332
  const { allowZero = true } = options;
5335
5333
  if (!Number.isFinite(value) || !Number.isInteger(value)) {
@@ -5363,37 +5361,22 @@ var DopplerFactory = class {
5363
5361
  scheduleIds: Array.from({ length: args.recipientCount }, () => 0n)
5364
5362
  };
5365
5363
  }
5366
- const schedules = args.vesting.schedules?.map((schedule) => ({
5367
- cliff: BigInt(schedule.cliffDuration ?? 0),
5368
- duration: BigInt(schedule.duration ?? 0)
5369
- })) ?? [];
5370
- const explicitScheduleIds = args.vesting.scheduleIds;
5371
- if (explicitScheduleIds && explicitScheduleIds.length > 0) {
5372
- return {
5373
- schedules,
5374
- scheduleIds: explicitScheduleIds.map(
5375
- (scheduleId, index) => this.normalizeV2ScheduleId(
5376
- scheduleId,
5377
- `Vesting scheduleIds[${index}]`
5378
- )
5379
- )
5380
- };
5381
- }
5382
- if (schedules.length === 1) {
5383
- return {
5384
- schedules,
5385
- scheduleIds: Array.from({ length: args.recipientCount }, () => 0n)
5386
- };
5387
- }
5388
- if (schedules.length === args.recipientCount) {
5389
- return {
5390
- schedules,
5391
- scheduleIds: schedules.map((_, index) => BigInt(index))
5392
- };
5364
+ const schedules = [];
5365
+ const scheduleIds = [];
5366
+ const scheduleIdsByKey = /* @__PURE__ */ new Map();
5367
+ for (const allocation of args.vesting.allocations ?? []) {
5368
+ const cliff = BigInt(allocation.schedule.cliffDuration ?? 0);
5369
+ const duration = BigInt(allocation.schedule.duration ?? 0);
5370
+ const key = `${cliff}:${duration}`;
5371
+ let scheduleId = scheduleIdsByKey.get(key);
5372
+ if (scheduleId === void 0) {
5373
+ scheduleId = BigInt(schedules.length);
5374
+ schedules.push({ cliff, duration });
5375
+ scheduleIdsByKey.set(key, scheduleId);
5376
+ }
5377
+ scheduleIds.push(scheduleId);
5393
5378
  }
5394
- throw new Error(
5395
- "Vesting schedules must either contain exactly one shared schedule or one schedule per recipient when scheduleIds are omitted"
5396
- );
5379
+ return { schedules, scheduleIds };
5397
5380
  }
5398
5381
  resolveStandardTokenFactoryMode(args) {
5399
5382
  if (this.usesDerc20V2Vesting(args.vesting)) {
@@ -8237,87 +8220,70 @@ var DopplerFactory = class {
8237
8220
  const cliffDuration = vesting.cliffDuration ?? 0;
8238
8221
  const duration = vesting.duration ?? 0;
8239
8222
  const hasCustomSchedules = this.hasCustomV2Schedules(vesting);
8240
- if (hasCustomSchedules && (cliffDuration > 0 || duration > 0)) {
8223
+ if (hasCustomSchedules && (cliffDuration > 0 || duration > 0 || vesting.recipients !== void 0 || vesting.amounts !== void 0)) {
8241
8224
  throw new Error(
8242
- "Use vesting.schedules instead of top-level duration/cliffDuration when configuring multiple vesting schedules"
8225
+ "Use vesting.allocations instead of top-level duration/cliffDuration/recipients/amounts when configuring per-beneficiary vesting"
8243
8226
  );
8244
8227
  }
8245
- if (vesting.recipients && vesting.amounts) {
8246
- if (vesting.recipients.length !== vesting.amounts.length) {
8247
- throw new Error(
8248
- "Vesting recipients and amounts arrays must have the same length"
8249
- );
8228
+ const availableForVesting = sale.initialSupply - sale.numTokensToSell;
8229
+ if (vesting.allocations) {
8230
+ if (vesting.allocations.length === 0) {
8231
+ throw new Error("Vesting allocations array cannot be empty");
8250
8232
  }
8251
- if (vesting.recipients.length === 0) {
8252
- throw new Error("Vesting recipients array cannot be empty");
8253
- }
8254
- const totalVested = vesting.amounts.reduce((sum, amt) => sum + amt, 0n);
8255
- const availableForVesting = sale.initialSupply - sale.numTokensToSell;
8233
+ const totalVested = vesting.allocations.reduce(
8234
+ (sum, allocation) => sum + allocation.amount,
8235
+ 0n
8236
+ );
8256
8237
  if (totalVested > availableForVesting) {
8257
8238
  throw new Error(
8258
8239
  `Total vesting amount (${totalVested}) exceeds available tokens (${availableForVesting})`
8259
8240
  );
8260
8241
  }
8261
- } else {
8262
- const vestedAmount = sale.initialSupply - sale.numTokensToSell;
8263
- if (vestedAmount <= 0n) {
8264
- throw new Error("No tokens available for vesting");
8265
- }
8266
- }
8267
- if (hasCustomSchedules) {
8268
- const schedules = vesting.schedules;
8269
- if (!schedules || schedules.length === 0) {
8270
- throw new Error(
8271
- "Vesting schedules are required when using scheduleIds or multiple vesting schedules"
8272
- );
8273
- }
8274
- const recipientCount = vesting.recipients && vesting.amounts ? vesting.recipients.length : 1;
8275
- if (vesting.scheduleIds) {
8276
- if (vesting.scheduleIds.length !== recipientCount) {
8277
- throw new Error(
8278
- "Vesting scheduleIds array must have the same length as vesting recipients"
8279
- );
8280
- }
8281
- for (const [index, scheduleId] of vesting.scheduleIds.entries()) {
8282
- this.validateUint64LikeNumber(
8283
- scheduleId,
8284
- `Vesting scheduleIds[${index}]`
8285
- );
8286
- if (scheduleId >= schedules.length) {
8287
- throw new Error(
8288
- `Vesting scheduleIds[${index}] references missing schedule ${scheduleId}`
8289
- );
8290
- }
8291
- }
8292
- } else if (schedules.length !== 1 && schedules.length !== recipientCount) {
8293
- throw new Error(
8294
- "Vesting schedules must either contain exactly one shared schedule or one schedule per recipient when scheduleIds are omitted"
8295
- );
8296
- }
8297
- for (const [index, schedule] of schedules.entries()) {
8298
- const scheduleCliff = schedule.cliffDuration ?? 0;
8299
- const scheduleDuration = schedule.duration ?? 0;
8242
+ for (const [index, allocation] of vesting.allocations.entries()) {
8243
+ const scheduleCliff = allocation.schedule.cliffDuration ?? 0;
8244
+ const scheduleDuration = allocation.schedule.duration ?? 0;
8300
8245
  this.validateUint64LikeNumber(
8301
8246
  scheduleCliff,
8302
- `Vesting schedules[${index}].cliffDuration`
8247
+ `Vesting allocations[${index}].schedule.cliffDuration`
8303
8248
  );
8304
8249
  this.validateUint64LikeNumber(
8305
8250
  scheduleDuration,
8306
- `Vesting schedules[${index}].duration`
8251
+ `Vesting allocations[${index}].schedule.duration`
8307
8252
  );
8308
8253
  if (scheduleCliff > scheduleDuration) {
8309
8254
  throw new Error(
8310
- `Vesting schedules[${index}].cliffDuration cannot exceed duration`
8255
+ `Vesting allocations[${index}].schedule.cliffDuration cannot exceed duration`
8311
8256
  );
8312
8257
  }
8313
8258
  if (scheduleCliff > 0 && scheduleDuration > 0 && scheduleDuration < DERC20_V2_MIN_VESTING_DURATION) {
8314
8259
  throw new Error(
8315
- `Vesting schedules[${index}].duration must be 0 or at least ${DERC20_V2_MIN_VESTING_DURATION} seconds when using cliffs`
8260
+ `Vesting allocations[${index}].schedule.duration must be 0 or at least ${DERC20_V2_MIN_VESTING_DURATION} seconds when using cliffs`
8316
8261
  );
8317
8262
  }
8318
8263
  }
8319
8264
  return;
8320
8265
  }
8266
+ if (vesting.recipients && vesting.amounts) {
8267
+ if (vesting.recipients.length !== vesting.amounts.length) {
8268
+ throw new Error(
8269
+ "Vesting recipients and amounts arrays must have the same length"
8270
+ );
8271
+ }
8272
+ if (vesting.recipients.length === 0) {
8273
+ throw new Error("Vesting recipients array cannot be empty");
8274
+ }
8275
+ const totalVested = vesting.amounts.reduce((sum, amt) => sum + amt, 0n);
8276
+ if (totalVested > availableForVesting) {
8277
+ throw new Error(
8278
+ `Total vesting amount (${totalVested}) exceeds available tokens (${availableForVesting})`
8279
+ );
8280
+ }
8281
+ } else {
8282
+ const vestedAmount = sale.initialSupply - sale.numTokensToSell;
8283
+ if (vestedAmount <= 0n) {
8284
+ throw new Error("No tokens available for vesting");
8285
+ }
8286
+ }
8321
8287
  if (cliffDuration < 0) {
8322
8288
  throw new Error("Vesting cliff duration cannot be negative");
8323
8289
  }
@@ -13576,23 +13542,14 @@ function normalizeBuilderVestingScheduleDuration(value, fieldPath) {
13576
13542
  }
13577
13543
  return Number(duration);
13578
13544
  }
13579
- function normalizeBuilderScheduleId(scheduleId, fieldPath) {
13580
- if (typeof scheduleId === "bigint") {
13581
- if (scheduleId < 0n) {
13582
- throw new RangeError(`${fieldPath} cannot be negative`);
13583
- }
13584
- if (scheduleId > MAX_SAFE_INTEGER_BIGINT) {
13585
- throw new RangeError(`${fieldPath} must be a safe integer`);
13586
- }
13587
- return Number(scheduleId);
13588
- }
13589
- if (!Number.isSafeInteger(scheduleId)) {
13590
- throw new RangeError(`${fieldPath} must be a safe integer`);
13591
- }
13592
- if (scheduleId < 0) {
13593
- throw new RangeError(`${fieldPath} cannot be negative`);
13594
- }
13595
- return scheduleId;
13545
+ function normalizeBuilderVestingSchedule(schedule, fieldPath) {
13546
+ return {
13547
+ duration: normalizeBuilderVestingScheduleDuration(
13548
+ schedule.duration,
13549
+ `${fieldPath}.duration`
13550
+ ),
13551
+ cliffDuration: schedule.cliffDuration ?? 0
13552
+ };
13596
13553
  }
13597
13554
  function computeTicks(priceRange, tickSpacing) {
13598
13555
  const startTick = Math.floor(
@@ -13889,24 +13846,24 @@ var StaticAuctionBuilder = class _StaticAuctionBuilder {
13889
13846
  this.vesting = void 0;
13890
13847
  return this;
13891
13848
  }
13892
- const hasCustomSchedules = (params.schedules?.length ?? 0) > 0 || (params.scheduleIds?.length ?? 0) > 0;
13849
+ if (params.allocations) {
13850
+ this.vesting = {
13851
+ allocations: params.allocations.map((allocation, index) => ({
13852
+ recipient: allocation.recipient,
13853
+ amount: allocation.amount,
13854
+ schedule: normalizeBuilderVestingSchedule(
13855
+ allocation.schedule,
13856
+ `Vesting allocations[${index}].schedule`
13857
+ )
13858
+ }))
13859
+ };
13860
+ return this;
13861
+ }
13893
13862
  this.vesting = {
13894
- duration: Number(
13895
- params.duration ?? (hasCustomSchedules ? 0n : DEFAULT_V3_VESTING_DURATION)
13896
- ),
13863
+ duration: Number(params.duration ?? DEFAULT_V3_VESTING_DURATION),
13897
13864
  cliffDuration: params.cliffDuration ?? 0,
13898
13865
  recipients: params.recipients,
13899
- amounts: params.amounts,
13900
- schedules: params.schedules?.map((schedule) => ({
13901
- duration: normalizeBuilderVestingScheduleDuration(
13902
- schedule.duration,
13903
- "Vesting schedule duration"
13904
- ),
13905
- cliffDuration: schedule.cliffDuration ?? 0
13906
- })),
13907
- scheduleIds: params.scheduleIds?.map(
13908
- (scheduleId, index) => normalizeBuilderScheduleId(scheduleId, `Vesting scheduleIds[${index}]`)
13909
- )
13866
+ amounts: params.amounts
13910
13867
  };
13911
13868
  return this;
13912
13869
  }
@@ -14234,21 +14191,24 @@ var DynamicAuctionBuilder = class _DynamicAuctionBuilder {
14234
14191
  this.vesting = void 0;
14235
14192
  return this;
14236
14193
  }
14194
+ if (params.allocations) {
14195
+ this.vesting = {
14196
+ allocations: params.allocations.map((allocation, index) => ({
14197
+ recipient: allocation.recipient,
14198
+ amount: allocation.amount,
14199
+ schedule: normalizeBuilderVestingSchedule(
14200
+ allocation.schedule,
14201
+ `Vesting allocations[${index}].schedule`
14202
+ )
14203
+ }))
14204
+ };
14205
+ return this;
14206
+ }
14237
14207
  this.vesting = {
14238
14208
  duration: Number(params.duration ?? 0n),
14239
14209
  cliffDuration: params.cliffDuration ?? 0,
14240
14210
  recipients: params.recipients,
14241
- amounts: params.amounts,
14242
- schedules: params.schedules?.map((schedule) => ({
14243
- duration: normalizeBuilderVestingScheduleDuration(
14244
- schedule.duration,
14245
- "Vesting schedule duration"
14246
- ),
14247
- cliffDuration: schedule.cliffDuration ?? 0
14248
- })),
14249
- scheduleIds: params.scheduleIds?.map(
14250
- (scheduleId, index) => normalizeBuilderScheduleId(scheduleId, `Vesting scheduleIds[${index}]`)
14251
- )
14211
+ amounts: params.amounts
14252
14212
  };
14253
14213
  return this;
14254
14214
  }
@@ -14850,21 +14810,24 @@ var MulticurveBuilder = class _MulticurveBuilder {
14850
14810
  this.vesting = void 0;
14851
14811
  return this;
14852
14812
  }
14813
+ if (params.allocations) {
14814
+ this.vesting = {
14815
+ allocations: params.allocations.map((allocation, index) => ({
14816
+ recipient: allocation.recipient,
14817
+ amount: allocation.amount,
14818
+ schedule: normalizeBuilderVestingSchedule(
14819
+ allocation.schedule,
14820
+ `Vesting allocations[${index}].schedule`
14821
+ )
14822
+ }))
14823
+ };
14824
+ return this;
14825
+ }
14853
14826
  this.vesting = {
14854
14827
  duration: Number(params.duration ?? 0n),
14855
14828
  cliffDuration: params.cliffDuration ?? 0,
14856
14829
  recipients: params.recipients,
14857
- amounts: params.amounts,
14858
- schedules: params.schedules?.map((schedule) => ({
14859
- duration: normalizeBuilderVestingScheduleDuration(
14860
- schedule.duration,
14861
- "Vesting schedule duration"
14862
- ),
14863
- cliffDuration: schedule.cliffDuration ?? 0
14864
- })),
14865
- scheduleIds: params.scheduleIds?.map(
14866
- (scheduleId, index) => normalizeBuilderScheduleId(scheduleId, `Vesting scheduleIds[${index}]`)
14867
- )
14830
+ amounts: params.amounts
14868
14831
  };
14869
14832
  return this;
14870
14833
  }
@@ -15249,21 +15212,24 @@ var OpeningAuctionBuilder = class _OpeningAuctionBuilder {
15249
15212
  this.vesting = void 0;
15250
15213
  return this;
15251
15214
  }
15215
+ if (params.allocations) {
15216
+ this.vesting = {
15217
+ allocations: params.allocations.map((allocation, index) => ({
15218
+ recipient: allocation.recipient,
15219
+ amount: allocation.amount,
15220
+ schedule: normalizeBuilderVestingSchedule(
15221
+ allocation.schedule,
15222
+ `Vesting allocations[${index}].schedule`
15223
+ )
15224
+ }))
15225
+ };
15226
+ return this;
15227
+ }
15252
15228
  this.vesting = {
15253
15229
  duration: Number(params.duration ?? 0n),
15254
15230
  cliffDuration: params.cliffDuration ?? 0,
15255
15231
  recipients: params.recipients,
15256
- amounts: params.amounts,
15257
- schedules: params.schedules?.map((schedule) => ({
15258
- duration: normalizeBuilderVestingScheduleDuration(
15259
- schedule.duration,
15260
- "Vesting schedule duration"
15261
- ),
15262
- cliffDuration: schedule.cliffDuration ?? 0
15263
- })),
15264
- scheduleIds: params.scheduleIds?.map(
15265
- (scheduleId, index) => normalizeBuilderScheduleId(scheduleId, `Vesting scheduleIds[${index}]`)
15266
- )
15232
+ amounts: params.amounts
15267
15233
  };
15268
15234
  return this;
15269
15235
  }