@juicedollar/jusd 1.0.0

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.
Files changed (65) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +356 -0
  3. package/contracts/Equity.sol +457 -0
  4. package/contracts/JuiceDollar.sol +363 -0
  5. package/contracts/Leadrate.sol +79 -0
  6. package/contracts/MintingHubV2/MintingHub.sol +445 -0
  7. package/contracts/MintingHubV2/Position.sol +810 -0
  8. package/contracts/MintingHubV2/PositionFactory.sol +69 -0
  9. package/contracts/MintingHubV2/PositionRoller.sol +159 -0
  10. package/contracts/MintingHubV2/interface/IMintingHub.sol +26 -0
  11. package/contracts/MintingHubV2/interface/IPosition.sol +90 -0
  12. package/contracts/MintingHubV2/interface/IPositionFactory.sol +20 -0
  13. package/contracts/Savings.sol +141 -0
  14. package/contracts/SavingsVaultJUSD.sol +140 -0
  15. package/contracts/StablecoinBridge.sol +109 -0
  16. package/contracts/StartUSD.sol +16 -0
  17. package/contracts/gateway/CoinLendingGateway.sol +223 -0
  18. package/contracts/gateway/FrontendGateway.sol +224 -0
  19. package/contracts/gateway/MintingHubGateway.sol +87 -0
  20. package/contracts/gateway/SavingsGateway.sol +51 -0
  21. package/contracts/gateway/interface/ICoinLendingGateway.sol +73 -0
  22. package/contracts/gateway/interface/IFrontendGateway.sol +49 -0
  23. package/contracts/gateway/interface/IMintingHubGateway.sol +12 -0
  24. package/contracts/impl/ERC3009.sol +171 -0
  25. package/contracts/interface/IJuiceDollar.sol +54 -0
  26. package/contracts/interface/ILeadrate.sol +7 -0
  27. package/contracts/interface/IReserve.sol +9 -0
  28. package/contracts/interface/ISavingsJUSD.sol +49 -0
  29. package/contracts/test/FreakToken.sol +25 -0
  30. package/contracts/test/Math.sol +339 -0
  31. package/contracts/test/MockEquity.sol +15 -0
  32. package/contracts/test/PositionExpirationTest.sol +75 -0
  33. package/contracts/test/PositionRollingTest.sol +65 -0
  34. package/contracts/test/TestFlashLoan.sol +84 -0
  35. package/contracts/test/TestFlashLoanGateway.sol +49 -0
  36. package/contracts/test/TestMathUtil.sol +40 -0
  37. package/contracts/test/TestToken.sol +45 -0
  38. package/contracts/test/TestWcBTC.sol +35 -0
  39. package/contracts/utils/MathUtil.sol +61 -0
  40. package/dist/index.d.mts +8761 -0
  41. package/dist/index.d.ts +8761 -0
  42. package/dist/index.js +11119 -0
  43. package/dist/index.mjs +11073 -0
  44. package/exports/abis/MintingHubV2/PositionFactoryV2.ts +90 -0
  45. package/exports/abis/MintingHubV2/PositionRoller.ts +183 -0
  46. package/exports/abis/MintingHubV2/PositionV2.ts +999 -0
  47. package/exports/abis/core/CoinLendingGateway.ts +427 -0
  48. package/exports/abis/core/Equity.ts +1286 -0
  49. package/exports/abis/core/FrontendGateway.ts +906 -0
  50. package/exports/abis/core/JuiceDollar.ts +1366 -0
  51. package/exports/abis/core/MintingHubGateway.ts +865 -0
  52. package/exports/abis/core/SavingsGateway.ts +559 -0
  53. package/exports/abis/core/SavingsVaultJUSD.ts +920 -0
  54. package/exports/abis/utils/ERC20.ts +310 -0
  55. package/exports/abis/utils/ERC20PermitLight.ts +520 -0
  56. package/exports/abis/utils/Leadrate.ts +175 -0
  57. package/exports/abis/utils/MintingHubV2.ts +682 -0
  58. package/exports/abis/utils/Ownable.ts +76 -0
  59. package/exports/abis/utils/Savings.ts +453 -0
  60. package/exports/abis/utils/StablecoinBridge.ts +209 -0
  61. package/exports/abis/utils/StartUSD.ts +315 -0
  62. package/exports/abis/utils/UniswapV3Pool.ts +638 -0
  63. package/exports/address.config.ts +48 -0
  64. package/exports/index.ts +28 -0
  65. package/package.json +87 -0
