@juicedollar/jusd 1.0.0 → 1.0.2

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
@@ -139,9 +139,8 @@ yarn install
139
139
  Create a `.env` file (see `.env.example`):
140
140
 
141
141
  ```bash
142
- # Required: Use EITHER private key OR seed phrase
142
+ # Required: Deployer wallet private key
143
143
  DEPLOYER_PRIVATE_KEY=your_private_key_here
144
- # DEPLOYER_ACCOUNT_SEED="twelve word seed phrase goes here"
145
144
 
146
145
  # Optional: For contract verification on Citrea explorer
147
146
  # CITREA_EXPLORER_API_KEY=your_api_key_here
@@ -247,26 +246,39 @@ npx hardhat ignition verify $DEPLOYMENT --include-unrelated-contracts
247
246
  ### Package Info
248
247
 
249
248
  - **Name**: `@juicedollar/jusd`
250
- - **Version**: `1.0.16` (see `package.json`)
249
+ - **Version**: `1.0.0` (see `package.json`)
251
250
  - **Registry**: https://registry.npmjs.org
252
251
 
253
- ### Build & Publish
252
+ ### First-Time Publish
254
253
 
255
254
  ```bash
256
- # 1. Update version in package.json
257
- # "version": "1.0.17"
255
+ # 1. Login to NPM
256
+ npm login
258
257
 
259
- # 2. Build TypeScript package
260
- yarn run build
258
+ # 2. Publish (build happens automatically via prepublishOnly)
259
+ yarn run publish
260
+ ```
261
261
 
262
- # 3. Login to NPM
263
- npm login
262
+ ### Publishing Updates
263
+
264
+ ```bash
265
+ # 1. Update contracts (if changed)
266
+ # Edit contracts, then export ABIs:
267
+ yarn run ts:export:abis
268
+
269
+ # 2. Update version in package.json (semantic versioning)
270
+ # Patch: 1.0.0 → 1.0.1 (bug fixes)
271
+ # Minor: 1.0.0 → 1.1.0 (new features)
272
+ # Major: 1.0.0 → 2.0.0 (breaking changes)
273
+
274
+ # 3. Commit changes
275
+ git add . && git commit -m "Release v1.0.1: Description"
264
276
 
265
- # 4. Publish package
277
+ # 4. Publish (build happens automatically)
266
278
  yarn run publish
