From 35cf9f2a7411b81d025522d7c7361a46ee15686b Mon Sep 17 00:00:00 2001 From: Admazzola Date: Mon, 1 Jul 2024 16:32:24 -0400 Subject: [PATCH 01/16] adding pauser role --- packages/contracts/contracts/TellerV2.sol | 35 +++++++++++++++---- .../contracts/contracts/TellerV2Storage.sol | 6 +++- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/packages/contracts/contracts/TellerV2.sol b/packages/contracts/contracts/TellerV2.sol index 31c03fbe..f6041829 100644 --- a/packages/contracts/contracts/TellerV2.sol +++ b/packages/contracts/contracts/TellerV2.sol @@ -164,6 +164,16 @@ contract TellerV2 is _; } + + modifier onlyPauser() { + if (pauserRoleBearer[_msgSender()] != true) { + revert ( "Requires role: Pauser"); + } + + _; + } + + /** Constant Variables **/ uint8 public constant CURRENT_CODE_VERSION = 10; @@ -260,14 +270,14 @@ contract TellerV2 is // Check uri mapping first metadataURI_ = uris[_bidId]; // If the URI is not present in the mapping - if ( + /* if ( keccak256(abi.encodePacked(metadataURI_)) == 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 // hardcoded constant of keccak256('') ) { // Return deprecated bytes32 uri as a string uint256 convertedURI = uint256(bids[_bidId]._metadataURI); metadataURI_ = StringsUpgradeable.toHexString(convertedURI, 32); - } + }*/ } /** @@ -443,7 +453,7 @@ contract TellerV2 is * @notice Function for a market owner to cancel a bid in the market. * @param _bidId The id of the bid to cancel. */ - function marketOwnerCancelBid(uint256 _bidId) external { + /* function marketOwnerCancelBid(uint256 _bidId) external { if ( _msgSender() != marketRegistry.getMarketOwner(bids[_bidId].marketplaceId) @@ -456,7 +466,7 @@ contract TellerV2 is } _cancelBid(_bidId); emit MarketOwnerCancelledBid(_bidId); - } + }*/ /** * @notice Function for users to cancel a bid. @@ -710,17 +720,30 @@ contract TellerV2 is /** * @notice Lets the DAO/owner of the protocol implement an emergency stop mechanism. */ - function pauseProtocol() public virtual onlyOwner whenNotPaused { + function pauseProtocol() public virtual onlyPauser whenNotPaused { _pause(); } /** * @notice Lets the DAO/owner of the protocol undo a previously implemented emergency stop. */ - function unpauseProtocol() public virtual onlyOwner whenPaused { + function unpauseProtocol() public virtual onlyPauser whenPaused { _unpause(); } + function addPauser(address _pauser) public virtual onlyOwner { + pauserRoleBearer[_pauser] = true; + } + + + function removePauser(address _pauser) public virtual onlyOwner { + pauserRoleBearer[_pauser] = false; + } + + + + + function lenderCloseLoan(uint256 _bidId) external acceptedLoan(_bidId, "lenderClaimCollateral") diff --git a/packages/contracts/contracts/TellerV2Storage.sol b/packages/contracts/contracts/TellerV2Storage.sol index c79e3933..df3ea5b3 100644 --- a/packages/contracts/contracts/TellerV2Storage.sol +++ b/packages/contracts/contracts/TellerV2Storage.sol @@ -162,4 +162,8 @@ abstract contract TellerV2Storage_G6 is TellerV2Storage_G5 { mapping(uint256 => address) public repaymentListenerForBid; } -abstract contract TellerV2Storage is TellerV2Storage_G6 {} +abstract contract TellerV2Storage_G7 is TellerV2Storage_G6 { + mapping(address => bool) public pauserRoleBearer; +} + +abstract contract TellerV2Storage is TellerV2Storage_G7 {} From 1f7ed84abe4d8506228e454d7b5dc93c94f0ed58 Mon Sep 17 00:00:00 2001 From: Admazzola Date: Tue, 2 Jul 2024 11:41:28 -0400 Subject: [PATCH 02/16] un-remove marketOwnerCloseBid --- packages/contracts/contracts/TellerV2.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/contracts/contracts/TellerV2.sol b/packages/contracts/contracts/TellerV2.sol index f6041829..22498d6b 100644 --- a/packages/contracts/contracts/TellerV2.sol +++ b/packages/contracts/contracts/TellerV2.sol @@ -453,7 +453,7 @@ contract TellerV2 is * @notice Function for a market owner to cancel a bid in the market. * @param _bidId The id of the bid to cancel. */ - /* function marketOwnerCancelBid(uint256 _bidId) external { + function marketOwnerCancelBid(uint256 _bidId) external { if ( _msgSender() != marketRegistry.getMarketOwner(bids[_bidId].marketplaceId) @@ -466,7 +466,7 @@ contract TellerV2 is } _cancelBid(_bidId); emit MarketOwnerCancelledBid(_bidId); - }*/ + } /** * @notice Function for users to cancel a bid. From 282b133f8e1b42bc89382c6a1472b2fc2e884d3b Mon Sep 17 00:00:00 2001 From: Admazzola Date: Tue, 2 Jul 2024 11:55:57 -0400 Subject: [PATCH 03/16] adding pauser functionality , need to fix tests --- packages/contracts/contracts/TellerV2.sol | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/contracts/contracts/TellerV2.sol b/packages/contracts/contracts/TellerV2.sol index 22498d6b..9f59ca99 100644 --- a/packages/contracts/contracts/TellerV2.sol +++ b/packages/contracts/contracts/TellerV2.sol @@ -745,7 +745,7 @@ contract TellerV2 is function lenderCloseLoan(uint256 _bidId) - external + external whenNotPaused acceptedLoan(_bidId, "lenderClaimCollateral") { Bid storage bid = bids[_bidId]; @@ -761,7 +761,7 @@ contract TellerV2 is function lenderCloseLoanWithRecipient( uint256 _bidId, address _collateralRecipient - ) external { + ) external whenNotPaused { _lenderCloseLoanWithRecipient(_bidId, _collateralRecipient); } @@ -788,7 +788,7 @@ contract TellerV2 is * @param _bidId The id of the loan to make the payment towards. */ function liquidateLoanFull(uint256 _bidId) - external + external whenNotPaused acceptedLoan(_bidId, "liquidateLoan") { Bid storage bid = bids[_bidId]; @@ -800,7 +800,7 @@ contract TellerV2 is } function liquidateLoanFullWithRecipient(uint256 _bidId, address _recipient) - external + external whenNotPaused acceptedLoan(_bidId, "liquidateLoan") { _liquidateLoanFull(_bidId, _recipient); @@ -885,6 +885,8 @@ contract TellerV2 is // If loan is is being liquidated and backed by collateral, withdraw and send to borrower if (_shouldWithdrawCollateral) { + + require( paused() == false, "Cannot withdraw collateral while protocol is paused." ); // _getCollateralManagerForBid(_bidId).withdraw(_bidId); collateralManager.withdraw(_bidId); } From f2ab89942bf609c1d2a82ab3700d5aa8ca6c4c6e Mon Sep 17 00:00:00 2001 From: Admazzola Date: Tue, 2 Jul 2024 12:10:03 -0400 Subject: [PATCH 04/16] fixed more tests --- .../contracts/contracts/CollateralManager.sol | 20 +++++++++++++------ packages/contracts/contracts/TellerV2.sol | 15 +++++++------- .../tests/TellerV2/TellerV2_pause.sol | 2 +- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/packages/contracts/contracts/CollateralManager.sol b/packages/contracts/contracts/CollateralManager.sol index 5b0a68fe..00d15a22 100644 --- a/packages/contracts/contracts/CollateralManager.sol +++ b/packages/contracts/contracts/CollateralManager.sol @@ -7,7 +7,7 @@ import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; // Libraries import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol"; - +import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; // Interfaces import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol"; @@ -70,7 +70,7 @@ contract CollateralManager is OwnableUpgradeable, ICollateralManager { _; } - modifier onlyProtocolOwner() { + modifier onlyProtocolOwner() { address protocolOwner = OwnableUpgradeable(address(tellerV2)).owner(); @@ -78,6 +78,13 @@ contract CollateralManager is OwnableUpgradeable, ICollateralManager { _; } + modifier whenProtocolNotPaused() { + + + require( PausableUpgradeable(address(tellerV2)).paused() == false , "Protocol is paused"); + _; + } + /* External Functions */ /** @@ -262,7 +269,7 @@ contract CollateralManager is OwnableUpgradeable, ICollateralManager { * @notice Withdraws deposited collateral from the created escrow of a bid that has been successfully repaid. * @param _bidId The id of the bid to withdraw collateral for. */ - function withdraw(uint256 _bidId) external { + function withdraw(uint256 _bidId) external whenProtocolNotPaused { BidState bidState = tellerV2.getBidState(_bidId); require(bidState == BidState.PAID, "collateral cannot be withdrawn"); @@ -277,7 +284,7 @@ contract CollateralManager is OwnableUpgradeable, ICollateralManager { address _tokenAddress, uint256 _amount, address _recipientAddress - ) external onlyProtocolOwner { + ) external onlyProtocolOwner whenProtocolNotPaused { ICollateralEscrowV1(_escrows[_bidId]).withdrawDustTokens( _tokenAddress, @@ -290,7 +297,7 @@ contract CollateralManager is OwnableUpgradeable, ICollateralManager { * @notice Withdraws deposited collateral from the created escrow of a bid that has been CLOSED after being defaulted. * @param _bidId The id of the bid to withdraw collateral for. */ - function lenderClaimCollateral(uint256 _bidId) external onlyTellerV2 { + function lenderClaimCollateral(uint256 _bidId) external onlyTellerV2 whenProtocolNotPaused { if (isBidCollateralBacked(_bidId)) { BidState bidState = tellerV2.getBidState(_bidId); @@ -308,7 +315,7 @@ contract CollateralManager is OwnableUpgradeable, ICollateralManager { * @notice Withdraws deposited collateral from the created escrow of a bid that has been CLOSED after being defaulted. * @param _bidId The id of the bid to withdraw collateral for. */ - function lenderClaimCollateralWithRecipient(uint256 _bidId, address _collateralRecipient) external onlyTellerV2 { + function lenderClaimCollateralWithRecipient(uint256 _bidId, address _collateralRecipient) external onlyTellerV2 whenProtocolNotPaused { if (isBidCollateralBacked(_bidId)) { BidState bidState = tellerV2.getBidState(_bidId); @@ -331,6 +338,7 @@ contract CollateralManager is OwnableUpgradeable, ICollateralManager { function liquidateCollateral(uint256 _bidId, address _liquidatorAddress) external onlyTellerV2 + whenProtocolNotPaused { if (isBidCollateralBacked(_bidId)) { BidState bidState = tellerV2.getBidState(_bidId); diff --git a/packages/contracts/contracts/TellerV2.sol b/packages/contracts/contracts/TellerV2.sol index 9f59ca99..6ff29413 100644 --- a/packages/contracts/contracts/TellerV2.sol +++ b/packages/contracts/contracts/TellerV2.sol @@ -166,9 +166,9 @@ contract TellerV2 is modifier onlyPauser() { - if (pauserRoleBearer[_msgSender()] != true) { - revert ( "Requires role: Pauser"); - } + + require( pauserRoleBearer[_msgSender()] || owner() == _msgSender(), "Requires role: Pauser"); + _; } @@ -270,14 +270,14 @@ contract TellerV2 is // Check uri mapping first metadataURI_ = uris[_bidId]; // If the URI is not present in the mapping - /* if ( + if ( keccak256(abi.encodePacked(metadataURI_)) == 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 // hardcoded constant of keccak256('') ) { // Return deprecated bytes32 uri as a string uint256 convertedURI = uint256(bids[_bidId]._metadataURI); metadataURI_ = StringsUpgradeable.toHexString(convertedURI, 32); - }*/ + } } /** @@ -884,9 +884,8 @@ contract TellerV2 is _borrowerBidsActive[bid.borrower].remove(_bidId); // If loan is is being liquidated and backed by collateral, withdraw and send to borrower - if (_shouldWithdrawCollateral) { - - require( paused() == false, "Cannot withdraw collateral while protocol is paused." ); + if (_shouldWithdrawCollateral) { + // _getCollateralManagerForBid(_bidId).withdraw(_bidId); collateralManager.withdraw(_bidId); } diff --git a/packages/contracts/tests/TellerV2/TellerV2_pause.sol b/packages/contracts/tests/TellerV2/TellerV2_pause.sol index fcbb9c6a..88f06a3e 100644 --- a/packages/contracts/tests/TellerV2/TellerV2_pause.sol +++ b/packages/contracts/tests/TellerV2/TellerV2_pause.sol @@ -26,7 +26,7 @@ contract TellerV2_pause_test is Testable { } function test_pauseProtocol_invalid_if_not_owner() public { - vm.expectRevert("Ownable: caller is not the owner"); + vm.expectRevert("Requires role: Pauser"); tellerV2.pauseProtocol(); } From 2455ccf2862d7485d8b4828eb84a00bcc653cc6b Mon Sep 17 00:00:00 2001 From: Admazzola Date: Tue, 2 Jul 2024 12:40:03 -0400 Subject: [PATCH 05/16] tests pass --- packages/contracts/contracts/mock/TellerV2SolMock.sol | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/contracts/contracts/mock/TellerV2SolMock.sol b/packages/contracts/contracts/mock/TellerV2SolMock.sol index bea8c4ef..798ec74b 100644 --- a/packages/contracts/contracts/mock/TellerV2SolMock.sol +++ b/packages/contracts/contracts/mock/TellerV2SolMock.sol @@ -19,6 +19,7 @@ contract TellerV2SolMock is ITellerV2, IProtocolFee, TellerV2Storage , ILoanRepa uint256 public amountOwedMockPrincipal; uint256 public amountOwedMockInterest; address public approvedForwarder; + bool public isPausedMock; PaymentCycleType globalBidPaymentCycleType = PaymentCycleType.Seconds; @@ -45,6 +46,11 @@ contract TellerV2SolMock is ITellerV2, IProtocolFee, TellerV2Storage , ILoanRepa } + function paused() external view returns(bool){ + return isPausedMock; + } + + function approveMarketForwarder(uint256 _marketId, address _forwarder) external { From ee2beea70196e162c7da84b9ce171232f4e52e07 Mon Sep 17 00:00:00 2001 From: Admazzola Date: Tue, 2 Jul 2024 12:43:28 -0400 Subject: [PATCH 06/16] add pauser check --- .../SmartCommitmentForwarder.sol | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/contracts/contracts/LenderCommitmentForwarder/SmartCommitmentForwarder.sol b/packages/contracts/contracts/LenderCommitmentForwarder/SmartCommitmentForwarder.sol index d7867cf1..1301910d 100644 --- a/packages/contracts/contracts/LenderCommitmentForwarder/SmartCommitmentForwarder.sol +++ b/packages/contracts/contracts/LenderCommitmentForwarder/SmartCommitmentForwarder.sol @@ -7,12 +7,15 @@ import "../interfaces/ILenderCommitmentForwarder.sol"; import "../interfaces/ISmartCommitmentForwarder.sol"; import "./LenderCommitmentForwarder_G1.sol"; +import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; + import { CommitmentCollateralType, ISmartCommitment } from "../interfaces/ISmartCommitment.sol"; contract SmartCommitmentForwarder is - ExtensionsContextUpgradeable, //this should always be first for upgradeability + ExtensionsContextUpgradeable, //this should always be first for upgradeability TellerV2MarketForwarder_G3, + PausableUpgradeable, //this does add some storage ISmartCommitmentForwarder { event ExercisedSmartCommitment( @@ -24,6 +27,16 @@ contract SmartCommitmentForwarder is error InsufficientBorrowerCollateral(uint256 required, uint256 actual); + + + modifier onlyProtocolPauser() { + + require( ITellerV2( _protocolAddress ).isPauser(_msgSender()) , "Sender not authorized"); + _; + } + + + constructor(address _protocolAddress, address _marketRegistry) TellerV2MarketForwarder_G3(_protocolAddress, _marketRegistry) {} From 826361d73813727d6da33df19d9db54469664431 Mon Sep 17 00:00:00 2001 From: andy Date: Tue, 2 Jul 2024 16:37:23 -0400 Subject: [PATCH 07/16] mock pausing on SCF --- .../contracts/contracts/CollateralManager.sol | 4 +-- .../SmartCommitmentForwarder.sol | 33 +++++++++++++++---- .../LenderCommitmentGroup_Smart.sol | 21 ++++++++---- packages/contracts/contracts/TellerV2.sol | 4 ++- .../contracts/interfaces/ITellerV2.sol | 3 ++ .../contracts/mock/TellerV2SolMock.sol | 4 +++ .../LenderCommitmentGroup_Smart_Test.sol | 9 ++++- 7 files changed, 60 insertions(+), 18 deletions(-) diff --git a/packages/contracts/contracts/CollateralManager.sol b/packages/contracts/contracts/CollateralManager.sol index 00d15a22..5d1b5a83 100644 --- a/packages/contracts/contracts/CollateralManager.sol +++ b/packages/contracts/contracts/CollateralManager.sol @@ -78,9 +78,7 @@ contract CollateralManager is OwnableUpgradeable, ICollateralManager { _; } - modifier whenProtocolNotPaused() { - - + modifier whenProtocolNotPaused() { require( PausableUpgradeable(address(tellerV2)).paused() == false , "Protocol is paused"); _; } diff --git a/packages/contracts/contracts/LenderCommitmentForwarder/SmartCommitmentForwarder.sol b/packages/contracts/contracts/LenderCommitmentForwarder/SmartCommitmentForwarder.sol index 1301910d..de1a39c1 100644 --- a/packages/contracts/contracts/LenderCommitmentForwarder/SmartCommitmentForwarder.sol +++ b/packages/contracts/contracts/LenderCommitmentForwarder/SmartCommitmentForwarder.sol @@ -15,7 +15,7 @@ import { CommitmentCollateralType, ISmartCommitment } from "../interfaces/ISmart contract SmartCommitmentForwarder is ExtensionsContextUpgradeable, //this should always be first for upgradeability TellerV2MarketForwarder_G3, - PausableUpgradeable, //this does add some storage + PausableUpgradeable, //this does add some storage but AFTER all other storage ISmartCommitmentForwarder { event ExercisedSmartCommitment( @@ -29,9 +29,8 @@ contract SmartCommitmentForwarder is - modifier onlyProtocolPauser() { - - require( ITellerV2( _protocolAddress ).isPauser(_msgSender()) , "Sender not authorized"); + modifier onlyProtocolPauser() { + require( ITellerV2( _tellerV2 ).isPauser(_msgSender()) , "Sender not authorized"); _; } @@ -39,7 +38,12 @@ contract SmartCommitmentForwarder is constructor(address _protocolAddress, address _marketRegistry) TellerV2MarketForwarder_G3(_protocolAddress, _marketRegistry) - {} + { } + + function initialize() public initializer { + __Pausable_init(); + } + /** * @notice Accept the commitment to submitBid and acceptBid using the funds @@ -63,7 +67,7 @@ contract SmartCommitmentForwarder is address _recipient, uint16 _interestRate, uint32 _loanDuration - ) public returns (uint256 bidId) { + ) public whenNotPaused returns (uint256 bidId) { require( ISmartCommitment(_smartCommitmentAddress) .getCollateralTokenType() <= @@ -175,6 +179,23 @@ contract SmartCommitmentForwarder is + /** + * @notice Lets the DAO/owner of the protocol implement an emergency stop mechanism. + */ + function pause() public virtual onlyProtocolPauser whenNotPaused { + _pause(); + } + + /** + * @notice Lets the DAO/owner of the protocol undo a previously implemented emergency stop. + */ + function unpause() public virtual onlyProtocolPauser whenPaused { + _unpause(); + } + + + // ----- + //Overrides function _msgSender() internal diff --git a/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol b/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol index 72481fbd..b54b56e8 100644 --- a/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol +++ b/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol @@ -210,6 +210,13 @@ contract LenderCommitmentGroup_Smart is _; } + modifier whenForwarderNotPaused() { + require( PausableUpgradeable(address(SMART_COMMITMENT_FORWARDER)).paused() == false , "Protocol is paused"); + _; + } + + + /// @custom:oz-upgrades-unsafe-allow constructor constructor( address _tellerV2, @@ -374,7 +381,7 @@ contract LenderCommitmentGroup_Smart is uint256 _amount, address _sharesRecipient, uint256 _minSharesAmountOut - ) external returns (uint256 sharesAmount_) { + ) external whenForwarderNotPaused returns (uint256 sharesAmount_) { //transfers the primary principal token from msg.sender into this contract escrow @@ -445,7 +452,7 @@ contract LenderCommitmentGroup_Smart is uint256 _collateralTokenId, uint32 _loanDuration, uint16 _interestRate - ) external onlySmartCommitmentForwarder whenNotPaused { + ) external onlySmartCommitmentForwarder whenForwarderNotPaused { require( _collateralTokenAddress == address(collateralToken), @@ -505,7 +512,7 @@ contract LenderCommitmentGroup_Smart is function prepareSharesForWithdraw( uint256 _amountPoolSharesTokens - ) external returns (bool) { + ) external whenForwarderNotPaused returns (bool) { require( poolSharesToken.balanceOf(msg.sender) >= _amountPoolSharesTokens ); poolSharesPreparedToWithdrawForLender[msg.sender] = _amountPoolSharesTokens; @@ -523,7 +530,7 @@ contract LenderCommitmentGroup_Smart is uint256 _amountPoolSharesTokens, address _recipient, uint256 _minAmountOut - ) external returns (uint256) { + ) external whenForwarderNotPaused returns (uint256) { require(poolSharesPreparedToWithdrawForLender[msg.sender] >= _amountPoolSharesTokens,"Shares not prepared for withdraw"); require(poolSharesPreparedTimestamp[msg.sender] <= block.timestamp - WITHDRAW_DELAY_TIME_SECONDS,"Shares not prepared for withdraw"); @@ -566,7 +573,7 @@ contract LenderCommitmentGroup_Smart is function liquidateDefaultedLoanWithIncentive( uint256 _bidId, int256 _tokenAmountDifference - ) public bidIsActiveForGroup(_bidId) { + ) public whenForwarderNotPaused bidIsActiveForGroup(_bidId) { //use original principal amount as amountDue @@ -863,7 +870,7 @@ contract LenderCommitmentGroup_Smart is address repayer, uint256 principalAmount, uint256 interestAmount - ) external onlyTellerV2 { + ) external onlyTellerV2 whenForwarderNotPaused { //can use principal amt to increment amt paid back!! nice for math . totalPrincipalTokensRepaid += principalAmount; totalInterestCollected += interestAmount; @@ -883,7 +890,7 @@ contract LenderCommitmentGroup_Smart is If principaltokens get stuck in the escrow vault for any reason, anyone may call this function to move them from that vault in to this contract */ - function withdrawFromEscrowVault ( uint256 _amount ) public { + function withdrawFromEscrowVault ( uint256 _amount ) public whenForwarderNotPaused { address _escrowVault = ITellerV2(TELLER_V2).getEscrowVault(); diff --git a/packages/contracts/contracts/TellerV2.sol b/packages/contracts/contracts/TellerV2.sol index 6ff29413..1182070d 100644 --- a/packages/contracts/contracts/TellerV2.sol +++ b/packages/contracts/contracts/TellerV2.sol @@ -741,7 +741,9 @@ contract TellerV2 is } - + function isPauser(address _account) public view returns(bool){ + return pauserRoleBearer[_account] ; + } function lenderCloseLoan(uint256 _bidId) diff --git a/packages/contracts/contracts/interfaces/ITellerV2.sol b/packages/contracts/contracts/interfaces/ITellerV2.sol index 9837d6da..a930167a 100644 --- a/packages/contracts/contracts/interfaces/ITellerV2.sol +++ b/packages/contracts/contracts/interfaces/ITellerV2.sol @@ -171,4 +171,7 @@ interface ITellerV2 { function getEscrowVault() external view returns(address); + + + function isPauser(address _account) external view returns(bool); } diff --git a/packages/contracts/contracts/mock/TellerV2SolMock.sol b/packages/contracts/contracts/mock/TellerV2SolMock.sol index 798ec74b..341a5b71 100644 --- a/packages/contracts/contracts/mock/TellerV2SolMock.sol +++ b/packages/contracts/contracts/mock/TellerV2SolMock.sol @@ -51,6 +51,10 @@ contract TellerV2SolMock is ITellerV2, IProtocolFee, TellerV2Storage , ILoanRepa } + function isPauser(address _account) public view returns(bool){ + return false; //for now + } + function approveMarketForwarder(uint256 _marketId, address _forwarder) external { diff --git a/packages/contracts/tests/LenderCommitmentForwarder/extensions/SmartCommitments/LenderCommitmentGroup_Smart_Test.sol b/packages/contracts/tests/LenderCommitmentForwarder/extensions/SmartCommitments/LenderCommitmentGroup_Smart_Test.sol index e61c6e93..4af1e40e 100644 --- a/packages/contracts/tests/LenderCommitmentForwarder/extensions/SmartCommitments/LenderCommitmentGroup_Smart_Test.sol +++ b/packages/contracts/tests/LenderCommitmentForwarder/extensions/SmartCommitments/LenderCommitmentGroup_Smart_Test.sol @@ -59,6 +59,7 @@ contract LenderCommitmentGroup_Smart_Test is Testable { _tellerV2 = new TellerV2SolMock(); _smartCommitmentForwarder = new SmartCommitmentForwarder(); + _uniswapV3Pool = new UniswapV3PoolMock(); _uniswapV3Factory = new UniswapV3FactoryMock(); @@ -1080,4 +1081,10 @@ function test_liquidateDefaultedLoanWithIncentive_does_not_double_count_repaid() contract User {} -contract SmartCommitmentForwarder {} \ No newline at end of file +contract SmartCommitmentForwarder { + + function paused() external returns (bool){ + return false; + } + +} \ No newline at end of file From 1b871026c93c0bf4b2d6a44990577eeec85d2a8a Mon Sep 17 00:00:00 2001 From: Admazzola Date: Wed, 3 Jul 2024 14:45:39 -0400 Subject: [PATCH 08/16] can pause liquidations only --- packages/contracts/contracts/TellerV2.sol | 37 ++++++++++++++++--- .../contracts/contracts/TellerV2Storage.sol | 1 + 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/packages/contracts/contracts/TellerV2.sol b/packages/contracts/contracts/TellerV2.sol index 1182070d..429e1c95 100644 --- a/packages/contracts/contracts/TellerV2.sol +++ b/packages/contracts/contracts/TellerV2.sol @@ -174,6 +174,14 @@ contract TellerV2 is } + modifier whenLiquidationsNotPaused() { + require(!liquidationsPaused, "Liquidations are paused"); + + _; + } + + + /** Constant Variables **/ uint8 public constant CURRENT_CODE_VERSION = 10; @@ -718,19 +726,36 @@ contract TellerV2 is } /** - * @notice Lets the DAO/owner of the protocol implement an emergency stop mechanism. + * @notice Lets a pauser of the protocol implement an emergency stop mechanism. */ function pauseProtocol() public virtual onlyPauser whenNotPaused { _pause(); } /** - * @notice Lets the DAO/owner of the protocol undo a previously implemented emergency stop. + * @notice Lets a pauser of the protocol undo a previously implemented emergency stop. */ function unpauseProtocol() public virtual onlyPauser whenPaused { _unpause(); } + + /** + * @notice Lets a pauser of the protocol implement an emergency stop mechanism. + */ + function pauseLiquidations() public virtual onlyPauser { + liquidationsPaused = true; + } + + /** + * @notice Lets a pauser of the protocol undo a previously implemented emergency stop. + */ + function unpauseLiquidations() public virtual onlyPauser { + liquidationsPaused = false; + } + + + function addPauser(address _pauser) public virtual onlyOwner { pauserRoleBearer[_pauser] = true; } @@ -747,7 +772,7 @@ contract TellerV2 is function lenderCloseLoan(uint256 _bidId) - external whenNotPaused + external whenNotPaused whenLiquidationsNotPaused acceptedLoan(_bidId, "lenderClaimCollateral") { Bid storage bid = bids[_bidId]; @@ -763,7 +788,7 @@ contract TellerV2 is function lenderCloseLoanWithRecipient( uint256 _bidId, address _collateralRecipient - ) external whenNotPaused { + ) external whenNotPaused whenLiquidationsNotPaused { _lenderCloseLoanWithRecipient(_bidId, _collateralRecipient); } @@ -790,7 +815,7 @@ contract TellerV2 is * @param _bidId The id of the loan to make the payment towards. */ function liquidateLoanFull(uint256 _bidId) - external whenNotPaused + external whenNotPaused whenLiquidationsNotPaused acceptedLoan(_bidId, "liquidateLoan") { Bid storage bid = bids[_bidId]; @@ -802,7 +827,7 @@ contract TellerV2 is } function liquidateLoanFullWithRecipient(uint256 _bidId, address _recipient) - external whenNotPaused + external whenNotPaused whenLiquidationsNotPaused acceptedLoan(_bidId, "liquidateLoan") { _liquidateLoanFull(_bidId, _recipient); diff --git a/packages/contracts/contracts/TellerV2Storage.sol b/packages/contracts/contracts/TellerV2Storage.sol index df3ea5b3..bbbe8852 100644 --- a/packages/contracts/contracts/TellerV2Storage.sol +++ b/packages/contracts/contracts/TellerV2Storage.sol @@ -164,6 +164,7 @@ abstract contract TellerV2Storage_G6 is TellerV2Storage_G5 { abstract contract TellerV2Storage_G7 is TellerV2Storage_G6 { mapping(address => bool) public pauserRoleBearer; + bool public liquidationsPaused; } abstract contract TellerV2Storage is TellerV2Storage_G7 {} From d22bc2c71c96b94562e9edc5c5c3ce38c4547cdd Mon Sep 17 00:00:00 2001 From: Admazzola Date: Wed, 24 Jul 2024 12:41:57 -0400 Subject: [PATCH 09/16] protocol owner can modify delay time --- .../LenderCommitmentGroup_Smart.sol | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol b/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol index 72481fbd..e8f517c2 100644 --- a/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol +++ b/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol @@ -117,7 +117,7 @@ contract LenderCommitmentGroup_Smart is mapping(address => uint256) public poolSharesPreparedToWithdrawForLender; mapping(address => uint256) public poolSharesPreparedTimestamp; - uint256 immutable public WITHDRAW_DELAY_TIME_SECONDS = 300; + uint256 immutable public DEFAULT_WITHDRAWL_DELAY_TIME_SECONDS = 300; //mapping(address => uint256) public principalTokensCommittedByLender; @@ -128,6 +128,7 @@ contract LenderCommitmentGroup_Smart is int256 tokenDifferenceFromLiquidations; bool public firstDepositMade; + uint256 public withdrawlDelayTimeSeconds; @@ -204,6 +205,15 @@ contract LenderCommitmentGroup_Smart is _; } + + modifier onlyProtocolOwner() { + require( + msg.sender == Ownable(address(TELLER_V2)).owner(), + "Can only be called by TellerV2" + ); + _; + } + modifier bidIsActiveForGroup(uint256 _bidId) { require(activeBids[_bidId] == true, "Bid is not active for group"); @@ -219,6 +229,7 @@ contract LenderCommitmentGroup_Smart is TELLER_V2 = _tellerV2; SMART_COMMITMENT_FORWARDER = _smartCommitmentForwarder; UNISWAP_V3_FACTORY = _uniswapV3Factory; + } /* @@ -257,6 +268,8 @@ contract LenderCommitmentGroup_Smart is marketId = _marketId; + withdrawlDelayTimeSeconds = DEFAULT_WITHDRAWL_DELAY_TIME_SECONDS; + //in order for this to succeed, first, that SmartCommitmentForwarder needs to be THE trusted forwarder for the market @@ -299,6 +312,12 @@ contract LenderCommitmentGroup_Smart is ); } + + function setWithdrawlDelayTime(uint256 _seconds) onlyProtocolOwner { + + withdrawlDelayTimeSeconds = _seconds; + } + function _deployPoolSharesToken() internal onlyInitializing @@ -526,7 +545,7 @@ contract LenderCommitmentGroup_Smart is ) external returns (uint256) { require(poolSharesPreparedToWithdrawForLender[msg.sender] >= _amountPoolSharesTokens,"Shares not prepared for withdraw"); - require(poolSharesPreparedTimestamp[msg.sender] <= block.timestamp - WITHDRAW_DELAY_TIME_SECONDS,"Shares not prepared for withdraw"); + require(poolSharesPreparedTimestamp[msg.sender] <= block.timestamp - withdrawlDelayTimeSeconds,"Shares not prepared for withdraw"); poolSharesPreparedToWithdrawForLender[msg.sender] = 0; From d35939d0218708173c2c48409e3ae0d580024a37 Mon Sep 17 00:00:00 2001 From: andy Date: Wed, 28 Aug 2024 11:19:33 -0400 Subject: [PATCH 10/16] clean up --- .../LenderCommitmentGroup_Smart.sol | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol b/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol index 72481fbd..c8b596d2 100644 --- a/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol +++ b/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol @@ -210,6 +210,13 @@ contract LenderCommitmentGroup_Smart is _; } + modifier whenForwarderNotPaused() { + require( PausableUpgradeable(address(SMART_COMMITMENT_FORWARDER)).paused() == false , "Protocol is paused"); + _; + } + + + /// @custom:oz-upgrades-unsafe-allow constructor constructor( address _tellerV2, @@ -374,7 +381,7 @@ contract LenderCommitmentGroup_Smart is uint256 _amount, address _sharesRecipient, uint256 _minSharesAmountOut - ) external returns (uint256 sharesAmount_) { + ) external whenForwarderNotPaused returns (uint256 sharesAmount_) { //transfers the primary principal token from msg.sender into this contract escrow @@ -402,8 +409,10 @@ contract LenderCommitmentGroup_Smart is poolSharesToken.mint(_sharesRecipient, sharesAmount_); - //reset prepared amount - poolSharesPreparedToWithdrawForLender[msg.sender] = 0; + // prepare current balance + uint256 sharesBalance = poolSharesToken.balanceOf(address(this)); + _prepareSharesForWithdraw(sharesBalance); + emit LenderAddedPrincipal( @@ -445,7 +454,7 @@ contract LenderCommitmentGroup_Smart is uint256 _collateralTokenId, uint32 _loanDuration, uint16 _interestRate - ) external onlySmartCommitmentForwarder whenNotPaused { + ) external onlySmartCommitmentForwarder whenForwarderNotPaused { require( _collateralTokenAddress == address(collateralToken), @@ -505,17 +514,25 @@ contract LenderCommitmentGroup_Smart is function prepareSharesForWithdraw( uint256 _amountPoolSharesTokens - ) external returns (bool) { + ) external whenForwarderNotPaused returns (bool) { + + return _prepareSharesForWithdraw(_amountPoolSharesTokens); + } + + + function _prepareSharesForWithdraw( + uint256 _amountPoolSharesTokens + ) internal returns (bool) { require( poolSharesToken.balanceOf(msg.sender) >= _amountPoolSharesTokens ); poolSharesPreparedToWithdrawForLender[msg.sender] = _amountPoolSharesTokens; - poolSharesPreparedTimestamp[msg.sender] = block.timestamp; - + poolSharesPreparedTimestamp[msg.sender] = block.timestamp; return true; } + /* */ @@ -523,14 +540,14 @@ contract LenderCommitmentGroup_Smart is uint256 _amountPoolSharesTokens, address _recipient, uint256 _minAmountOut - ) external returns (uint256) { + ) external whenForwarderNotPaused returns (uint256) { require(poolSharesPreparedToWithdrawForLender[msg.sender] >= _amountPoolSharesTokens,"Shares not prepared for withdraw"); require(poolSharesPreparedTimestamp[msg.sender] <= block.timestamp - WITHDRAW_DELAY_TIME_SECONDS,"Shares not prepared for withdraw"); poolSharesPreparedToWithdrawForLender[msg.sender] = 0; - poolSharesPreparedTimestamp[msg.sender] = 0; + poolSharesPreparedTimestamp[msg.sender] = block.timestamp; //this should compute BEFORE shares burn @@ -566,7 +583,7 @@ contract LenderCommitmentGroup_Smart is function liquidateDefaultedLoanWithIncentive( uint256 _bidId, int256 _tokenAmountDifference - ) public bidIsActiveForGroup(_bidId) { + ) public whenForwarderNotPaused bidIsActiveForGroup(_bidId) { //use original principal amount as amountDue @@ -863,7 +880,7 @@ contract LenderCommitmentGroup_Smart is address repayer, uint256 principalAmount, uint256 interestAmount - ) external onlyTellerV2 { + ) external onlyTellerV2 whenForwarderNotPaused { //can use principal amt to increment amt paid back!! nice for math . totalPrincipalTokensRepaid += principalAmount; totalInterestCollected += interestAmount; @@ -883,7 +900,7 @@ contract LenderCommitmentGroup_Smart is If principaltokens get stuck in the escrow vault for any reason, anyone may call this function to move them from that vault in to this contract */ - function withdrawFromEscrowVault ( uint256 _amount ) public { + function withdrawFromEscrowVault ( uint256 _amount ) public whenForwarderNotPaused { address _escrowVault = ITellerV2(TELLER_V2).getEscrowVault(); From 6d7e2717b3378c418180bb49de9fb24610ab31e3 Mon Sep 17 00:00:00 2001 From: andy Date: Wed, 28 Aug 2024 11:27:01 -0400 Subject: [PATCH 11/16] remove code from other pr --- .../LenderCommitmentGroup_Smart.sol | 29 +++++++------------ 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol b/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol index c8b596d2..d1252ddb 100644 --- a/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol +++ b/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol @@ -210,13 +210,6 @@ contract LenderCommitmentGroup_Smart is _; } - modifier whenForwarderNotPaused() { - require( PausableUpgradeable(address(SMART_COMMITMENT_FORWARDER)).paused() == false , "Protocol is paused"); - _; - } - - - /// @custom:oz-upgrades-unsafe-allow constructor constructor( address _tellerV2, @@ -381,7 +374,7 @@ contract LenderCommitmentGroup_Smart is uint256 _amount, address _sharesRecipient, uint256 _minSharesAmountOut - ) external whenForwarderNotPaused returns (uint256 sharesAmount_) { + ) external returns (uint256 sharesAmount_) { //transfers the primary principal token from msg.sender into this contract escrow @@ -407,7 +400,8 @@ contract LenderCommitmentGroup_Smart is //mint shares equal to _amount and give them to the shares recipient !!! poolSharesToken.mint(_sharesRecipient, sharesAmount_); - + + // prepare current balance uint256 sharesBalance = poolSharesToken.balanceOf(address(this)); @@ -454,7 +448,7 @@ contract LenderCommitmentGroup_Smart is uint256 _collateralTokenId, uint32 _loanDuration, uint16 _interestRate - ) external onlySmartCommitmentForwarder whenForwarderNotPaused { + ) external onlySmartCommitmentForwarder whenNotPaused { require( _collateralTokenAddress == address(collateralToken), @@ -514,12 +508,10 @@ contract LenderCommitmentGroup_Smart is function prepareSharesForWithdraw( uint256 _amountPoolSharesTokens - ) external whenForwarderNotPaused returns (bool) { - + ) external returns (bool) { return _prepareSharesForWithdraw(_amountPoolSharesTokens); } - function _prepareSharesForWithdraw( uint256 _amountPoolSharesTokens ) internal returns (bool) { @@ -532,7 +524,6 @@ contract LenderCommitmentGroup_Smart is } - /* */ @@ -540,14 +531,14 @@ contract LenderCommitmentGroup_Smart is uint256 _amountPoolSharesTokens, address _recipient, uint256 _minAmountOut - ) external whenForwarderNotPaused returns (uint256) { + ) external returns (uint256) { require(poolSharesPreparedToWithdrawForLender[msg.sender] >= _amountPoolSharesTokens,"Shares not prepared for withdraw"); require(poolSharesPreparedTimestamp[msg.sender] <= block.timestamp - WITHDRAW_DELAY_TIME_SECONDS,"Shares not prepared for withdraw"); poolSharesPreparedToWithdrawForLender[msg.sender] = 0; - poolSharesPreparedTimestamp[msg.sender] = block.timestamp; + poolSharesPreparedTimestamp[msg.sender] = block.timestamp; //this should compute BEFORE shares burn @@ -583,7 +574,7 @@ contract LenderCommitmentGroup_Smart is function liquidateDefaultedLoanWithIncentive( uint256 _bidId, int256 _tokenAmountDifference - ) public whenForwarderNotPaused bidIsActiveForGroup(_bidId) { + ) public bidIsActiveForGroup(_bidId) { //use original principal amount as amountDue @@ -880,7 +871,7 @@ contract LenderCommitmentGroup_Smart is address repayer, uint256 principalAmount, uint256 interestAmount - ) external onlyTellerV2 whenForwarderNotPaused { + ) external onlyTellerV2 { //can use principal amt to increment amt paid back!! nice for math . totalPrincipalTokensRepaid += principalAmount; totalInterestCollected += interestAmount; @@ -900,7 +891,7 @@ contract LenderCommitmentGroup_Smart is If principaltokens get stuck in the escrow vault for any reason, anyone may call this function to move them from that vault in to this contract */ - function withdrawFromEscrowVault ( uint256 _amount ) public whenForwarderNotPaused { + function withdrawFromEscrowVault ( uint256 _amount ) public { address _escrowVault = ITellerV2(TELLER_V2).getEscrowVault(); From 4e4a6c1a6431a6ec3e8f5bffe4e633aa8b11e503 Mon Sep 17 00:00:00 2001 From: Admazzola Date: Wed, 28 Aug 2024 14:40:41 -0400 Subject: [PATCH 12/16] fix fn --- .../LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol b/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol index b88b5ed6..f84f6edf 100644 --- a/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol +++ b/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol @@ -320,7 +320,9 @@ contract LenderCommitmentGroup_Smart is } - function setWithdrawlDelayTime(uint256 _seconds) onlyProtocolOwner { + function setWithdrawlDelayTime(uint256 _seconds) + external + onlyProtocolOwner { withdrawlDelayTimeSeconds = _seconds; } From 81760610d9b3b73ba1b9e47f5904a6befa825fa9 Mon Sep 17 00:00:00 2001 From: Admazzola Date: Wed, 28 Aug 2024 14:57:11 -0400 Subject: [PATCH 13/16] add factory --- .../LenderCommitmentGroup_Factory.sol | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Factory.sol diff --git a/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Factory.sol b/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Factory.sol new file mode 100644 index 00000000..61b827d4 --- /dev/null +++ b/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Factory.sol @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +// Contracts +import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +// Interfaces +import "../../../interfaces/ITellerV2.sol"; +import "../../../interfaces/IProtocolFee.sol"; +import "../../../interfaces/ITellerV2Storage.sol"; +//import "../../../interfaces/ILenderCommitmentForwarder.sol"; +import "../../../libraries/NumbersLib.sol"; + +import "./LenderCommitmentGroup_Smart.sol"; +//import {CreateCommitmentArgs} from "../../interfaces/ILenderCommitmentGroup.sol"; + +import { ILenderCommitmentGroup } from "../../../interfaces/ILenderCommitmentGroup.sol"; + +contract LenderCommitmentGroupFactory { + using AddressUpgradeable for address; + using NumbersLib for uint256; + + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + ITellerV2 public immutable TELLER_V2; + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address public immutable SMART_COMMITMENT_FORWARDER; + address public immutable UNISWAP_V3_FACTORY; + + mapping(address => uint256) public deployedLenderGroupContracts; + + event DeployedLenderGroupContract(address indexed groupContract); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor( + address _tellerV2, + address _smartCommitmentForwarder, + address _uniswapV3Factory + ) { + TELLER_V2 = ITellerV2(_tellerV2); + SMART_COMMITMENT_FORWARDER = _smartCommitmentForwarder; + UNISWAP_V3_FACTORY = _uniswapV3Factory; + } + + /* + This should deploy a new lender commitment group pool contract. + It will use create commitment args in order to define the pool contracts parameters such as its primary principal token. + Shares will be distributed at a 1:1 ratio of the primary principal token so if 1e18 raw WETH are deposited, the depositor gets 1e18 shares for the group pool. + */ + function deployLenderCommitmentGroupPool( + uint256 _initialPrincipalAmount, + address _principalTokenAddress, + address _collateralTokenAddress, + uint256 _marketId, + uint32 _maxLoanDuration, + uint16 _interestRateLowerBound, + uint16 _interestRateUpperBound, + uint16 _liquidityThresholdPercent, + uint16 _loanToValuePercent, + uint24 _uniswapPoolFee, + uint32 _twapInterval + ) external returns (address newGroupContract_) { + //these should be upgradeable proxies ??? + newGroupContract_ = address( + new LenderCommitmentGroup_Smart( + address(TELLER_V2), + address(SMART_COMMITMENT_FORWARDER), + address(UNISWAP_V3_FACTORY) + ) + ); + + deployedLenderGroupContracts[newGroupContract_] = block.number; //consider changing this ? + emit DeployedLenderGroupContract(newGroupContract_); + + /* + The max principal should be a very high number! higher than usual + The expiration time should be far in the future! farther than usual + */ + ILenderCommitmentGroup(newGroupContract_).initialize( + _principalTokenAddress, + _collateralTokenAddress, + _marketId, + _maxLoanDuration, + _interestRateLowerBound, + _interestRateUpperBound, + _liquidityThresholdPercent, + _loanToValuePercent, + _uniswapPoolFee, + _twapInterval + ); + + //it is not absolutely necessary to have this call here but it allows the user to potentially save a tx step so it is nice to have . + if (_initialPrincipalAmount > 0) { + //should pull in the creators initial committed principal tokens . + + //send the initial principal tokens to _newgroupcontract here ! + // so it will have them for addPrincipalToCommitmentGroup which will pull them from here + + IERC20(_principalTokenAddress).transferFrom( + msg.sender, + address(this), + _initialPrincipalAmount + ); + IERC20(_principalTokenAddress).approve( + address(newGroupContract_), + _initialPrincipalAmount + ); + + address sharesRecipient = msg.sender; + + + + uint256 sharesAmount_ = ILenderCommitmentGroup(newGroupContract_) + .addPrincipalToCommitmentGroup( + _initialPrincipalAmount, + sharesRecipient, + 0 //_minShares + ); + } + } +} From c220b0d1bd5ceaf97a143696808aa584963d11f2 Mon Sep 17 00:00:00 2001 From: Admazzola Date: Thu, 29 Aug 2024 12:38:05 -0400 Subject: [PATCH 14/16] remove get metadata to save space --- packages/contracts/contracts/TellerV2.sol | 24 +------------------ .../contracts/tests/GetMetaDataURI_Test.sol | 3 ++- .../tests/TellerV2/TellerV2_getData.sol | 3 ++- 3 files changed, 5 insertions(+), 25 deletions(-) diff --git a/packages/contracts/contracts/TellerV2.sol b/packages/contracts/contracts/TellerV2.sol index 429e1c95..d219a239 100644 --- a/packages/contracts/contracts/TellerV2.sol +++ b/packages/contracts/contracts/TellerV2.sol @@ -265,29 +265,7 @@ contract TellerV2 is escrowVault = IEscrowVault(_escrowVault); } - /** - * @notice Gets the metadataURI for a bidId. - * @param _bidId The id of the bid to return the metadataURI for - * @return metadataURI_ The metadataURI for the bid, as a string. - */ - function getMetadataURI(uint256 _bidId) - public - view - returns (string memory metadataURI_) - { - // Check uri mapping first - metadataURI_ = uris[_bidId]; - // If the URI is not present in the mapping - if ( - keccak256(abi.encodePacked(metadataURI_)) == - 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 // hardcoded constant of keccak256('') - ) { - // Return deprecated bytes32 uri as a string - uint256 convertedURI = uint256(bids[_bidId]._metadataURI); - metadataURI_ = StringsUpgradeable.toHexString(convertedURI, 32); - } - } - + /** * @notice Function for a borrower to create a bid for a loan without Collateral. * @param _lendingToken The lending token asset requested to be borrowed. diff --git a/packages/contracts/tests/GetMetaDataURI_Test.sol b/packages/contracts/tests/GetMetaDataURI_Test.sol index da24125d..4b449410 100644 --- a/packages/contracts/tests/GetMetaDataURI_Test.sol +++ b/packages/contracts/tests/GetMetaDataURI_Test.sol @@ -15,6 +15,7 @@ contract GetMetaDataURI_Test is Testable, TellerV2 { uris[59] = "ipfs://QmMyDataHash"; } + /* function test_getMetaDataURI() public { string memory oldURI = getMetadataURI(0); assertEq( @@ -28,5 +29,5 @@ contract GetMetaDataURI_Test is Testable, TellerV2 { "ipfs://QmMyDataHash", "Expected URI does not match new value in uri mapping" ); - } + } */ } diff --git a/packages/contracts/tests/TellerV2/TellerV2_getData.sol b/packages/contracts/tests/TellerV2/TellerV2_getData.sol index 84f1f621..efd7e9a6 100644 --- a/packages/contracts/tests/TellerV2/TellerV2_getData.sol +++ b/packages/contracts/tests/TellerV2/TellerV2_getData.sol @@ -90,6 +90,7 @@ contract TellerV2_initialize is Testable { ); } +/* function test_getMetadataURI_without_mapping() public { uint256 bidId = 1; setMockBid(1); @@ -112,7 +113,7 @@ contract TellerV2_initialize is Testable { string memory uri = tellerV2.getMetadataURI(bidId); assertEq(uri, "0x1234"); - } + }*/ function test_isLoanLiquidateable_with_valid_bid() public { uint256 bidId = 1; From c129468b5597ac8b6e977a376dafe6216c629b11 Mon Sep 17 00:00:00 2001 From: Admazzola Date: Mon, 9 Sep 2024 09:52:48 -0400 Subject: [PATCH 15/16] fix prep --- .../LenderCommitmentGroup_Smart.sol | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol b/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol index f84f6edf..8040168c 100644 --- a/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol +++ b/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol @@ -188,6 +188,13 @@ contract LenderCommitmentGroup_Smart is uint256 totalInterestCollected ); + event PoolSharesPrepared( + address lender, + uint256 sharesAmount, + uint256 preparedAt + + ); + modifier onlySmartCommitmentForwarder() { require( @@ -432,7 +439,7 @@ contract LenderCommitmentGroup_Smart is // prepare current balance - uint256 sharesBalance = poolSharesToken.balanceOf(address(this)); + uint256 sharesBalance = poolSharesToken.balanceOf(address(_sharesRecipient)); _prepareSharesForWithdraw(sharesBalance); @@ -549,6 +556,17 @@ contract LenderCommitmentGroup_Smart is poolSharesPreparedToWithdrawForLender[msg.sender] = _amountPoolSharesTokens; poolSharesPreparedTimestamp[msg.sender] = block.timestamp; + + + emit PoolSharesPrepared( + + msg.sender, + _amountPoolSharesTokens, + block.timestamp + + ); + + return true; } From 8b5cf0e2637df9600148efabfd7300f2eab1bf84 Mon Sep 17 00:00:00 2001 From: Admazzola Date: Mon, 9 Sep 2024 10:01:28 -0400 Subject: [PATCH 16/16] fix shares prep --- .../LenderCommitmentGroup_Smart.sol | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol b/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol index 8040168c..6afa9311 100644 --- a/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol +++ b/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol @@ -440,7 +440,7 @@ contract LenderCommitmentGroup_Smart is // prepare current balance uint256 sharesBalance = poolSharesToken.balanceOf(address(_sharesRecipient)); - _prepareSharesForWithdraw(sharesBalance); + _prepareSharesForWithdraw(_sharesRecipient,sharesBalance); emit LenderAddedPrincipal( @@ -544,23 +544,24 @@ contract LenderCommitmentGroup_Smart is function prepareSharesForWithdraw( uint256 _amountPoolSharesTokens ) external whenForwarderNotPaused returns (bool) { - return _prepareSharesForWithdraw(_amountPoolSharesTokens); + return _prepareSharesForWithdraw(msg.sender,_amountPoolSharesTokens); } function _prepareSharesForWithdraw( + address _recipient, uint256 _amountPoolSharesTokens ) internal returns (bool) { - require( poolSharesToken.balanceOf(msg.sender) >= _amountPoolSharesTokens ); + require( poolSharesToken.balanceOf(_recipient) >= _amountPoolSharesTokens ); - poolSharesPreparedToWithdrawForLender[msg.sender] = _amountPoolSharesTokens; - poolSharesPreparedTimestamp[msg.sender] = block.timestamp; + poolSharesPreparedToWithdrawForLender[_recipient] = _amountPoolSharesTokens; + poolSharesPreparedTimestamp[_recipient] = block.timestamp; emit PoolSharesPrepared( - msg.sender, + _recipient, _amountPoolSharesTokens, block.timestamp