@juicedollar/jusd 1.0.2 → 1.0.3

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.
@@ -1,223 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.10;
3
-
4
- import {IMintingHubGateway} from "./interface/IMintingHubGateway.sol";
5
- import {ICoinLendingGateway} from "./interface/ICoinLendingGateway.sol";
6
- import {IPosition} from "../MintingHubV2/interface/IPosition.sol";
7
- import {IJuiceDollar} from "../interface/IJuiceDollar.sol";
8
- import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
9
- import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
10
- import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
11
- import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol";
12
-
13
- interface IWrappedCBTC is IERC20 {
14
- function deposit() external payable;
15
- function withdraw(uint256 wad) external;
16
- }
17
-
18
- /**
19
- * @title Coin Lending Gateway
20
- * @notice An improved gateway that enables true single-transaction native coin lending with custom liquidation prices
21
- * @dev This version handles the ownership transfer timing issue to allow price adjustments in the same transaction
22
- */
23
- contract CoinLendingGateway is ICoinLendingGateway, Ownable, ReentrancyGuard, Pausable {
24
- IMintingHubGateway public immutable MINTING_HUB;
25
- IWrappedCBTC public immutable WCBTC;
26
- IJuiceDollar public immutable JUSD;
27
-
28
- error InsufficientCoin();
29
- error InvalidPosition();
30
- error TransferFailed();
31
- error PriceAdjustmentFailed();
32
- error DirectCBTCNotAccepted();
33
-
34
- event CoinRescued(address indexed to, uint256 amount);
35
- event TokenRescued(address indexed token, address indexed to, uint256 amount);
36
-
37
- /**
38
- * @notice Initializes the Coin Lending Gateway
39
- * @param _mintingHub The address of the MintingHubGateway contract
40
- * @param _wcbtc The address of the Wrapped cBTC (WcBTC) token contract
41
- * @param _jusd The address of the JuiceDollar contract
42
- */
43
- constructor(address _mintingHub, address _wcbtc, address _jusd) Ownable(_msgSender()) {
44
- MINTING_HUB = IMintingHubGateway(_mintingHub);
45
- WCBTC = IWrappedCBTC(_wcbtc);
46
- JUSD = IJuiceDollar(_jusd);
47
- }
48
-
49
- /**
50
- * @notice Creates a lending position using native cBTC in a single transaction
51
- * @dev This improved version uses a two-step clone process to handle ownership and price adjustment correctly
52
- * @param parent The parent position to clone from
53
- * @param initialMint The amount of JUSD to mint
54
- * @param expiration The expiration timestamp for the position
55
- * @param frontendCode The frontend referral code
56
- * @param liquidationPrice The desired liquidation price (0 to skip adjustment)
57
- * @return position The address of the newly created position
58
- */
59
- function lendWithCoin(
60
- address parent,
61
- uint256 initialMint,
62
- uint40 expiration,
63
- bytes32 frontendCode,
64
- uint256 liquidationPrice
65
- ) external payable nonReentrant whenNotPaused returns (address position) {
66
- if (msg.value == 0) revert InsufficientCoin();
67
-
68
- return _lendWithCoin(
69
- _msgSender(),
70
- parent,
71
- initialMint,
72
- expiration,
73
- frontendCode,
74
- liquidationPrice
75
- );
76
- }
77
-
78
- /**
79
- * @notice Creates a lending position for another owner using native cBTC
80
- * @dev Same as lendWithCoin but allows specifying a different owner
81
- * @param owner The address that will own the position
82
- * @param parent The parent position to clone from
83
- * @param initialMint The amount of JUSD to mint
84
- * @param expiration The expiration timestamp for the position
85
- * @param frontendCode The frontend referral code
86
- * @param liquidationPrice The desired liquidation price (0 to skip adjustment)
87
- * @return position The address of the newly created position
88
- */
89
- function lendWithCoinFor(
90
- address owner,
91
- address parent,
92
- uint256 initialMint,
93
- uint40 expiration,
94
- bytes32 frontendCode,
95
- uint256 liquidationPrice
96
- ) external payable nonReentrant whenNotPaused returns (address position) {
97
- if (msg.value == 0) revert InsufficientCoin();
98
- if (owner == address(0)) revert InvalidPosition();
99
-
100
- return _lendWithCoin(
101
- owner,
102
- parent,
103
- initialMint,
104
- expiration,
105
- frontendCode,
106
- liquidationPrice
107
- );
108
- }
109
-
110
- /**
111
- * @dev Internal function containing the core lending logic
112
- * @param owner The address that will own the position
113
- * @param parent The parent position to clone from
114
- * @param initialMint The amount of JUSD to mint
115
- * @param expiration The expiration timestamp for the position
116
- * @param frontendCode The frontend referral code
117
- * @param liquidationPrice The desired liquidation price (0 to skip adjustment)
118
- * @return position The address of the newly created position
119
- */
120
- function _lendWithCoin(
121
- address owner,
122
- address parent,
123
- uint256 initialMint,
124
- uint40 expiration,
125
- bytes32 frontendCode,
126
- uint256 liquidationPrice
127
- ) internal returns (address position) {
128
- WCBTC.deposit{value: msg.value}();
129
-
130
- WCBTC.approve(address(MINTING_HUB), msg.value);
131
-
132
- // This contract must be initial owner to call adjustPrice before transferring ownership
133
- position = MINTING_HUB.clone(
134
- address(this), // temporary owner (this contract)
135
- parent, // parent position
136
- msg.value, // collateral amount
137
- initialMint, // mint amount
138
- expiration,
139
- frontendCode
140
- );
141
-
142
- if (position == address(0)) revert InvalidPosition();
143
-
144
- if (liquidationPrice > 0) {
145
- uint256 currentPrice = IPosition(position).price();
146
-
147
- if (liquidationPrice != currentPrice) {
148
- try IPosition(position).adjustPrice(liquidationPrice) {
149
- // Price adjustment succeeded
150
- } catch {
151
- revert PriceAdjustmentFailed();
152
- }
153
- }
154
- }
155
-
156
- uint256 jusdBalance = JUSD.balanceOf(address(this));
157
- if (jusdBalance > 0) {
158
- JUSD.transfer(owner, jusdBalance);
159
- }
160
-
161
- Ownable(position).transferOwnership(owner);
162
-
163
- emit PositionCreatedWithCoin(
164
- owner,
165
- position,
166
- msg.value,
167
- initialMint,
168
- liquidationPrice
169
- );
170
-
171
- return position;
172
- }
173
-
174
- /**
175
- * @notice Rescue function to withdraw accidentally sent native cBTC
176
- * @dev Only owner can call this function
177
- */
178
- function rescueCoin() external onlyOwner {
179
- uint256 balance = address(this).balance;
180
- if (balance > 0) {
181
- (bool success, ) = owner().call{value: balance}("");
182
- if (!success) revert TransferFailed();
183
- emit CoinRescued(owner(), balance);
184
- }
185
- }
186
-
187
- /**
188
- * @notice Rescue function to withdraw accidentally sent tokens
189
- * @dev Only owner can call this function
190
- * @param token The address of the token to rescue
191
- * @param to The address to send the tokens to
192
- * @param amount The amount of tokens to rescue
193
- */
194
- function rescueToken(address token, address to, uint256 amount) external onlyOwner {
195
- if (to == address(0)) revert TransferFailed();
196
- bool success = IERC20(token).transfer(to, amount);
197
- if (!success) revert TransferFailed();
198
- emit TokenRescued(token, to, amount);
199
- }
200
-
201
- /**
202
- * @notice Pause the contract (only owner)
203
- * @dev Prevents lendWithCoin functions from being called
204
- */
205
- function pause() external onlyOwner {
206
- _pause();
207
- }
208
-
209
- /**
210
- * @notice Unpause the contract (only owner)
211
- * @dev Re-enables lendWithCoin functions
212
- */
213
- function unpause() external onlyOwner {
214
- _unpause();
215
- }
216
-
217
- /**
218
- * @dev Reject direct cBTC transfers to prevent stuck funds
219
- */
220
- receive() external payable {
221
- revert DirectCBTCNotAccepted();
222
- }
223
- }
@@ -1,73 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.10;
3
-
4
- /**
5
- * @title ICoinLendingGateway
6
- * @notice Interface for the Coin Lending Gateway contract
7
- */
8
- interface ICoinLendingGateway {
9
- /**
10
- * @notice Emitted when a position is created with native coins
11
- * @param owner The owner of the newly created position
12
- * @param position The address of the newly created position
13
- * @param coinAmount The amount of native coin used as collateral
14
- * @param mintAmount The amount of JUSD minted
15
- * @param liquidationPrice The liquidation price set for the position
16
- */
17
- event PositionCreatedWithCoin(
18
- address indexed owner,
19
- address indexed position,
20
- uint256 coinAmount,
21
- uint256 mintAmount,
22
- uint256 liquidationPrice
23
- );
24
-
25
- /**
26
- * @notice Creates a lending position using native coins in a single transaction
27
- * @param parent The parent position to clone from
28
- * @param initialMint The amount of JUSD to mint
29
- * @param expiration The expiration timestamp for the position
30
- * @param frontendCode The frontend referral code
31
- * @param liquidationPrice The desired liquidation price (0 to skip adjustment)
32
- * @return position The address of the newly created position
33
- */
34
- function lendWithCoin(
35
- address parent,
36
- uint256 initialMint,
37
- uint40 expiration,
38
- bytes32 frontendCode,
39
- uint256 liquidationPrice
40
- ) external payable returns (address position);
41
-
42
- /**
43
- * @notice Creates a lending position for another owner using native coins
44
- * @param owner The address that will own the position
45
- * @param parent The parent position to clone from
46
- * @param initialMint The amount of JUSD to mint
47
- * @param expiration The expiration timestamp for the position
48
- * @param frontendCode The frontend referral code
49
- * @param liquidationPrice The desired liquidation price (0 to skip adjustment)
50
- * @return position The address of the newly created position
51
- */
52
- function lendWithCoinFor(
53
- address owner,
54
- address parent,
55
- uint256 initialMint,
56
- uint40 expiration,
57
- bytes32 frontendCode,
58
- uint256 liquidationPrice
59
- ) external payable returns (address position);
60
-
61
- /**
62
- * @notice Rescue function to withdraw accidentally sent native coins
63
- */
64
- function rescueCoin() external;
65
-
66
- /**
67
- * @notice Rescue function to withdraw accidentally sent tokens
68
- * @param token The address of the token to rescue
69
- * @param to The address to send the tokens to
70
- * @param amount The amount of tokens to rescue
71
- */
72
- function rescueToken(address token, address to, uint256 amount) external;
73
- }
@@ -1,427 +0,0 @@
1
- export const CoinLendingGatewayABI = [
2
- {
3
- inputs: [
4
- {
5
- internalType: 'address',
6
- name: '_mintingHub',
7
- type: 'address',
8
- },
9
- {
10
- internalType: 'address',
11
- name: '_wcbtc',
12
- type: 'address',
13
- },
14
- {
15
- internalType: 'address',
16
- name: '_jusd',
17
- type: 'address',
18
- },
19
- ],
20
- stateMutability: 'nonpayable',
21
- type: 'constructor',
22
- },
23
- {
24
- inputs: [],
25
- name: 'DirectCBTCNotAccepted',
26
- type: 'error',
27
- },
28
- {
29
- inputs: [],
30
- name: 'EnforcedPause',
31
- type: 'error',
32
- },
33
- {
34
- inputs: [],
35
- name: 'ExpectedPause',
36
- type: 'error',
37
- },
38
- {
39
- inputs: [],
40
- name: 'InsufficientCoin',
41
- type: 'error',
42
- },
43
- {
44
- inputs: [],
45
- name: 'InvalidPosition',
46
- type: 'error',
47
- },
48
- {
49
- inputs: [
50
- {
51
- internalType: 'address',
52
- name: 'owner',
53
- type: 'address',
54
- },
55
- ],
56
- name: 'OwnableInvalidOwner',
57
- type: 'error',
58
- },
59
- {
60
- inputs: [
61
- {
62
- internalType: 'address',
63
- name: 'account',
64
- type: 'address',
65
- },
66
- ],
67
- name: 'OwnableUnauthorizedAccount',
68
- type: 'error',
69
- },
70
- {
71
- inputs: [],
72
- name: 'PriceAdjustmentFailed',
73
- type: 'error',
74
- },
75
- {
76
- inputs: [],
77
- name: 'ReentrancyGuardReentrantCall',
78
- type: 'error',
79
- },
80
- {
81
- inputs: [],
82
- name: 'TransferFailed',
83
- type: 'error',
84
- },
85
- {
86
- anonymous: false,
87
- inputs: [
88
- {
89
- indexed: true,
90
- internalType: 'address',
91
- name: 'to',
92
- type: 'address',
93
- },
94
- {
95
- indexed: false,
96
- internalType: 'uint256',
97
- name: 'amount',
98
- type: 'uint256',
99
- },
100
- ],
101
- name: 'CoinRescued',
102
- type: 'event',
103
- },
104
- {
105
- anonymous: false,
106
- inputs: [
107
- {
108
- indexed: true,
109
- internalType: 'address',
110
- name: 'previousOwner',
111
- type: 'address',
112
- },
113
- {
114
- indexed: true,
115
- internalType: 'address',
116
- name: 'newOwner',
117
- type: 'address',
118
- },
119
- ],
120
- name: 'OwnershipTransferred',
121
- type: 'event',
122
- },
123
- {
124
- anonymous: false,
125
- inputs: [
126
- {
127
- indexed: false,
128
- internalType: 'address',
129
- name: 'account',
130
- type: 'address',
131
- },
132
- ],
133
- name: 'Paused',
134
- type: 'event',
135
- },
136
- {
137
- anonymous: false,
138
- inputs: [
139
- {
140
- indexed: true,
141
- internalType: 'address',
142
- name: 'owner',
143
- type: 'address',
144
- },
145
- {
146
- indexed: true,
147
- internalType: 'address',
148
- name: 'position',
149
- type: 'address',
150
- },
151
- {
152
- indexed: false,
153
- internalType: 'uint256',
154
- name: 'coinAmount',
155
- type: 'uint256',
156
- },
157
- {
158
- indexed: false,
159
- internalType: 'uint256',
160
- name: 'mintAmount',
161
- type: 'uint256',
162
- },
163
- {
164
- indexed: false,
165
- internalType: 'uint256',
166
- name: 'liquidationPrice',
167
- type: 'uint256',
168
- },
169
- ],
170
- name: 'PositionCreatedWithCoin',
171
- type: 'event',
172
- },
173
- {
174
- anonymous: false,
175
- inputs: [
176
- {
177
- indexed: true,
178
- internalType: 'address',
179
- name: 'token',
180
- type: 'address',
181
- },
182
- {
183
- indexed: true,
184
- internalType: 'address',
185
- name: 'to',
186
- type: 'address',
187
- },
188
- {
189
- indexed: false,
190
- internalType: 'uint256',
191
- name: 'amount',
192
- type: 'uint256',
193
- },
194
- ],
195
- name: 'TokenRescued',
196
- type: 'event',
197
- },
198
- {
199
- anonymous: false,
200
- inputs: [
201
- {
202
- indexed: false,
203
- internalType: 'address',
204
- name: 'account',
205
- type: 'address',
206
- },
207
- ],
208
- name: 'Unpaused',
209
- type: 'event',
210
- },
211
- {
212
- inputs: [],
213
- name: 'JUSD',
214
- outputs: [
215
- {
216
- internalType: 'contract IJuiceDollar',
217
- name: '',
218
- type: 'address',
219
- },
220
- ],
221
- stateMutability: 'view',
222
- type: 'function',
223
- },
224
- {
225
- inputs: [],
226
- name: 'MINTING_HUB',
227
- outputs: [
228
- {
229
- internalType: 'contract IMintingHubGateway',
230
- name: '',
231
- type: 'address',
232
- },
233
- ],
234
- stateMutability: 'view',
235
- type: 'function',
236
- },
237
- {
238
- inputs: [],
239
- name: 'WCBTC',
240
- outputs: [
241
- {
242
- internalType: 'contract IWrappedCBTC',
243
- name: '',
244
- type: 'address',
245
- },
246
- ],
247
- stateMutability: 'view',
248
- type: 'function',
249
- },
250
- {
251
- inputs: [
252
- {
253
- internalType: 'address',
254
- name: 'parent',
255
- type: 'address',
256
- },
257
- {
258
- internalType: 'uint256',
259
- name: 'initialMint',
260
- type: 'uint256',
261
- },
262
- {
263
- internalType: 'uint40',
264
- name: 'expiration',
265
- type: 'uint40',
266
- },
267
- {
268
- internalType: 'bytes32',
269
- name: 'frontendCode',
270
- type: 'bytes32',
271
- },
272
- {
273
- internalType: 'uint256',
274
- name: 'liquidationPrice',
275
- type: 'uint256',
276
- },
277
- ],
278
- name: 'lendWithCoin',
279
- outputs: [
280
- {
281
- internalType: 'address',
282
- name: 'position',
283
- type: 'address',
284
- },
285
- ],
286
- stateMutability: 'payable',
287
- type: 'function',
288
- },
289
- {
290
- inputs: [
291
- {
292
- internalType: 'address',
293
- name: 'owner',
294
- type: 'address',
295
- },
296
- {
297
- internalType: 'address',
298
- name: 'parent',
299
- type: 'address',
300
- },
301
- {
302
- internalType: 'uint256',
303
- name: 'initialMint',
304
- type: 'uint256',
305
- },
306
- {
307
- internalType: 'uint40',
308
- name: 'expiration',
309
- type: 'uint40',
310
- },
311
- {
312
- internalType: 'bytes32',
313
- name: 'frontendCode',
314
- type: 'bytes32',
315
- },
316
- {
317
- internalType: 'uint256',
318
- name: 'liquidationPrice',
319
- type: 'uint256',
320
- },
321
- ],
322
- name: 'lendWithCoinFor',
323
- outputs: [
324
- {
325
- internalType: 'address',
326
- name: 'position',
327
- type: 'address',
328
- },
329
- ],
330
- stateMutability: 'payable',
331
- type: 'function',
332
- },
333
- {
334
- inputs: [],
335
- name: 'owner',
336
- outputs: [
337
- {
338
- internalType: 'address',
339
- name: '',
340
- type: 'address',
341
- },
342
- ],
343
- stateMutability: 'view',
344
- type: 'function',
345
- },
346
- {
347
- inputs: [],
348
- name: 'pause',
349
- outputs: [],
350
- stateMutability: 'nonpayable',
351
- type: 'function',
352
- },
353
- {
354
- inputs: [],
355
- name: 'paused',
356
- outputs: [
357
- {
358
- internalType: 'bool',
359
- name: '',
360
- type: 'bool',
361
- },
362
- ],
363
- stateMutability: 'view',
364
- type: 'function',
365
- },
366
- {
367
- inputs: [],
368
- name: 'renounceOwnership',
369
- outputs: [],
370
- stateMutability: 'nonpayable',
371
- type: 'function',
372
- },
373
- {
374
- inputs: [],
375
- name: 'rescueCoin',
376
- outputs: [],
377
- stateMutability: 'nonpayable',
378
- type: 'function',
379
- },
380
- {
381
- inputs: [
382
- {
383
- internalType: 'address',
384
- name: 'token',
385
- type: 'address',
386
- },
387
- {
388
- internalType: 'address',
389
- name: 'to',
390
- type: 'address',
391
- },
392
- {
393
- internalType: 'uint256',
394
- name: 'amount',
395
- type: 'uint256',
396
- },
397
- ],
398
- name: 'rescueToken',
399
- outputs: [],
400
- stateMutability: 'nonpayable',
401
- type: 'function',
402
- },
403
- {
404
- inputs: [
405
- {
406
- internalType: 'address',
407
- name: 'newOwner',
408
- type: 'address',
409
- },
410
- ],
411
- name: 'transferOwnership',
412
- outputs: [],
413
- stateMutability: 'nonpayable',
414
- type: 'function',
415
- },
416
- {
417
- inputs: [],
418
- name: 'unpause',
419
- outputs: [],
420
- stateMutability: 'nonpayable',
421
- type: 'function',
422
- },
423
- {
424
- stateMutability: 'payable',
425
- type: 'receive',
426
- },
427
- ] as const;