267
279
  ```
268
280
 
269
- **Note:** The publish command may execute twice; the second will fail with a version conflict (expected behavior).
281
+ **Note:** The `prepublishOnly` script automatically runs `yarn run build` before publishing.
270
282
 
271
283
  ### Package Exports
272
284
 
@@ -29,10 +29,10 @@ contract Equity is ERC20Permit, ERC3009, MathUtil, IReserve, ERC165 {
29
29
  *
30
30
  * In the absence of fees, profits and losses, the variables grow as follows when JUICE tokens are minted:
31
31
  *
32
- * | Reserve | Market Cap | Price | Supply |
33
- * | 1_000 | 10_000 | 0.001 | 10_000_000 |
34
- * | 100_000_000 | 1_000_000_000 | 31.62 | 31_622_777 |
35
- * | 10_000_000_000_000 |100_000_000_000_000 | 1_000_000 | 100_000_000 |
32
+ * | Reserve | Market Cap | Price | Supply |
33
+ * | 1_000 | 10_000 | 0.0001 | 100_000_000 |
34
+ * | 100_000_000 | 1_000_000_000 | 3.162 | 316_227_766 |
35
+ * | 10_000_000_000_000 | 100_000_000_000_000 | 100_000 | 1_000_000_000 |
36
36
  *
37
37
  * i.e., the supply is proportional to the tenth root of the reserve and the price is proportional to
38
38
  * the ninth power of the tenth root (or Reserve^0.9). When profits accumulate or losses materialize,
@@ -122,7 +122,7 @@ contract Equity is ERC20Permit, ERC3009, MathUtil, IReserve, ERC165 {
122
122
  function price() public view returns (uint256) {
123
123
  uint256 equity = JUSD.equity();
124
124
  if (equity == 0 || totalSupply() == 0) {
125
- return 10 ** 14;
125
+ return 10 ** 13;
126
126
  } else {
127
127
  return (VALUATION_FACTOR * JUSD.equity() * ONE_DEC18) / totalSupply();
128
128
  }
@@ -358,9 +358,9 @@ contract Equity is ERC20Permit, ERC3009, MathUtil, IReserve, ERC165 {
358
358
  function _calculateShares(uint256 capitalBefore, uint256 investment) internal view returns (uint256) {
359
359
  uint256 totalShares = totalSupply();
360
360
  uint256 investmentExFees = (investment * 980) / 1_000; // remove 2% fee
361
- // Assign 10_000_000 JUICE for the initial deposit, calculate the amount otherwise
361
+ // Assign 100_000_000 JUICE for the initial deposit, calculate the amount otherwise
362
362
  uint256 newTotalShares = (capitalBefore < MINIMUM_EQUITY || totalShares == 0)
363
- ? totalShares + 10_000_000 * ONE_DEC18
363
+ ? totalShares + 100_000_000 * ONE_DEC18
364
364
  : _mulD18(totalShares, _tenthRoot(_divD18(capitalBefore + investmentExFees, capitalBefore)));
365
365
  return newTotalShares - totalShares;
366
366
  }
@@ -134,8 +134,8 @@ contract MintingHub is IMintingHub, ERC165 {
134
134
  bytes memory /*lowLevelData*/
135
135
  ) {}
136
136
  if (_initialCollateral < _minCollateral) revert InsufficientCollateral();
137
- // must start with at least 5000 JUSD worth of collateral
138
- if (_minCollateral * _liqPrice < 5000 ether * 10 ** 18) revert InsufficientCollateral();
137
+ // must start with at least 100 JUSD worth of collateral
138
+ if (_minCollateral * _liqPrice < 100 ether * 10 ** 18) revert InsufficientCollateral();
139
139
  }
140
140
  IPosition pos = IPosition(
141
141
  POSITION_FACTORY.createNewPosition(
@@ -140,6 +140,7 @@ contract Position is Ownable, IPosition, MathUtil {
140
140
  error InvalidExpiration();
141
141
  error AlreadyInitialized();
142
142
  error PriceTooHigh(uint256 newPrice, uint256 maxPrice);
143
+ error InvalidPriceReference();
143
144
 
144
145
  modifier alive() {
145
146
  if (block.timestamp >= expiration) revert Expired(uint40(block.timestamp), expiration);
@@ -313,6 +314,25 @@ contract Position is Ownable, IPosition, MathUtil {
313
314
  * and the price in one transaction.
314
315
  */
315
316
  function adjust(uint256 newPrincipal, uint256 newCollateral, uint256 newPrice) external onlyOwner {
317
+ _adjust(newPrincipal, newCollateral, newPrice, address(0));
318
+ }
319
+
320
+ /**
321
+ * @notice "All in one" function to adjust the principal, the collateral amount,
322
+ * and the price in one transaction, with optional reference position for cooldown-free price increase.
323
+ * @param newPrincipal The new principal amount
324
+ * @param newCollateral The new collateral amount
325
+ * @param newPrice The new liquidation price
326
+ * @param referencePosition Reference position for cooldown-free price increase (address(0) for normal logic with cooldown)
327
+ */
328
+ function adjust(uint256 newPrincipal, uint256 newCollateral, uint256 newPrice, address referencePosition) external onlyOwner {
329
+ _adjust(newPrincipal, newCollateral, newPrice, referencePosition);
330
+ }
331
+
332
+ /**
333
+ * @dev Internal implementation of adjust() - handles collateral, principal, and price adjustments.
334
+ */
335
+ function _adjust(uint256 newPrincipal, uint256 newCollateral, uint256 newPrice, address referencePosition) internal {
316
336
  uint256 colbal = _collateralBalance();
317
337
  if (newCollateral > colbal) {
318
338
  collateral.transferFrom(msg.sender, address(this), newCollateral - colbal);
@@ -330,7 +350,7 @@ contract Position is Ownable, IPosition, MathUtil {
330
350
  _mint(msg.sender, newPrincipal - principal, newCollateral);
331
351
  }
332
352
  if (newPrice != price) {
333
- _adjustPrice(newPrice);
353
+ _adjustPrice(newPrice, referencePosition);
334
354
  }
335
355
  emit MintingUpdate(newCollateral, newPrice, newPrincipal);
336
356
  }
@@ -341,19 +361,95 @@ contract Position is Ownable, IPosition, MathUtil {
341
361
  * Increasing the liquidation price triggers a cooldown period of 3 days, during which minting is suspended.
342
362
  */
343
363
  function adjustPrice(uint256 newPrice) public onlyOwner {
344
- _adjustPrice(newPrice);
364
+ _adjustPrice(newPrice, address(0));
345
365
  emit MintingUpdate(_collateralBalance(), price, principal);
346
366
  }
347
367
 
348
- function _adjustPrice(uint256 newPrice) internal noChallenge alive backed noCooldown {
368
+ /**
369
+ * @notice Adjusts the liquidation price without cooldown if a valid reference position is provided.
370
+ * @dev The reference position must be active (not in cooldown, not expired, not challenged, not closed),
371
+ * have the same collateral, and have a price >= newPrice.
372
+ * Note: For price decreases (newPrice <= current price), the reference position is ignored
373
+ * and only the collateral check is performed, as price decreases don't require cooldown protection.
374
+ * @param newPrice The new liquidation price
375
+ * @param referencePosition An active position with the same collateral and at least this price (only used for price increases)
376
+ */
377
+ function adjustPriceWithReference(uint256 newPrice, address referencePosition) external onlyOwner {
378
+ _adjustPrice(newPrice, referencePosition);
379
+ emit MintingUpdate(_collateralBalance(), price, principal);
380
+ }
381
+
382
+ /**
383
+ * @dev Unified internal price adjustment logic.
384
+ * @param newPrice The new liquidation price
385
+ * @param referencePosition For price increases: address(0) triggers 3-day cooldown,
386
+ * valid reference allows cooldown-free adjustment.
387
+ * For price decreases: ignored (only collateral check performed).
388
+ * Price decreases are allowed even during cooldown since they make the position safer.
389
+ */
390
+ function _adjustPrice(uint256 newPrice, address referencePosition) internal noChallenge alive backed {
349
391
  if (newPrice > price) {
350
- _restrictMinting(3 days);
392
+ if (block.timestamp <= cooldown) revert Hot();
393
+ if (referencePosition == address(0)) {
394
+ _restrictMinting(3 days);
395
+ } else if (!_isValidPriceReference(referencePosition, newPrice)) {
396
+ revert InvalidPriceReference();
397
+ }
351
398
  } else {
352
399
  _checkCollateral(_collateralBalance(), newPrice);
353
400
  }
354
401
  _setPrice(newPrice, principal + availableForMinting());
355
402
  }
356
403
 
404
+ /**
405
+ * @notice Checks if a reference position is valid for a cooldown-free price increase.
406
+ * @param referencePosition The address of the reference position to validate
407
+ * @param newPrice The new price that should be validated against the reference
408
+ * @return True if the reference position is valid, false otherwise
409
+ */
410
+ function _isValidPriceReference(address referencePosition, uint256 newPrice) internal view returns (bool) {
411
+ // 1. Reference must be registered in the same hub
412
+ if (jusd.getPositionParent(referencePosition) != hub) return false;
413
+
414
+ IPosition ref = IPosition(referencePosition);
415
+
416
+ // 2. Reference must not be this position itself
417
+ if (referencePosition == address(this)) return false;
418
+
419
+ // 3. Same collateral
420
+ if (address(ref.collateral()) != address(collateral)) return false;
421
+
422
+ // 4. Reference must be active (not in cooldown)
423
+ if (block.timestamp <= ref.cooldown()) return false;
424
+
425
+ // 5. Reference must not be expired
426
+ if (block.timestamp >= ref.expiration()) return false;
427
+
428
+ // 6. Reference must not be challenged
429
+ if (ref.challengedAmount() > 0) return false;
430
+
431
+ // 7. Reference must not be closed
432
+ if (ref.isClosed()) return false;
433
+
434
+ // 8. New price must be <= reference price
435
+ if (newPrice > ref.price()) return false;
436
+
437
+ // 9. Reference must have principal > 0 (actively used)
438
+ if (ref.principal() == 0) return false;
439
+
440
+ return true;
441
+ }
442
+
443
+ /**
444
+ * @notice Checks if a reference position is valid for a cooldown-free price increase.
445
+ * @param referencePosition The address of the reference position to validate
446
+ * @param newPrice The new price that should be validated against the reference
447
+ * @return True if the reference position is valid, false otherwise
448
+ */
449
+ function isValidPriceReference(address referencePosition, uint256 newPrice) external view returns (bool) {
450
+ return _isValidPriceReference(referencePosition, newPrice);
451
+ }
452
+
357
453
  function _setPrice(uint256 newPrice, uint256 bounds) internal {
358
454
  uint256 colBalance = _collateralBalance();
359
455
  if (block.timestamp >= start && newPrice > 2 * price) {
@@ -60,6 +60,14 @@ interface IPosition {
60
60
 
61
61
  function adjustPrice(uint256 newPrice) external;
62
62
 
63
+ function adjustPriceWithReference(uint256 newPrice, address referencePosition) external;
64
+
65
+ function adjust(uint256 newMinted, uint256 newCollateral, uint256 newPrice, address referencePosition) external;
66
+
67
+ function isValidPriceReference(address referencePosition, uint256 newPrice) external view returns (bool);
68
+
69
+ function isClosed() external view returns (bool);
70
+
63
71
  function mint(address target, uint256 amount) external;
64
72
 
65
73
  function getDebt() external view returns (uint256);
@@ -6,11 +6,11 @@ import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
6
6
  /**
7
7
  * @title StartUSD
8
8
  * @notice A minimal genesis stablecoin used to bootstrap the JuiceDollar protocol.
9
- * @dev Mints 10,000 SUSD to the deployer. Used to initialize the protocol with initial
9
+ * @dev Mints 100,000,000 SUSD to the deployer. Used to initialize the protocol with initial
10
10
  * JUSD supply through a StablecoinBridge, which then creates the initial JUICE tokens.
11
11
  */
12
12
  contract StartUSD is ERC20 {
13
13
  constructor() ERC20("StartUSD", "SUSD") {
14
- _mint(msg.sender, 10_000 * 10 ** 18);
14
+ _mint(msg.sender, 100_000_000 * 10 ** 18);
15
15
  }
16
16
  }
package/dist/index.d.mts CHANGED
@@ -5209,6 +5209,10 @@ declare const PositionV2ABI: readonly [{
5209
5209
  readonly inputs: readonly [];
5210
5210
  readonly name: "InvalidExpiration";
5211
5211
  readonly type: "error";
5212
+ }, {
5213
+ readonly inputs: readonly [];
5214
+ readonly name: "InvalidPriceReference";
5215
+ readonly type: "error";
5212
5216
  }, {
5213
5217
  readonly inputs: readonly [{
5214
5218
  readonly internalType: "uint256";
@@ -5337,6 +5341,28 @@ declare const PositionV2ABI: readonly [{
5337
5341
  readonly outputs: readonly [];
5338
5342
  readonly stateMutability: "nonpayable";
5339
5343
  readonly type: "function";
5344
+ }, {
5345
+ readonly inputs: readonly [{
5346
+ readonly internalType: "uint256";
5347
+ readonly name: "newPrincipal";
5348
+ readonly type: "uint256";
5349
+ }, {
5350
+ readonly internalType: "uint256";
5351
+ readonly name: "newCollateral";
5352
+ readonly type: "uint256";
5353
+ }, {
5354
+ readonly internalType: "uint256";
5355
+ readonly name: "newPrice";
5356
+ readonly type: "uint256";
5357
+ }, {
5358
+ readonly internalType: "address";
5359
+ readonly name: "referencePosition";
5360
+ readonly type: "address";
5361
+ }];
5362
+ readonly name: "adjust";
5363
+ readonly outputs: readonly [];
5364
+ readonly stateMutability: "nonpayable";
5365
+ readonly type: "function";
5340
5366
  }, {
5341
5367
  readonly inputs: readonly [{
5342
5368
  readonly internalType: "uint256";
@@ -5347,6 +5373,20 @@ declare const PositionV2ABI: readonly [{
5347
5373
  readonly outputs: readonly [];
5348
5374
  readonly stateMutability: "nonpayable";
5349
5375
  readonly type: "function";
5376
+ }, {
5377
+ readonly inputs: readonly [{
5378
+ readonly internalType: "uint256";
5379
+ readonly name: "newPrice";
5380
+ readonly type: "uint256";
5381
+ }, {
5382
+ readonly internalType: "address";
5383
+ readonly name: "referencePosition";
5384
+ readonly type: "address";
5385
+ }];
5386
+ readonly name: "adjustPriceWithReference";
5387
+ readonly outputs: readonly [];
5388
+ readonly stateMutability: "nonpayable";
5389
+ readonly type: "function";
5350
5390
  }, {
5351
5391
  readonly inputs: readonly [];
5352
5392
  readonly name: "assertCloneable";
@@ -5581,6 +5621,24 @@ declare const PositionV2ABI: readonly [{
5581
5621
  }];
5582
5622
  readonly stateMutability: "view";
5583
5623
  readonly type: "function";
5624
+ }, {
5625
+ readonly inputs: readonly [{
5626
+ readonly internalType: "address";
5627
+ readonly name: "referencePosition";
5628
+ readonly type: "address";
5629
+ }, {
5630
+ readonly internalType: "uint256";
5631
+ readonly name: "newPrice";
5632
+ readonly type: "uint256";
5633
+ }];
5634
+ readonly name: "isValidPriceReference";
5635
+ readonly outputs: readonly [{
5636
+ readonly internalType: "bool";
5637
+ readonly name: "";
5638
+ readonly type: "bool";
5639
+ }];
5640
+ readonly stateMutability: "view";
5641
+ readonly type: "function";
5584
5642
  }, {
5585
5643
  readonly inputs: readonly [];
5586
5644
  readonly name: "jusd";
package/dist/index.d.ts CHANGED
@@ -5209,6 +5209,10 @@ declare const PositionV2ABI: readonly [{
5209
5209
  readonly inputs: readonly [];
5210
5210
  readonly name: "InvalidExpiration";
5211
5211
  readonly type: "error";
5212
+ }, {
5213
+ readonly inputs: readonly [];
5214
+ readonly name: "InvalidPriceReference";
5215
+ readonly type: "error";
5212
5216
  }, {
5213
5217
  readonly inputs: readonly [{
5214
5218
  readonly internalType: "uint256";
@@ -5337,6 +5341,28 @@ declare const PositionV2ABI: readonly [{
5337
5341
  readonly outputs: readonly [];
5338
5342
  readonly stateMutability: "nonpayable";
5339
5343
  readonly type: "function";
5344
+ }, {
5345
+ readonly inputs: readonly [{
5346
+ readonly internalType: "uint256";
5347
+ readonly name: "newPrincipal";
5348
+ readonly type: "uint256";
5349
+ }, {
5350
+ readonly internalType: "uint256";
5351
+ readonly name: "newCollateral";
5352
+ readonly type: "uint256";
5353
+ }, {
5354
+ readonly internalType: "uint256";
5355
+ readonly name: "newPrice";
5356
+ readonly type: "uint256";
5357
+ }, {
5358
+ readonly internalType: "address";
5359
+ readonly name: "referencePosition";
5360
+ readonly type: "address";
5361
+ }];
5362
+ readonly name: "adjust";
5363
+ readonly outputs: readonly [];
5364
+ readonly stateMutability: "nonpayable";
5365
+ readonly type: "function";
5340
5366
  }, {
5341
5367
  readonly inputs: readonly [{
5342
5368
  readonly internalType: "uint256";
@@ -5347,6 +5373,20 @@ declare const PositionV2ABI: readonly [{
5347
5373
  readonly outputs: readonly [];
5348
5374
  readonly stateMutability: "nonpayable";
5349
5375
  readonly type: "function";
5376
+ }, {
5377
+ readonly inputs: readonly [{
5378
+ readonly internalType: "uint256";
5379
+ readonly name: "newPrice";
5380
+ readonly type: "uint256";
5381
+ }, {
5382
+ readonly internalType: "address";
5383
+ readonly name: "referencePosition";
5384
+ readonly type: "address";
5385
+ }];
5386
+ readonly name: "adjustPriceWithReference";
5387
+ readonly outputs: readonly [];
5388
+ readonly stateMutability: "nonpayable";
5389
+ readonly type: "function";
5350
5390
  }, {
5351
5391
  readonly inputs: readonly [];
5352
5392
  readonly name: "assertCloneable";
@@ -5581,6 +5621,24 @@ declare const PositionV2ABI: readonly [{
5581
5621
  }];
5582
5622
  readonly stateMutability: "view";
5583
5623
  readonly type: "function";
5624
+ }, {
5625
+ readonly inputs: readonly [{
5626
+ readonly internalType: "address";
5627
+ readonly name: "referencePosition";
5628
+ readonly type: "address";
5629
+ }, {
5630
+ readonly internalType: "uint256";
5631
+ readonly name: "newPrice";
5632
+ readonly type: "uint256";
5633
+ }];
5634
+ readonly name: "isValidPriceReference";
5635
+ readonly outputs: readonly [{
5636
+ readonly internalType: "bool";
5637
+ readonly name: "";
5638
+ readonly type: "bool";
5639
+ }];
5640
+ readonly stateMutability: "view";
5641
+ readonly type: "function";
5584
5642
  }, {
5585
5643
  readonly inputs: readonly [];
5586
5644
  readonly name: "jusd";
package/dist/index.js CHANGED
@@ -61,20 +61,17 @@ var ADDRESS = {
61
61
  positionFactoryV2: import_viem.zeroAddress
62
62
  },
63
63
  5115: {
64
- // Citrea Testnet - Deployed 2025-11-07
65
- juiceDollar: "0x1Dd3057888944ff1f914626aB4BD47Dc8b6285Fe",
66
- equity: "0xD82010E94737A4E4C3fc26314326Ff606E2Dcdf4",
67
- frontendGateway: "0xe8757e121593bBD9f784F196026259085461aB17",
68
- savingsGateway: "0x13531a4E00B36Fdb5f9f9A7c8C85cBc08Fd8EbDb",
69
- savingsVaultJUSD: import_viem.zeroAddress,
70
- // Not yet deployed
71
- mintingHubGateway: "0xFfcD888Eb52F0FdD894fef580370A2FF48d82279",
72
- coinLendingGateway: import_viem.zeroAddress,
73
- // Not yet deployed
74
- bridgeStartUSD: "0xFf862f932eB215A9C4aC8F3d20dd6dAe69DeC6D8",
75
- startUSD: "0xf0229A29172E3541F5578dFC02aa024b3Bdb96A1",
76
- roller: "0x851FF9f1F5fb7eEf75257aAa0adD2121D6b1Bd49",
77
- positionFactoryV2: "0x4cc067EfcD6E6386BA8D6fd31c907Cad6C005318"
64
+ juiceDollar: "0x258e525B6F9f62195478fe94d14AE20178AB2545",
65
+ equity: "0xDd965FCdcb4022414204B9BDc5dF949c2761e7Cc",
66
+ frontendGateway: "0xA9DAD130a5744Bc6DBD7151e184352BFfc57BC87",
67
+ savingsGateway: "0x71335aa01FB04C234B7CfA72361d7CdC355fE097",
68
+ savingsVaultJUSD: "0xA049fc273034D44515A81A564c8F43400B3f77B3",
69
+ mintingHubGateway: "0xF2D5F2F3fA1d048284a9d669805478F8ad677e5a",
70
+ coinLendingGateway: "0x16c530290662Dc04Dba3040e5e6EBD8e7D3bfe03",
71
+ bridgeStartUSD: "0x568965b5f8Fa9e6EE56b670e684F85b277545EFE",
72
+ startUSD: "0xD4A183699d0AbCf774b1ea23CDfC0B4b1d5cB30f",
73
+ roller: "0x2017C636AA98c7BAAAa68b48195d31Ef5869e37C",
74
+ positionFactoryV2: "0x171dAe92afc8AC3D581178163a1F993533a94c4B"
78
75
  }
79
76
  };
80
77
 
@@ -6833,6 +6830,11 @@ var PositionV2ABI = [
6833
6830
  name: "InvalidExpiration",
6834
6831
  type: "error"
6835
6832
  },
6833
+ {
6834
+ inputs: [],
6835
+ name: "InvalidPriceReference",
6836
+ type: "error"
6837
+ },
6836
6838
  {
6837
6839
  inputs: [
6838
6840
  {
@@ -6999,6 +7001,34 @@ var PositionV2ABI = [
6999
7001
  stateMutability: "nonpayable",
7000
7002
  type: "function"
7001
7003
  },
7004
+ {
7005
+ inputs: [
7006
+ {
7007
+ internalType: "uint256",
7008
+ name: "newPrincipal",
7009
+ type: "uint256"
7010
+ },
7011
+ {
7012
+ internalType: "uint256",
7013
+ name: "newCollateral",
7014
+ type: "uint256"
7015
+ },
7016
+ {
7017
+ internalType: "uint256",
7018
+ name: "newPrice",
7019
+ type: "uint256"
7020
+ },
7021
+ {
7022
+ internalType: "address",
7023
+ name: "referencePosition",
7024
+ type: "address"
7025
+ }
7026
+ ],
7027
+ name: "adjust",
7028
+ outputs: [],
7029
+ stateMutability: "nonpayable",
7030
+ type: "function"
7031
+ },
7002
7032
  {
7003
7033
  inputs: [
7004
7034
  {
@@ -7012,6 +7042,24 @@ var PositionV2ABI = [
7012
7042
  stateMutability: "nonpayable",
7013
7043
  type: "function"
7014
7044
  },
7045
+ {
7046
+ inputs: [
7047
+ {
7048
+ internalType: "uint256",
7049
+ name: "newPrice",
7050
+ type: "uint256"
7051
+ },
7052
+ {
7053
+ internalType: "address",
7054
+ name: "referencePosition",
7055
+ type: "address"
7056
+ }
7057
+ ],
7058
+ name: "adjustPriceWithReference",
7059
+ outputs: [],
7060
+ stateMutability: "nonpayable",
7061
+ type: "function"
7062
+ },
7015
7063
  {
7016
7064
  inputs: [],
7017
7065
  name: "assertCloneable",
@@ -7316,6 +7364,30 @@ var PositionV2ABI = [
7316
7364
  stateMutability: "view",
7317
7365
  type: "function"
7318
7366
  },
7367
+ {
7368
+ inputs: [
7369
+ {
7370
+ internalType: "address",
7371
+ name: "referencePosition",
7372
+ type: "address"
7373
+ },
7374
+ {
7375
+ internalType: "uint256",
7376
+ name: "newPrice",
7377
+ type: "uint256"
7378
+ }
7379
+ ],
7380
+ name: "isValidPriceReference",
7381
+ outputs: [
7382
+ {
7383
+ internalType: "bool",
7384
+ name: "",
7385
+ type: "bool"
7386
+ }
7387
+ ],
7388
+ stateMutability: "view",
7389
+ type: "function"
7390
+ },
7319
7391
  {
7320
7392
  inputs: [],
7321
7393
  name: "jusd",
package/dist/index.mjs CHANGED
@@ -16,20 +16,17 @@ var ADDRESS = {
16
16
  positionFactoryV2: zeroAddress
17
17
  },
18
18
  5115: {
19
- // Citrea Testnet - Deployed 2025-11-07
20
- juiceDollar: "0x1Dd3057888944ff1f914626aB4BD47Dc8b6285Fe",
21
- equity: "0xD82010E94737A4E4C3fc26314326Ff606E2Dcdf4",
22
- frontendGateway: "0xe8757e121593bBD9f784F196026259085461aB17",
23
- savingsGateway: "0x13531a4E00B36Fdb5f9f9A7c8C85cBc08Fd8EbDb",
24
- savingsVaultJUSD: zeroAddress,
25
- // Not yet deployed
26
- mintingHubGateway: "0xFfcD888Eb52F0FdD894fef580370A2FF48d82279",
27
- coinLendingGateway: zeroAddress,
28
- // Not yet deployed
29
- bridgeStartUSD: "0xFf862f932eB215A9C4aC8F3d20dd6dAe69DeC6D8",
30
- startUSD: "0xf0229A29172E3541F5578dFC02aa024b3Bdb96A1",
31
- roller: "0x851FF9f1F5fb7eEf75257aAa0adD2121D6b1Bd49",
32
- positionFactoryV2: "0x4cc067EfcD6E6386BA8D6fd31c907Cad6C005318"
19
+ juiceDollar: "0x258e525B6F9f62195478fe94d14AE20178AB2545",
20
+ equity: "0xDd965FCdcb4022414204B9BDc5dF949c2761e7Cc",
21
+ frontendGateway: "0xA9DAD130a5744Bc6DBD7151e184352BFfc57BC87",
22
+ savingsGateway: "0x71335aa01FB04C234B7CfA72361d7CdC355fE097",
23
+ savingsVaultJUSD: "0xA049fc273034D44515A81A564c8F43400B3f77B3",
24
+ mintingHubGateway: "0xF2D5F2F3fA1d048284a9d669805478F8ad677e5a",
25
+ coinLendingGateway: "0x16c530290662Dc04Dba3040e5e6EBD8e7D3bfe03",
26
+ bridgeStartUSD: "0x568965b5f8Fa9e6EE56b670e684F85b277545EFE",
27
+ startUSD: "0xD4A183699d0AbCf774b1ea23CDfC0B4b1d5cB30f",
28
+ roller: "0x2017C636AA98c7BAAAa68b48195d31Ef5869e37C",
29
+ positionFactoryV2: "0x171dAe92afc8AC3D581178163a1F993533a94c4B"
33
30
  }
34
31
  };
35
32
 
@@ -6788,6 +6785,11 @@ var PositionV2ABI = [
6788
6785
  name: "InvalidExpiration",
6789
6786
  type: "error"
6790
6787
  },
6788
+ {
6789
+ inputs: [],
6790
+ name: "InvalidPriceReference",
6791
+ type: "error"
6792
+ },
6791
6793
  {
6792
6794
  inputs: [
6793
6795
  {
@@ -6954,6 +6956,34 @@ var PositionV2ABI = [
6954
6956
  stateMutability: "nonpayable",
6955
6957
  type: "function"
6956
6958
  },
6959
+ {
6960
+ inputs: [
6961
+ {
6962
+ internalType: "uint256",
6963
+ name: "newPrincipal",
6964
+ type: "uint256"
6965
+ },
6966
+ {
6967
+ internalType: "uint256",
6968
+ name: "newCollateral",
6969
+ type: "uint256"
6970
+ },
6971
+ {
6972
+ internalType: "uint256",
6973
+ name: "newPrice",
6974
+ type: "uint256"
6975
+ },
6976
+ {
6977
+ internalType: "address",
6978
+ name: "referencePosition",
6979
+ type: "address"
6980
+ }
6981
+ ],
6982
+ name: "adjust",
6983
+ outputs: [],
6984
+ stateMutability: "nonpayable",
6985
+ type: "function"
6986
+ },
6957
6987
  {
6958
6988
  inputs: [
6959
6989
  {
@@ -6967,6 +6997,24 @@ var PositionV2ABI = [
6967
6997
  stateMutability: "nonpayable",
6968
6998
  type: "function"
6969
6999
  },
7000
+ {
7001
+ inputs: [
7002
+ {
7003
+ internalType: "uint256",
7004
+ name: "newPrice",
7005
+ type: "uint256"
7006
+ },
7007
+ {
7008
+ internalType: "address",
7009
+ name: "referencePosition",
7010
+ type: "address"
7011
+ }
7012
+ ],
7013
+ name: "adjustPriceWithReference",
7014
+ outputs: [],
7015
+ stateMutability: "nonpayable",
7016
+ type: "function"
7017
+ },
6970
7018
  {
6971
7019
  inputs: [],
6972
7020
  name: "assertCloneable",
@@ -7271,6 +7319,30 @@ var PositionV2ABI = [
7271
7319
  stateMutability: "view",
7272
7320
  type: "function"
7273
7321
  },
7322
+ {
7323
+ inputs: [
7324
+ {
7325
+ internalType: "address",
7326
+ name: "referencePosition",
7327
+ type: "address"
7328
+ },
7329
+ {
7330
+ internalType: "uint256",
7331
+ name: "newPrice",
7332
+ type: "uint256"
7333
+ }
7334
+ ],
7335
+ name: "isValidPriceReference",
7336
+ outputs: [
7337
+ {
7338
+ internalType: "bool",
7339
+ name: "",
7340
+ type: "bool"
7341
+ }
7342
+ ],
7343
+ stateMutability: "view",
7344
+ type: "function"
7345
+ },
7274
7346
  {
7275
7347
  inputs: [],
7276
7348
  name: "jusd",
@@ -132,6 +132,11 @@ export const PositionV2ABI = [
132
132
  name: 'InvalidExpiration',
133
133
  type: 'error',
134
134
  },
135
+ {
136
+ inputs: [],
137
+ name: 'InvalidPriceReference',
138
+ type: 'error',
139
+ },
135
140
  {
136
141
  inputs: [
137
142
  {
@@ -298,6 +303,34 @@ export const PositionV2ABI = [
298
303
  stateMutability: 'nonpayable',
299
304
  type: 'function',
300
305
  },
306
+ {
307
+ inputs: [
308
+ {
309
+ internalType: 'uint256',
310
+ name: 'newPrincipal',
311
+ type: 'uint256',
312
+ },
313
+ {
314
+ internalType: 'uint256',
315
+ name: 'newCollateral',
316
+ type: 'uint256',
317
+ },
318
+ {
319
+ internalType: 'uint256',
320
+ name: 'newPrice',
321
+ type: 'uint256',
322
+ },
323
+ {
324
+ internalType: 'address',
325
+ name: 'referencePosition',
326
+ type: 'address',
327
+ },
328
+ ],
329
+ name: 'adjust',
330
+ outputs: [],
331
+ stateMutability: 'nonpayable',
332
+ type: 'function',
333
+ },
301
334
  {
302
335
  inputs: [
303
336
  {
@@ -311,6 +344,24 @@ export const PositionV2ABI = [
311
344
  stateMutability: 'nonpayable',
312
345
  type: 'function',
313
346
  },
347
+ {
348
+ inputs: [
349
+ {
350
+ internalType: 'uint256',
351
+ name: 'newPrice',
352
+ type: 'uint256',
353
+ },
354
+ {
355
+ internalType: 'address',
356
+ name: 'referencePosition',
357
+ type: 'address',
358
+ },
359
+ ],
360
+ name: 'adjustPriceWithReference',
361
+ outputs: [],
362
+ stateMutability: 'nonpayable',
363
+ type: 'function',
364
+ },
314
365
  {
315
366
  inputs: [],
316
367
  name: 'assertCloneable',
@@ -615,6 +666,30 @@ export const PositionV2ABI = [
615
666
  stateMutability: 'view',
616
667
  type: 'function',
617
668
  },
669
+ {
670
+ inputs: [
671
+ {
672
+ internalType: 'address',
673
+ name: 'referencePosition',
674
+ type: 'address',
675
+ },
676
+ {
677
+ internalType: 'uint256',
678
+ name: 'newPrice',
679
+ type: 'uint256',
680
+ },
681
+ ],
682
+ name: 'isValidPriceReference',
683
+ outputs: [
684
+ {
685
+ internalType: 'bool',
686
+ name: '',
687
+ type: 'bool',
688
+ },
689
+ ],
690
+ stateMutability: 'view',
691
+ type: 'function',
692
+ },
618
693
  {
619
694
  inputs: [],
620
695
  name: 'jusd',
@@ -32,17 +32,16 @@ export const ADDRESS: Record<number, ChainAddress> = {
32
32
  positionFactoryV2: zeroAddress,
33
33
  },
34
34
  5115: {
35
- // Citrea Testnet - Deployed 2025-11-07
36
- juiceDollar: "0x1Dd3057888944ff1f914626aB4BD47Dc8b6285Fe",
37
- equity: "0xD82010E94737A4E4C3fc26314326Ff606E2Dcdf4",
38
- frontendGateway: "0xe8757e121593bBD9f784F196026259085461aB17",
39
- savingsGateway: "0x13531a4E00B36Fdb5f9f9A7c8C85cBc08Fd8EbDb",
40
- savingsVaultJUSD: zeroAddress, // Not yet deployed
41
- mintingHubGateway: "0xFfcD888Eb52F0FdD894fef580370A2FF48d82279",
42
- coinLendingGateway: zeroAddress, // Not yet deployed
43
- bridgeStartUSD: "0xFf862f932eB215A9C4aC8F3d20dd6dAe69DeC6D8",
44
- startUSD: "0xf0229A29172E3541F5578dFC02aa024b3Bdb96A1",
45
- roller: "0x851FF9f1F5fb7eEf75257aAa0adD2121D6b1Bd49",
46
- positionFactoryV2: "0x4cc067EfcD6E6386BA8D6fd31c907Cad6C005318",
35
+ juiceDollar: "0x258e525B6F9f62195478fe94d14AE20178AB2545",
36
+ equity: "0xDd965FCdcb4022414204B9BDc5dF949c2761e7Cc",
37
+ frontendGateway: "0xA9DAD130a5744Bc6DBD7151e184352BFfc57BC87",
38
+ savingsGateway: "0x71335aa01FB04C234B7CfA72361d7CdC355fE097",
39
+ savingsVaultJUSD: "0xA049fc273034D44515A81A564c8F43400B3f77B3",
40
+ mintingHubGateway: "0xF2D5F2F3fA1d048284a9d669805478F8ad677e5a",
41
+ coinLendingGateway: "0x16c530290662Dc04Dba3040e5e6EBD8e7D3bfe03",
42
+ bridgeStartUSD: "0x568965b5f8Fa9e6EE56b670e684F85b277545EFE",
43
+ startUSD: "0xD4A183699d0AbCf774b1ea23CDfC0B4b1d5cB30f",
44
+ roller: "0x2017C636AA98c7BAAAa68b48195d31Ef5869e37C",
45
+ positionFactoryV2: "0x171dAe92afc8AC3D581178163a1F993533a94c4B",
47
46
  },
48
47
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juicedollar/jusd",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "JuiceDollar (JUSD) - Oracle-free, Bitcoin-collateralized stablecoin on Citrea. Decentralized minting with democratic governance.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -19,6 +19,7 @@
19
19
  "lint:sol:fix": "prettier --write \"contracts/**/*.sol\"",
20
20
  "lint:test:fix": "prettier --write \"test/**/**.test.ts\"",
21
21
  "compile": "npx hardhat compile",
22
+ "prepare": "hardhat compile",
22
23
  "wallet": "npx ts-node helper/wallet.info.ts",
23
24
  "coverage": "npx hardhat coverage",
24
25
  "deploy": "npx hardhat run scripts/deployment/deploy/deployProtocol.ts",