From 74ee0c41e1c0e1db17cc4ac1c4fda18a974ce078 Mon Sep 17 00:00:00 2001 From: Admazzola Date: Wed, 15 Mar 2023 12:11:34 -0400 Subject: [PATCH 01/15] drafted and compiles --- .../contracts/LenderCommitmentForwarder.sol | 64 +++++++++++-------- .../allowlist/EnumerableSetAllowlist.sol | 57 +++++++++++++++++ .../interfaces/IAllowlistManager.sol | 9 +++ .../interfaces/IEnumerableSetAllowlist.sol | 11 ++++ 4 files changed, 114 insertions(+), 27 deletions(-) create mode 100644 packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol create mode 100644 packages/contracts/contracts/interfaces/IAllowlistManager.sol create mode 100644 packages/contracts/contracts/interfaces/IEnumerableSetAllowlist.sol diff --git a/packages/contracts/contracts/LenderCommitmentForwarder.sol b/packages/contracts/contracts/LenderCommitmentForwarder.sol index afe1ffc2a..31ee82567 100644 --- a/packages/contracts/contracts/LenderCommitmentForwarder.sol +++ b/packages/contracts/contracts/LenderCommitmentForwarder.sol @@ -6,16 +6,22 @@ import "./TellerV2MarketForwarder.sol"; // Interfaces import "./interfaces/ICollateralManager.sol"; + +import "./interfaces/IAllowlistManager.sol"; +import "./interfaces/IEnumerableSetAllowlist.sol"; import { Collateral, CollateralType } from "./interfaces/escrow/ICollateralEscrowV1.sol"; -import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol"; +//import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol"; // Libraries import { MathUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol"; + + + contract LenderCommitmentForwarder is TellerV2MarketForwarder { - using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet; + // using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet; enum CommitmentCollateralType { NONE, // no collateral required @@ -58,8 +64,10 @@ contract LenderCommitmentForwarder is TellerV2MarketForwarder { uint256 commitmentCount; - mapping(uint256 => EnumerableSetUpgradeable.AddressSet) - internal commitmentBorrowersList; + mapping(uint256 => address) + internal __commitmentBorrowersList; //DEPRECATED -> moved to manager + + mapping(uint256 => address) public commitmentAllowListManagers; /** * @notice This event is emitted when a lender's commitment is created. @@ -171,12 +179,13 @@ contract LenderCommitmentForwarder is TellerV2MarketForwarder { /** * @notice Creates a loan commitment from a lender for a market. * @param _commitment The new commitment data expressed as a struct - * @param _borrowerAddressList The array of borrowers that are allowed to accept loans using this commitment + * @param borrowerAllowlistManager The address of the allowlist contract * @return commitmentId_ returns the commitmentId for the created commitment */ function createCommitment( Commitment calldata _commitment, - address[] calldata _borrowerAddressList + // address[] calldata _borrowerAddressList, + address borrowerAllowlistManager ) public returns (uint256 commitmentId_) { commitmentId_ = commitmentCount++; @@ -186,10 +195,11 @@ contract LenderCommitmentForwarder is TellerV2MarketForwarder { ); commitments[commitmentId_] = _commitment; + commitmentAllowListManagers[commitmentId_] = borrowerAllowlistManager; validateCommitment(commitments[commitmentId_]); - _addBorrowersToCommitmentAllowlist(commitmentId_, _borrowerAddressList); + //_addBorrowersToCommitmentAllowlist(commitmentId_, _borrowerAddressList); emit CreatedCommitment( commitmentId_, @@ -241,25 +251,17 @@ contract LenderCommitmentForwarder is TellerV2MarketForwarder { uint256 _commitmentId, address[] calldata _borrowerAddressList ) public commitmentLender(_commitmentId) { - delete commitmentBorrowersList[_commitmentId]; - _addBorrowersToCommitmentAllowlist(_commitmentId, _borrowerAddressList); - } + //delete commitmentBorrowersList[_commitmentId]; + //_addBorrowersToCommitmentAllowlist(_commitmentId, _borrowerAddressList); - /** - * @notice Adds a borrower to the allowlist for a commmitment. - * @param _commitmentId The id of the commitment that will allow the new borrower - * @param _borrowerArray the address array of the borrowers that will be allowed to accept loans using the commitment - */ - function _addBorrowersToCommitmentAllowlist( - uint256 _commitmentId, - address[] calldata _borrowerArray - ) internal { - for (uint256 i = 0; i < _borrowerArray.length; i++) { - commitmentBorrowersList[_commitmentId].add(_borrowerArray[i]); - } - emit UpdatedCommitmentBorrowers(_commitmentId); + address allowlistManager = commitmentAllowListManagers[_commitmentId]; + + IEnumerableSetAllowlist(allowlistManager).setAllowlist(_commitmentId, _borrowerAddressList); + + //emit UpdatedAllowList(_commitmentId); } + /** * @notice Removes the commitment of a lender to a market. * @param _commitmentId The id of the commitment to delete. @@ -269,7 +271,7 @@ contract LenderCommitmentForwarder is TellerV2MarketForwarder { commitmentLender(_commitmentId) { delete commitments[_commitmentId]; - delete commitmentBorrowersList[_commitmentId]; + //delete commitmentBorrowersList[_commitmentId]; emit DeletedCommitment(_commitmentId); } @@ -325,11 +327,19 @@ contract LenderCommitmentForwarder is TellerV2MarketForwarder { "Invalid loan max duration" ); - require( + /* require( commitmentBorrowersList[_commitmentId].length() == 0 || commitmentBorrowersList[_commitmentId].contains(borrower), "unauthorized commitment borrower" + );*/ + + require(commitmentAllowListManagers[_commitmentId] == address(0) || + IAllowlistManager(commitmentAllowListManagers[_commitmentId]).addressIsAllowed( + _commitmentId, borrower + ), + "Borrower not allowlisted" ); + if (_principalAmount > commitment.maxPrincipal) { revert InsufficientCommitmentAllocation({ @@ -446,13 +456,13 @@ contract LenderCommitmentForwarder is TellerV2MarketForwarder { * @param _commitmentId The commitment id for the commitment to query. * @return borrowers_ An array of addresses restricted to accept the commitment. Empty array means unrestricted. */ - function getCommitmentBorrowers(uint256 _commitmentId) + /* function getCommitmentBorrowers(uint256 _commitmentId) external view returns (address[] memory borrowers_) { borrowers_ = commitmentBorrowersList[_commitmentId].values(); - } + }*/ /** * @notice Internal function to submit a bid to the lending protocol using a commitment diff --git a/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol b/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol new file mode 100644 index 000000000..0f48074ce --- /dev/null +++ b/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol @@ -0,0 +1,57 @@ + + +import "../interfaces/IAllowlistManager.sol"; +import "../interfaces/IEnumerableSetAllowlist.sol"; + +import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol"; + + +contract EnumerableSetAllowlist is IAllowlistManager,IEnumerableSetAllowlist { + using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet; + + event UpdatedAllowList(uint256 commitmentId); + + address public immutable authorized; + + mapping(uint256 => EnumerableSetUpgradeable.AddressSet) internal allowList; + + modifier onlyAuthorized(){ + require(msg.sender == authorized,"Must be authorized."); + _; + } + + constructor(address _authorized){ + authorized = _authorized; + } + + + function setAllowlist( + uint256 _commitmentId, + address[] calldata _addressList + ) public onlyAuthorized { + delete allowList[_commitmentId]; + _addToAllowlist(_commitmentId, _addressList); + } + + + /** + * @notice Adds a borrower to the allowlist for a commmitment. + * @param _commitmentId The id of the commitment that will allow the new borrower + * @param _addressList the address array that will be allowed to accept loans using the commitment + */ + function _addToAllowlist( + uint256 _commitmentId, + address[] calldata _addressList + ) internal { + for (uint256 i = 0; i < _addressList.length; i++) { + allowList[_commitmentId].add(_addressList[i]); + } + emit UpdatedAllowList(_commitmentId); + } + + + function addressIsAllowed(uint256 _commitmentId, address _account) public returns (bool _allowed) { + _allowed = allowList[_commitmentId].contains(_account); + } + +} \ No newline at end of file diff --git a/packages/contracts/contracts/interfaces/IAllowlistManager.sol b/packages/contracts/contracts/interfaces/IAllowlistManager.sol new file mode 100644 index 000000000..61e058cd9 --- /dev/null +++ b/packages/contracts/contracts/interfaces/IAllowlistManager.sol @@ -0,0 +1,9 @@ + + + +interface IAllowlistManager { + + + function addressIsAllowed(uint256 _commitmentId,address _account) external returns (bool allowed_) ; + +} \ No newline at end of file diff --git a/packages/contracts/contracts/interfaces/IEnumerableSetAllowlist.sol b/packages/contracts/contracts/interfaces/IEnumerableSetAllowlist.sol new file mode 100644 index 000000000..ecf4ed37d --- /dev/null +++ b/packages/contracts/contracts/interfaces/IEnumerableSetAllowlist.sol @@ -0,0 +1,11 @@ + + + +interface IEnumerableSetAllowlist { + + function setAllowlist( + uint256 _commitmentId, + address[] calldata _addressList + ) external; + +} \ No newline at end of file From aa5cbfd40d0ec6296f801122f1f5f9b62c8f4573 Mon Sep 17 00:00:00 2001 From: Admazzola Date: Wed, 15 Mar 2023 12:38:33 -0400 Subject: [PATCH 02/15] tests compile --- .../contracts/mock/AllowlistManagerMock.sol | 11 ++++++++++ .../tests/LenderCommitmentForwarder_Test.sol | 20 ++++++++++++++----- 2 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 packages/contracts/contracts/mock/AllowlistManagerMock.sol diff --git a/packages/contracts/contracts/mock/AllowlistManagerMock.sol b/packages/contracts/contracts/mock/AllowlistManagerMock.sol new file mode 100644 index 000000000..e1ec32612 --- /dev/null +++ b/packages/contracts/contracts/mock/AllowlistManagerMock.sol @@ -0,0 +1,11 @@ + +import "../interfaces/IAllowlistManager.sol"; +contract AllowlistManagerMock is IAllowlistManager { + + + function addressIsAllowed(uint256 _commitmentId, address _account) public returns (bool _allowed) { + return true; + } + + +} diff --git a/packages/contracts/tests/LenderCommitmentForwarder_Test.sol b/packages/contracts/tests/LenderCommitmentForwarder_Test.sol index 64cf1008d..3389f9f6f 100644 --- a/packages/contracts/tests/LenderCommitmentForwarder_Test.sol +++ b/packages/contracts/tests/LenderCommitmentForwarder_Test.sol @@ -16,6 +16,7 @@ import { Collateral, CollateralType } from "../contracts/interfaces/escrow/IColl import { User } from "./Test_Helpers.sol"; import "../contracts/mock/MarketRegistryMock.sol"; +import "../contracts/mock/AllowlistManagerMock.sol"; contract LenderCommitmentForwarder_Test is Testable, LenderCommitmentForwarder { LenderCommitmentForwarderTest_TellerV2Mock private tellerV2Mock; @@ -40,6 +41,8 @@ contract LenderCommitmentForwarder_Test is Testable, LenderCommitmentForwarder { bool submitBidWasCalled; bool submitBidWithCollateralWasCalled; + AllowlistManagerMock allowlistManager; + TestERC20Token principalToken; uint8 constant principalTokenDecimals = 18; @@ -59,13 +62,17 @@ contract LenderCommitmentForwarder_Test is Testable, LenderCommitmentForwarder { ); mockMarketRegistry = MarketRegistryMock(address(getMarketRegistry())); - marketOwner = new LenderCommitmentUser(address(tellerV2Mock), (this)); - borrower = new LenderCommitmentUser(address(tellerV2Mock), (this)); - lender = new LenderCommitmentUser(address(tellerV2Mock), (this)); + allowlistManager = new AllowlistManagerMock(); + + marketOwner = new LenderCommitmentUser(address(tellerV2Mock), (this), address(allowlistManager)); + borrower = new LenderCommitmentUser(address(tellerV2Mock), (this), address(allowlistManager)); + lender = new LenderCommitmentUser(address(tellerV2Mock), (this), address(allowlistManager)); tellerV2Mock.__setMarketOwner(marketOwner); mockMarketRegistry.setMarketOwner(address(marketOwner)); + + //tokenAddress = address(0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174); marketId = 2; maxAmount = 100000000000000000000; @@ -850,12 +857,15 @@ contract LenderCommitmentForwarder_Test is Testable, LenderCommitmentForwarder { contract LenderCommitmentUser is User { LenderCommitmentForwarder public immutable commitmentForwarder; + AllowlistManagerMock allowlistManager; constructor( address _tellerV2, - LenderCommitmentForwarder _commitmentForwarder + LenderCommitmentForwarder _commitmentForwarder, + address _allowlistManager ) User(_tellerV2) { commitmentForwarder = _commitmentForwarder; + allowlistManager = AllowlistManagerMock(_allowlistManager); } function _createCommitment( @@ -865,7 +875,7 @@ contract LenderCommitmentUser is User { return commitmentForwarder.createCommitment( _commitment, - borrowerAddressList + address(allowlistManager) ); } From 11af3583032af651b3ae5bf8f8adfffaf8dbc57b Mon Sep 17 00:00:00 2001 From: Admazzola Date: Wed, 15 Mar 2023 13:02:09 -0400 Subject: [PATCH 03/15] added fix to require legacy commitments with nonzero allowlist to set a manager --- .../contracts/LenderCommitmentForwarder.sol | 19 +- .../tests/EnumerableSetAllowlist_Test.sol | 949 ++++++++++++++++++ .../tests/LenderCommitmentForwarder_Test.sol | 5 +- 3 files changed, 962 insertions(+), 11 deletions(-) create mode 100644 packages/contracts/tests/EnumerableSetAllowlist_Test.sol diff --git a/packages/contracts/contracts/LenderCommitmentForwarder.sol b/packages/contracts/contracts/LenderCommitmentForwarder.sol index 31ee82567..ec86a84c3 100644 --- a/packages/contracts/contracts/LenderCommitmentForwarder.sol +++ b/packages/contracts/contracts/LenderCommitmentForwarder.sol @@ -11,7 +11,7 @@ import "./interfaces/IAllowlistManager.sol"; import "./interfaces/IEnumerableSetAllowlist.sol"; import { Collateral, CollateralType } from "./interfaces/escrow/ICollateralEscrowV1.sol"; -//import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol"; // Libraries import { MathUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol"; @@ -21,7 +21,7 @@ import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20Metadat contract LenderCommitmentForwarder is TellerV2MarketForwarder { - // using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet; + using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet; enum CommitmentCollateralType { NONE, // no collateral required @@ -64,7 +64,7 @@ contract LenderCommitmentForwarder is TellerV2MarketForwarder { uint256 commitmentCount; - mapping(uint256 => address) + mapping(uint256 => EnumerableSetUpgradeable.AddressSet) internal __commitmentBorrowersList; //DEPRECATED -> moved to manager mapping(uint256 => address) public commitmentAllowListManagers; @@ -327,11 +327,12 @@ contract LenderCommitmentForwarder is TellerV2MarketForwarder { "Invalid loan max duration" ); - /* require( - commitmentBorrowersList[_commitmentId].length() == 0 || - commitmentBorrowersList[_commitmentId].contains(borrower), - "unauthorized commitment borrower" - );*/ + require( + __commitmentBorrowersList[_commitmentId].length() == 0 || + commitmentAllowListManagers[_commitmentId] != address(0), + "Commitments with legacy borrower list must now set an allow list manager" + ); + require(commitmentAllowListManagers[_commitmentId] == address(0) || IAllowlistManager(commitmentAllowListManagers[_commitmentId]).addressIsAllowed( @@ -408,6 +409,8 @@ contract LenderCommitmentForwarder is TellerV2MarketForwarder { ); } + + /** * @notice Calculate the amount of collateral required to borrow a loan with _principalAmount of principal * @param _principalAmount The amount of currency to borrow for the loan. diff --git a/packages/contracts/tests/EnumerableSetAllowlist_Test.sol b/packages/contracts/tests/EnumerableSetAllowlist_Test.sol new file mode 100644 index 000000000..a6c8ba161 --- /dev/null +++ b/packages/contracts/tests/EnumerableSetAllowlist_Test.sol @@ -0,0 +1,949 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/utils/Address.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "../contracts/TellerV2MarketForwarder.sol"; + +import "./resolvers/TestERC20Token.sol"; +import "../contracts/TellerV2Context.sol"; + +import { Testable } from "./Testable.sol"; +import { LenderCommitmentForwarder } from "../contracts/LenderCommitmentForwarder.sol"; + +import { Collateral, CollateralType } from "../contracts/interfaces/escrow/ICollateralEscrowV1.sol"; + +import { User } from "./Test_Helpers.sol"; + +import "../contracts/mock/MarketRegistryMock.sol"; +import "../contracts/mock/AllowlistManagerMock.sol"; + +contract EnumerableSetAllowlist_Test is Testable, LenderCommitmentForwarder { + LenderCommitmentForwarderTest_TellerV2Mock private tellerV2Mock; + MarketRegistryMock mockMarketRegistry; + + LenderCommitmentUser private marketOwner; + LenderCommitmentUser private lender; + LenderCommitmentUser private borrower; + + // address tokenAddress; + uint256 marketId; + uint256 maxAmount; + + address[] emptyArray; + address[] borrowersArray; + + uint32 maxLoanDuration; + uint16 minInterestRate; + uint32 expiration; + + bool acceptBidWasCalled; + bool submitBidWasCalled; + bool submitBidWithCollateralWasCalled; + + AllowlistManagerMock allowlistManager; + + TestERC20Token principalToken; + uint8 constant principalTokenDecimals = 18; + + TestERC20Token collateralToken; + uint8 constant collateralTokenDecimals = 6; + + constructor() + LenderCommitmentForwarder( + address(new LenderCommitmentForwarderTest_TellerV2Mock()), ///_protocolAddress + address(new MarketRegistryMock(address(0))) + ) + {} + + function setUp() public { + tellerV2Mock = LenderCommitmentForwarderTest_TellerV2Mock( + address(getTellerV2()) + ); + mockMarketRegistry = MarketRegistryMock(address(getMarketRegistry())); + + allowlistManager = new AllowlistManagerMock(); + + marketOwner = new LenderCommitmentUser(address(tellerV2Mock), (this), address(allowlistManager)); + borrower = new LenderCommitmentUser(address(tellerV2Mock), (this), address(allowlistManager)); + lender = new LenderCommitmentUser(address(tellerV2Mock), (this), address(allowlistManager)); + tellerV2Mock.__setMarketOwner(marketOwner); + + mockMarketRegistry.setMarketOwner(address(marketOwner)); + + + //tokenAddress = address(0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174); + marketId = 2; + maxAmount = 100000000000000000000; + maxLoanDuration = 2480000; + minInterestRate = 3000; + expiration = uint32(block.timestamp) + uint32(64000); + + marketOwner.setTrustedMarketForwarder(marketId, address(this)); + lender.approveMarketForwarder(marketId, address(this)); + + borrowersArray = new address[](1); + borrowersArray[0] = address(borrower); + + principalToken = new TestERC20Token( + "Test Wrapped ETH", + "TWETH", + 0, + principalTokenDecimals + ); + + collateralToken = new TestERC20Token( + "Test USDC", + "TUSDC", + 0, + collateralTokenDecimals + ); + + delete acceptBidWasCalled; + delete submitBidWasCalled; + delete submitBidWithCollateralWasCalled; + + delete commitmentCount; + } + + function _createCommitment( + CommitmentCollateralType _collateralType, + uint256 _maxPrincipalPerCollateral + ) internal returns (Commitment storage commitment_) { + commitment_ = commitments[0]; + commitment_.marketId = marketId; + commitment_.principalTokenAddress = address(principalToken); + commitment_.maxPrincipal = maxAmount; + commitment_.maxDuration = maxLoanDuration; + commitment_.minInterestRate = minInterestRate; + commitment_.expiration = expiration; + commitment_.lender = address(lender); + + commitment_.collateralTokenType = _collateralType; + commitment_.maxPrincipalPerCollateralAmount = + _maxPrincipalPerCollateral * + 10**principalTokenDecimals; + + if (_collateralType == CommitmentCollateralType.ERC20) { + commitment_.collateralTokenAddress = address(collateralToken); + } else if (_collateralType == CommitmentCollateralType.ERC721) { + commitment_.collateralTokenAddress = address( + 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174 + ); + } else if (_collateralType == CommitmentCollateralType.ERC1155) { + commitment_.collateralTokenAddress = address( + 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174 + ); + } + } + + function test_createCommitment() public { + uint256 commitmentId = 0; + + Commitment storage existingCommitment = _createCommitment( + CommitmentCollateralType.ERC20, + 1000e6 * 1e18 + ); + + lender._createCommitment(existingCommitment, emptyArray); + } + + function test_updateCommitment() public { + uint256 commitmentId = 0; + + Commitment storage existingCommitment = _createCommitment( + CommitmentCollateralType.ERC20, + 1000e6 + ); + + assertEq( + address(lender), + existingCommitment.lender, + "Not the owner of created commitment" + ); + + lender._updateCommitment(commitmentId, existingCommitment); + } + + function test_deleteCommitment() public { + uint256 commitmentId = 0; + Commitment storage commitment = _createCommitment( + CommitmentCollateralType.ERC20, + 1000e6 + ); + + assertEq( + commitment.lender, + address(lender), + "Not the owner of created commitment" + ); + + lender._deleteCommitment(commitmentId); + + assertEq( + commitment.lender, + address(0), + "The commitment was not deleted" + ); + } + + function test_acceptCommitment() public { + uint256 commitmentId = 0; + + Commitment storage commitment = _createCommitment( + CommitmentCollateralType.ERC20, + maxAmount + ); + + assertEq( + acceptBidWasCalled, + false, + "Expect accept bid not called before exercise" + ); + + uint256 bidId = borrower._acceptCommitment( + commitmentId, + maxAmount - 100, //principal + maxAmount, //collateralAmount + 0, //collateralTokenId + address(collateralToken), + minInterestRate, + maxLoanDuration + ); + + assertEq( + acceptBidWasCalled, + true, + "Expect accept bid called after exercise" + ); + + assertEq( + commitment.maxPrincipal == 100, + true, + "Commitment max principal was not decremented" + ); + + bidId = borrower._acceptCommitment( + commitmentId, + 100, //principalAmount + 100, //collateralAmount + 0, //collateralTokenId + address(collateralToken), + minInterestRate, + maxLoanDuration + ); + + assertEq(commitment.maxPrincipal == 0, true, "commitment not accepted"); + + bool acceptCommitTwiceFails; + + try + borrower._acceptCommitment( + commitmentId, + 100, //principalAmount + 100, //collateralAmount + 0, //collateralTokenId + address(collateralToken), + minInterestRate, + maxLoanDuration + ) + {} catch { + acceptCommitTwiceFails = true; + } + + assertEq( + acceptCommitTwiceFails, + true, + "Should fail when accepting commit twice" + ); + } + + /* function test_acceptCommitmentWithBorrowersArray_valid() public { + uint256 commitmentId = 0; + + Commitment storage commitment = _createCommitment( + CommitmentCollateralType.ERC20, + maxAmount + ); + + lender._updateCommitmentBorrowers(commitmentId, borrowersArray); + + uint256 bidId = borrower._acceptCommitment( + commitmentId, + 0, //principal + maxAmount, //collateralAmount + 0, //collateralTokenId + address(collateralToken), + minInterestRate, + maxLoanDuration + ); + + assertEq( + acceptBidWasCalled, + true, + "Expect accept bid called after exercise" + ); + } + + function test_acceptCommitmentWithBorrowersArray_invalid() public { + uint256 commitmentId = 0; + + Commitment storage commitment = _createCommitment( + CommitmentCollateralType.ERC20, + maxAmount + ); + + lender._updateCommitmentBorrowers(commitmentId, borrowersArray); + + bool acceptCommitAsMarketOwnerFails; + + try + marketOwner._acceptCommitment( + commitmentId, + 100, //principal + maxAmount, //collateralAmount + 0, //collateralTokenId + address(collateralToken), + minInterestRate, + maxLoanDuration + ) + {} catch { + acceptCommitAsMarketOwnerFails = true; + } + + assertEq( + acceptCommitAsMarketOwnerFails, + true, + "Should fail when accepting as invalid borrower" + ); + + lender._updateCommitmentBorrowers(commitmentId, emptyArray); + + acceptBidWasCalled = false; + + marketOwner._acceptCommitment( + commitmentId, + 0, //principal + maxAmount, //collateralAmount + 0, //collateralTokenId + address(collateralToken), + minInterestRate, + maxLoanDuration + ); + + assertEq( + acceptBidWasCalled, + true, + "Expect accept bid called after exercise" + ); + } + + function test_acceptCommitmentWithBorrowersArray_reset() public { + uint256 commitmentId = 0; + + Commitment storage commitment = _createCommitment( + CommitmentCollateralType.ERC20, + maxAmount + ); + + lender._updateCommitmentBorrowers(commitmentId, borrowersArray); + + lender._updateCommitmentBorrowers(commitmentId, emptyArray); + + marketOwner._acceptCommitment( + commitmentId, + 0, //principal + maxAmount, //collateralAmount + 0, //collateralTokenId + address(collateralToken), + minInterestRate, + maxLoanDuration + ); + + assertEq( + acceptBidWasCalled, + true, + "Expect accept bid called after exercise" + ); + }*/ + + function test_acceptCommitmentFailsWithInsufficientCollateral() public { + uint256 commitmentId = 0; + + Commitment storage commitment = _createCommitment( + CommitmentCollateralType.ERC20, + 1000e6 + ); + + bool failedToAcceptCommitment; + + try + marketOwner._acceptCommitment( + commitmentId, + 100, //principal + 0, //collateralAmount + 0, //collateralTokenId + address(collateralToken), + minInterestRate, + maxLoanDuration + ) + {} catch { + failedToAcceptCommitment = true; + } + + assertEq( + failedToAcceptCommitment, + true, + "Should fail to accept commitment with insufficient collateral" + ); + } + + function test_acceptCommitmentFailsWithInvalidAmount() public { + uint256 commitmentId = 0; + + Commitment storage commitment = _createCommitment( + CommitmentCollateralType.ERC721, + 1000e6 + ); + + bool failedToAcceptCommitment; + + try + marketOwner._acceptCommitment( + commitmentId, + 100, //principal + 2, //collateralAmount + 22, //collateralTokenId + address(collateralToken), + minInterestRate, + maxLoanDuration + ) + {} catch { + failedToAcceptCommitment = true; + } + + assertEq( + failedToAcceptCommitment, + true, + "Should fail to accept commitment with invalid amount for ERC721" + ); + } + + function decrementCommitment_before() public {} + + function test_decrementCommitment() public { + uint256 commitmentId = 0; + uint256 _decrementAmount = 22; + + Commitment storage commitment = _createCommitment( + CommitmentCollateralType.ERC20, + 1000e6 + ); + + _decrementCommitment(commitmentId, _decrementAmount); + + assertEq( + commitment.maxPrincipal == maxAmount - _decrementAmount, + true, + "Commitment max principal was not decremented" + ); + } + + /** + * collateral token = WETH (10**18) + * principal token = USDC (10**6) + * principal = 700 USDC + * max principal per collateral = 500 USDC + */ + + function test_getRequiredCollateral_700_USDC__500_per_WETH() public { + TestERC20Token usdcToken = new TestERC20Token( + "Test USDC", + "TUSDC", + 0, + 6 + ); + + TestERC20Token collateralToken = new TestERC20Token( + "Test Wrapped ETH", + "TWETH", + 0, + 18 + ); + assertEq( + super.getRequiredCollateral( + 700 * (1e6), // 700 USDC loan + 500 * (1e6) * (1e6), // 500 USDC loan allowed per WETH, expanded by principal token decimals + CommitmentCollateralType.ERC20, + address(collateralToken), + address(usdcToken) + ), + 14e17, // 1.4 WETH + "expected 1.4 WETH collateral" + ); + } + + /** + * collateral token = NFT (10**0) + * principal token = USDC (10**6) + * principal = 700 USDC + * max principal per collateral = 500 USDC + */ + function test_getRequiredCollateral_700_USDC_loan__500_per_ERC1155() + public + { + TestERC20Token usdcToken = new TestERC20Token( + "Test USDC", + "TUSDC", + 0, + 6 + ); + + assertEq( + super.getRequiredCollateral( + 700e6, // 700 USDC loan + 500e6 * (10**6) * (10**0), // 500 USDC per NFT + CommitmentCollateralType.ERC1155, + address(0), + address(usdcToken) + ), + 2, // 2 NFTs + "expected 2 NFTs collateral" + ); + } + + /** + * collateral token = NFT (10**0) + * principal token = USDC (10**6) + * principal = 500 USDC + * max principal per collateral = 500 USDC + */ + + function test_getRequiredCollateral_500_USDC_loan__500_per_ERC721() public { + TestERC20Token usdcToken = new TestERC20Token( + "Test USDC", + "TUSDC", + 0, + 6 + ); + + assertEq( + super.getRequiredCollateral( + 500e6, // 7500 USDC loan + 500e6 * (1e6), // 500 USDC per NFT, expanded by principal token decimals + CommitmentCollateralType.ERC721, + address(0), + address(usdcToken) + ), + 1, // 1 NFT + "expected 1 NFT collateral" + ); + } + + /** + * collateral token = USDC (10**6) + * principal token = WETH (10**18) + * principal = 1 WETH + * max principal per collateral = 0.00059 WETH + */ + function test_getRequiredCollateral_1_WETH_loan__00059_per_USDC() public { + TestERC20Token collateralToken = new TestERC20Token( + "Test USDC", + "TUSDC", + 0, + 6 + ); + assertEq( + super.getRequiredCollateral( + 1e18, // 1 WETH loan + 59e13 * (1e18), // 0.00059 WETH per USDC base unit + CommitmentCollateralType.ERC20, + address(collateralToken), + address(principalToken) + ), + 1_694_915_255, // 1,694.915255 USDC (1694.915254237 rounded up to 6 decimals) + "expected 1,694.915255 USDC collateral" + ); + } + + /** + * collateral token = WETH (10**18) + * principal token = USDC (10**6) + * principal = 1000 USDC $ + * max principal per collateral = 1.0 WETH + */ + + function test_getRequiredCollateral_1000_USDC_loan_9_gwei_per_usdc_unit() + public + { + TestERC20Token usdcToken = new TestERC20Token( + "Test USDC", + "TUSDC", + 0, + 6 + ); + + TestERC20Token collateralToken = new TestERC20Token( + "Test WETH", + "TWETH", + 0, + 18 + ); + + assertEq( + super.getRequiredCollateral( + 1000 * (1e6), // 1000 USDC loan //principal + 1e9 * (1e6), // 1000000000 wei per USDC base unit //ratio + CommitmentCollateralType.ERC20, + address(collateralToken), + address(usdcToken) + ), + 1e18, // 1 wETH + "expected 1 ETH required collateral" + ); + } + + /** + * collateral token = WETH (10**18) + * principal token = USDC (10**6) + * principal = 8888 USDC $ + * max principal per collateral = 1 gwei per USDDC base unit + */ + + function test_getRequiredCollateral_8888_USDC_loan__9_gwei_per_usdc_unit() + public + { + TestERC20Token usdcToken = new TestERC20Token( + "Test USDC", + "TUSDC", + 0, + 6 + ); + + TestERC20Token collateralToken = new TestERC20Token( + "Test WETH", + "TWETH", + 0, + 18 + ); + + assertEq( + super.getRequiredCollateral( + 8888 * (1e6), // 8888 USDC loan //principal + 1e9 * (1e6), // 1000000000 wei per USDC base unit //ratio + CommitmentCollateralType.ERC20, + address(collateralToken), + address(usdcToken) + ), + 8888e15, // 8.888 wETH + "expected 1 ETH required collateral" + ); + } + + /** + * collateral token = WETH (10**18) + * principal token = USDC (10**8) + * principal = 8888 USDC + * max principal per collateral = 8888000000 wei per USDC base unit + */ + function test_getRequiredCollateral_8888_USDC_loan__unit() public { + TestERC20Token usdcToken = new TestERC20Token( + "Test USDC", + "TUSDC", + 0, + 6 + ); + + TestERC20Token collateralToken = new TestERC20Token( + "Test WETH", + "TWETH", + 0, + 18 + ); + + assertEq( + super.getRequiredCollateral( + 8888 * (1e6), // 8888 USDC loan //principal + 8888000000 * (1e6), // 8888000000 wei per USDC base unit + CommitmentCollateralType.ERC20, + address(collateralToken), + address(usdcToken) + ), + 1e18, // 1 wETH + "expected 1 ETH required collateral" + ); + } + + /** + * collateral token = USDC (10**6) + * principal token = GWEI (10**9) + * principal = 6 GWEI + * max principal per collateral = 0.00059 USDC per gwei + */ + function test_getRequiredCollateral_6_GWEI_loan__00059_WETH_per_USDC() + public + { + TestERC20Token gweiToken = new TestERC20Token( + "Test USDC", + "TUSDC", + 0, + 9 + ); + + TestERC20Token collateralToken = new TestERC20Token( + "Test USDC", + "TUSDC", + 0, + 6 + ); + assertEq( + super.getRequiredCollateral( + 6 gwei, // 6 GWEI loan + 59e13 * (1e9), // 0.00059 USDC per gwei + CommitmentCollateralType.ERC20, + address(collateralToken), + address(gweiToken) + ), + 11, // 0.000011 USDC (0.000010169 rounded up to 6 decimals) + "expected 0.000011 USDC collateral" + ); + } + + /** + * collateral token = USDC (10**6) + * principal token = WEI (10**0) + * principal = 1 WEI + * max principal per collateral = // 0.00059 WETH per usdc base unit + */ + function test_getRequiredCollateral_1_WEI_loan__00059_WETH_per_USDC() + public + { + TestERC20Token collateralToken = new TestERC20Token( + "Test USDC", + "TUSDC", + 0, + 6 + ); + assertEq( + super.getRequiredCollateral( + 1, // 1 WEI loan + 59e13 * 1e18, // 0.00059 WETH per USDC base unit + CommitmentCollateralType.ERC20, + address(collateralToken), + address(principalToken) + ), + 1, // 0.001695 USDC rounded up + "expected at least 1 unit of collateral" + ); + } + + /** + * collateral token = USDC (10**6) + * principal token = WETH (10**18) + * principal = 1 GWEI + * max principal per collateral = 0.00059 WETH per gwei + */ + function test_getRequiredCollateral_1_GWEI_loan__00059_WETH_per_USDC() + public + { + TestERC20Token collateralToken = new TestERC20Token( + "Test USDC", + "TUSDC", + 0, + 6 + ); + assertEq( + super.getRequiredCollateral( + 1e9, // 1 GWEI loan + 59e13 * 1e18, // 0.00059 WETH per USDC base unit (hence why not multiplying by 1e6) + CommitmentCollateralType.ERC20, + address(collateralToken), + address(principalToken) + ), + 2, + "expected at least 2 units of collateral" + ); + } + + /** + * collateral token = USDC (10**6) + * principal token = WETH (10**18) + * principal = 1 GWEI + * max principal per collateral = 1 wei per usdc $ + */ + function test_getRequiredCollateral_1_wei_loan__1_Wei_per_USDC() public { + TestERC20Token collateralToken = new TestERC20Token( + "Test USDC", + "TUSDC", + 0, + 6 + ); + assertEq( + super.getRequiredCollateral( + 1e9, // 1 gwei + (1 * 1e6) * 1e18, // must provide 1:1 ratio usdc $ to wei + CommitmentCollateralType.ERC20, + address(collateralToken), + address(principalToken) + ), + 1e3 * 1e6, // 1000 usdc $ + "expected at least 1 unit of collateral" + ); + } + + /** + * collateral token = USDC (10**6) + * principal token = WETH (10**18) + * principal = 1 wei + * max principal per collateral = 1 wei per usdc $ + */ + function test_getRequiredCollateral_1_wei_loan__1_Wei_per_USDC_unit() + public + { + TestERC20Token collateralToken = new TestERC20Token( + "Test USDC", + "TUSDC", + 0, + 6 + ); + assertEq( + super.getRequiredCollateral( + 1, // 1 wei + (1 * 1e6) * 1e18, // must provide 1 usdc to get loan of 1 wei, expanded by principal decimals + CommitmentCollateralType.ERC20, + address(collateralToken), + address(principalToken) + ), + 1, // 1 usdc base unit + "expected at least 1 unit of collateral" + ); + } + + /* + Overrider methods for exercise + */ + + function _submitBid(CreateLoanArgs memory, address) + internal + override + returns (uint256 bidId) + { + submitBidWasCalled = true; + return 1; + } + + function _submitBidWithCollateral( + CreateLoanArgs memory, + Collateral[] memory, + address + ) internal override returns (uint256 bidId) { + submitBidWithCollateralWasCalled = true; + return 1; + } + + function _acceptBid(uint256, address) internal override returns (bool) { + acceptBidWasCalled = true; + + assertEq( + submitBidWithCollateralWasCalled, + true, + "Submit bid must be called before accept bid" + ); + + return true; + } +} + +contract LenderCommitmentUser is User { + LenderCommitmentForwarder public immutable commitmentForwarder; + AllowlistManagerMock allowlistManager; + + constructor( + address _tellerV2, + LenderCommitmentForwarder _commitmentForwarder, + address _allowlistManager + ) User(_tellerV2) { + commitmentForwarder = _commitmentForwarder; + allowlistManager = AllowlistManagerMock(_allowlistManager); + } + + function _createCommitment( + LenderCommitmentForwarder.Commitment calldata _commitment, + address[] calldata borrowerAddressList + ) public returns (uint256) { + return + commitmentForwarder.createCommitment( + _commitment, + address(allowlistManager) + ); + } + + function _updateCommitment( + uint256 commitmentId, + LenderCommitmentForwarder.Commitment calldata _commitment + ) public { + commitmentForwarder.updateCommitment(commitmentId, _commitment); + } + + function _updateCommitmentBorrowers( + uint256 commitmentId, + address[] calldata borrowerAddressList + ) public { + commitmentForwarder.updateCommitmentBorrowers( + commitmentId, + borrowerAddressList + ); + } + + function _acceptCommitment( + uint256 commitmentId, + uint256 principal, + uint256 collateralAmount, + uint256 collateralTokenId, + address collateralTokenAddress, + uint16 interestRate, + uint32 loanDuration + ) public returns (uint256) { + return + commitmentForwarder.acceptCommitment( + commitmentId, + principal, + collateralAmount, + collateralTokenId, + collateralTokenAddress, + interestRate, + loanDuration + ); + } + + function _deleteCommitment(uint256 _commitmentId) public { + commitmentForwarder.deleteCommitment(_commitmentId); + } +} + +//Move to a helper file ! +contract LenderCommitmentForwarderTest_TellerV2Mock is TellerV2Context { + constructor() TellerV2Context(address(0)) {} + + function __setMarketOwner(User _marketOwner) external { + marketRegistry = IMarketRegistry( + address(new MarketRegistryMock(address(_marketOwner))) + ); + } + + function getSenderForMarket(uint256 _marketId) + external + view + returns (address) + { + return _msgSenderForMarket(_marketId); + } + + function getDataForMarket(uint256 _marketId) + external + view + returns (bytes calldata) + { + return _msgDataForMarket(_marketId); + } +} diff --git a/packages/contracts/tests/LenderCommitmentForwarder_Test.sol b/packages/contracts/tests/LenderCommitmentForwarder_Test.sol index 3389f9f6f..9834cd6bc 100644 --- a/packages/contracts/tests/LenderCommitmentForwarder_Test.sol +++ b/packages/contracts/tests/LenderCommitmentForwarder_Test.sol @@ -70,7 +70,6 @@ contract LenderCommitmentForwarder_Test is Testable, LenderCommitmentForwarder { tellerV2Mock.__setMarketOwner(marketOwner); mockMarketRegistry.setMarketOwner(address(marketOwner)); - //tokenAddress = address(0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174); @@ -259,7 +258,7 @@ contract LenderCommitmentForwarder_Test is Testable, LenderCommitmentForwarder { ); } - function test_acceptCommitmentWithBorrowersArray_valid() public { + /* function test_acceptCommitmentWithBorrowersArray_valid() public { uint256 commitmentId = 0; Commitment storage commitment = _createCommitment( @@ -366,7 +365,7 @@ contract LenderCommitmentForwarder_Test is Testable, LenderCommitmentForwarder { true, "Expect accept bid called after exercise" ); - } + }*/ function test_acceptCommitmentFailsWithInsufficientCollateral() public { uint256 commitmentId = 0; From 7f871a20d426e97fe99202e93db8abcfbbec25e2 Mon Sep 17 00:00:00 2001 From: Admazzola Date: Wed, 15 Mar 2023 13:21:27 -0400 Subject: [PATCH 04/15] conv to storage --- .../contracts/LenderCommitmentForwarder.sol | 2 +- .../allowlist/EnumerableSetAllowlist.sol | 6 +- .../tests/EnumerableSetAllowlist_Test.sol | 837 +----------------- 3 files changed, 47 insertions(+), 798 deletions(-) diff --git a/packages/contracts/contracts/LenderCommitmentForwarder.sol b/packages/contracts/contracts/LenderCommitmentForwarder.sol index ec86a84c3..e2b1d2b8a 100644 --- a/packages/contracts/contracts/LenderCommitmentForwarder.sol +++ b/packages/contracts/contracts/LenderCommitmentForwarder.sol @@ -327,7 +327,7 @@ contract LenderCommitmentForwarder is TellerV2MarketForwarder { "Invalid loan max duration" ); - require( + require( __commitmentBorrowersList[_commitmentId].length() == 0 || commitmentAllowListManagers[_commitmentId] != address(0), "Commitments with legacy borrower list must now set an allow list manager" diff --git a/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol b/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol index 0f48074ce..c9d135ea9 100644 --- a/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol +++ b/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol @@ -35,14 +35,14 @@ contract EnumerableSetAllowlist is IAllowlistManager,IEnumerableSetAllowlist { /** - * @notice Adds a borrower to the allowlist for a commmitment. + * @notice Adds a addresses to the allowlist for a commmitment. * @param _commitmentId The id of the commitment that will allow the new borrower * @param _addressList the address array that will be allowed to accept loans using the commitment */ function _addToAllowlist( uint256 _commitmentId, address[] calldata _addressList - ) internal { + ) internal virtual { for (uint256 i = 0; i < _addressList.length; i++) { allowList[_commitmentId].add(_addressList[i]); } @@ -50,7 +50,7 @@ contract EnumerableSetAllowlist is IAllowlistManager,IEnumerableSetAllowlist { } - function addressIsAllowed(uint256 _commitmentId, address _account) public returns (bool _allowed) { + function addressIsAllowed(uint256 _commitmentId, address _account) public virtual returns (bool _allowed) { _allowed = allowList[_commitmentId].contains(_account); } diff --git a/packages/contracts/tests/EnumerableSetAllowlist_Test.sol b/packages/contracts/tests/EnumerableSetAllowlist_Test.sol index a6c8ba161..ddc174594 100644 --- a/packages/contracts/tests/EnumerableSetAllowlist_Test.sol +++ b/packages/contracts/tests/EnumerableSetAllowlist_Test.sol @@ -3,261 +3,88 @@ pragma solidity ^0.8.0; import "@openzeppelin/contracts/utils/Address.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import "../contracts/TellerV2MarketForwarder.sol"; - + import "./resolvers/TestERC20Token.sol"; -import "../contracts/TellerV2Context.sol"; - + import { Testable } from "./Testable.sol"; import { LenderCommitmentForwarder } from "../contracts/LenderCommitmentForwarder.sol"; -import { Collateral, CollateralType } from "../contracts/interfaces/escrow/ICollateralEscrowV1.sol"; - + import { User } from "./Test_Helpers.sol"; + +import "../contracts/allowlist/EnumerableSetAllowlist.sol"; -import "../contracts/mock/MarketRegistryMock.sol"; -import "../contracts/mock/AllowlistManagerMock.sol"; - -contract EnumerableSetAllowlist_Test is Testable, LenderCommitmentForwarder { - LenderCommitmentForwarderTest_TellerV2Mock private tellerV2Mock; - MarketRegistryMock mockMarketRegistry; - - LenderCommitmentUser private marketOwner; - LenderCommitmentUser private lender; - LenderCommitmentUser private borrower; - - // address tokenAddress; - uint256 marketId; - uint256 maxAmount; +contract EnumerableSetAllowlist_Test is Testable, EnumerableSetAllowlist { + address[] emptyArray; address[] borrowersArray; - uint32 maxLoanDuration; - uint16 minInterestRate; - uint32 expiration; - - bool acceptBidWasCalled; - bool submitBidWasCalled; - bool submitBidWithCollateralWasCalled; - - AllowlistManagerMock allowlistManager; + User private marketOwner; + User private lender; + User private borrower; - TestERC20Token principalToken; - uint8 constant principalTokenDecimals = 18; + bool addToAllowlistCalled; - TestERC20Token collateralToken; - uint8 constant collateralTokenDecimals = 6; constructor() - LenderCommitmentForwarder( - address(new LenderCommitmentForwarderTest_TellerV2Mock()), ///_protocolAddress - address(new MarketRegistryMock(address(0))) - ) + EnumerableSetAllowlist(address(0)) {} function setUp() public { - tellerV2Mock = LenderCommitmentForwarderTest_TellerV2Mock( - address(getTellerV2()) - ); - mockMarketRegistry = MarketRegistryMock(address(getMarketRegistry())); - - allowlistManager = new AllowlistManagerMock(); + + //allowlistManager = new AllowlistManagerMock(); - marketOwner = new LenderCommitmentUser(address(tellerV2Mock), (this), address(allowlistManager)); - borrower = new LenderCommitmentUser(address(tellerV2Mock), (this), address(allowlistManager)); - lender = new LenderCommitmentUser(address(tellerV2Mock), (this), address(allowlistManager)); - tellerV2Mock.__setMarketOwner(marketOwner); - - mockMarketRegistry.setMarketOwner(address(marketOwner)); - - - //tokenAddress = address(0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174); - marketId = 2; - maxAmount = 100000000000000000000; - maxLoanDuration = 2480000; - minInterestRate = 3000; - expiration = uint32(block.timestamp) + uint32(64000); - - marketOwner.setTrustedMarketForwarder(marketId, address(this)); - lender.approveMarketForwarder(marketId, address(this)); - - borrowersArray = new address[](1); - borrowersArray[0] = address(borrower); - - principalToken = new TestERC20Token( - "Test Wrapped ETH", - "TWETH", - 0, - principalTokenDecimals - ); - - collateralToken = new TestERC20Token( - "Test USDC", - "TUSDC", - 0, - collateralTokenDecimals - ); - - delete acceptBidWasCalled; - delete submitBidWasCalled; - delete submitBidWithCollateralWasCalled; - - delete commitmentCount; - } - - function _createCommitment( - CommitmentCollateralType _collateralType, - uint256 _maxPrincipalPerCollateral - ) internal returns (Commitment storage commitment_) { - commitment_ = commitments[0]; - commitment_.marketId = marketId; - commitment_.principalTokenAddress = address(principalToken); - commitment_.maxPrincipal = maxAmount; - commitment_.maxDuration = maxLoanDuration; - commitment_.minInterestRate = minInterestRate; - commitment_.expiration = expiration; - commitment_.lender = address(lender); - - commitment_.collateralTokenType = _collateralType; - commitment_.maxPrincipalPerCollateralAmount = - _maxPrincipalPerCollateral * - 10**principalTokenDecimals; - - if (_collateralType == CommitmentCollateralType.ERC20) { - commitment_.collateralTokenAddress = address(collateralToken); - } else if (_collateralType == CommitmentCollateralType.ERC721) { - commitment_.collateralTokenAddress = address( - 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174 - ); - } else if (_collateralType == CommitmentCollateralType.ERC1155) { - commitment_.collateralTokenAddress = address( - 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174 - ); - } - } - - function test_createCommitment() public { - uint256 commitmentId = 0; - - Commitment storage existingCommitment = _createCommitment( - CommitmentCollateralType.ERC20, - 1000e6 * 1e18 - ); - - lender._createCommitment(existingCommitment, emptyArray); + borrowersArray = new address[](1); + borrowersArray[0] = address(borrower); + + addToAllowlistCalled = false; } + + function test_setAllowlist() public { - function test_updateCommitment() public { - uint256 commitmentId = 0; - - Commitment storage existingCommitment = _createCommitment( - CommitmentCollateralType.ERC20, - 1000e6 - ); - - assertEq( - address(lender), - existingCommitment.lender, - "Not the owner of created commitment" - ); - - lender._updateCommitment(commitmentId, existingCommitment); - } - - function test_deleteCommitment() public { - uint256 commitmentId = 0; - Commitment storage commitment = _createCommitment( - CommitmentCollateralType.ERC20, - 1000e6 - ); - - assertEq( - commitment.lender, - address(lender), - "Not the owner of created commitment" + super.setAllowlist( + 0, + borrowersArray ); - lender._deleteCommitment(commitmentId); - assertEq( - commitment.lender, - address(0), - "The commitment was not deleted" + addToAllowlistCalled, + true, + "addToAllowlist not called" ); } - function test_acceptCommitment() public { - uint256 commitmentId = 0; - - Commitment storage commitment = _createCommitment( - CommitmentCollateralType.ERC20, - maxAmount - ); + function test_addToAllowlist() public { - assertEq( - acceptBidWasCalled, - false, - "Expect accept bid not called before exercise" + + super._addToAllowlist( + 0, + borrowersArray ); - uint256 bidId = borrower._acceptCommitment( - commitmentId, - maxAmount - 100, //principal - maxAmount, //collateralAmount - 0, //collateralTokenId - address(collateralToken), - minInterestRate, - maxLoanDuration - ); + bool isAllowed = super.addressIsAllowed(0,address(borrower)); assertEq( - acceptBidWasCalled, + isAllowed, true, - "Expect accept bid called after exercise" - ); - - assertEq( - commitment.maxPrincipal == 100, - true, - "Commitment max principal was not decremented" - ); - - bidId = borrower._acceptCommitment( - commitmentId, - 100, //principalAmount - 100, //collateralAmount - 0, //collateralTokenId - address(collateralToken), - minInterestRate, - maxLoanDuration + "Expected borrower to be allowed" ); + } - assertEq(commitment.maxPrincipal == 0, true, "commitment not accepted"); - bool acceptCommitTwiceFails; - try - borrower._acceptCommitment( - commitmentId, - 100, //principalAmount - 100, //collateralAmount - 0, //collateralTokenId - address(collateralToken), - minInterestRate, - maxLoanDuration - ) - {} catch { - acceptCommitTwiceFails = true; - } + //overrides - assertEq( - acceptCommitTwiceFails, - true, - "Should fail when accepting commit twice" - ); + function _addToAllowlist( + uint256 _commitmentId, + address[] calldata _addressList + ) internal override { + addToAllowlistCalled = true; } + + /* function test_acceptCommitmentWithBorrowersArray_valid() public { uint256 commitmentId = 0; @@ -367,583 +194,5 @@ contract EnumerableSetAllowlist_Test is Testable, LenderCommitmentForwarder { ); }*/ - function test_acceptCommitmentFailsWithInsufficientCollateral() public { - uint256 commitmentId = 0; - - Commitment storage commitment = _createCommitment( - CommitmentCollateralType.ERC20, - 1000e6 - ); - - bool failedToAcceptCommitment; - - try - marketOwner._acceptCommitment( - commitmentId, - 100, //principal - 0, //collateralAmount - 0, //collateralTokenId - address(collateralToken), - minInterestRate, - maxLoanDuration - ) - {} catch { - failedToAcceptCommitment = true; - } - - assertEq( - failedToAcceptCommitment, - true, - "Should fail to accept commitment with insufficient collateral" - ); - } - - function test_acceptCommitmentFailsWithInvalidAmount() public { - uint256 commitmentId = 0; - - Commitment storage commitment = _createCommitment( - CommitmentCollateralType.ERC721, - 1000e6 - ); - - bool failedToAcceptCommitment; - - try - marketOwner._acceptCommitment( - commitmentId, - 100, //principal - 2, //collateralAmount - 22, //collateralTokenId - address(collateralToken), - minInterestRate, - maxLoanDuration - ) - {} catch { - failedToAcceptCommitment = true; - } - - assertEq( - failedToAcceptCommitment, - true, - "Should fail to accept commitment with invalid amount for ERC721" - ); - } - - function decrementCommitment_before() public {} - - function test_decrementCommitment() public { - uint256 commitmentId = 0; - uint256 _decrementAmount = 22; - - Commitment storage commitment = _createCommitment( - CommitmentCollateralType.ERC20, - 1000e6 - ); - - _decrementCommitment(commitmentId, _decrementAmount); - - assertEq( - commitment.maxPrincipal == maxAmount - _decrementAmount, - true, - "Commitment max principal was not decremented" - ); - } - /** - * collateral token = WETH (10**18) - * principal token = USDC (10**6) - * principal = 700 USDC - * max principal per collateral = 500 USDC - */ - - function test_getRequiredCollateral_700_USDC__500_per_WETH() public { - TestERC20Token usdcToken = new TestERC20Token( - "Test USDC", - "TUSDC", - 0, - 6 - ); - - TestERC20Token collateralToken = new TestERC20Token( - "Test Wrapped ETH", - "TWETH", - 0, - 18 - ); - assertEq( - super.getRequiredCollateral( - 700 * (1e6), // 700 USDC loan - 500 * (1e6) * (1e6), // 500 USDC loan allowed per WETH, expanded by principal token decimals - CommitmentCollateralType.ERC20, - address(collateralToken), - address(usdcToken) - ), - 14e17, // 1.4 WETH - "expected 1.4 WETH collateral" - ); - } - - /** - * collateral token = NFT (10**0) - * principal token = USDC (10**6) - * principal = 700 USDC - * max principal per collateral = 500 USDC - */ - function test_getRequiredCollateral_700_USDC_loan__500_per_ERC1155() - public - { - TestERC20Token usdcToken = new TestERC20Token( - "Test USDC", - "TUSDC", - 0, - 6 - ); - - assertEq( - super.getRequiredCollateral( - 700e6, // 700 USDC loan - 500e6 * (10**6) * (10**0), // 500 USDC per NFT - CommitmentCollateralType.ERC1155, - address(0), - address(usdcToken) - ), - 2, // 2 NFTs - "expected 2 NFTs collateral" - ); - } - - /** - * collateral token = NFT (10**0) - * principal token = USDC (10**6) - * principal = 500 USDC - * max principal per collateral = 500 USDC - */ - - function test_getRequiredCollateral_500_USDC_loan__500_per_ERC721() public { - TestERC20Token usdcToken = new TestERC20Token( - "Test USDC", - "TUSDC", - 0, - 6 - ); - - assertEq( - super.getRequiredCollateral( - 500e6, // 7500 USDC loan - 500e6 * (1e6), // 500 USDC per NFT, expanded by principal token decimals - CommitmentCollateralType.ERC721, - address(0), - address(usdcToken) - ), - 1, // 1 NFT - "expected 1 NFT collateral" - ); - } - - /** - * collateral token = USDC (10**6) - * principal token = WETH (10**18) - * principal = 1 WETH - * max principal per collateral = 0.00059 WETH - */ - function test_getRequiredCollateral_1_WETH_loan__00059_per_USDC() public { - TestERC20Token collateralToken = new TestERC20Token( - "Test USDC", - "TUSDC", - 0, - 6 - ); - assertEq( - super.getRequiredCollateral( - 1e18, // 1 WETH loan - 59e13 * (1e18), // 0.00059 WETH per USDC base unit - CommitmentCollateralType.ERC20, - address(collateralToken), - address(principalToken) - ), - 1_694_915_255, // 1,694.915255 USDC (1694.915254237 rounded up to 6 decimals) - "expected 1,694.915255 USDC collateral" - ); - } - - /** - * collateral token = WETH (10**18) - * principal token = USDC (10**6) - * principal = 1000 USDC $ - * max principal per collateral = 1.0 WETH - */ - - function test_getRequiredCollateral_1000_USDC_loan_9_gwei_per_usdc_unit() - public - { - TestERC20Token usdcToken = new TestERC20Token( - "Test USDC", - "TUSDC", - 0, - 6 - ); - - TestERC20Token collateralToken = new TestERC20Token( - "Test WETH", - "TWETH", - 0, - 18 - ); - - assertEq( - super.getRequiredCollateral( - 1000 * (1e6), // 1000 USDC loan //principal - 1e9 * (1e6), // 1000000000 wei per USDC base unit //ratio - CommitmentCollateralType.ERC20, - address(collateralToken), - address(usdcToken) - ), - 1e18, // 1 wETH - "expected 1 ETH required collateral" - ); - } - - /** - * collateral token = WETH (10**18) - * principal token = USDC (10**6) - * principal = 8888 USDC $ - * max principal per collateral = 1 gwei per USDDC base unit - */ - - function test_getRequiredCollateral_8888_USDC_loan__9_gwei_per_usdc_unit() - public - { - TestERC20Token usdcToken = new TestERC20Token( - "Test USDC", - "TUSDC", - 0, - 6 - ); - - TestERC20Token collateralToken = new TestERC20Token( - "Test WETH", - "TWETH", - 0, - 18 - ); - - assertEq( - super.getRequiredCollateral( - 8888 * (1e6), // 8888 USDC loan //principal - 1e9 * (1e6), // 1000000000 wei per USDC base unit //ratio - CommitmentCollateralType.ERC20, - address(collateralToken), - address(usdcToken) - ), - 8888e15, // 8.888 wETH - "expected 1 ETH required collateral" - ); - } - - /** - * collateral token = WETH (10**18) - * principal token = USDC (10**8) - * principal = 8888 USDC - * max principal per collateral = 8888000000 wei per USDC base unit - */ - function test_getRequiredCollateral_8888_USDC_loan__unit() public { - TestERC20Token usdcToken = new TestERC20Token( - "Test USDC", - "TUSDC", - 0, - 6 - ); - - TestERC20Token collateralToken = new TestERC20Token( - "Test WETH", - "TWETH", - 0, - 18 - ); - - assertEq( - super.getRequiredCollateral( - 8888 * (1e6), // 8888 USDC loan //principal - 8888000000 * (1e6), // 8888000000 wei per USDC base unit - CommitmentCollateralType.ERC20, - address(collateralToken), - address(usdcToken) - ), - 1e18, // 1 wETH - "expected 1 ETH required collateral" - ); - } - - /** - * collateral token = USDC (10**6) - * principal token = GWEI (10**9) - * principal = 6 GWEI - * max principal per collateral = 0.00059 USDC per gwei - */ - function test_getRequiredCollateral_6_GWEI_loan__00059_WETH_per_USDC() - public - { - TestERC20Token gweiToken = new TestERC20Token( - "Test USDC", - "TUSDC", - 0, - 9 - ); - - TestERC20Token collateralToken = new TestERC20Token( - "Test USDC", - "TUSDC", - 0, - 6 - ); - assertEq( - super.getRequiredCollateral( - 6 gwei, // 6 GWEI loan - 59e13 * (1e9), // 0.00059 USDC per gwei - CommitmentCollateralType.ERC20, - address(collateralToken), - address(gweiToken) - ), - 11, // 0.000011 USDC (0.000010169 rounded up to 6 decimals) - "expected 0.000011 USDC collateral" - ); - } - - /** - * collateral token = USDC (10**6) - * principal token = WEI (10**0) - * principal = 1 WEI - * max principal per collateral = // 0.00059 WETH per usdc base unit - */ - function test_getRequiredCollateral_1_WEI_loan__00059_WETH_per_USDC() - public - { - TestERC20Token collateralToken = new TestERC20Token( - "Test USDC", - "TUSDC", - 0, - 6 - ); - assertEq( - super.getRequiredCollateral( - 1, // 1 WEI loan - 59e13 * 1e18, // 0.00059 WETH per USDC base unit - CommitmentCollateralType.ERC20, - address(collateralToken), - address(principalToken) - ), - 1, // 0.001695 USDC rounded up - "expected at least 1 unit of collateral" - ); - } - - /** - * collateral token = USDC (10**6) - * principal token = WETH (10**18) - * principal = 1 GWEI - * max principal per collateral = 0.00059 WETH per gwei - */ - function test_getRequiredCollateral_1_GWEI_loan__00059_WETH_per_USDC() - public - { - TestERC20Token collateralToken = new TestERC20Token( - "Test USDC", - "TUSDC", - 0, - 6 - ); - assertEq( - super.getRequiredCollateral( - 1e9, // 1 GWEI loan - 59e13 * 1e18, // 0.00059 WETH per USDC base unit (hence why not multiplying by 1e6) - CommitmentCollateralType.ERC20, - address(collateralToken), - address(principalToken) - ), - 2, - "expected at least 2 units of collateral" - ); - } - - /** - * collateral token = USDC (10**6) - * principal token = WETH (10**18) - * principal = 1 GWEI - * max principal per collateral = 1 wei per usdc $ - */ - function test_getRequiredCollateral_1_wei_loan__1_Wei_per_USDC() public { - TestERC20Token collateralToken = new TestERC20Token( - "Test USDC", - "TUSDC", - 0, - 6 - ); - assertEq( - super.getRequiredCollateral( - 1e9, // 1 gwei - (1 * 1e6) * 1e18, // must provide 1:1 ratio usdc $ to wei - CommitmentCollateralType.ERC20, - address(collateralToken), - address(principalToken) - ), - 1e3 * 1e6, // 1000 usdc $ - "expected at least 1 unit of collateral" - ); - } - - /** - * collateral token = USDC (10**6) - * principal token = WETH (10**18) - * principal = 1 wei - * max principal per collateral = 1 wei per usdc $ - */ - function test_getRequiredCollateral_1_wei_loan__1_Wei_per_USDC_unit() - public - { - TestERC20Token collateralToken = new TestERC20Token( - "Test USDC", - "TUSDC", - 0, - 6 - ); - assertEq( - super.getRequiredCollateral( - 1, // 1 wei - (1 * 1e6) * 1e18, // must provide 1 usdc to get loan of 1 wei, expanded by principal decimals - CommitmentCollateralType.ERC20, - address(collateralToken), - address(principalToken) - ), - 1, // 1 usdc base unit - "expected at least 1 unit of collateral" - ); - } - - /* - Overrider methods for exercise - */ - - function _submitBid(CreateLoanArgs memory, address) - internal - override - returns (uint256 bidId) - { - submitBidWasCalled = true; - return 1; - } - - function _submitBidWithCollateral( - CreateLoanArgs memory, - Collateral[] memory, - address - ) internal override returns (uint256 bidId) { - submitBidWithCollateralWasCalled = true; - return 1; - } - - function _acceptBid(uint256, address) internal override returns (bool) { - acceptBidWasCalled = true; - - assertEq( - submitBidWithCollateralWasCalled, - true, - "Submit bid must be called before accept bid" - ); - - return true; - } -} - -contract LenderCommitmentUser is User { - LenderCommitmentForwarder public immutable commitmentForwarder; - AllowlistManagerMock allowlistManager; - - constructor( - address _tellerV2, - LenderCommitmentForwarder _commitmentForwarder, - address _allowlistManager - ) User(_tellerV2) { - commitmentForwarder = _commitmentForwarder; - allowlistManager = AllowlistManagerMock(_allowlistManager); - } - - function _createCommitment( - LenderCommitmentForwarder.Commitment calldata _commitment, - address[] calldata borrowerAddressList - ) public returns (uint256) { - return - commitmentForwarder.createCommitment( - _commitment, - address(allowlistManager) - ); - } - - function _updateCommitment( - uint256 commitmentId, - LenderCommitmentForwarder.Commitment calldata _commitment - ) public { - commitmentForwarder.updateCommitment(commitmentId, _commitment); - } - - function _updateCommitmentBorrowers( - uint256 commitmentId, - address[] calldata borrowerAddressList - ) public { - commitmentForwarder.updateCommitmentBorrowers( - commitmentId, - borrowerAddressList - ); - } - - function _acceptCommitment( - uint256 commitmentId, - uint256 principal, - uint256 collateralAmount, - uint256 collateralTokenId, - address collateralTokenAddress, - uint16 interestRate, - uint32 loanDuration - ) public returns (uint256) { - return - commitmentForwarder.acceptCommitment( - commitmentId, - principal, - collateralAmount, - collateralTokenId, - collateralTokenAddress, - interestRate, - loanDuration - ); - } - - function _deleteCommitment(uint256 _commitmentId) public { - commitmentForwarder.deleteCommitment(_commitmentId); - } -} - -//Move to a helper file ! -contract LenderCommitmentForwarderTest_TellerV2Mock is TellerV2Context { - constructor() TellerV2Context(address(0)) {} - - function __setMarketOwner(User _marketOwner) external { - marketRegistry = IMarketRegistry( - address(new MarketRegistryMock(address(_marketOwner))) - ); - } - - function getSenderForMarket(uint256 _marketId) - external - view - returns (address) - { - return _msgSenderForMarket(_marketId); - } - - function getDataForMarket(uint256 _marketId) - external - view - returns (bytes calldata) - { - return _msgDataForMarket(_marketId); - } } From d96677e653db1273729f3da8a8bfa7bcc711c968 Mon Sep 17 00:00:00 2001 From: Admazzola Date: Wed, 15 Mar 2023 14:50:39 -0400 Subject: [PATCH 05/15] test passes --- .../allowlist/EnumerableSetAllowlist.sol | 14 +- .../tests/EnumerableSetAllowlist_Test.sol | 171 ++++-------------- 2 files changed, 50 insertions(+), 135 deletions(-) diff --git a/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol b/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol index c9d135ea9..60b68deb8 100644 --- a/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol +++ b/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol @@ -29,6 +29,7 @@ contract EnumerableSetAllowlist is IAllowlistManager,IEnumerableSetAllowlist { uint256 _commitmentId, address[] calldata _addressList ) public onlyAuthorized { + delete allowList[_commitmentId]; _addToAllowlist(_commitmentId, _addressList); } @@ -43,6 +44,7 @@ contract EnumerableSetAllowlist is IAllowlistManager,IEnumerableSetAllowlist { uint256 _commitmentId, address[] calldata _addressList ) internal virtual { + for (uint256 i = 0; i < _addressList.length; i++) { allowList[_commitmentId].add(_addressList[i]); } @@ -50,8 +52,16 @@ contract EnumerableSetAllowlist is IAllowlistManager,IEnumerableSetAllowlist { } - function addressIsAllowed(uint256 _commitmentId, address _account) public virtual returns (bool _allowed) { - _allowed = allowList[_commitmentId].contains(_account); + function addressIsAllowed(uint256 _commitmentId, address _account) public virtual returns (bool) { + return allowList[_commitmentId].contains(_account); + } + + function getAllowedAddresses(uint256 _commitmentId) + public + view + returns (address[] memory borrowers_) + { + borrowers_ = allowList[_commitmentId].values(); } } \ No newline at end of file diff --git a/packages/contracts/tests/EnumerableSetAllowlist_Test.sol b/packages/contracts/tests/EnumerableSetAllowlist_Test.sol index ddc174594..67fd0ce4f 100644 --- a/packages/contracts/tests/EnumerableSetAllowlist_Test.sol +++ b/packages/contracts/tests/EnumerableSetAllowlist_Test.sol @@ -6,6 +6,8 @@ import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "./resolvers/TestERC20Token.sol"; +import "forge-std/console.sol"; + import { Testable } from "./Testable.sol"; import { LenderCommitmentForwarder } from "../contracts/LenderCommitmentForwarder.sol"; @@ -20,21 +22,22 @@ contract EnumerableSetAllowlist_Test is Testable, EnumerableSetAllowlist { address[] emptyArray; address[] borrowersArray; - User private marketOwner; - User private lender; - User private borrower; + + AllowlistUser private lender; + AllowlistUser private borrower; bool addToAllowlistCalled; constructor() - EnumerableSetAllowlist(address(0)) + EnumerableSetAllowlist(address(new AllowlistUser(address(this)))) {} function setUp() public { - - //allowlistManager = new AllowlistManagerMock(); + + borrower = new AllowlistUser(address(this)); + borrowersArray = new address[](1); borrowersArray[0] = address(borrower); @@ -43,156 +46,58 @@ contract EnumerableSetAllowlist_Test is Testable, EnumerableSetAllowlist { function test_setAllowlist() public { - super.setAllowlist( - 0, - borrowersArray - ); + + bool isAllowedBefore = addressIsAllowed(0,address(borrower)); assertEq( - addToAllowlistCalled, - true, - "addToAllowlist not called" + isAllowedBefore, + false, + "Expected borrower to be disallowed" ); - } - function test_addToAllowlist() public { - - super._addToAllowlist( + + + AllowlistUser(authorized).call_setAllowList( 0, borrowersArray ); - bool isAllowed = super.addressIsAllowed(0,address(borrower)); + address[] memory allowedBorrowers = super.getAllowedAddresses(0); + + + bool isAllowedAfter = addressIsAllowed(0,address(borrower)); assertEq( - isAllowed, + isAllowedAfter, true, "Expected borrower to be allowed" ); - } - - - //overrides - - function _addToAllowlist( - uint256 _commitmentId, - address[] calldata _addressList - ) internal override { - addToAllowlistCalled = true; + } + + - - - /* function test_acceptCommitmentWithBorrowersArray_valid() public { - uint256 commitmentId = 0; +} - Commitment storage commitment = _createCommitment( - CommitmentCollateralType.ERC20, - maxAmount - ); - lender._updateCommitmentBorrowers(commitmentId, borrowersArray); +contract AllowlistUser { - uint256 bidId = borrower._acceptCommitment( - commitmentId, - 0, //principal - maxAmount, //collateralAmount - 0, //collateralTokenId - address(collateralToken), - minInterestRate, - maxLoanDuration - ); + address allowlistManager; - assertEq( - acceptBidWasCalled, - true, - "Expect accept bid called after exercise" - ); + constructor( address _allowlistManager ){ + allowlistManager = _allowlistManager; } - function test_acceptCommitmentWithBorrowersArray_invalid() public { - uint256 commitmentId = 0; - - Commitment storage commitment = _createCommitment( - CommitmentCollateralType.ERC20, - maxAmount - ); - - lender._updateCommitmentBorrowers(commitmentId, borrowersArray); + function call_setAllowList( + uint256 commitmentId, + address[] memory borrowersArray + ) public { + + EnumerableSetAllowlist(allowlistManager).setAllowlist( 0, borrowersArray ); - bool acceptCommitAsMarketOwnerFails; - - try - marketOwner._acceptCommitment( - commitmentId, - 100, //principal - maxAmount, //collateralAmount - 0, //collateralTokenId - address(collateralToken), - minInterestRate, - maxLoanDuration - ) - {} catch { - acceptCommitAsMarketOwnerFails = true; - } - - assertEq( - acceptCommitAsMarketOwnerFails, - true, - "Should fail when accepting as invalid borrower" - ); - - lender._updateCommitmentBorrowers(commitmentId, emptyArray); - - acceptBidWasCalled = false; - - marketOwner._acceptCommitment( - commitmentId, - 0, //principal - maxAmount, //collateralAmount - 0, //collateralTokenId - address(collateralToken), - minInterestRate, - maxLoanDuration - ); - - assertEq( - acceptBidWasCalled, - true, - "Expect accept bid called after exercise" - ); } + - function test_acceptCommitmentWithBorrowersArray_reset() public { - uint256 commitmentId = 0; - - Commitment storage commitment = _createCommitment( - CommitmentCollateralType.ERC20, - maxAmount - ); - - lender._updateCommitmentBorrowers(commitmentId, borrowersArray); - - lender._updateCommitmentBorrowers(commitmentId, emptyArray); - - marketOwner._acceptCommitment( - commitmentId, - 0, //principal - maxAmount, //collateralAmount - 0, //collateralTokenId - address(collateralToken), - minInterestRate, - maxLoanDuration - ); - - assertEq( - acceptBidWasCalled, - true, - "Expect accept bid called after exercise" - ); - }*/ - - -} +} \ No newline at end of file From d8fe3a2eefb1a66b2a336b9323a81ef54f04a069 Mon Sep 17 00:00:00 2001 From: Admazzola Date: Wed, 15 Mar 2023 16:44:40 -0400 Subject: [PATCH 06/15] adding tests for 721 --- .../contracts/LenderCommitmentForwarder.sol | 4 +- .../contracts/allowlist/ERC721Allowlist.sol | 41 ++++++++++ .../allowlist/EnumerableSetAllowlist.sol | 7 +- .../{ => allowlist}/IAllowlistManager.sol | 0 .../interfaces/allowlist/IERC721Allowlist.sol | 6 ++ .../IEnumerableSetAllowlist.sol | 0 .../contracts/mock/AllowlistManagerMock.sol | 2 +- .../contracts/tests/ERC721Allowlist_Test.sol | 75 +++++++++++++++++++ .../tests/EnumerableSetAllowlist_Test.sol | 2 +- .../tests/LenderCommitmentForwarder_Test.sol | 2 +- packages/contracts/tests/TellerV2_Test.sol | 2 +- .../{resolvers => tokens}/TestERC20Token.sol | 0 .../tests/tokens/TestERC721Token.sol | 19 +++++ 13 files changed, 151 insertions(+), 9 deletions(-) create mode 100644 packages/contracts/contracts/allowlist/ERC721Allowlist.sol rename packages/contracts/contracts/interfaces/{ => allowlist}/IAllowlistManager.sol (100%) create mode 100644 packages/contracts/contracts/interfaces/allowlist/IERC721Allowlist.sol rename packages/contracts/contracts/interfaces/{ => allowlist}/IEnumerableSetAllowlist.sol (100%) create mode 100644 packages/contracts/tests/ERC721Allowlist_Test.sol rename packages/contracts/tests/{resolvers => tokens}/TestERC20Token.sol (100%) create mode 100644 packages/contracts/tests/tokens/TestERC721Token.sol diff --git a/packages/contracts/contracts/LenderCommitmentForwarder.sol b/packages/contracts/contracts/LenderCommitmentForwarder.sol index e2b1d2b8a..75b9d97da 100644 --- a/packages/contracts/contracts/LenderCommitmentForwarder.sol +++ b/packages/contracts/contracts/LenderCommitmentForwarder.sol @@ -7,8 +7,8 @@ import "./TellerV2MarketForwarder.sol"; // Interfaces import "./interfaces/ICollateralManager.sol"; -import "./interfaces/IAllowlistManager.sol"; -import "./interfaces/IEnumerableSetAllowlist.sol"; +import "./interfaces/allowlist/IAllowlistManager.sol"; +import "./interfaces/allowlist/IEnumerableSetAllowlist.sol"; import { Collateral, CollateralType } from "./interfaces/escrow/ICollateralEscrowV1.sol"; import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol"; diff --git a/packages/contracts/contracts/allowlist/ERC721Allowlist.sol b/packages/contracts/contracts/allowlist/ERC721Allowlist.sol new file mode 100644 index 000000000..b005346bf --- /dev/null +++ b/packages/contracts/contracts/allowlist/ERC721Allowlist.sol @@ -0,0 +1,41 @@ + +pragma solidity >=0.8.0 <0.9.0; +// SPDX-License-Identifier: MIT +import "../interfaces/allowlist/IAllowlistManager.sol"; + +import "../interfaces/allowlist/IERC721Allowlist.sol"; + + import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol"; + +contract ERC721Allowlist is IAllowlistManager,IERC721Allowlist { + + event UpdatedAllowList(uint256 commitmentId); + + address public immutable authorized; + IERC721Upgradeable public immutable accessToken; //IERC721 + + + modifier onlyAuthorized(){ + require(msg.sender == authorized,"Must be authorized."); + _; + } + + constructor(address _authorized, address _accessToken){ + authorized = _authorized; + accessToken = IERC721Upgradeable(_accessToken); + } + + function addressIsAllowed(uint256 _commitmentId, address _account) public virtual returns (bool) { + return accessToken.balanceOf(_account) >= 1; + } + + /* + function getAllowedAddresses(uint256 _commitmentId) + public + view + returns (address[] memory borrowers_) + { + borrowers_ = allowList[_commitmentId].values(); + }*/ + +} \ No newline at end of file diff --git a/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol b/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol index 60b68deb8..1fe0e525e 100644 --- a/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol +++ b/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol @@ -1,7 +1,8 @@ +pragma solidity >=0.8.0 <0.9.0; +// SPDX-License-Identifier: MIT - -import "../interfaces/IAllowlistManager.sol"; -import "../interfaces/IEnumerableSetAllowlist.sol"; +import "../interfaces/allowlist/IAllowlistManager.sol"; +import "../interfaces/allowlist/IEnumerableSetAllowlist.sol"; import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol"; diff --git a/packages/contracts/contracts/interfaces/IAllowlistManager.sol b/packages/contracts/contracts/interfaces/allowlist/IAllowlistManager.sol similarity index 100% rename from packages/contracts/contracts/interfaces/IAllowlistManager.sol rename to packages/contracts/contracts/interfaces/allowlist/IAllowlistManager.sol diff --git a/packages/contracts/contracts/interfaces/allowlist/IERC721Allowlist.sol b/packages/contracts/contracts/interfaces/allowlist/IERC721Allowlist.sol new file mode 100644 index 000000000..8bf56c350 --- /dev/null +++ b/packages/contracts/contracts/interfaces/allowlist/IERC721Allowlist.sol @@ -0,0 +1,6 @@ + + +interface IERC721Allowlist { + + +} \ No newline at end of file diff --git a/packages/contracts/contracts/interfaces/IEnumerableSetAllowlist.sol b/packages/contracts/contracts/interfaces/allowlist/IEnumerableSetAllowlist.sol similarity index 100% rename from packages/contracts/contracts/interfaces/IEnumerableSetAllowlist.sol rename to packages/contracts/contracts/interfaces/allowlist/IEnumerableSetAllowlist.sol diff --git a/packages/contracts/contracts/mock/AllowlistManagerMock.sol b/packages/contracts/contracts/mock/AllowlistManagerMock.sol index e1ec32612..cc312a2c8 100644 --- a/packages/contracts/contracts/mock/AllowlistManagerMock.sol +++ b/packages/contracts/contracts/mock/AllowlistManagerMock.sol @@ -1,5 +1,5 @@ -import "../interfaces/IAllowlistManager.sol"; +import "../interfaces/allowlist/IAllowlistManager.sol"; contract AllowlistManagerMock is IAllowlistManager { diff --git a/packages/contracts/tests/ERC721Allowlist_Test.sol b/packages/contracts/tests/ERC721Allowlist_Test.sol new file mode 100644 index 000000000..b40f138ef --- /dev/null +++ b/packages/contracts/tests/ERC721Allowlist_Test.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/utils/Address.sol"; +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; + +import "forge-std/console.sol"; + +import { Testable } from "./Testable.sol"; +import { LenderCommitmentForwarder } from "../contracts/LenderCommitmentForwarder.sol"; + + +import "./tokens/TestERC721Token.sol"; + +import { User } from "./Test_Helpers.sol"; + +import "../contracts/allowlist/ERC721Allowlist.sol"; + +contract EnumerableSetAllowlist_Test is Testable, ERC721Allowlist { + + + + AllowlistUser private lender; + AllowlistUser private borrower; + + + constructor() + ERC721Allowlist(address(new AllowlistUser(address(this))) ,address(new TestERC721Token("TEST","TST")) ) + {} + + function setUp() public { + + borrower = new AllowlistUser(address(this)); + + + } + + function test_addressIsAllowed() public { + + bool allowedBefore = super.addressIsAllowed(0,address(borrower)); + + assertEq( + allowedBefore, + false, + "Expected borrower to be disallowed" + ); + + uint256 tokenId = TestERC721Token(address(accessToken)).mint(address(borrower)); + + + bool allowedAfter = super.addressIsAllowed(0,address(borrower)); + + assertEq( + allowedAfter, + true, + "Expected borrower to be allowed" + ); + } + + +} + + +contract AllowlistUser { + + address allowlistManager; + + constructor( address _allowlistManager ){ + allowlistManager = _allowlistManager; + } + + + + +} \ No newline at end of file diff --git a/packages/contracts/tests/EnumerableSetAllowlist_Test.sol b/packages/contracts/tests/EnumerableSetAllowlist_Test.sol index 67fd0ce4f..f136472b1 100644 --- a/packages/contracts/tests/EnumerableSetAllowlist_Test.sol +++ b/packages/contracts/tests/EnumerableSetAllowlist_Test.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.0; import "@openzeppelin/contracts/utils/Address.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import "./resolvers/TestERC20Token.sol"; +import "./tokens/TestERC20Token.sol"; import "forge-std/console.sol"; diff --git a/packages/contracts/tests/LenderCommitmentForwarder_Test.sol b/packages/contracts/tests/LenderCommitmentForwarder_Test.sol index 9834cd6bc..9e5a6abdc 100644 --- a/packages/contracts/tests/LenderCommitmentForwarder_Test.sol +++ b/packages/contracts/tests/LenderCommitmentForwarder_Test.sol @@ -5,7 +5,7 @@ import "@openzeppelin/contracts/utils/Address.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "../contracts/TellerV2MarketForwarder.sol"; -import "./resolvers/TestERC20Token.sol"; +import "./tokens/TestERC20Token.sol"; import "../contracts/TellerV2Context.sol"; import { Testable } from "./Testable.sol"; diff --git a/packages/contracts/tests/TellerV2_Test.sol b/packages/contracts/tests/TellerV2_Test.sol index 4b69b4af1..6d9553d40 100644 --- a/packages/contracts/tests/TellerV2_Test.sol +++ b/packages/contracts/tests/TellerV2_Test.sol @@ -20,7 +20,7 @@ import { User } from "./Test_Helpers.sol"; import "../contracts/escrow/CollateralEscrowV1.sol"; import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; import "../contracts/LenderCommitmentForwarder.sol"; -import "./resolvers/TestERC20Token.sol"; +import "./tokens/TestERC20Token.sol"; import "../contracts/CollateralManager.sol"; import { Collateral } from "../contracts/interfaces/escrow/ICollateralEscrowV1.sol"; diff --git a/packages/contracts/tests/resolvers/TestERC20Token.sol b/packages/contracts/tests/tokens/TestERC20Token.sol similarity index 100% rename from packages/contracts/tests/resolvers/TestERC20Token.sol rename to packages/contracts/tests/tokens/TestERC20Token.sol diff --git a/packages/contracts/tests/tokens/TestERC721Token.sol b/packages/contracts/tests/tokens/TestERC721Token.sol new file mode 100644 index 000000000..4a62a29aa --- /dev/null +++ b/packages/contracts/tests/tokens/TestERC721Token.sol @@ -0,0 +1,19 @@ +pragma solidity >=0.8.0 <0.9.0; +// SPDX-License-Identifier: MIT + +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; + +contract TestERC721Token is ERC721 { + + uint256 public _totalSupply; + constructor( + string memory _name, + string memory _symbol + ) ERC721(_name, _symbol) { } + + function mint(address recipient) public returns (uint256) { + uint256 tokenId = _totalSupply++; + _mint(recipient, tokenId); + return tokenId; + } +} From 20a2c0875be0dd0d6c8080d9394f7df8703953a4 Mon Sep 17 00:00:00 2001 From: Admazzola Date: Wed, 15 Mar 2023 16:49:01 -0400 Subject: [PATCH 07/15] adding method to update the manager address for a commitment --- .../contracts/LenderCommitmentForwarder.sol | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/contracts/contracts/LenderCommitmentForwarder.sol b/packages/contracts/contracts/LenderCommitmentForwarder.sol index 75b9d97da..1dcb015f3 100644 --- a/packages/contracts/contracts/LenderCommitmentForwarder.sol +++ b/packages/contracts/contracts/LenderCommitmentForwarder.sol @@ -100,6 +100,11 @@ contract LenderCommitmentForwarder is TellerV2MarketForwarder { uint256 tokenAmount ); + event UpdatedAllowlistManager( + uint256 indexed commitmentId, + address manager + ); + /** * @notice This event is emitted when the allowed borrowers for a commitment is updated. * @param commitmentId The id of the commitment that was updated. @@ -242,6 +247,18 @@ contract LenderCommitmentForwarder is TellerV2MarketForwarder { ); } + function updateAllowlistManager( + uint256 _commitmentId, + address _allowlistManager + ) public commitmentLender(_commitmentId) { + + commitmentAllowListManagers[_commitmentId] = _allowlistManager; + + emit UpdatedAllowlistManager(_commitmentId,_allowlistManager); + //emit UpdatedAllowList(_commitmentId); + } + + /** * @notice Updates the borrowers allowed to accept a commitment * @param _commitmentId The Id of the commitment to update. @@ -251,9 +268,7 @@ contract LenderCommitmentForwarder is TellerV2MarketForwarder { uint256 _commitmentId, address[] calldata _borrowerAddressList ) public commitmentLender(_commitmentId) { - //delete commitmentBorrowersList[_commitmentId]; - //_addBorrowersToCommitmentAllowlist(_commitmentId, _borrowerAddressList); - + address allowlistManager = commitmentAllowListManagers[_commitmentId]; IEnumerableSetAllowlist(allowlistManager).setAllowlist(_commitmentId, _borrowerAddressList); From bb0981f7c8d21e4cfd2564cad1b5511287a1fce6 Mon Sep 17 00:00:00 2001 From: Admazzola Date: Wed, 15 Mar 2023 16:49:46 -0400 Subject: [PATCH 08/15] emit second event --- packages/contracts/contracts/LenderCommitmentForwarder.sol | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/contracts/contracts/LenderCommitmentForwarder.sol b/packages/contracts/contracts/LenderCommitmentForwarder.sol index 1dcb015f3..283a5f9e5 100644 --- a/packages/contracts/contracts/LenderCommitmentForwarder.sol +++ b/packages/contracts/contracts/LenderCommitmentForwarder.sol @@ -213,6 +213,11 @@ contract LenderCommitmentForwarder is TellerV2MarketForwarder { _commitment.principalTokenAddress, _commitment.maxPrincipal ); + + emit UpdatedAllowlistManager( + commitmentId_, + borrowerAllowlistManager + ); } /** From 7a0e6f3511859d1f37892d4e024a2a4a4dd80d07 Mon Sep 17 00:00:00 2001 From: andy Date: Thu, 16 Mar 2023 10:15:35 -0400 Subject: [PATCH 09/15] yarn lock --- yarn.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index acdf464b1..897387c36 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8527,7 +8527,7 @@ __metadata: yargs-parser: ^16.1.0 bin: gluegun: bin/gluegun - checksum: 7a45a5a606a1e651c891467a693552b5237f8e90410f9c9daad4621ff0693d1c92b69aa35fc30eccf7c3b92ee724f15fc297e054086cfb312717ef01f48d2290 + checksum: 872685026db07ad1687056a78388f17c6a9bcd22bbf9d99d1e2b21e2d196c6e99a128bcff48063b3f0cf692a4365142fae9dd06cf8c532bc557a45f8ac853308 languageName: node linkType: hard From 18abc29648b3d77c51791cdac1650eaf4ba0fa09 Mon Sep 17 00:00:00 2001 From: andy Date: Thu, 16 Mar 2023 10:44:56 -0400 Subject: [PATCH 10/15] ignore --- .gitignore | 1 + .../contracts/LenderCommitmentForwarder.sol | 2 + .../contracts/allowlist/MasaAllowlist.sol | 41 +++++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 packages/contracts/contracts/allowlist/MasaAllowlist.sol diff --git a/.gitignore b/.gitignore index 209674337..4823e9893 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ **/node_modules packages/contracts/generated +packages/contracts/lib/forge-std packages/contracts/deployments/hardhat packages/contracts/deployments/tenderly packages/contracts/deployments/localhost diff --git a/packages/contracts/contracts/LenderCommitmentForwarder.sol b/packages/contracts/contracts/LenderCommitmentForwarder.sol index 283a5f9e5..83c0818bd 100644 --- a/packages/contracts/contracts/LenderCommitmentForwarder.sol +++ b/packages/contracts/contracts/LenderCommitmentForwarder.sol @@ -264,6 +264,8 @@ contract LenderCommitmentForwarder is TellerV2MarketForwarder { } +//should be able to set this in one tx + /** * @notice Updates the borrowers allowed to accept a commitment * @param _commitmentId The Id of the commitment to update. diff --git a/packages/contracts/contracts/allowlist/MasaAllowlist.sol b/packages/contracts/contracts/allowlist/MasaAllowlist.sol new file mode 100644 index 000000000..b005346bf --- /dev/null +++ b/packages/contracts/contracts/allowlist/MasaAllowlist.sol @@ -0,0 +1,41 @@ + +pragma solidity >=0.8.0 <0.9.0; +// SPDX-License-Identifier: MIT +import "../interfaces/allowlist/IAllowlistManager.sol"; + +import "../interfaces/allowlist/IERC721Allowlist.sol"; + + import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol"; + +contract ERC721Allowlist is IAllowlistManager,IERC721Allowlist { + + event UpdatedAllowList(uint256 commitmentId); + + address public immutable authorized; + IERC721Upgradeable public immutable accessToken; //IERC721 + + + modifier onlyAuthorized(){ + require(msg.sender == authorized,"Must be authorized."); + _; + } + + constructor(address _authorized, address _accessToken){ + authorized = _authorized; + accessToken = IERC721Upgradeable(_accessToken); + } + + function addressIsAllowed(uint256 _commitmentId, address _account) public virtual returns (bool) { + return accessToken.balanceOf(_account) >= 1; + } + + /* + function getAllowedAddresses(uint256 _commitmentId) + public + view + returns (address[] memory borrowers_) + { + borrowers_ = allowList[_commitmentId].values(); + }*/ + +} \ No newline at end of file From 6ab0ffad6c8e9700c888d23a203bc133112fe320 Mon Sep 17 00:00:00 2001 From: andy Date: Fri, 17 Mar 2023 13:14:10 -0400 Subject: [PATCH 11/15] restructure enumerable set allowlist --- .../contracts/LenderCommitmentForwarder.sol | 36 +++++----------- .../contracts/allowlist/ERC721Allowlist.sol | 11 ++--- .../allowlist/EnumerableSetAllowlist.sol | 16 ++++---- .../contracts/allowlist/MasaAllowlist.sol | 41 ------------------- .../contracts/allowlist/OpenAllowlist.sol | 20 +++++++++ .../interfaces/ILenderCommitmentForwarder.sol | 9 ++++ .../contracts/tests/ERC721Allowlist_Test.sol | 2 +- .../tests/EnumerableSetAllowlist_Test.sol | 7 +--- .../tests/LenderCommitmentForwarder_Test.sol | 10 ----- 9 files changed, 55 insertions(+), 97 deletions(-) delete mode 100644 packages/contracts/contracts/allowlist/MasaAllowlist.sol create mode 100644 packages/contracts/contracts/allowlist/OpenAllowlist.sol create mode 100644 packages/contracts/contracts/interfaces/ILenderCommitmentForwarder.sol diff --git a/packages/contracts/contracts/LenderCommitmentForwarder.sol b/packages/contracts/contracts/LenderCommitmentForwarder.sol index 83c0818bd..56a2ecdaa 100644 --- a/packages/contracts/contracts/LenderCommitmentForwarder.sol +++ b/packages/contracts/contracts/LenderCommitmentForwarder.sol @@ -9,6 +9,9 @@ import "./interfaces/ICollateralManager.sol"; import "./interfaces/allowlist/IAllowlistManager.sol"; import "./interfaces/allowlist/IEnumerableSetAllowlist.sol"; + +import "./interfaces/ILenderCommitmentForwarder.sol"; + import { Collateral, CollateralType } from "./interfaces/escrow/ICollateralEscrowV1.sol"; import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol"; @@ -20,7 +23,7 @@ import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20Metadat -contract LenderCommitmentForwarder is TellerV2MarketForwarder { +contract LenderCommitmentForwarder is TellerV2MarketForwarder, ILenderCommitmentForwarder { using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet; enum CommitmentCollateralType { @@ -147,6 +150,11 @@ contract LenderCommitmentForwarder is TellerV2MarketForwarder { _; } + + function getCommitmentLender(uint256 _commitmentId) public returns (address lender_){ + lender_ = commitments[_commitmentId].lender; + } + function validateCommitment(Commitment storage _commitment) internal { require( _commitment.expiration > uint32(block.timestamp), @@ -189,7 +197,6 @@ contract LenderCommitmentForwarder is TellerV2MarketForwarder { */ function createCommitment( Commitment calldata _commitment, - // address[] calldata _borrowerAddressList, address borrowerAllowlistManager ) public returns (uint256 commitmentId_) { commitmentId_ = commitmentCount++; @@ -252,7 +259,7 @@ contract LenderCommitmentForwarder is TellerV2MarketForwarder { ); } - function updateAllowlistManager( + function updateAllowlistManager( uint256 _commitmentId, address _allowlistManager ) public commitmentLender(_commitmentId) { @@ -260,29 +267,8 @@ contract LenderCommitmentForwarder is TellerV2MarketForwarder { commitmentAllowListManagers[_commitmentId] = _allowlistManager; emit UpdatedAllowlistManager(_commitmentId,_allowlistManager); - //emit UpdatedAllowList(_commitmentId); } - - -//should be able to set this in one tx - - /** - * @notice Updates the borrowers allowed to accept a commitment - * @param _commitmentId The Id of the commitment to update. - * @param _borrowerAddressList The array of borrowers that are allowed to accept loans using this commitment - */ - function updateCommitmentBorrowers( - uint256 _commitmentId, - address[] calldata _borrowerAddressList - ) public commitmentLender(_commitmentId) { - - address allowlistManager = commitmentAllowListManagers[_commitmentId]; - - IEnumerableSetAllowlist(allowlistManager).setAllowlist(_commitmentId, _borrowerAddressList); - - //emit UpdatedAllowList(_commitmentId); - } - + /** * @notice Removes the commitment of a lender to a market. diff --git a/packages/contracts/contracts/allowlist/ERC721Allowlist.sol b/packages/contracts/contracts/allowlist/ERC721Allowlist.sol index b005346bf..a30ab3868 100644 --- a/packages/contracts/contracts/allowlist/ERC721Allowlist.sol +++ b/packages/contracts/contracts/allowlist/ERC721Allowlist.sol @@ -11,17 +11,12 @@ contract ERC721Allowlist is IAllowlistManager,IERC721Allowlist { event UpdatedAllowList(uint256 commitmentId); - address public immutable authorized; + IERC721Upgradeable public immutable accessToken; //IERC721 - - modifier onlyAuthorized(){ - require(msg.sender == authorized,"Must be authorized."); - _; - } + - constructor(address _authorized, address _accessToken){ - authorized = _authorized; + constructor(address _accessToken){ accessToken = IERC721Upgradeable(_accessToken); } diff --git a/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol b/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol index 1fe0e525e..13bac0c55 100644 --- a/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol +++ b/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol @@ -4,6 +4,8 @@ pragma solidity >=0.8.0 <0.9.0; import "../interfaces/allowlist/IAllowlistManager.sol"; import "../interfaces/allowlist/IEnumerableSetAllowlist.sol"; +import "../interfaces/ILenderCommitmentForwarder.sol"; + import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol"; @@ -11,25 +13,25 @@ contract EnumerableSetAllowlist is IAllowlistManager,IEnumerableSetAllowlist { using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet; event UpdatedAllowList(uint256 commitmentId); - - address public immutable authorized; + + address public immutable commitmentManager; mapping(uint256 => EnumerableSetUpgradeable.AddressSet) internal allowList; - modifier onlyAuthorized(){ - require(msg.sender == authorized,"Must be authorized."); + modifier onlyCommitmentOwner(uint256 _commitmentId){ + require(msg.sender == ILenderCommitmentForwarder(commitmentManager).getCommitmentLender(_commitmentId),"Must be the lender of the commitment."); _; } - constructor(address _authorized){ - authorized = _authorized; + constructor(address _commitmentManager){ + commitmentManager = _commitmentManager; } function setAllowlist( uint256 _commitmentId, address[] calldata _addressList - ) public onlyAuthorized { + ) public onlyCommitmentOwner(_commitmentId) { delete allowList[_commitmentId]; _addToAllowlist(_commitmentId, _addressList); diff --git a/packages/contracts/contracts/allowlist/MasaAllowlist.sol b/packages/contracts/contracts/allowlist/MasaAllowlist.sol deleted file mode 100644 index b005346bf..000000000 --- a/packages/contracts/contracts/allowlist/MasaAllowlist.sol +++ /dev/null @@ -1,41 +0,0 @@ - -pragma solidity >=0.8.0 <0.9.0; -// SPDX-License-Identifier: MIT -import "../interfaces/allowlist/IAllowlistManager.sol"; - -import "../interfaces/allowlist/IERC721Allowlist.sol"; - - import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol"; - -contract ERC721Allowlist is IAllowlistManager,IERC721Allowlist { - - event UpdatedAllowList(uint256 commitmentId); - - address public immutable authorized; - IERC721Upgradeable public immutable accessToken; //IERC721 - - - modifier onlyAuthorized(){ - require(msg.sender == authorized,"Must be authorized."); - _; - } - - constructor(address _authorized, address _accessToken){ - authorized = _authorized; - accessToken = IERC721Upgradeable(_accessToken); - } - - function addressIsAllowed(uint256 _commitmentId, address _account) public virtual returns (bool) { - return accessToken.balanceOf(_account) >= 1; - } - - /* - function getAllowedAddresses(uint256 _commitmentId) - public - view - returns (address[] memory borrowers_) - { - borrowers_ = allowList[_commitmentId].values(); - }*/ - -} \ No newline at end of file diff --git a/packages/contracts/contracts/allowlist/OpenAllowlist.sol b/packages/contracts/contracts/allowlist/OpenAllowlist.sol new file mode 100644 index 000000000..04a18a504 --- /dev/null +++ b/packages/contracts/contracts/allowlist/OpenAllowlist.sol @@ -0,0 +1,20 @@ + +pragma solidity >=0.8.0 <0.9.0; +// SPDX-License-Identifier: MIT +import "../interfaces/allowlist/IAllowlistManager.sol"; + + +contract OpenAllowlist is IAllowlistManager { + + event UpdatedAllowList(uint256 commitmentId); + + constructor( ){ + + } + + function addressIsAllowed(uint256, address) public virtual returns (bool) { + return true; + } + + +} \ No newline at end of file diff --git a/packages/contracts/contracts/interfaces/ILenderCommitmentForwarder.sol b/packages/contracts/contracts/interfaces/ILenderCommitmentForwarder.sol new file mode 100644 index 000000000..562131e1f --- /dev/null +++ b/packages/contracts/contracts/interfaces/ILenderCommitmentForwarder.sol @@ -0,0 +1,9 @@ +// SPDX-Licence-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + + +interface ILenderCommitmentForwarder { + + function getCommitmentLender(uint256 _commitmentId) external returns (address lender_); + +} diff --git a/packages/contracts/tests/ERC721Allowlist_Test.sol b/packages/contracts/tests/ERC721Allowlist_Test.sol index b40f138ef..b06183055 100644 --- a/packages/contracts/tests/ERC721Allowlist_Test.sol +++ b/packages/contracts/tests/ERC721Allowlist_Test.sol @@ -25,7 +25,7 @@ contract EnumerableSetAllowlist_Test is Testable, ERC721Allowlist { constructor() - ERC721Allowlist(address(new AllowlistUser(address(this))) ,address(new TestERC721Token("TEST","TST")) ) + ERC721Allowlist(address(new TestERC721Token("TEST","TST")) ) {} function setUp() public { diff --git a/packages/contracts/tests/EnumerableSetAllowlist_Test.sol b/packages/contracts/tests/EnumerableSetAllowlist_Test.sol index f136472b1..40ae4640d 100644 --- a/packages/contracts/tests/EnumerableSetAllowlist_Test.sol +++ b/packages/contracts/tests/EnumerableSetAllowlist_Test.sol @@ -53,12 +53,9 @@ contract EnumerableSetAllowlist_Test is Testable, EnumerableSetAllowlist { isAllowedBefore, false, "Expected borrower to be disallowed" - ); - - - + ); - AllowlistUser(authorized).call_setAllowList( + AllowlistUser(commitmentManager).call_setAllowList( 0, borrowersArray ); diff --git a/packages/contracts/tests/LenderCommitmentForwarder_Test.sol b/packages/contracts/tests/LenderCommitmentForwarder_Test.sol index 9e5a6abdc..a282c56ee 100644 --- a/packages/contracts/tests/LenderCommitmentForwarder_Test.sol +++ b/packages/contracts/tests/LenderCommitmentForwarder_Test.sol @@ -885,16 +885,6 @@ contract LenderCommitmentUser is User { commitmentForwarder.updateCommitment(commitmentId, _commitment); } - function _updateCommitmentBorrowers( - uint256 commitmentId, - address[] calldata borrowerAddressList - ) public { - commitmentForwarder.updateCommitmentBorrowers( - commitmentId, - borrowerAddressList - ); - } - function _acceptCommitment( uint256 commitmentId, uint256 principal, From 6c43d7d6a6ceb477d945d0e7bc6390d378ee2615 Mon Sep 17 00:00:00 2001 From: andy Date: Fri, 17 Mar 2023 13:41:56 -0400 Subject: [PATCH 12/15] trying to call set allowlist --- .../mock/LenderCommitmentForwarderMock.sol | 24 +++++++++++++++++++ .../tests/EnumerableSetAllowlist_Test.sol | 18 ++++++++++---- 2 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 packages/contracts/contracts/mock/LenderCommitmentForwarderMock.sol diff --git a/packages/contracts/contracts/mock/LenderCommitmentForwarderMock.sol b/packages/contracts/contracts/mock/LenderCommitmentForwarderMock.sol new file mode 100644 index 000000000..a37be6cd6 --- /dev/null +++ b/packages/contracts/contracts/mock/LenderCommitmentForwarderMock.sol @@ -0,0 +1,24 @@ +pragma solidity ^0.8.0; + +// SPDX-License-Identifier: MIT + +import "../interfaces/ILenderCommitmentForwarder.sol"; + +contract LenderCommitmentForwarderMock is ILenderCommitmentForwarder { + + address lender; + + function setLender(address _lender) public { + _lender = lender; + } + + function getCommitmentLender(uint256 _commitmentId) external returns (address lender_){ + + return lender; + + } + + + + +} diff --git a/packages/contracts/tests/EnumerableSetAllowlist_Test.sol b/packages/contracts/tests/EnumerableSetAllowlist_Test.sol index 40ae4640d..3dedc14de 100644 --- a/packages/contracts/tests/EnumerableSetAllowlist_Test.sol +++ b/packages/contracts/tests/EnumerableSetAllowlist_Test.sol @@ -15,6 +15,7 @@ import { LenderCommitmentForwarder } from "../contracts/LenderCommitmentForwarde import { User } from "./Test_Helpers.sol"; import "../contracts/allowlist/EnumerableSetAllowlist.sol"; +import "../contracts/mock/LenderCommitmentForwarderMock.sol"; contract EnumerableSetAllowlist_Test is Testable, EnumerableSetAllowlist { @@ -28,18 +29,22 @@ contract EnumerableSetAllowlist_Test is Testable, EnumerableSetAllowlist { bool addToAllowlistCalled; + LenderCommitmentForwarderMock lenderCommitmentForwarderMock; + constructor() - EnumerableSetAllowlist(address(new AllowlistUser(address(this)))) + EnumerableSetAllowlist(address( new LenderCommitmentForwarderMock() )) {} - function setUp() public { - + function setUp() public { + borrower = new AllowlistUser(address(this)); - borrower = new AllowlistUser(address(this)); borrowersArray = new address[](1); borrowersArray[0] = address(borrower); + + LenderCommitmentForwarderMock( commitmentManager ).setLender(address(lender)); + addToAllowlistCalled = false; } @@ -54,8 +59,11 @@ contract EnumerableSetAllowlist_Test is Testable, EnumerableSetAllowlist { false, "Expected borrower to be disallowed" ); + + + - AllowlistUser(commitmentManager).call_setAllowList( + AllowlistUser(lender).call_setAllowList( 0, borrowersArray ); From 9b69489f3099449327e25baad38a205d6d2ed120 Mon Sep 17 00:00:00 2001 From: andy Date: Fri, 17 Mar 2023 13:55:59 -0400 Subject: [PATCH 13/15] tests pass --- .../contracts/allowlist/EnumerableSetAllowlist.sol | 4 +++- .../contracts/mock/LenderCommitmentForwarderMock.sol | 6 +++--- packages/contracts/tests/EnumerableSetAllowlist_Test.sol | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol b/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol index 13bac0c55..1eec01075 100644 --- a/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol +++ b/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol @@ -31,7 +31,9 @@ contract EnumerableSetAllowlist is IAllowlistManager,IEnumerableSetAllowlist { function setAllowlist( uint256 _commitmentId, address[] calldata _addressList - ) public onlyCommitmentOwner(_commitmentId) { + ) public + onlyCommitmentOwner(_commitmentId) + { delete allowList[_commitmentId]; _addToAllowlist(_commitmentId, _addressList); diff --git a/packages/contracts/contracts/mock/LenderCommitmentForwarderMock.sol b/packages/contracts/contracts/mock/LenderCommitmentForwarderMock.sol index a37be6cd6..e545f4f9e 100644 --- a/packages/contracts/contracts/mock/LenderCommitmentForwarderMock.sol +++ b/packages/contracts/contracts/mock/LenderCommitmentForwarderMock.sol @@ -9,12 +9,12 @@ contract LenderCommitmentForwarderMock is ILenderCommitmentForwarder { address lender; function setLender(address _lender) public { - _lender = lender; + lender = _lender; } - function getCommitmentLender(uint256 _commitmentId) external returns (address lender_){ + function getCommitmentLender(uint256 _commitmentId) external returns (address){ - return lender; + return lender; } diff --git a/packages/contracts/tests/EnumerableSetAllowlist_Test.sol b/packages/contracts/tests/EnumerableSetAllowlist_Test.sol index 3dedc14de..e6d268169 100644 --- a/packages/contracts/tests/EnumerableSetAllowlist_Test.sol +++ b/packages/contracts/tests/EnumerableSetAllowlist_Test.sol @@ -38,6 +38,7 @@ contract EnumerableSetAllowlist_Test is Testable, EnumerableSetAllowlist { function setUp() public { borrower = new AllowlistUser(address(this)); + lender = new AllowlistUser(address(this)); borrowersArray = new address[](1); @@ -60,8 +61,8 @@ contract EnumerableSetAllowlist_Test is Testable, EnumerableSetAllowlist { "Expected borrower to be disallowed" ); - - + LenderCommitmentForwarderMock( commitmentManager ).setLender(address(lender)); + AllowlistUser(lender).call_setAllowList( 0, From 58cc5304b495911406e0d453819f9c6e58d27fda Mon Sep 17 00:00:00 2001 From: andy Date: Fri, 17 Mar 2023 13:59:20 -0400 Subject: [PATCH 14/15] merge --- packages/contracts/tests/MarketLiquidityRewards_Test.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contracts/tests/MarketLiquidityRewards_Test.sol b/packages/contracts/tests/MarketLiquidityRewards_Test.sol index 3641b86c0..9ebf3c2dc 100644 --- a/packages/contracts/tests/MarketLiquidityRewards_Test.sol +++ b/packages/contracts/tests/MarketLiquidityRewards_Test.sol @@ -5,7 +5,7 @@ import "@openzeppelin/contracts/utils/Address.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "../contracts/TellerV2MarketForwarder.sol"; -import "./resolvers/TestERC20Token.sol"; +import "./tokens/TestERC20Token.sol"; import "../contracts/TellerV2Context.sol"; import { Testable } from "./Testable.sol"; From 2eee3b0892e75e9d50af56054c958c480bb17fbb Mon Sep 17 00:00:00 2001 From: andy Date: Fri, 17 Mar 2023 14:22:48 -0400 Subject: [PATCH 15/15] fix up deploy scripts --- .../allowlist/EnumerableSetAllowlist.sol | 2 +- .../deploy/00_deploy_commitment_allowlists.ts | 38 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 packages/contracts/deploy/00_deploy_commitment_allowlists.ts diff --git a/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol b/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol index 1eec01075..487fa2a35 100644 --- a/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol +++ b/packages/contracts/contracts/allowlist/EnumerableSetAllowlist.sol @@ -33,7 +33,7 @@ contract EnumerableSetAllowlist is IAllowlistManager,IEnumerableSetAllowlist { address[] calldata _addressList ) public onlyCommitmentOwner(_commitmentId) - { + { delete allowList[_commitmentId]; _addToAllowlist(_commitmentId, _addressList); diff --git a/packages/contracts/deploy/00_deploy_commitment_allowlists.ts b/packages/contracts/deploy/00_deploy_commitment_allowlists.ts new file mode 100644 index 000000000..e61778465 --- /dev/null +++ b/packages/contracts/deploy/00_deploy_commitment_allowlists.ts @@ -0,0 +1,38 @@ +import { DeployFunction } from 'hardhat-deploy/dist/types' +import { deploy } from 'helpers/deploy-helpers' + +const deployFn: DeployFunction = async (hre) => { + + + // const tellerV2 = await hre.contracts.get('TellerV2') + const lenderCommitmentForwarder = await hre.contracts.get('LenderCommitmentForwarder') + + + + await deploy({ + contract: 'EnumerableSetAllowlist', + args: [ lenderCommitmentForwarder.address ], + proxy: { + proxyContract: 'OpenZeppelinTransparentProxy', + + }, + skipIfAlreadyDeployed: true, + hre, + }) + + await deploy({ + contract: 'OpenAllowlist', + args: [ ], + proxy: { + proxyContract: 'OpenZeppelinTransparentProxy', + + }, + skipIfAlreadyDeployed: true, + hre, + }) +} + +// tags and deployment +deployFn.tags = ['commitment-allowlists'] +deployFn.dependencies = ['teller-v2'] +export default deployFn