@@ -0,0 +1,51 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.10;
3
+
4
+ import {IFrontendGateway} from "./interface/IFrontendGateway.sol";
5
+ import {Context} from "@openzeppelin/contracts/utils/Context.sol";
6
+ import {IJuiceDollar} from "../interface/IJuiceDollar.sol";
7
+ import {Savings} from "../Savings.sol";
8
+
9
+ contract SavingsGateway is Savings, Context {
10
+ IFrontendGateway public immutable GATEWAY;
11
+
12
+ constructor(IJuiceDollar jusd_, uint24 initialRatePPM, address gateway_) Savings(jusd_, initialRatePPM) {
13
+ GATEWAY = IFrontendGateway(gateway_);
14
+ }
15
+
16
+ function refresh(address accountOwner) internal override returns (Account storage) {
17
+ Account storage account = savings[accountOwner];
18
+ uint64 ticks = currentTicks();
19
+ if (ticks > account.ticks) {
20
+ uint192 earnedInterest = calculateInterest(account, ticks);
21
+ if (earnedInterest > 0) {
22
+ // collect interest as you go and trigger accounting event
23
+ (IJuiceDollar(address(jusd))).distributeProfits(address(this), earnedInterest);
24
+ account.saved += earnedInterest;
25
+ GATEWAY.updateSavingRewards(accountOwner, earnedInterest);
26
+ emit InterestCollected(accountOwner, earnedInterest);
27
+ }
28
+ account.ticks = ticks;
29
+ }
30
+ return account;
31
+ }
32
+
33
+ function save(uint192 amount, bytes32 frontendCode) public {
34
+ save(_msgSender(), amount, frontendCode);
35
+ }
36
+
37
+ function save(address owner, uint192 amount, bytes32 frontendCode) public {
38
+ GATEWAY.updateSavingCode(_msgSender(), frontendCode);
39
+ save(owner, amount);
40
+ }
41
+
42
+ function adjust(uint192 targetAmount, bytes32 frontendCode) public {
43
+ GATEWAY.updateSavingCode(_msgSender(), frontendCode);
44
+ adjust(targetAmount);
45
+ }
46
+
47
+ function withdraw(address target, uint192 amount, bytes32 frontendCode) public returns (uint256) {
48
+ GATEWAY.updateSavingCode(_msgSender(), frontendCode);
49
+ return withdraw(target, amount);
50
+ }
51
+ }
@@ -0,0 +1,73 @@
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
+ }
@@ -0,0 +1,49 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ interface IFrontendGateway {
5
+ struct FrontendCode {
6
+ uint256 balance;
7
+ address owner;
8
+ }
9
+
10
+ event FrontendCodeRegistered(address owner, bytes32 frontendCode);
11
+ event FrontendCodeTransferred(address from, address to, bytes32 frontendCode);
12
+ event FrontendCodeRewardsWithdrawn(address to, uint256 amount, bytes32 frontendCode);
13
+ event NewPositionRegistered(address position, bytes32 frontendCode);
14
+ event RateChangesProposed(address who, uint24 nextFeeRate, uint24 nextSavingsFeeRate, uint24 nextMintingFeeRate, uint256 nextChange);
15
+ event RateChangesExecuted(address who, uint24 nextFeeRate, uint24 nextSavingsFeeRate, uint24 nextMintingFeeRate);
16
+
17
+ event InvestRewardAdded(bytes32 frontendCode, address user, uint256 amount, uint256 reward);
18
+ event RedeemRewardAdded(bytes32 frontendCode, address user, uint256 amount, uint256 reward);
19
+ event SavingsRewardAdded(bytes32 frontendCode, address saver, uint256 interest, uint256 reward);
20
+ event PositionRewardAdded(bytes32 frontendCode, address position, uint256 amount, uint256 reward);
21
+
22
+ error FrontendCodeAlreadyExists();
23
+ error NotFrontendCodeOwner();
24
+ error NotGatewayService();
25
+ error ProposedChangesToHigh();
26
+ error NoOpenChanges();
27
+ error NotDoneWaiting(uint256 minmumExecutionTime);
28
+ error EquityTooLow();
29
+
30
+ function invest(uint256 amount, uint256 expectedShares, bytes32 frontendCode) external returns (uint256);
31
+ function redeem(address target, uint256 shares, uint256 expectedProceeds, bytes32 frontendCode) external returns (uint256);
32
+
33
+ function updateSavingCode(address savingsOwner, bytes32 frontendCode) external;
34
+ function updateSavingRewards(address saver, uint256 interest) external;
35
+
36
+ function registerPosition(address position, bytes32 frontendCode) external;
37
+ function updatePositionRewards(address position, uint256 amount) external;
38
+ function getPositionFrontendCode(address position)view external returns(bytes32);
39
+
40
+ // Frontend Code Logic
41
+ function registerFrontendCode(bytes32 frontendCode) external returns (bool);
42
+ function transferFrontendCode(bytes32 frontendCode, address to) external returns (bool);
43
+ function withdrawRewards(bytes32 frontendCode) external returns (uint256);
44
+ function withdrawRewardsTo(bytes32 frontendCode, address to) external returns (uint256);
45
+
46
+ // Governance
47
+ function proposeChanges(uint24 newFeeRatePPM_, uint24 newSavingsFeeRatePPM_, uint24 newMintingFeeRatePPM_, address[] calldata helpers) external;
48
+ function executeChanges() external;
49
+ }
@@ -0,0 +1,12 @@
1
+ // SPDX-License-Identifier: UNLICENSED
2
+ pragma solidity ^0.8.10;
3
+
4
+ import {IMintingHub} from "../../MintingHubV2/interface/IMintingHub.sol";
5
+ import {IFrontendGateway} from "./IFrontendGateway.sol";
6
+
7
+ interface IMintingHubGateway {
8
+ function GATEWAY() external view returns (IFrontendGateway);
9
+ function notifyInterestPaid(uint256 amount) external;
10
+ function openPosition(address _collateralAddress, uint256 _minCollateral, uint256 _initialCollateral, uint256 _mintingMaximum, uint40 _initPeriodSeconds, uint40 _expirationSeconds, uint40 _challengeSeconds, uint24 _riskPremium, uint256 _liqPrice, uint24 _reservePPM, bytes32 _frontendCode) external returns (address);
11
+ function clone(address owner, address parent, uint256 _initialCollateral, uint256 _initialMint, uint40 expiration, bytes32 frontendCode) external returns (address);
12
+ }
@@ -0,0 +1,171 @@
1
+ // SPDX-License-Identifier: UNLICENSED
2
+ pragma solidity ^0.8.10;
3
+
4
+ import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
5
+ import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
6
+ import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
7
+
8
+ abstract contract ERC3009 is ERC20, EIP712 {
9
+ bytes32 public constant TRANSFER_WITH_AUTHORIZATION_TYPEHASH =
10
+ keccak256(
11
+ "TransferWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)"
12
+ );
13
+
14
+ bytes32 public constant RECEIVE_WITH_AUTHORIZATION_TYPEHASH =
15
+ keccak256(
16
+ "ReceiveWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)"
17
+ );
18
+
19
+ bytes32 public constant CANCEL_AUTHORIZATION_TYPEHASH =
20
+ keccak256("CancelAuthorization(address authorizer,bytes32 nonce)");
21
+
22
+ /**
23
+ * @dev authorizer address => nonce => state (true = used / false = unused)
24
+ */
25
+ mapping(address => mapping(bytes32 => bool)) internal _authorizationStates;
26
+
27
+ event AuthorizationUsed(address indexed authorizer, bytes32 indexed nonce);
28
+ event AuthorizationCanceled(address indexed authorizer, bytes32 indexed nonce);
29
+
30
+ string internal constant _INVALID_SIGNATURE_ERROR = "EIP3009: invalid signature";
31
+ string internal constant _AUTHORIZATION_USED_ERROR = "EIP3009: authorization is used";
32
+
33
+ /**
34
+ * @notice Returns the state of an authorization
35
+ * @dev Nonces are randomly generated 32-byte data unique to the authorizer's
36
+ * address
37
+ * @param authorizer Authorizer's address
38
+ * @param nonce Nonce of the authorization
39
+ * @return True if the nonce is used
40
+ */
41
+ function authorizationState(address authorizer, bytes32 nonce) external view returns (bool) {
42
+ return _authorizationStates[authorizer][nonce];
43
+ }
44
+
45
+ /**
46
+ * @notice Execute a transfer with a signed authorization
47
+ * @param from Payer's address (Authorizer)
48
+ * @param to Payee's address
49
+ * @param value Amount to be transferred
50
+ * @param validAfter The time after which this is valid (unix time)
51
+ * @param validBefore The time before which this is valid (unix time)
52
+ * @param nonce Unique nonce
53
+ * @param v v of the signature
54
+ * @param r r of the signature
55
+ * @param s s of the signature
56
+ */
57
+ function transferWithAuthorization(
58
+ address from,
59
+ address to,
60
+ uint256 value,
61
+ uint256 validAfter,
62
+ uint256 validBefore,
63
+ bytes32 nonce,
64
+ uint8 v,
65
+ bytes32 r,
66
+ bytes32 s
67
+ ) external {
68
+ _transferWithAuthorization(
69
+ TRANSFER_WITH_AUTHORIZATION_TYPEHASH,
70
+ from,
71
+ to,
72
+ value,
73
+ validAfter,
74
+ validBefore,
75
+ nonce,
76
+ v,
77
+ r,
78
+ s
79
+ );
80
+ }
81
+
82
+ /**
83
+ * @notice Receive a transfer with a signed authorization from the payer
84
+ * @dev This has an additional check to ensure that the payee's address matches
85
+ * the caller of this function to prevent front-running attacks. (See security
86
+ * considerations)
87
+ * @param from Payer's address (Authorizer)
88
+ * @param to Payee's address
89
+ * @param value Amount to be transferred
90
+ * @param validAfter The time after which this is valid (unix time)
91
+ * @param validBefore The time before which this is valid (unix time)
92
+ * @param nonce Unique nonce
93
+ * @param v v of the signature
94
+ * @param r r of the signature
95
+ * @param s s of the signature
96
+ */
97
+ function receiveWithAuthorization(
98
+ address from,
99
+ address to,
100
+ uint256 value,
101
+ uint256 validAfter,
102
+ uint256 validBefore,
103
+ bytes32 nonce,
104
+ uint8 v,
105
+ bytes32 r,
106
+ bytes32 s
107
+ ) external {
108
+ require(to == msg.sender, "EIP3009: caller must be the payee");
109
+
110
+ _transferWithAuthorization(
111
+ RECEIVE_WITH_AUTHORIZATION_TYPEHASH,
112
+ from,
113
+ to,
114
+ value,
115
+ validAfter,
116
+ validBefore,
117
+ nonce,
118
+ v,
119
+ r,
120
+ s
121
+ );
122
+ }
123
+
124
+ /**
125
+ * @notice Attempt to cancel an authorization
126
+ * @param authorizer Authorizer's address
127
+ * @param nonce Nonce of the authorization
128
+ * @param v v of the signature
129
+ * @param r r of the signature
130
+ * @param s s of the signature
131
+ */
132
+ function cancelAuthorization(address authorizer, bytes32 nonce, uint8 v, bytes32 r, bytes32 s) external {
133
+ require(!_authorizationStates[authorizer][nonce], _AUTHORIZATION_USED_ERROR);
134
+
135
+ bytes memory data = abi.encode(CANCEL_AUTHORIZATION_TYPEHASH, authorizer, nonce);
136
+
137
+ bytes32 hash = _hashTypedDataV4(keccak256(data));
138
+ require(ECDSA.recover(hash, v, r, s) == authorizer, _INVALID_SIGNATURE_ERROR);
139
+
140
+ _authorizationStates[authorizer][nonce] = true;
141
+ emit AuthorizationCanceled(authorizer, nonce);
142
+ }
143
+
144
+ function _transferWithAuthorization(
145
+ bytes32 typeHash,
146
+ address from,
147
+ address to,
148
+ uint256 value,
149
+ uint256 validAfter,
150
+ uint256 validBefore,
151
+ bytes32 nonce,
152
+ uint8 v,
153
+ bytes32 r,
154
+ bytes32 s
155
+ ) internal {
156
+ require(block.timestamp > validAfter, "EIP3009: authorization is not yet valid");
157
+ require(block.timestamp < validBefore, "EIP3009: authorization is expired");
158
+ require(!_authorizationStates[from][nonce], _AUTHORIZATION_USED_ERROR);
159
+
160
+ bytes memory data = abi.encode(typeHash, from, to, value, validAfter, validBefore, nonce);
161
+
162
+ bytes32 hash = _hashTypedDataV4(keccak256(data));
163
+
164
+ require(ECDSA.recover(hash, v, r, s) == from, _INVALID_SIGNATURE_ERROR);
165
+
166
+ _authorizationStates[from][nonce] = true;
167
+ emit AuthorizationUsed(from, nonce);
168
+
169
+ _transfer(from, to, value);
170
+ }
171
+ }
@@ -0,0 +1,54 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ import {IReserve} from "./IReserve.sol";
5
+ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
6
+
7
+ interface IJuiceDollar is IERC20 {
8
+ function suggestMinter(
9
+ address _minter,
10
+ uint256 _applicationPeriod,
11
+ uint256 _applicationFee,
12
+ string calldata _message
13
+ ) external;
14
+
15
+ function registerPosition(address position) external;
16
+
17
+ function denyMinter(address minter, address[] calldata helpers, string calldata message) external;
18
+
19
+ function reserve() external view returns (IReserve);
20
+
21
+ function minterReserve() external view returns (uint256);
22
+
23
+ function calculateAssignedReserve(uint256 mintedAmount, uint32 _reservePPM) external view returns (uint256);
24
+
25
+ function calculateFreedAmount(uint256 amountExcludingReserve, uint32 _reservePPM) external view returns (uint256);
26
+
27
+ function equity() external view returns (uint256);
28
+
29
+ function isMinter(address minter) external view returns (bool);
30
+
31
+ function getPositionParent(address position) external view returns (address);
32
+
33
+ function mint(address target, uint256 amount) external;
34
+
35
+ function mintWithReserve(address target, uint256 amount, uint32 reservePPM) external;
36
+
37
+ function burn(uint256 amount) external;
38
+
39
+ function burnFrom(address target, uint256 amount) external;
40
+
41
+ function burnWithoutReserve(uint256 amount, uint32 reservePPM) external;
42
+
43
+ function burnFromWithReserve(
44
+ address payer,
45
+ uint256 targetTotalBurnAmount,
46
+ uint32 reservePPM
47
+ ) external returns (uint256);
48
+
49
+ function coverLoss(address source, uint256 amount) external;
50
+
51
+ function distributeProfits(address recipient, uint256 amount) external;
52
+
53
+ function collectProfits(address source, uint256 _amount) external;
54
+ }
@@ -0,0 +1,7 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ interface ILeadrate {
5
+ function currentRatePPM() external view returns (uint24);
6
+ function currentTicks() external view returns (uint64);
7
+ }
@@ -0,0 +1,9 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
5
+
6
+ interface IReserve is IERC20 {
7
+ function invest(uint256 amount, uint256 expected) external returns (uint256);
8
+ function checkQualified(address sender, address[] calldata helpers) external view;
9
+ }
@@ -0,0 +1,49 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ interface ISavingsJUSD {
5
+ struct Account {
6
+ uint192 saved;
7
+ uint64 ticks;
8
+ }
9
+
10
+ // ---------------------------------------------------------------------------------------
11
+
12
+ event Saved(address indexed account, uint192 amount);
13
+ event InterestCollected(address indexed account, uint256 interest);
14
+ event Withdrawn(address indexed account, uint192 amount);
15
+
16
+ // ---------------------------------------------------------------------------------------
17
+
18
+ error ModuleDisabled();
19
+
20
+ // ---------------------------------------------------------------------------------------
21
+
22
+ function savings(address account) external view returns (Account memory);
23
+
24
+ // ---------------------------------------------------------------------------------------
25
+
26
+ function currentTicks() external view returns (uint64);
27
+
28
+ function currentRatePPM() external view returns (uint24);
29
+
30
+ function accruedInterest(address accountOwner) external view returns (uint192);
31
+
32
+ function accruedInterest(address accountOwner, uint256 timestamp) external view returns (uint192);
33
+
34
+ function calculateInterest(Account memory account, uint64 ticks) external view returns (uint192);
35
+
36
+ // ---------------------------------------------------------------------------------------
37
+
38
+ function save(uint192 amount) external;
39
+
40
+ function save(address owner, uint192 amount) external;
41
+
42
+ function withdraw(address target, uint192 amount) external returns (uint256);
43
+
44
+ function adjust(uint192 targetAmount) external;
45
+
46
+ function refreshMyBalance() external returns (uint192);
47
+
48
+ function refreshBalance(address owner) external returns (uint192);
49
+ }
@@ -0,0 +1,25 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
5
+
6
+ contract FreakToken is ERC20 {
7
+ uint8 private _decimals;
8
+
9
+ constructor(string memory name_, string memory symbol_, uint8 decimals_) ERC20(name_, symbol_) {
10
+ _decimals = decimals_;
11
+ _mint(msg.sender, 1_000_000 * 1e18);
12
+ }
13
+
14
+ function decimals() public view override returns (uint8) {
15
+ return _decimals;
16
+ }
17
+
18
+ function mint(address _account, uint256 _amount) external {
19
+ _mint(_account, _amount);
20
+ }
21
+
22
+ function transfer(address, uint256) public virtual override returns (bool) {
23
+ return true;
24
+ }
25
+ }