@juicedollar/jusd 1.0.2 → 1.0.4
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/contracts/MintingHubV2/MintingHub.sol +58 -17
- package/contracts/MintingHubV2/Position.sol +94 -24
- package/contracts/MintingHubV2/PositionFactory.sol +2 -2
- package/contracts/MintingHubV2/PositionRoller.sol +160 -42
- package/contracts/MintingHubV2/interface/IMintingHub.sol +3 -1
- package/contracts/MintingHubV2/interface/IPosition.sol +5 -3
- package/contracts/gateway/MintingHubGateway.sol +14 -19
- package/contracts/gateway/interface/IMintingHubGateway.sol +2 -2
- package/contracts/interface/IWrappedNative.sol +10 -0
- package/contracts/test/PositionExpirationTest.sol +3 -3
- package/contracts/test/ReentrantAttacker.sol +74 -0
- package/contracts/test/RejectNative.sol +17 -0
- package/dist/index.d.mts +225 -497
- package/dist/index.d.ts +225 -497
- package/dist/index.js +286 -641
- package/dist/index.mjs +286 -640
- package/exports/abis/MintingHubV2/PositionRoller.ts +90 -18
- package/exports/abis/MintingHubV2/PositionV2.ts +68 -26
- package/exports/abis/core/MintingHubGateway.ts +41 -76
- package/exports/abis/utils/MintingHubV2.ts +36 -37
- package/exports/address.config.ts +10 -13
- package/exports/index.ts +0 -1
- package/package.json +1 -1
- package/contracts/gateway/CoinLendingGateway.sol +0 -223
- package/contracts/gateway/interface/ICoinLendingGateway.sol +0 -73
- package/exports/abis/core/CoinLendingGateway.ts +0 -427
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
pragma solidity ^0.8.0;
|
|
3
3
|
|
|
4
4
|
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
|
|
5
|
+
import {IWrappedNative} from "../interface/IWrappedNative.sol";
|
|
5
6
|
import {IJuiceDollar} from "../interface/IJuiceDollar.sol";
|
|
6
7
|
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
|
|
7
8
|
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
@@ -36,6 +37,7 @@ contract MintingHub is IMintingHub, ERC165 {
|
|
|
36
37
|
IJuiceDollar public immutable JUSD; // currency
|
|
37
38
|
PositionRoller public immutable ROLLER; // helper to roll positions
|
|
38
39
|
ILeadrate public immutable RATE; // to determine the interest rate
|
|
40
|
+
address public immutable WCBTC; // wrapped native token (cBTC) address
|
|
39
41
|
|
|
40
42
|
Challenge[] public challenges; // list of open challenges
|
|
41
43
|
|
|
@@ -45,6 +47,12 @@ contract MintingHub is IMintingHub, ERC165 {
|
|
|
45
47
|
*/
|
|
46
48
|
mapping(address collateral => mapping(address owner => uint256 amount)) public pendingReturns;
|
|
47
49
|
|
|
50
|
+
/**
|
|
51
|
+
* @notice Tracks whether the first position has been created.
|
|
52
|
+
* @dev The first position (genesis) can skip the 3-day init period requirement.
|
|
53
|
+
*/
|
|
54
|
+
bool private _genesisPositionCreated;
|
|
55
|
+
|
|
48
56
|
struct Challenge {
|
|
49
57
|
address challenger; // the address from which the challenge was initiated
|
|
50
58
|
uint40 start; // the start of the challenge
|
|
@@ -75,17 +83,20 @@ contract MintingHub is IMintingHub, ERC165 {
|
|
|
75
83
|
error InvalidCollateralDecimals();
|
|
76
84
|
error ChallengeTimeTooShort();
|
|
77
85
|
error InitPeriodTooShort();
|
|
86
|
+
error NativeOnlyForWCBTC();
|
|
87
|
+
error ValueMismatch();
|
|
78
88
|
|
|
79
89
|
modifier validPos(address position) {
|
|
80
90
|
if (JUSD.getPositionParent(position) != address(this)) revert InvalidPos();
|
|
81
91
|
_;
|
|
82
92
|
}
|
|
83
93
|
|
|
84
|
-
constructor(address _jusd, address _leadrate, address _roller, address _factory) {
|
|
94
|
+
constructor(address _jusd, address _leadrate, address payable _roller, address _factory, address _wcbtc) {
|
|
85
95
|
JUSD = IJuiceDollar(_jusd);
|
|
86
96
|
RATE = ILeadrate(_leadrate);
|
|
87
97
|
POSITION_FACTORY = IPositionFactory(_factory);
|
|
88
98
|
ROLLER = PositionRoller(_roller);
|
|
99
|
+
WCBTC = _wcbtc;
|
|
89
100
|
}
|
|
90
101
|
|
|
91
102
|
/**
|
|
@@ -118,15 +129,20 @@ contract MintingHub is IMintingHub, ERC165 {
|
|
|
118
129
|
uint24 _riskPremium,
|
|
119
130
|
uint256 _liqPrice,
|
|
120
131
|
uint24 _reservePPM
|
|
121
|
-
) public returns (address) {
|
|
132
|
+
) public payable returns (address) {
|
|
122
133
|
{
|
|
123
134
|
if (_riskPremium > 1_000_000) revert InvalidRiskPremium();
|
|
124
135
|
if (CHALLENGER_REWARD > _reservePPM || _reservePPM > 1_000_000) revert InvalidReservePPM();
|
|
125
136
|
if (IERC20Metadata(_collateralAddress).decimals() > 24) revert InvalidCollateralDecimals(); // leaves 12 digits for price
|
|
126
137
|
if (_challengeSeconds < 1 days) revert ChallengeTimeTooShort();
|
|
127
|
-
|
|
138
|
+
// First position (genesis) can skip init period, all others require 3 days minimum
|
|
139
|
+
if (_genesisPositionCreated) {
|
|
140
|
+
if (_initPeriodSeconds < 3 days) revert InitPeriodTooShort();
|
|
141
|
+
} else {
|
|
142
|
+
_genesisPositionCreated = true;
|
|
143
|
+
}
|
|
128
144
|
uint256 invalidAmount = IERC20(_collateralAddress).totalSupply() + 1;
|
|
129
|
-
// TODO: Improve for older tokens that revert with assert,
|
|
145
|
+
// TODO: Improve for older tokens that revert with assert,
|
|
130
146
|
// which consumes all gas and makes the entire tx fail (uncatchable)
|
|
131
147
|
try IERC20(_collateralAddress).transfer(address(0x123), invalidAmount) {
|
|
132
148
|
revert IncompatibleCollateral(); // we need a collateral that reverts on failed transfers
|
|
@@ -137,6 +153,7 @@ contract MintingHub is IMintingHub, ERC165 {
|
|
|
137
153
|
// must start with at least 100 JUSD worth of collateral
|
|
138
154
|
if (_minCollateral * _liqPrice < 100 ether * 10 ** 18) revert InsufficientCollateral();
|
|
139
155
|
}
|
|
156
|
+
|
|
140
157
|
IPosition pos = IPosition(
|
|
141
158
|
POSITION_FACTORY.createNewPosition(
|
|
142
159
|
msg.sender,
|
|
@@ -154,41 +171,65 @@ contract MintingHub is IMintingHub, ERC165 {
|
|
|
154
171
|
);
|
|
155
172
|
JUSD.registerPosition(address(pos));
|
|
156
173
|
JUSD.collectProfits(msg.sender, OPENING_FEE);
|
|
157
|
-
|
|
174
|
+
|
|
175
|
+
// Transfer collateral (handles native coin positions)
|
|
176
|
+
if (msg.value > 0) {
|
|
177
|
+
if (_collateralAddress != WCBTC) revert NativeOnlyForWCBTC();
|
|
178
|
+
if (msg.value != _initialCollateral) revert ValueMismatch();
|
|
179
|
+
IWrappedNative(WCBTC).deposit{value: msg.value}();
|
|
180
|
+
IERC20(WCBTC).transfer(address(pos), _initialCollateral);
|
|
181
|
+
} else {
|
|
182
|
+
IERC20(_collateralAddress).transferFrom(msg.sender, address(pos), _initialCollateral); // TODO: Use SafeERC20
|
|
183
|
+
}
|
|
158
184
|
|
|
159
185
|
emit PositionOpened(msg.sender, address(pos), address(pos), _collateralAddress);
|
|
160
186
|
return address(pos);
|
|
161
187
|
}
|
|
162
188
|
|
|
163
|
-
function clone(
|
|
164
|
-
address parent,
|
|
165
|
-
uint256 _initialCollateral,
|
|
166
|
-
uint256 _initialMint,
|
|
167
|
-
uint40 expiration
|
|
168
|
-
) public returns (address) {
|
|
169
|
-
return clone(msg.sender, parent, _initialCollateral, _initialMint, expiration);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
189
|
/**
|
|
173
190
|
* @notice Clones an existing position and immediately tries to mint the specified amount using the given collateral.
|
|
174
191
|
* @dev This needs an allowance to be set on the collateral contract such that the minting hub can get the collateral.
|
|
192
|
+
* For native coin positions (WcBTC), send msg.value equal to _initialCollateral.
|
|
193
|
+
* @param owner The owner of the cloned position
|
|
194
|
+
* @param parent The parent position to clone from
|
|
195
|
+
* @param _initialCollateral Amount of collateral to deposit
|
|
196
|
+
* @param _initialMint Amount of JUSD to mint
|
|
197
|
+
* @param expiration Expiration timestamp for the clone
|
|
198
|
+
* @param _liqPrice The liquidation price. If 0, inherits from parent.
|
|
175
199
|
*/
|
|
176
200
|
function clone(
|
|
177
201
|
address owner,
|
|
178
202
|
address parent,
|
|
179
203
|
uint256 _initialCollateral,
|
|
180
204
|
uint256 _initialMint,
|
|
181
|
-
uint40 expiration
|
|
182
|
-
|
|
205
|
+
uint40 expiration,
|
|
206
|
+
uint256 _liqPrice
|
|
207
|
+
) public payable validPos(parent) returns (address) {
|
|
183
208
|
address pos = POSITION_FACTORY.clonePosition(parent);
|
|
184
209
|
IPosition child = IPosition(pos);
|
|
185
210
|
child.initialize(parent, expiration);
|
|
186
211
|
JUSD.registerPosition(pos);
|
|
187
212
|
IERC20 collateral = child.collateral();
|
|
188
213
|
if (_initialCollateral < child.minimumCollateral()) revert InsufficientCollateral();
|
|
189
|
-
|
|
214
|
+
|
|
215
|
+
// Transfer collateral (handles native coin positions)
|
|
216
|
+
if (msg.value > 0) {
|
|
217
|
+
if (address(collateral) != WCBTC) revert NativeOnlyForWCBTC();
|
|
218
|
+
if (msg.value != _initialCollateral) revert ValueMismatch();
|
|
219
|
+
IWrappedNative(WCBTC).deposit{value: msg.value}();
|
|
220
|
+
collateral.transfer(pos, _initialCollateral);
|
|
221
|
+
} else {
|
|
222
|
+
collateral.transferFrom(msg.sender, pos, _initialCollateral); // collateral must still come from sender for security
|
|
223
|
+
}
|
|
224
|
+
|
|
190
225
|
emit PositionOpened(owner, address(pos), parent, address(collateral));
|
|
191
226
|
child.mint(owner, _initialMint);
|
|
227
|
+
|
|
228
|
+
// Adjust price if requested, incurs cooldown on price increase
|
|
229
|
+
if (_liqPrice > 0 && _liqPrice != child.price()) {
|
|
230
|
+
child.adjustPrice(_liqPrice);
|
|
231
|
+
}
|
|
232
|
+
|
|
192
233
|
Ownable(address(child)).transferOwnership(owner);
|
|
193
234
|
return address(pos);
|
|
194
235
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
pragma solidity ^0.8.0;
|
|
3
3
|
|
|
4
4
|
import {IMintingHubGateway} from "../gateway/interface/IMintingHubGateway.sol";
|
|
5
|
+
import {IWrappedNative} from "../interface/IWrappedNative.sol";
|
|
5
6
|
import {IJuiceDollar} from "../interface/IJuiceDollar.sol";
|
|
6
7
|
import {IReserve} from "../interface/IReserve.sol";
|
|
7
8
|
import {MathUtil} from "../utils/MathUtil.sol";
|
|
@@ -141,6 +142,8 @@ contract Position is Ownable, IPosition, MathUtil {
|
|
|
141
142
|
error AlreadyInitialized();
|
|
142
143
|
error PriceTooHigh(uint256 newPrice, uint256 maxPrice);
|
|
143
144
|
error InvalidPriceReference();
|
|
145
|
+
error NativeTransferFailed();
|
|
146
|
+
error CannotRescueCollateral();
|
|
144
147
|
|
|
145
148
|
modifier alive() {
|
|
146
149
|
if (block.timestamp >= expiration) revert Expired(uint40(block.timestamp), expiration);
|
|
@@ -205,7 +208,7 @@ contract Position is Ownable, IPosition, MathUtil {
|
|
|
205
208
|
reserveContribution = _reservePPM;
|
|
206
209
|
minimumCollateral = _minCollateral;
|
|
207
210
|
challengePeriod = _challengePeriod;
|
|
208
|
-
start = uint40(block.timestamp) + _initPeriod; // at least
|
|
211
|
+
start = uint40(block.timestamp) + _initPeriod; // at least three days time to deny the position
|
|
209
212
|
cooldown = start;
|
|
210
213
|
expiration = start + _duration;
|
|
211
214
|
limit = _initialLimit;
|
|
@@ -219,10 +222,10 @@ contract Position is Ownable, IPosition, MathUtil {
|
|
|
219
222
|
*/
|
|
220
223
|
function initialize(address parent, uint40 _expiration) external onlyHub {
|
|
221
224
|
if (expiration != 0) revert AlreadyInitialized();
|
|
222
|
-
if (_expiration < block.timestamp || _expiration > Position(original).expiration()) revert InvalidExpiration(); // expiration must not be later than original
|
|
225
|
+
if (_expiration < block.timestamp || _expiration > Position(payable(original)).expiration()) revert InvalidExpiration(); // expiration must not be later than original
|
|
223
226
|
expiration = _expiration;
|
|
224
|
-
price = Position(parent).price();
|
|
225
|
-
_fixRateToLeadrate(Position(parent).riskPremiumPPM());
|
|
227
|
+
price = Position(payable(parent)).price();
|
|
228
|
+
_fixRateToLeadrate(Position(payable(parent)).riskPremiumPPM());
|
|
226
229
|
_transferOwnership(hub);
|
|
227
230
|
}
|
|
228
231
|
|
|
@@ -268,7 +271,7 @@ contract Position is Ownable, IPosition, MathUtil {
|
|
|
268
271
|
if (address(this) == original) {
|
|
269
272
|
return limit - totalMinted;
|
|
270
273
|
} else {
|
|
271
|
-
return Position(original).availableForClones();
|
|
274
|
+
return Position(payable(original)).availableForClones();
|
|
272
275
|
}
|
|
273
276
|
}
|
|
274
277
|
|
|
@@ -312,27 +315,46 @@ contract Position is Ownable, IPosition, MathUtil {
|
|
|
312
315
|
/**
|
|
313
316
|
* @notice "All in one" function to adjust the principal, the collateral amount,
|
|
314
317
|
* and the price in one transaction.
|
|
318
|
+
* @dev For native coin positions (WCBTC), msg.value will be wrapped and added as collateral.
|
|
319
|
+
* If withdrawAsNative is true, collateral withdrawals will be unwrapped to native coin.
|
|
320
|
+
* @param newPrincipal The new principal amount
|
|
321
|
+
* @param newCollateral The new collateral amount
|
|
322
|
+
* @param newPrice The new liquidation price
|
|
323
|
+
* @param withdrawAsNative If true, withdraw collateral as native coin instead of wrapped token
|
|
315
324
|
*/
|
|
316
|
-
function adjust(uint256 newPrincipal, uint256 newCollateral, uint256 newPrice) external onlyOwner {
|
|
317
|
-
_adjust(newPrincipal, newCollateral, newPrice, address(0));
|
|
325
|
+
function adjust(uint256 newPrincipal, uint256 newCollateral, uint256 newPrice, bool withdrawAsNative) external payable onlyOwner {
|
|
326
|
+
_adjust(newPrincipal, newCollateral, newPrice, address(0), withdrawAsNative);
|
|
318
327
|
}
|
|
319
328
|
|
|
320
329
|
/**
|
|
321
330
|
* @notice "All in one" function to adjust the principal, the collateral amount,
|
|
322
331
|
* and the price in one transaction, with optional reference position for cooldown-free price increase.
|
|
332
|
+
* @dev For native coin positions (WCBTC), msg.value will be wrapped and added as collateral.
|
|
333
|
+
* If withdrawAsNative is true, collateral withdrawals will be unwrapped to native coin.
|
|
323
334
|
* @param newPrincipal The new principal amount
|
|
324
335
|
* @param newCollateral The new collateral amount
|
|
325
336
|
* @param newPrice The new liquidation price
|
|
326
337
|
* @param referencePosition Reference position for cooldown-free price increase (address(0) for normal logic with cooldown)
|
|
338
|
+
* @param withdrawAsNative If true, withdraw collateral as native coin instead of wrapped token
|
|
327
339
|
*/
|
|
328
|
-
function
|
|
329
|
-
_adjust(newPrincipal, newCollateral, newPrice, referencePosition);
|
|
340
|
+
function adjustWithReference(uint256 newPrincipal, uint256 newCollateral, uint256 newPrice, address referencePosition, bool withdrawAsNative) external payable onlyOwner {
|
|
341
|
+
_adjust(newPrincipal, newCollateral, newPrice, referencePosition, withdrawAsNative);
|
|
330
342
|
}
|
|
331
343
|
|
|
332
344
|
/**
|
|
333
345
|
* @dev Internal implementation of adjust() - handles collateral, principal, and price adjustments.
|
|
346
|
+
* @param newPrincipal The new principal amount
|
|
347
|
+
* @param newCollateral The new collateral amount
|
|
348
|
+
* @param newPrice The new liquidation price
|
|
349
|
+
* @param referencePosition Reference position for cooldown-free price increase (address(0) for normal logic)
|
|
350
|
+
* @param withdrawAsNative If true and withdrawing collateral, unwrap to native coin
|
|
334
351
|
*/
|
|
335
|
-
function _adjust(uint256 newPrincipal, uint256 newCollateral, uint256 newPrice, address referencePosition) internal {
|
|
352
|
+
function _adjust(uint256 newPrincipal, uint256 newCollateral, uint256 newPrice, address referencePosition, bool withdrawAsNative) internal {
|
|
353
|
+
// Handle native coin deposit first (wraps to WCBTC)
|
|
354
|
+
if (msg.value > 0) {
|
|
355
|
+
IWrappedNative(address(collateral)).deposit{value: msg.value}();
|
|
356
|
+
}
|
|
357
|
+
|
|
336
358
|
uint256 colbal = _collateralBalance();
|
|
337
359
|
if (newCollateral > colbal) {
|
|
338
360
|
collateral.transferFrom(msg.sender, address(this), newCollateral - colbal);
|
|
@@ -343,7 +365,11 @@ contract Position is Ownable, IPosition, MathUtil {
|
|
|
343
365
|
_payDownDebt(debt - newPrincipal);
|
|
344
366
|
}
|
|
345
367
|
if (newCollateral < colbal) {
|
|
346
|
-
|
|
368
|
+
if (withdrawAsNative) {
|
|
369
|
+
_withdrawCollateralAsNative(msg.sender, colbal - newCollateral);
|
|
370
|
+
} else {
|
|
371
|
+
_withdrawCollateral(msg.sender, colbal - newCollateral);
|
|
372
|
+
}
|
|
347
373
|
}
|
|
348
374
|
// Must be called after collateral withdrawal
|
|
349
375
|
if (newPrincipal > principal) {
|
|
@@ -359,6 +385,7 @@ contract Position is Ownable, IPosition, MathUtil {
|
|
|
359
385
|
* @notice Allows the position owner to adjust the liquidation price as long as there is no pending challenge.
|
|
360
386
|
* Lowering the liquidation price can be done with immediate effect, given that there is enough collateral.
|
|
361
387
|
* Increasing the liquidation price triggers a cooldown period of 3 days, during which minting is suspended.
|
|
388
|
+
* @param newPrice The new liquidation price
|
|
362
389
|
*/
|
|
363
390
|
function adjustPrice(uint256 newPrice) public onlyOwner {
|
|
364
391
|
_adjustPrice(newPrice, address(0));
|
|
@@ -589,7 +616,7 @@ contract Position is Ownable, IPosition, MathUtil {
|
|
|
589
616
|
_accrueInterest(); // accrue interest
|
|
590
617
|
_fixRateToLeadrate(riskPremiumPPM); // sync interest rate with leadrate
|
|
591
618
|
|
|
592
|
-
Position(original).notifyMint(amount);
|
|
619
|
+
Position(payable(original)).notifyMint(amount);
|
|
593
620
|
jusd.mintWithReserve(target, amount, reserveContribution);
|
|
594
621
|
|
|
595
622
|
principal += amount;
|
|
@@ -643,7 +670,7 @@ contract Position is Ownable, IPosition, MathUtil {
|
|
|
643
670
|
*/
|
|
644
671
|
function _notifyRepaid(uint256 amount) internal {
|
|
645
672
|
if (amount > principal) revert RepaidTooMuch(amount - principal);
|
|
646
|
-
Position(original).notifyRepaid(amount);
|
|
673
|
+
Position(payable(original)).notifyRepaid(amount);
|
|
647
674
|
principal -= amount;
|
|
648
675
|
}
|
|
649
676
|
|
|
@@ -713,36 +740,68 @@ contract Position is Ownable, IPosition, MathUtil {
|
|
|
713
740
|
}
|
|
714
741
|
|
|
715
742
|
/**
|
|
716
|
-
* @notice
|
|
717
|
-
*
|
|
743
|
+
* @notice Rescue ERC20 tokens that were accidentally sent to this address.
|
|
744
|
+
* @dev Cannot be used for collateral - use withdrawCollateral() instead.
|
|
745
|
+
* @param token The ERC20 token to rescue
|
|
746
|
+
* @param target The address to send rescued tokens to
|
|
747
|
+
* @param amount The amount of tokens to rescue
|
|
718
748
|
*/
|
|
719
|
-
function
|
|
720
|
-
if (token == address(collateral))
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
IERC20(token).transfer(target, amount);
|
|
725
|
-
require(balance == _collateralBalance()); // guard against double-entry-point tokens
|
|
726
|
-
}
|
|
749
|
+
function rescueToken(address token, address target, uint256 amount) external onlyOwner {
|
|
750
|
+
if (token == address(collateral)) revert CannotRescueCollateral();
|
|
751
|
+
uint256 balance = _collateralBalance();
|
|
752
|
+
IERC20(token).transfer(target, amount);
|
|
753
|
+
require(balance == _collateralBalance()); // guard against double-entry-point tokens
|
|
727
754
|
}
|
|
728
755
|
|
|
729
756
|
/**
|
|
730
757
|
* @notice Withdraw collateral from the position up to the extent that it is still well collateralized afterwards.
|
|
731
758
|
* Not possible as long as there is an open challenge or the contract is subject to a cooldown.
|
|
732
|
-
*
|
|
733
759
|
* Withdrawing collateral below the minimum collateral amount formally closes the position.
|
|
760
|
+
* @param target Address to receive the collateral
|
|
761
|
+
* @param amount Amount of collateral to withdraw
|
|
734
762
|
*/
|
|
735
763
|
function withdrawCollateral(address target, uint256 amount) public ownerOrRoller {
|
|
736
764
|
uint256 balance = _withdrawCollateral(target, amount);
|
|
737
765
|
emit MintingUpdate(balance, price, principal);
|
|
738
766
|
}
|
|
739
767
|
|
|
768
|
+
/**
|
|
769
|
+
* @notice Withdraw collateral as native coin (unwrapped).
|
|
770
|
+
* @dev Only works for wrapped native collateral tokens.
|
|
771
|
+
* @param target Address to receive the native coin
|
|
772
|
+
* @param amount Amount of collateral to withdraw and unwrap
|
|
773
|
+
*/
|
|
774
|
+
function withdrawCollateralAsNative(address target, uint256 amount) public onlyOwner {
|
|
775
|
+
uint256 balance = _withdrawCollateralAsNative(target, amount);
|
|
776
|
+
emit MintingUpdate(balance, price, principal);
|
|
777
|
+
}
|
|
778
|
+
|
|
740
779
|
function _withdrawCollateral(address target, uint256 amount) internal noCooldown noChallenge returns (uint256) {
|
|
741
780
|
uint256 balance = _sendCollateral(target, amount);
|
|
742
781
|
_checkCollateral(balance, price);
|
|
743
782
|
return balance;
|
|
744
783
|
}
|
|
745
784
|
|
|
785
|
+
/**
|
|
786
|
+
* @dev Internal helper for native coin withdrawal. Used by withdrawCollateralAsNative() and _adjust().
|
|
787
|
+
* Does NOT emit MintingUpdate - callers are responsible for emitting.
|
|
788
|
+
*/
|
|
789
|
+
function _withdrawCollateralAsNative(address target, uint256 amount) internal noCooldown noChallenge returns (uint256) {
|
|
790
|
+
if (amount > 0) {
|
|
791
|
+
IWrappedNative(address(collateral)).withdraw(amount);
|
|
792
|
+
(bool success, ) = target.call{value: amount}("");
|
|
793
|
+
if (!success) revert NativeTransferFailed();
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
uint256 balance = _collateralBalance();
|
|
797
|
+
if (balance < minimumCollateral) {
|
|
798
|
+
_close();
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
_checkCollateral(balance, price);
|
|
802
|
+
return balance;
|
|
803
|
+
}
|
|
804
|
+
|
|
746
805
|
/**
|
|
747
806
|
* @notice Transfer the challenged collateral to the bidder. Only callable by minting hub.
|
|
748
807
|
*/
|
|
@@ -903,4 +962,15 @@ contract Position is Ownable, IPosition, MathUtil {
|
|
|
903
962
|
|
|
904
963
|
return (owner(), _size, principalToPay, interestToPay, reserveContribution);
|
|
905
964
|
}
|
|
965
|
+
|
|
966
|
+
/**
|
|
967
|
+
* @notice Receive native coin and auto-wrap to collateral.
|
|
968
|
+
* @dev Reverts for non-native positions to prevent stuck funds.
|
|
969
|
+
* Checks if sender is collateral to prevent unwrap loops.
|
|
970
|
+
*/
|
|
971
|
+
receive() external payable {
|
|
972
|
+
if (msg.sender != address(collateral)) {
|
|
973
|
+
IWrappedNative(address(collateral)).deposit{value: msg.value}();
|
|
974
|
+
}
|
|
975
|
+
}
|
|
906
976
|
}
|
|
@@ -48,9 +48,9 @@ contract PositionFactory {
|
|
|
48
48
|
* @return address of the newly created clone position
|
|
49
49
|
*/
|
|
50
50
|
function clonePosition(address _parent) external returns (address) {
|
|
51
|
-
Position parent = Position(_parent);
|
|
51
|
+
Position parent = Position(payable(_parent));
|
|
52
52
|
parent.assertCloneable();
|
|
53
|
-
Position clone = Position(_createClone(parent.original()));
|
|
53
|
+
Position clone = Position(payable(_createClone(parent.original())));
|
|
54
54
|
return address(clone);
|
|
55
55
|
}
|
|
56
56
|
|